去重压缩
1047-删除字符串中的所有相邻重复项

题意分析:
解题思路:
- 栈实现。即将入栈元素与栈顶元素进行对比。
- StringBuilder实现。top 指针指向 sb 的‘栈’顶位置。
注意点:
代码:
public String removeDuplicates(String s) {if (s.length() < 2) {return s;}StringBuilder sb = new StringBuilder();int top = -1;for (int i = 0; i < s.length(); i++) {char ch = s.charAt(i);if (top >= 0 && sb.charAt(top) == ch) {sb.deleteCharAt(top);top--;} else {sb.append(ch);top++;}}return sb.toString();}
*1209-删除字符串中的所有相邻重复项II

题意分析:
解题思路:
注意点:
代码:
/*** 用辅助数组记录所有字符位置出现的次数,重复则倒退。* @param s* @param k* @return*/public String removeDuplicates(String s, int k) {StringBuilder sb = new StringBuilder(s);// 记录元素连续出现次数int[] cnts = new int[s.length()];for (int i = 0; i < sb.length(); i++) {if (i == 0 || sb.charAt(i) != sb.charAt(i-1)) {cnts[i] = 1;} else {cnts[i] = cnts[i-1] + 1;if (cnts[i] == k) {sb.delete(i-k+1, i+1);i = i - k;}}}return sb.toString();}/*** 用辅助栈单独记录连续元素出现的次数,重复则倒退。* @param s* @param k* @return*/public String removeDuplicates2(String s, int k) {StringBuilder sb = new StringBuilder(s);// 记录元素连续出现次数Stack<Integer> stack = new Stack<>();for (int i = 0; i < sb.length(); i++) {if (i == 0 || sb.charAt(i) != sb.charAt(i-1)) {stack.push(1);} else {stack.push(stack.pop() + 1);if (stack.peek() == k) {// sb删除重复的k个元素,然后更新i位置继续遍历。sb.delete(i-k+1, i+1);i = i - k;// 栈中等于k的元素出栈stack.pop();}}}return sb.toString();}
*443-压缩字符串

题意分析:
- 思路有点像删除数组中的重复元素,边扫描边更新历史字符,并记录重复字符的长度。
解题思路:
- 双指针原地更新。read 和 write 指针同时走动,read 指针负责向前读取字符,write 指针更新字符扫描记录。
- 时间复杂度:O(n)。
- 空间复杂度:O(1)。
注意点:
- 字符如果出现一次则不需要记录次数,超过十次需要分别每个元素的值。
代码:
/*** 双指针。读指针和写指针,read指针不停扫描,write指针更新数据* @param chars* @return*/public int compress(char[] chars) {int n = chars.length;int read = 0, write = 0;// 记录一个字符的起始位置int start = 0;for (read = 0; read < n; read++) {// 判断字符变化的 read 位置,以及 read 指针是否走到了最后一个节点if (read == n-1 || chars[read] != chars[read+1]) {chars[write++] = chars[read];int nums = read - start + 1;if (nums > 1) {// sb用来记录重复字符的数量StringBuffer sb = new StringBuffer();while (nums > 0) {sb.append(nums % 10);nums /= 10;}// System.out.println("sb = " + sb.toString());// 将 sb 中的数量存在在 chars 数据中for (int i = sb.length() - 1; i >= 0; i--) {chars[write++] = sb.charAt(i);}}// 更新元素第一次出现的位置start = read + 1;}}// System.out.println(Arrays.toString(chars));// 求解,write指针是记录压缩后的字符位置return write;}
滑动窗口系列
3-无重复字符的最长字串

题意分析:
解题思路:
注意点:
代码:
/*** Hash记录重复字符出现位置*/public int lengthOfLongestSubstring(String s) {int i = 0, j = 0;Map<Character, Integer> map = new HashMap<>();int len = 0;for (j = 0; j < s.length(); j++) {if (map.containsKey(s.charAt(j))) {// i 起始值不能回退i = Math.max(map.get(s.charAt(j)) + 1, i);}len = Math.max(len, j - i + 1);map.put(s.charAt(j), j);}return len;}/*** 滑动窗口。"abcabcbb"*/public int lengthOfLongestSubstring2(String s) {int left = 0, right = 0;int len = 0;Map<Character, Integer> window = new HashMap<>();while (right < s.length()) {char ch = s.charAt(right);right++;if (window.containsKey(ch))window.put(ch, window.get(ch) + 1);elsewindow.put(ch, 1);// 更新左窗口 leftwhile (window.get(ch) > 1) {char chdel = s.charAt(left);left++;window.put(chdel, window.get(chdel) - 1);}len = Math.max(len, right - left);}return len;}
567-字符串的排列

题意分析:
解题思路:
- 滑动窗口。
注意点:
代码:
public boolean checkInclusion(String s1, String s2) {String str = s2, substr = s1;int left = 0, right = 0;Map<Character, Integer> window = new HashMap<>();Map<Character, Integer> need = new HashMap<>();// 关键变量,记录 window 中数据是否包含 need 的元素int valid = 0;for (int i = 0; i < substr.length(); i++) {char ch = substr.charAt(i);if (need.containsKey(ch)) need.put(ch, need.get(ch) + 1); else need.put(ch, 1);}while (right < str.length()) {char chadd = str.charAt(right);right++;// 更新窗口数据if (need.containsKey(chadd)) {if (window.containsKey(chadd)) window.put(chadd, window.get(chadd) + 1); else window.put(chadd, 1);if (window.get(chadd).equals(need.get(chadd))) {valid++;}}// 缩小窗口while (valid == need.size()) {if (right - left == substr.length()) {return true;}char chdel = str.charAt(left);left++;// 更新窗口数据if (need.containsKey(chdel)) {if (window.get(chdel).equals(need.get(chdel))) {valid--;}window.put(chdel, window.get(chdel) -1);}}}return false;}
438-找到字符串中所有字母异位词

题意分析:
解题思路:
注意点:
代码:
public List<Integer> findAnagrams(String s, String p) {String str = s, substr = p;Map<Character, Integer> window = new HashMap<>(), need = new HashMap<>();for (int i = 0; i< substr.length(); i++) {char ch = substr.charAt(i);if (need.containsKey(ch)) need.put(ch, need.get(ch) + 1); else need.put(ch, 1);}int left = 0, right = 0;// 记录是否是可行解int valid = 0;List<Integer> list = new ArrayList<>();while (right < str.length()) {char chadd = str.charAt(right);right++;// 记录「可行解」if (need.containsKey(chadd)) {if (window.containsKey(chadd)) window.put(chadd, window.get(chadd) + 1); else window.put(chadd, 1);if (window.get(chadd).equals(need.get(chadd))) {valid++;}}// 缩小窗口while (valid == need.size()) {// 判断是否要更新结果if (right - left == substr.length()) {list.add(left);}char chdel = str.charAt(left);left++;// 更新「可行解」if (need.containsKey(chdel)) {if (window.get(chdel).equals(need.get(chdel))) {valid--;}window.put(chdel, window.get(chdel) - 1);}}}return list;}
76-最小覆盖子串

题意分析:
解题思路:
注意点:
代码:
public String minWindow(String s, String t) {String str = s, substr = t;Map<Character, Integer> window = new HashMap<>(), need = new HashMap<>();for (int i = 0; i< substr.length(); i++) {char ch = substr.charAt(i);if (need.containsKey(ch)) need.put(ch, need.get(ch) + 1); else need.put(ch, 1);}int left = 0, right = 0;// 记录是否是可行解int valid = 0;int start = -1;int len = Integer.MAX_VALUE;while (right < str.length()) {char chadd = str.charAt(right);right++;// 记录「可行解」if (need.containsKey(chadd)) {if (window.containsKey(chadd)) window.put(chadd, window.get(chadd) + 1); else window.put(chadd, 1);if (window.get(chadd).equals(need.get(chadd))) {valid++;}}// 缩小窗口while (valid == need.size()) {// 判断是否要更新结果if (right - left < len) {start = left;len = right - left;}char chdel = str.charAt(left);left++;// 更新「可行解」if (need.containsKey(chdel)) {if (window.get(chdel).equals(need.get(chdel))) {valid--;}window.put(chdel, window.get(chdel) - 1);}}}System.out.println("start=" + start + "; len = " + len);return (start == -1) ? "" : str.substring(start, start+len);}
未分类
*1081-不同字符的最小子序列

题意分析:
- 去掉字符串中的重复字符,并保证字符的相对顺序,且去重后在字典序中序列最小。
解题思路:
- 三步曲。
- 去重。
- 去重后字符相对顺序不能打乱。(单调递减栈)
- 字典序列最小。(这一点最难)
注意点:
- 记录每个字符次数 HashMap。
- 记录每个字符是否被访问过。 isAccessed = new boolean[size]。这里是以 ASCII 字符作为索引的 size 要好好理解。
代码:
/*** 解题思路* 1、字符去重* 2、字符子顺序不变* 3、字典序最小* @param s* @return*/public String smallestSubsequence(String s) {// 用栈保存遍历字符串的字符Stack<Character> stack = new Stack<>();// 记录字符是否已经存在boolean[] isExisted = new boolean[s.length()];// 记录每个字符出现的次数(求最小字典序时会用到)Map<Character, Integer> cntMap = new HashMap<>();// 初始化字符出现次数for (char ch : s.toCharArray()) {if (!cntMap.containsKey(ch))cntMap.put(ch, 1);elsecntMap.put(ch, cntMap.get(ch) + 1);}// 更新栈for (char ch : s.toCharArray()) {// 每遍历一个字符对应的计数减 1。(后续串中该元素还剩多少个)cntMap.put(ch, cntMap.get(ch) - 1);// 重复字符不处理if (isExisted[ch - 'a'] == true) continue;// 重点是处理入栈的小字符while (!stack.isEmpty() && ch < stack.peek()) {if (cntMap.get(stack.peek()) == 0)break;isExisted[stack.pop() - 'a'] = false;}// 常规入栈并标记动作stack.push(ch);isExisted[ch - 'a'] = true;// System.out.println(isExisted.length + " : " + Arrays.toString(isExisted));}// 出栈字符与实际字符反向StringBuilder sb = new StringBuilder();while (!stack.isEmpty()) {sb.append(stack.pop());}return sb.reverse().toString();}
171-Excel 表列序号
题意分析:
解题思路:
注意点:
代码:
public int titleToNumber(String columnTitle) {int ret = 0;for (int i = 0; i < columnTitle.length(); i++) {char ch = columnTitle.charAt(i);int val = ch - 'A' + 1;ret += val * Math.pow(26, columnTitle.length() - i -1);}return ret;}
415-字符串相加(大数相加)

题意分析:
- 两个大数以字符串的形式做加法。
解题思路:
- 按位计算,个位+个位,十位+十位……
- 时间复杂度:max(O(m), O(n))
注意点:
扩展:
- 多个大数相加如何处理,超过 INT 最大值如何处理,如果有负数又如何处理。
代码:
/*** 解题思路:按位相加,如何处理 sum 和 carry** 扩展:* 1、如果处理多个字符串的相加* 2、如果相加中包含负数该如何处理* 3、相加后如何判断超过 Int 类型限制(大数相加)* @param num1* @param num2* @return*/public String addTwoStrings(String num1, String num2) {int i = num1.length() - 1, j = num2.length() - 1;StringBuilder sb = new StringBuilder();int carry = 0, sum = 0;while (i >= 0 || j >= 0) {// 双指针按位相加,如果没有位则按0值处理int a = i >= 0 ? num1.charAt(i) - '0' : 0;int b = j >= 0 ? num2.charAt(j) - '0' : 0;// System.out.println("a = " + a + "; b = " + b);sum = a + b + carry;carry = sum / 10;sb.append(sum % 10);i--;j--;}if (carry == 1) sb.append(carry);return sb.reverse().toString();}/*** 多个字符串相加* @param strs* @return*/public String addMultiStrings(String[] strs) {if (strs.length == 1) return strs[0];String twoSum = addTwoStrings(strs[0] , "0");System.out.println("first = " + twoSum);for (int i = 1; i < strs.length; i++) {twoSum = addTwoStrings(strs[i], twoSum);System.out.println("iter twoSum = " + twoSum);}return twoSum;}
模版
题意分析:
解题思路:
注意点:
扩展:
代码:
