【算法基础】String、Hash 与 Stack
14. 最长公共前缀 - 力扣(LeetCode)
思路:贪心、模拟。从第一个字符串作为初始前缀开始,逐步缩短前缀以适应后续字符串,确保每次调整后前缀仍然是当前字符串的公共前缀。
使用到的内置方法:startsWith()、isEmpty()、substring()
class Solution {public String longestCommonPrefix(String[] strs) {String prefix = strs[0];for (int i = 1; i < strs.length; i++) {while (!prefix.isEmpty() && !strs[i].startsWith(prefix)) {prefix = prefix.substring(0, prefix.length() - 1);}}return prefix;}
}
67. 二进制求和 - 力扣(LeetCode)
思路:高精度运算。
class Solution {public String addBinary(String a, String b) {int cur1 = a.length() - 1;int cur2 = b.length() - 1;int carryBit = 0;StringBuilder ret = new StringBuilder();// 该循环条件是高精度运算的固定写法while (cur1 >= 0 || cur2 >= 0 || carryBit != 0) {// 若该位不存在,以 0 代替其值int num1 = cur1 < 0 ? 0 : a.charAt(cur1) - '0';int num2 = cur2 < 0 ? 0 : b.charAt(cur2) - '0';int sum = num1 + num2 + carryBit;ret.append(sum % 2);carryBit = sum / 2;cur1--;cur2--;}return ret.reverse().toString();}
}
43. 字符串相乘 - 力扣(LeetCode)
思路:高精度运算。
技巧:统一进位处理。在计算完所有乘积后,一次性处理进位,这样会使逻辑简单许多。进位处理从低位到高位,自然传递进位值。
class Solution {public String multiply(String num1, String num2) {if (num1.equals("0") || num2.equals("0")) {return "0";}int len1 = num1.length();int len2 = num2.length();int len = len1 + len2 - 1;int[] temp = new int[len];// 做高精度运算前,可以先将原字符串逆序,这样比较方便char[] n1 = new StringBuilder(num1).reverse().toString().toCharArray();char[] n2 = new StringBuilder(num2).reverse().toString().toCharArray();// 模拟乘法运算for (int i = 0; i < len1; i++) {for (int j = 0; j < len2; j++) {temp[i + j] += (n1[i] - '0') * (n2[j] - '0');}}// 统一进位处理int carryBit = 0;StringBuilder ret = new StringBuilder();for (int num : temp) {ret.append((num + carryBit) % 10);carryBit = (num + carryBit) / 10;}if (carryBit != 0) {ret.append(carryBit);}// 返回结果return ret.reverse().toString();}
}
1. 两数之和 - 力扣(LeetCode)
思路:哈希表。
使用到的内置方法:containsKey()
class Solution {public int[] twoSum(int[] nums, int target) {int len = nums.length;Map<Integer, Integer> hash = new HashMap<>();for (int i = 0; i < len; i++) {int x = target - nums[i];if (hash.containsKey(x)) {return new int[]{i, hash.get(x)};}hash.put(nums[i], i);}return null;}
}
217. 存在重复元素 - 力扣(LeetCode)
思路:哈希表、Set。
技巧:使用 Set 去重。
class Solution {public boolean containsDuplicate(int[] nums) {Set<Integer> set = new HashSet<Integer>();for (int x : nums) {if (!set.add(x)) {return true;}}return false;}
}
49. 字母异位词分组 - 力扣(LeetCode)
思路:哈希表。
技巧:将每个字符串排序后作为哈希表的键,所有排序后相同的字符串(即字母异位词)会被分到同一组。
使用到的内置方法:Arrays.sort()、computeIfAbsent()
注意:new ArrayList(hash.values()) 可以简洁地将 Hash 的 value 集合转换为一个独立的 ArrayList。但值得注意的是,这个操作创建的是 "浅拷贝",List<String> 是共享的。换句话说,这个操作只是改变集合视图。
class Solution {public List<List<String>> groupAnagrams(String[] strs) {int len = strs.length;Map<String, List<String>> hash = new HashMap<>();for (String str : strs) { // 为 str 排序char[] temp = str.toCharArray();Arrays.sort(temp);String targetKey = new String(temp);// 传入 Hashhash.computeIfAbsent(targetKey, K -> new ArrayList()).add(str);}return new ArrayList(hash.values());}
}
844. 比较含退格的字符串 - 力扣(LeetCode)
思路:栈。
技巧:使用数组模拟栈。使用 new String(char[], start, end),直接创建字符串,无需 StringBuilder。
class Solution {public boolean backspaceCompare(String s, String t) {return backspace(s).equals(backspace(t));}public String backspace(String s) {char[] stack = new char[s.length()];int cur = 0;for (int i = 0; i < s.length(); i++) {if (s.charAt(i) != '#') { stack[cur++] = s.charAt(i); // 压栈} else {if (cur > 0) { // 出栈cur--;}}}return new String(stack, 0, cur);}
}
1047. 删除字符串中的所有相邻重复项 - 力扣(LeetCode)
思路:栈。
技巧:使用数组模拟栈。使用辅助节点。
class Solution {public String removeDuplicates(String s) {char[] stack = new char[s.length() + 1]; // stack[0] 为辅助节点int cur = 1;for (int i = 0; i < s.length(); i++) {if (s.charAt(i) != stack[cur - 1]) { // 先 peek 栈顶stack[cur++] = s.charAt(i); // 压栈} else {cur--; // 出栈}}return new String(stack, 1, cur - 1);}
}
227. 基本计算器 II - 力扣(LeetCode)
思路:栈。
技巧:注意在字符数组中截取数字部分,并转化为 int 的通用写法。
// 这种写法效率较高// 思路是每次循环都为数字整体加权,表示前进一位,再加上当前位的值int num1 = 0;while (cur < arr.length && Character.isDigit(arr[cur])) {num1 = num1 * 10 + (arr[cur] - '0');cur++;}
完整代码:
class Solution {public int calculate(String s) {Deque<Integer> stack = new ArrayDeque<>();char operator = '+';int cur = 0;char[] arr = s.toCharArray();while (cur < arr.length) {// 空格的情况if (arr[cur] == ' ') {cur++;continue;}// 运算符的情况if (arr[cur] == '+' || arr[cur] == '-'|| arr[cur] == '*' || arr[cur] == '/') {operator = arr[cur];cur++;continue;}// 数字的情况int num1 = 0;while (cur < arr.length && Character.isDigit(arr[cur])) {num1 = num1 * 10 + (arr[cur] - '0');cur++;}if (operator == '-') {stack.push(-num1);} else if (operator == '*') {int num2 = stack.pop();stack.push(num2 * num1);} else if (operator == '/') {int num2 = stack.pop();stack.push(num2 / num1);} else {stack.push(num1);}}int ret = 0;while (!stack.isEmpty()) {ret += stack.pop();}return ret;}
}