468. 验证IP地址【中等题】【每日一题】
思路:【模拟】
分情况讨论即可。
代码:
class Solution {
public String validIPAddress(String queryIP) {
String[] ans = {"IPv4","IPv6","Neither"};
if (queryIP.contains(":")){//可能是IPv6
//如果 有 . 肯定不合法
if (queryIP.contains(".")){
return ans[2];
}
//如果结尾为 : 肯定不合法
if (queryIP.charAt(queryIP.length()-1) == ':'){
return ans[2];
}
String[] split = queryIP.split(":");
//如果长度不是8 肯定不合法
if (split.length != 8){
return ans[2];
}
for (String s : split) {
//如果长度不在[1,4]之间 肯定不合法
int n = s.length();
if (n >= 1 && n <= 4){
for (char c : s.toCharArray()) {
if (Character.isDigit(c)){
continue;
}
if (Character.isUpperCase(c)){
//如果是大写字母 且大写字母比F还大 肯定不合法
if (c - 'F' > 0){
return ans[2];
}
}else {//根据输入规则 排除数字之后 不是大写字母 那肯定是小写字母
//如果小写字母比 f 大 肯定不合法
if (c - 'f' > 0){
return ans[2];
}
}
}
}else {
return ans[2];
}
}
//排除了所有可能的不合法的情况之后,程序能走到这里 那说明这个地址是合法的IPv6地址
return ans[1];
}else {//可能是IPv4
//没有 : 说明可能是IPv4 但是那肯定得有 . ,没有 . 的话 那肯定不合法
if (!queryIP.contains(".")){
return ans[2];
}
//如果结尾为 . 肯定不合法
if (queryIP.charAt(queryIP.length()-1) == '.'){
return ans[2];
}
String[] split = queryIP.split("\\.");
//如果长度不是4 那肯定不合法
if (split.length != 4){
return ans[2];
}
for (String s : split) {
//首先对每一段的字符长度进行筛选 IPv4地址每个分段地址要求大于等于0,小于等于255 所以长度区间为 [1,3]
int n = s.length();
if (n >= 1 && n <= 3){
for (char c : s.toCharArray()) {
if (!Character.isDigit(c)){
return ans[2];
}
}
int addr = Integer.parseInt(s);
//排除大于255的情况
if (addr > 255){
return ans[2];
}
//排除前导0
if (n == 2 && s.charAt(0) == '0'){
return ans[2];
}
if (n == 3 && s.charAt(0) == '0'){
return ans[2];
}
}else {
return ans[2];
}
}
//每一段都排除掉不合法的情况后,如果程序能执行到这里 说明这个地址是合法的IPv4地址
return ans[0];
}
}
}
剑指 Offer II 064. 神奇的字典【中等题】
思路:【不使用前缀树】
这题评论区都是前缀树解法,说实话,前缀树看的我脑瓜子疼,这里提供一种非前缀树解法。
代码:
class MagicDictionary {
//村塾神奇字典
List<String> dic;
/** Initialize your data structure here. */
public MagicDictionary() {
//将神奇字典初始化
this.dic = new ArrayList<>();
}
public void buildDict(String[] dictionary) {
//将传入数组存入神奇字典
dic.addAll(Arrays.asList(dictionary));
}
public boolean search(String searchWord) {
int n = searchWord.length();
//是否当前单词是否能通过只换一个字母的方式换成神奇字典中单词的标志位,初始状态为false
boolean flag = false;
//遍历神奇字典
for (String s : dic) {
//取出当前遍历到的单词长度
int sn = s.length();
//当前遍历到的单词长度与传入单词相等,才有继续判断下去的意义
if (sn == n){
//遍历遍历单词和传入单词,比较两个单词的对应字母是否相等
for (int i = 0; i < n; i++) {
//当两个单词仅有一个字母相等时,flag为true
if (s.charAt(i) != searchWord.charAt(i)){
//如果flag为false,说明这是第一个不相等的字母,将flag标记为true
if (!flag){
flag = true;
}else {
//如果flag为true,说明已经遇到过不相等的字母了,现在又遇到不相等字母,说明传入单词不可能仅通过改变一个字母变成遍历单词,于是将flag还原为false,退出当前循环
flag = false;
break;
}
}
}
//当两个单词对应字母比较结束,如果flag为true,说明传入单词可以通过仅改变一个字母变为当前的遍历单词,于是返回true,否则,比较神奇字典中下一个单词
if(flag){
return true;
}
}
}
//如果神奇字典中所有的单词遍历完了也没有返回true,返回false
return false;
}
}
/**
* Your MagicDictionary object will be instantiated and called as such:
* MagicDictionary obj = new MagicDictionary();
* obj.buildDict(dictionary);
* boolean param_2 = obj.search(searchWord);
*/
剑指 Offer II 065. 最短的单词编码【中等题】
思路;【哈希删除】
看评论区又是前缀~ 吐了 还好官解有非前缀树解法,好人一生平安。
代码;
class Solution {
public int minimumLengthEncoding(String[] words) {
//将所有的单词都存入hashset中
Set<String> set = new HashSet<>(Arrays.asList(words));
//遍历words中每一个单词,尝试求出当前单词的所有后缀 如果当前单词的后缀在set中存在,说明单词列表中有单词可以隐藏在本单词后面,从而不用计算在编码长度之内
//于是这个set中与当前单词的后缀重复的单词不用计入长度,将其从set中删除
for (String word : words) {
int n = word.length();
for (int i = 1; i < n; i++) {
set.remove(word.substring(i));
}
}
//经过上述循环之后,set中剩余的单词就是我们需要进行编码的单词,需要使用的长度为 当前单词 + 1(1为 # 字符的长度)
int ans = 0;
for (String s : set) {
ans += s.length() + 1;
}
return ans;
}
}