423. 从英文中重建数字
最初思路
首先要有一个指针,对于3/4/5为一组地跳跃。起初想的是后瞻性,如果符合0-9任意,则更换index、跳跃。此时写了一个函数,用来判断s的截取段和0-9中有无符合。这个思路并没有进行下去,虽然可行,但满地补丁、没有美感,代码量和耗时耗空间量实在太大了。
顺便一提,除了two和six的ascii码量相同外,其他的都各自不同。也可以通过这个来比较,额外判断一下是two还是six。
boolean isMatch(String s,String t){int lenS = s.length();int lenT = t.length();if(lenS!=lenT){return false;}else{IntStream S = s.codePoints().sorted();IntStream T = t.codePoints().sorted();if(S.allMatch((IntPredicate) T)){return true;}else{return false;}}}
解法一、独特标识
计数每个字母的出现次数。使用唯一标识符来确定每个数字的数量。例如,"z" 只出现在 "zero" 中,所以可以用它来确定 0 的数量。逐步减少每个字母的计数,直到恢复所有的数字。
其余见注释,digitOrder里取出偶数放前面很重要
class Solution {public String originalDigits(String s) {// 数字单词与其唯一标识符String[] digits = {"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine"};char[] uniqueChars = {'z', 'o', 'w', 't', 'u', 'f', 'x', 's', 'g', 'i'};int[] digitOrder = {0, 2, 4, 6, 8, 1, 3, 5, 7, 9};//02468是具有唯一标识符的数字,奇数是除去前面后有唯一标识符的数字,所以处理顺序自动去了冗余。这里其实有表驱动思想。int[] charCount = new int[26]; // 记录每个字母的出现次数for (char c : s.toCharArray()) {charCount[c - 'a']++;}int[] digitCount = new int[10];//数字的出现计数for (int i = 0; i < 10; i++) {int digit = digitOrder[I];//判断数字char uniqueChar = uniqueChars[digit];//取特殊符int count = charCount[uniqueChar - 'a'];//count标识出现了几次digitCount[digit] = count;//最后计数for (char c : digits[digit].toCharArray()) {//也是表驱动。对于该单词,出现次数里减掉它的所有。charCount[c - 'a'] -= count;}}StringBuilder result = new StringBuilder();//把数字按升序加进去for (int i = 0; i < 10; i++) {while (digitCount[i]-- > 0) {result.append(i);}}return result.toString();}
}
657. 机器人能否返回原点
解法一、x、y坐标模拟
也就是说要模拟机器人移动。面朝方向无所谓,只需要考虑坐标。但是如果模拟二维数组,空间耗费太大了,它实则只需要考虑x坐标和y坐标。不妨直接设俩坐标,判断改换完在不在原点。
本质上是字符统计问题。即R、L出现的次数一致,U、D出现的次数一致。
class Solution {public boolean judgeCircle(String moves) {int len = moves.length();int x = 0;int y = 0;if(len % 2 == 1){//如果是奇数,那么直接返回。return false;}for(int i = 0; i< len;i++){switch (moves.charAt(i)){case'R':x++;break;case'L':x--;break;case'U':y--;break;case'D':y++;break;}}if(x == 0 && y==0){return true;}else{return false;}}
}
551. 学生出勤记录 I
解法一、遍历按条件求解
只需要考虑A和L的情况,分别是计数和后视两位
class Solution {public boolean checkRecord(String s) {int len = s.length();int countA = 0;//记录缺勤次数for(int i = 0;i < len;i++){if(s.charAt(i) == 'A'){countA++;if(countA >1){return false;}}else if(s.charAt(i) == 'L' && len - i > 2){if(s.charAt(i+1) == 'L' && s.charAt(i+2) == 'L'){return false;}}}return true;}
}
解法二、api战士
A第一次出现的下标与最后一次出现的下标比较,并判断是否含有LLL
class Solution {public boolean checkRecord(String s) {return (s.indexOf('A')==s.lastIndexOf('A')) && (!s.contains("LLL"));}
}
696. 计数二进制子串
解法一、分组统计,取最小值
感觉也是脑筋急转弯题。不像简单的。
如"001110",分组统计为231,取2和3的最小2,取3和1的最小1,2+1=3个最小子串
class Solution {public static int countBinarySubstrings(String s) {int len = s.length();int count = 1;if(len == 1)return 0;List<Integer> counts = new ArrayList<>();for(int i = 1;i<len;i++){if(i < len &&s.charAt(i-1) == s.charAt(i)){count++;}else{counts.add(count);count = 1;}}counts.add(count);int sum = 0;for (int i = 1; i < counts.size(); i++) {sum += Math.min(counts.get(i - 1), counts.get(i));}return sum;}
}
解法一的优化版本
对于counts[i],我们只需要和上一个进行比较。所以可以优化掉counts
class Solution {public int countBinarySubstrings(String s) {int ptr = 0, n = s.length(), last = 0, ans = 0;while (ptr < n) {char c = s.charAt(ptr);int count = 0;while (ptr < n && s.charAt(ptr) == c) {++ptr;++count;}ans += Math.min(count, last);last = count;}return ans;}
}作者:力扣官方题解
链接:https://leetcode.cn/problems/count-binary-substrings/solutions/367704/ji-shu-er-jin-zhi-zi-chuan-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
解法二、找"01""10"然后向外扩展
int countBinarySubstrings(string s)
{int i = 0, l = s.size(), sum = 0;while (i < s.size() - 1){if ((s[i] == '0' && s[i + 1] == '1') || (s[i] == '1' && s[i + 1] == '0')){char lov = s[i], hiv = s[i + 1];int lo = i - 1, hi = i + 2;sum++;while (lo >= 0 && hi <= l - 1){if (s[lo] == lov && s[hi] == hiv)sum++;elsebreak;lo--, hi++;}}i++;}return sum;
};
467. 环绕字符串中唯一的子字符串
解法一、动态规划
这个完全没做出来!所以看了题解
感慨一下1或者-25能够这么写好巧妙(a-z是-25,其余是1)
class Solution {public int findSubstringInWraproundString(String p) {int[] dp = new int[26];//26个字母的最大子串数int k = 0;for (int i = 0; i < p.length(); ++i) {if (i > 0 && (p.charAt(i) - p.charAt(i - 1) + 26) % 26 == 1) { // 字符之差为 1 或 -25++k;//计数} else {k = 1;//重置k}dp[p.charAt(i) - 'a'] = Math.max(dp[p.charAt(i) - 'a'], k);//取最大值}return Arrays.stream(dp).sum();//返回求和(也是很巧妙的写法,转为输入流}
}作者:力扣官方题解
链接:https://leetcode.cn/problems/unique-substrings-in-wraparound-string/solutions/1514359/huan-rao-zi-fu-chuan-zhong-wei-yi-de-zi-ndvea/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
535. TinyURL 的加密与解密
解法一、不讲武德
双百通关。本来就是想试试,没想到真可以。假如人与人之间多一点信任。。
public class Codec {// Encodes a URL to a shortened URL.public String encode(String longUrl) {return longUrl;}// Decodes a shortened URL to its original URL.public String decode(String shortUrl) {return shortUrl;}
}
解法二、哈希表+独特标识
自设一个id
public class Codec {private Map<Integer, String> dataBase = new HashMap<Integer, String>();private int id;public String encode(String longUrl) {id++;dataBase.put(id, longUrl);return "http://tinyurl.com/" + id;}public String decode(String shortUrl) {int p = shortUrl.lastIndexOf('/') + 1;int key = Integer.parseInt(shortUrl.substring(p));return dataBase.get(key);}
}作者:力扣官方题解
链接:https://leetcode.cn/problems/encode-and-decode-tinyurl/solutions/1630074/tinyurl-de-jia-mi-yu-jie-mi-by-leetcode-ty5yp/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
解法三、哈希生成
将哈希值作为 longUrl 的 key,将键值对 (key,longUrl) 插入数据库 dataBase,然后返回带有 key 的字符串作为 shortUrl。UrlToKey用来避免相同字符串反复哈希冲突的情况
其实相当于对二的id加密。以下是哈希函数
Hash(longUrl)=(∑i=0n−1longUrl[i]×k1i)modk2
public class Codec {static final int K1 = 1117;static final int K2 = 1000000007;//两个合适的质数private Map<Integer, String> dataBase = new HashMap<Integer, String>();
//用来存private Map<String, Integer> urlToKey = new HashMap<String, Integer>();
//public String encode(String longUrl) {if (urlToKey.containsKey(longUrl)) {//如果已经有了,那么return "http://tinyurl.com/" + urlToKey.get(longUrl);}int key = 0;long base = 1;for (int i = 0; i < longUrl.length(); i++) {//哈希函数char c = longUrl.charAt(i);key = (int) ((key + (long) c * base) % K2);base = (base * K1) % K2;}while (dataBase.containsKey(key)) {//如果冲突,则加一key = (key + 1) % K2;}dataBase.put(key, longUrl);//存储urlToKey.put(longUrl, key);//反向存储return "http://tinyurl.com/" + key;}public String decode(String shortUrl) {int p = shortUrl.lastIndexOf('/') + 1;int key = Integer.parseInt(shortUrl.substring(p));return dataBase.get(key);}
}作者:力扣官方题解
链接:https://leetcode.cn/problems/encode-and-decode-tinyurl/solutions/1630074/tinyurl-de-jia-mi-yu-jie-mi-by-leetcode-ty5yp/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
碎碎念
- 几乎每道题都需要简化/找到独特的基准标识。要么独特标识(423),要么分组讨论(696)本质上是遍历→模拟情况、取出需要的信息
- 学会了Array.stream、一些字符串api的用法,了解到了一点动态规划
昨天挺累的,恰逢周日,就放了一天假,今天写起来果然舒服多了。果然人还是得放过自己jpg每天都能打卡固然很厉害,断了一天后没彻底摆烂也很重要啊!共勉~
六道题写了两小时一刻钟,其中还有不少是看了题解。