Leetcode-MT-Simple
文章实际写于2021年,那个炎热的夏天。
Leet Code 美团题库简单类总结,题目按照解法可大致分为数学法、计数法、位运算、双指针法、字符串、哈希表、栈、递归/迭代、排序法、匹配法、记忆化法、二分法、分治法、摩尔投票法、前缀和、模拟法、动态规划几大类。大部分题目可以有多种解法。
数学法、计数法、位运算、双指针法、字符串、哈希表、栈、递归/迭代、排序法、匹配法、记忆化法、二分法、分治法、摩尔投票法、前缀和、模拟法、动态规划
- 数学法: 即利用 +、-、*、/、% 等数学思想来解决,一般结合递归/迭代使用。
- 计数法: 即通过统计元素个数来解决。如字符串中的字母个数,数组中的元素个数。
- 位运算: 即通过 &、|、^、<<、>> 等位运算来解决。
- 双指针法: 即通过两个指针来解决。两个指针可以同时从前往后,也可以从后往前,也可以一个双向奔赴,还有快慢指针法。
- 字符串: 即利用字符串相关类的相关函数来解决。如 String 中的 substring()、replace()、split() 等方法;StringBuilder 的 reverse() 等方法。
- 哈希表: 即利用哈希表的相关特性来解决。如 map key 的唯一性、set 的去重及其 contains() 方法等功能。
- 栈: 即利用栈先进后出的特性来解决。
- 递归/迭代: 递归/迭代可以配合大部分解法使用,在链表、树等数据结构中最常用。
- 排序法: 即利用排序或排序的某些特性来解决。如归并排序中的合并功能,快排思想等。
- 匹配法: 即字符串匹配。
- 记忆化法: 记忆化搜索与动态规划类似。
- 二分法: 即二分法。
- 分治法: 即分治法,分而治之。
- 摩尔投票法: 类似于计数法,一换一的思想。
- 前缀和: 就是前缀和。
- 模拟法: 那也就是模拟法。
- 动态规划: 遇事不决,动态规划。
1、数学法
1.1、整数
-
9、回文数
回文数指一个整数,正序读和倒序读都是一样的整数。// 数学法、双指针法、哈希表 // 数学法 public static boolean isPalindrome(int n) {if (n < 0) {return false;}if (n < 10) {return true;}int temp = 0, m = n;while ( m != 0) {temp = temp * 10 + m % 10;m /= 10;}return temp == n; }
-
202、快乐数
对于一个整数,每一次都将其替换为其每个位置上的数字的平方和,直到变为 1,则说明其是快乐数,也有可能便不到 1,一直无限循环。// 数学法、双指针法、哈希表 // 数学法 + 哈希表 public static boolean isHappy(int n) {List<Integer> list = new ArrayList<>();while (true) {if (n == 1) {return true;}if (list.contains(n)) {return false;}list.add(n);int sum = 0;while (n > 0) {sum += Math.pow(n % 10, 2);n /= 10;}n = sum;} }
-
interview-16-05、阶乘尾数
给定一个整数 n,求其 n 阶乘有多少个尾随零。// 数学法、递归/迭代 // 数学法 + 迭代 // 只有 2 和 5 相乘等于 10,也就是只有 2 和 5 的乘积结果会出现 0,0 ~ 10 以内 5 不可以作为任何树的因数,所以化解为求 n 由多少个 5 组成 public static int trailingZeroes(int n) {int temp = 0;while (n > 0) {n /= 5;temp += n;}return temp; }
1.2、字符串
-
415、字符串相加;二进制相加、链表相加
给定两个字符串形式的数,求其和。// 数学法 // 字符串相加、二进制相加、链表相加 都可以用此方法求解 public static String add(String a, String b) {char[] m = a.toCharArray();char[] n = b.toCharArray();StringBuilder sb = new StringBuilder();int i = m.length - 1, j = n.length - 1, carry = 0;while (i >= 0 || j >= 0 || carry != 0) {carry += i >= 0 ? m[i--] - '0' : 0;carry += j >= 0 ? n[j--] - '0' : 0;sb.append(carry % 10);carry /= 10;}return sb.reverse().toString(); }
-
461、汉明距离
汉明距离是值两个整数,其对应二进制的值的位不同的个数。// 数学法、动态规划 // 数学法 public static int hanmingDistance(int m, int n) {int length = 0;while (m != 0 || n != 0) {if (m % 2 != n % 2) {length++;}m /= 2;n /= 2;}return length; }
1.3、数组
-
Offer61、扑克牌顺子
在若干副扑克牌中,随意抽取五张,判断其是不是顺子,即是不是连续。其中 A 用 1 表示,J、Q、K 分别用 11、12、13 表示,大小王用 0 表示,且可以代表任意数字。// 数学法、哈希表 // 数学法 + 哈希表/集合 public static boolean isStraight(int[] nums) {List<Integer> list = new ArrayList<>(5);int max = 0, min = 13;for (int item : nums) {if (item == 0) {continue;}if (list.contanins(item)) {return false;}list.add(item);max = Math.max(max, item);min = Math.min(min, item);}return max - min <= 4; }
-
Offer62、约瑟夫环
圆圈中最后一个数字,给定 n 个数,0 ~ n - 1,从 0 开始,删除第 m 个数字,然后从下一个元素开始,再删除第 m 个数字,求最后剩下的那个数字。即约瑟夫环。// 数学法、递归/迭代 // 数学法 // f(n, m) = (f(n - 1, m) + m) % n 表示 再 n 个数字中,删除第 m 个数字最后剩下的数字 public static boolean lastRemaining(int n, int m) {int temp = 0;for (int i = 2; i <= n; i++) {temp = (temp + m) % i;}return temp; }
2、计数法
2.1、字符串
-
409、最长回文串
给定一个由大小写字母构成的字符串 s,求由这些字母构成的最长回文串的长度。// 计数法、哈希表 // 计数法 public static int longestPalindrome(String s) {char[] c = s.toCharArray();int[] temp = new int[58]; // ASCII 码表中 A ~ z 的长度for (char item : c) {temp[item - 'A']++;}int length = 0;for (int item : temp) {if (item != 0) {length = (item / 2) * 2;}}return length < c.length ? length + 1 : length; }
2.2、数组
-
645、错误的集合
设定一个数据集 nums,其中包含了 1 ~ n 的元素,但由于复制错误导致其中一个元素重复,一个元素丢失,求重复的元素和丢失的元素。// 计数法、位运算、哈希表、排序法 // 计数法 public static int[] findErrorNums(int[] nums) {int[] temp = new int[nums.length + 1];int[] res = new int[2];for (int item : nums) {temp[item]++;}for (int item : temp) {if (item == 2) {res[0] = item;}if (item == 0) {res[1] = item;}if (res[0] > 0 && res[1] > 0) {break;}}return res; }
-
997、小镇法官
小镇有 n 个人,分别用 1 ~ n 表示,传言称小镇里有一个法官,法官不信任任何人,但其他人都信任这个法官,请找出他。trust[2, 4] 表示 2 信任 4。// 计数法、哈希表 // 计数法 public static int findJudge(int n, int[][] trust) {int[] temp = new int[n + 1];for (int[] item : trust) {temp[item[0]]--;temp[item[1]]++;}for (int i = 1; i < temp.length; i++) {if (temp[i] == n - 1) {return i;}}return -1; }
-
1207、独一无二的出现次数
给定一个整数数组 nums,请统计数组中元素的出现次数,若每个元素的出现次数都是独一无二的,则返回 true,否则返回 false。// 计数法、哈希表 // 哈希表 public static boolean uniqueOccurrences(int[] nums) {Map<Integer, Integer> map = new HashMap<>();for (int item : nums) {map.put(item, map.getOrDefault(item, 0) + 1);}return map.size() == new HashSet<>(map.values()).size(); }
-
Offer03、数组中重复的数字
给定一个长度为 n 的数组,数组元素为 0 ~ n - 1,数组中某些数字是重复的,请找出任意一个重复的元素。// 计数法、哈希表、排序法 // 剑指 offer 原解 // 1、若要求低时间,则用集合法(也就是字典法) // 2、若要求低空间,则用排序法(冒泡、选择、插入等空间复杂度为 O(1)的)或如下示例法 // 3、若要求低空间且不能修改原数组,则使用二分法 public static int findRepeatNumber(int[] nums) {int length = nums.length;for (int i = 0; i < length; i++) {int k = nums[i];if (k < 0) {k += length;}if (nums[k] < 0) { return k;}nums[k] -= length;}return -1; }
3、位运算
-
231、2 的幂
给定一个整数,判断其是否为 2 的幂次方。// 数学法、位运算 // 位运算 2^n & (2^n - 1) == 0 public static boolean isPowerOfTwo(int n) {if (n <= 0) {return false;}return (n & n - 1) == 0; }
-
Offer65、不用 +、-、*、/ 做加法
不使用 +、-、*、/ 实现加法功能。// 数学法、位运算 // 位运算 // a ^ b 异域:表示 a 和 b 的无进位求和,如 23 ^ 7 = 10;a & b 与:表示 a 和 b 的和进位,如 23 & 7 = 3 public static int add(int a, int b) {int m = a ^ b, n = a & b;if (n == 0) {return m;}return add(m, n << 1); }
4、双指针法
4.1、字符串
-
125、回文串
给定一个字符串,验证其是否为回文串,只考虑字母数字,忽略大小写。// 双指针法、哈希表 // 双指针法 public static boolean isPalindrome(String s) {String temp = s.replaceAll("[A-Za-z0-9]", "");for (int i = 0, j = temp.length() - 1; i < j; i++, j--) {if (temp.charAt(i) != temp.charAt(j)) {return false;}}return true; }
-
344、反转字符串
给定一个字符串,将其中的字符串反转过来。// 双指针法 public static void reverseString(char[] c) {for (int i = 0, j = c.length - 1; i < j; i++, j--) {char temp = c[i];c[i] = c[j];c[j] = temp;} }
-
459、重复的子字符串
给定一个字符串 s,判断其是否可以由其某个子字符串重复多次构成。// 双指针、匹配 // 双指针 public static boolean repeatedSubstringPattern(String s) {char[] c = s.toCharArry();for (int i = 1; i < c.length / 2; i++) {if (c.length % i != 0) {continue;}int m = 0, n = m + i;while (n < c.length) {if (c[m] != c[n]) {break;}m++;n++;}if (n == c.length) {return true;}}return false; }
-
1047、删除字符串中所有的相邻重复项
给定一个字符串,删除其中所有相邻重复项。// 双指针法、栈 // 双指针 public static String removeDuplicates(String s) {char[] c = s.toCharArray();int index = -1;for (int i = 0; i < c.length; i++) {if (index != -1 && c[index] == c[i]) {index--;} else {c[++index] = c[i];}}return String.copyValueOf(c, 0, index + 1); }
4.2、数组
-
26、移除有序数组中的重复项
给定一个升序数组 nums,请原地移除重复出现的元素,且使元素的相对顺序保持一致。若最终结果为 k 个,则不考虑 k 及之口的元素。// 双指针法 public static int removeDuplicates(int[] nums) {int i = 0;for (int j = 1; j < nums.length; ) {if (nums[i] == nums[j]) {j++;} else {i++;if (i != j) {nums[i] = nums[j];}j++;}}return i + 1; }
-
27、移除指定元素
给定一个数组及一个值,原地移除该元素。// 双指针法 public static int removeElement(int[] nums, int n) {int index = 0;for (int i = 0; i < nums.length; i++) {if (nums[i] != n) {nums[index++] = nums[i];}}return index; }
-
283、移动数组元素零
给定一个数组,将元素 0 移至末尾。// 双指针法 public static void moveZeroes(int[] nums) {int index = 0;for (int i = 0; i < nums.length; i++) {if (nums[i] != 0) {if (index != i) {nums[index] = nums[i];nums[i] = 0;}index++;}} }
-
350、数组交集
给定两个数组,返回数组交集,若元素出现多次,则以出现次数较小的为准。// 双指针法、哈希表、排序法 // 双指针法 public static int[] intersect(int[] m, int[] n) {Arrays.sort(m);Arrays.sort(n);List<Integer> list = new ArrayList<>();for (int i = 0, j = 0; i < m.length && j < n.length; ) {if (m[i] < n[j]) {i++;} else if (m[i] > n[j]) {j++;} else {list.add(m[i]);i++;j++;}}int[] temp = new int[list.size()];int index = 0;for (int item : list) {temp[index++] = item;}return temp; }
-
557、反转字符串中的单词
给定一个字符串,反转字符串中每个单词的字母顺序。// 双指针 public static String reverseWords(String s) {char[] c = s.toCharArray();int i, j;for (i = 0, j = 0; j < c.length(); ) {if (c[j] != ' ') {j++;} else {reverse(c, i, j);i = j + 1;j = i;}}reverse(c, i, j - 1);return new String(c); }public static void reverse(char[] c, int start, int end) {while (start < end) {char temp = c[start];c[start] = c[end];c[end] = temp;start++;end--;} }
-
1470、重新排列数组
重新排列数组x1x2x3…xn y1y2y3…yn => x1y2x2y2x3yy3…xnyn。// 双指针 public static int[] shuffle(int[] nums, int n) {int[] temp = new int[n * 2];int index = 0;for (int i = 0, j = n; j < nums.length; i++, j++) {temp[index++] = nums[i];temp[index++] = nums[j];}return temp; }
-
Offer21调整数组元素使奇数在偶数前面
嗯,就像题目那样。// 双指针 public static int[] exchange(int[] nums) {for (int i = 0, j = nums.length - 1; i < j;) {if (nums[i] % 2 != 0) {i++;}if (nums[j] % 2 == 0) {j--;}if (i < j && nums[i] % 2 == 0 && nums[j] % 2 != 0) {int temp = nums[i];nums[i] = nums[j];nums[j] = temp;i++;j--;}}return nums; }
-
Offer57-II、和为 s 的连续正整数序列
和为 s 的连续正整数序列。// 双指针 public static int[][] findContinuousSequence(int target) {int[][] res = new int[0][];for (int i = 1, j = 2; j < target; ) {int sum = ((i + j) * ( j - i + 1)) / 2;if (sum == target) {int[] temp = new int[j - 1];int index = 0, start = i;while (start <= j) {temp[index++] = start++;}res = Arrays.copyOf(res, res.length + 1);res[res.length - 1] = temp;i++;} else if (sum < target) {j++;} else {i++;}}return res; }
4.3、链表
-
141、环形链表
给定一个链表,判断其是否为环形链表。// 双指针、哈希表 // 双指针(快慢指针) public static boolean hasCycle(Node node) {Node slow = node, fast = node;while (slow != null && fast != null && fast.next != null) {slow = slow.next;fast = fast.next.next;if (slow == fast) {return true;}}return false; }
-
160、Offer52、相交链表
给定两个链表,判断其是否相交,若相交则返回相交节点,若不想交则返回 null。// 双指针、哈希表 // 双指针 public static Node getIntersectionNode(Node node1, Node node2) {Node first = node1, second = node2;while (first != second) {first = first != null ? first.next : node2;second = second != null ? second.next : node1;}return first; }
-
Offer22、链表中倒数第 k 个节点
给定一个链表,返回链表中倒数第 k 个节点。// 双指针 public static Node getKthFromEnd(Node node, int k) {Node first = node, second = node;while (k > 0 && second != null) {second = second.next;k--;}while (second != null) {first = first.next;second = second.next;}return first; }
5、字符串
-
Offer58-I、反转字符串中的单词顺序
给定一个字符串,反转字符串中的单词顺序。// 双指针、字符串 // 字符串 public static String reverseWords(String s) {if (s == null || s.length() == 0 || s.replaceAll(" ", "").length() == 0) {return "";}String[] temp = s.split(" ");StringBuilder sb = new StringBuilder();for (int i = temp.length - 1; i >= 0; i--) {if (!temp[i].equals("")) {sb.append(temp[i]).append(" ");}}return sb.substring(0, sb.length() - 1); }
-
14、最长公共前缀
给定一个字符串数组,求其最长公共前缀。// 字符串 public static String longestCommonPrefix(String[] s) {String prefix = s[0];for (String item : s) {while (!item.startsWith(prefix)) {if (prefix.length() == 0) {return "";}prefix = prefix.substring(0, prefix.length() - 1);}}return prefix; }
-
1556、千位分隔数
给定一个整数 n,返回其千位分隔后的字符串。// 字符串 public static String thousandSeparator(int n) {StringBuilder sb = new StringBuilder(String.valueOf(n));if (sb.length() <= 3) {return sb.toString();}for (int i = sb.length() - 1 - 3; i >= 0; i -= 3) {sb.insert(i + 1, '.');}return sb.toString(); }
6、哈希表
-
771、宝石与石头
给定两个字符串 j 和 s,j 中的每个字符代表了一种宝石,s 代表你拥有的石头,统计你拥有的石头中的宝石的数量。// 哈希表 public static int numJewelsInStones(String j, String s) {Set<Character> set = new HashSet<>(j.length());for (char c : j.toCharArray()) {set.add(c);}int num = 0;for (char c: s.toCharrray()) {if (set.contains(c)) {num++;}}return num; }
-
859、亲密字符串
给定两个字符串 s 和 g,如果只交换 s 中两个字符的位置久能得到与 g 相等的结果,那就认为 s 和 g 是亲密字符串。// 哈希表 public static boolean buddyStrings(String s, String g) {if (s.length() != g.length()) {return false;}if (s.equals(g)) {int[] temp = new int[26]; // s g 只包含小写字母for (char c : s.toCharAray()) {temp[c - 'a']++;if (temp[c - 'a'] > 1) {return true;}}return false;} else {int first = -1, second = -1;for (int i = 0; i < s.length(); i++) {if (s.charAt(i) != g.charAt(i)) {if (first == -1) {first = i;} else if (second == -1) {second = i;} else {return false;}}}return first != -1 && second != -1 && s.charAt(second) == g.charAt(first) && s.charAt(first) == g.charAt(second);} }
-
1、两数之和
给定一个整数数组和一个目标整数,请返回数组中和为目标整数的元素下标。// 哈希表 public static int[] twoSum(int[] nums, int target) {Map<Integer, Integer> map = new HashMap<>(nums.length());int[] res = new int[2];for (int i = 0; i < nums.length; i++) {if (map.containsKey(nums[i])) {res[0] = map.get(nums[i]);res[1] = i;} else {map.put(target - nums[i], i);}}return res; }
7、栈
7.1、链表
-
Offer06、从尾到头打印链表
给定一个链表,从尾到头打印链表。// 双指针、栈、递归/迭代 // 栈 public static int[] reversePrint(Node node) {Stack<Integer> stack = new Stack<>();while (node != null) {stack.push(node.value);node = node.next;}int[] res = new int[stack.size()];int index = 0;while (!stack.isEmpty()) {res[index++] = stack.pop();}return res; }
7.2、字符串
-
20、有效的括号
给定一个只包含 ‘(’、‘)’、‘[’、‘]’、‘{’、‘}’ 字符的字符串,判断其是否有效。有效定义为,左括号必须在对应位置上有正确的右括号。// 栈 public static boolean isValid(String s) {Stack<Character> stack = new Stack<>();for (char c : s.toCharArray()) {if (c == '(') {stack.push(')');} else if (c == '[') {stack.push(']');} else if (c == '{') {stack.push('}');} else if (stack.isEmpty() || c!= stack.pop()) {return false;}}return stack.isEmpty(); }
7.3、栈
-
716、最大栈;Offer30、最小栈
设计一个最大栈数据结构,既支持栈操作,又能查找栈中最大元素。// 双栈 // 一个栈用来提供栈操作,另一个栈用来提供最大元素操作,利用栈的先进后出的特性
-
232、Offer09、实现队列
用双栈实现队列。// 双栈 // 一个栈用来入列,一个栈用来出列。
8、递归/迭代
8.1、链表
-
83、删除排序链表中的重复元素
给定一个排序链表,删除其中重复的元素。// 栈、递归/迭代 // 递归/迭代 public static Node deleteDuplicates(Node node) {Node last = node;Node temp = last.next;while (last != null && temp != null) {if (last.value != temp.value) {last.next = temp;last = last.next;}temp = temp.next;}last.next = null;return node; }
-
206、Offer24、反转链表
给定一个链表,反转链表,返回反转后的头节点。// 栈、递归/迭代 // 迭代 public static Node reverseList(Node node) {Node prev = null, curr = node, temp;while (curr != null) {temp = curr.next;curr.next = prev;prev = curr;curr = temp;}return prev; }
-
237、Offer18、删除链表节点
给定一个链表及一个目标值,删除链表中节点值等于目标值的一个节点。// 栈、递归/迭代 // 迭代 public static Node deleteNode(Node node, int value) {if (node == null) {return null;}Node root;if (node.value == value) {root = node.next;} else {root = node;}while (node.next != null) {if (node.next.value == value) {node.next = node.next.next;break;}node = node.next;}return root; }
8.2、二叉树
-
144、前;94、中;145、后;深;广遍历
// 前中后深广遍历就不用多说了吧
-
108、有序数组转化为二叉搜索树
给定一个有序数组,将其转化为二叉搜索树。// 递归/迭代、分治 // 递归 public static Tree sortedArrayToBST(int[] nums) {return nums == null ? null : build(nums, 0, nums.length - 1); }public static Tree build(int[] ums, int left, int right) {if (left > right) {return null;}int mid = left + (right - left) / 2;Tree tree = new Tree(nums[mid]);tree.left = build(nums, left, mid - 1);tree.right = build(nums, mid + 1, right);return tree; }
-
104、二叉树的最大;111、最小深度;112、路径总和
给定一个二叉树,求其最大深度。// 递归/迭代、深、广 public static int maxDepth(Tree tree) {return tree == null ? 0 : Math.max(tree.left, tree.right) + 1; }// 最小深度 public static int minDepth(Tree tree) {if (tree == null) {return 0;}if (tree.left != null && tree.right == null) {return minDepth(tree.left) + 1;}if (tree.left == null && tree.right != null) {return minDepth(tree.right) + 1;}return Math.min(minDepth(tree.left), minDepth(tree.right)) + 1; }// 路径总和 // 给定一个二叉树根节点和一个目标值,判断二叉树的每个叶子节点的总和中是否有和目标值相等的。 public static boolean hasPathSum(Tree tree, int target) {if (tree == null) {return false;}if (tree.left == null && tree.right == null) {return targte - tree.value == 0;}return hasPathSum(tree.left, target - tree.value) || hasPathSum(tree.right, target - tree.value); }
-
101、Offer28、对称二叉树
给定一个二叉树,判断其是否为对称二叉树。// 递归 public static boolean isSymmetric(Tree tree) {return tree == null ? true : check(tree.left, tree.right); }public static boolean check(Tree left, Tree right) {if (left == null || right == null) {return false;}return left.value == right.value && check(left.left, right.right) && check(left.right, right.left); }
-
226、翻转二叉树
给定一颗二叉树,翻转其左右节点。// 前、中、后、深、广、笨比 // 前 public static Tree before(Tree tree) {if (tree == null) {return null;}Tree temp = tree.left;tree.left = brfore(tree.right);tree.right = before(temp);return tree; }// 中 public static Tree middle(Tree tree) {if (tree == null) {return null;}middle(tree.left);Tree temp = tree.left;tree.left = tree.right;tree.right = temp;middle(tree.left);return tree; }// 后 public static Tree after(Tree tree) {if (tree =null) {return null;}Tree left = after(tree.left);Tree right = after(tree.right);tree.left = right;tree.right = left;return tree; }// 广 public static Tree bfs(Tree tree) {if (tree == null) {return null;}Queue<Tree> queue = new LinkedList<>();queue.add(tree);while (!queue.isEmpty()) {Tree tree1 = tree.poll();Tree temp = tree1.left;tree1.left = tree1.right;tree1.right = temp;if (tree1.left != null) {queue.add(tree1.left);}if (tree1.right != null) {queue.add(tree1.right);}}return tree;}
-
617、合并二叉树
给定两个二叉树,合并二叉树。// 递归 public static Tree mergeTrees(Tree tree1, Tree tree2) {if (tree1 == null) {return tree2;}if (tree2 == null) {return tree1;}tree1.value += tree2.value;tree1.left = mergeTrees(tree1.left, tree2.left);tree1.right = mergeTrees(tree1.right, tree2.right);return tree1; }
-
257、二叉树的所有路径(深)
给定一颗二叉树,返回其所有路径。// 深 public static List<String> binaryTreePaths(Tree tree) {List<String> list = new ArrayList<>();StringBuildr sb = new StringBuilder();path(tree, list, sb);return list; }public static void path(Tree tree, List<String> list, StringBuilder sb) {if (tree == null) {return;}sb.append(tree.value).append('->');if (tree.left != null) {path(tree.left, list, new StringBuilder(sb));}if (tree.right != null) {path(tree.right, list, new StringBuilder(sb));}if (tree.left == null && tree.right == null) {list.add(sb.substring(0, sb.length() - 2));return;} }
-
543、二叉树的直径(深)
给定一颗二叉树,求其直径。二叉树直径为任意两个叶节点之间的路径长度。// 深 int max = 0; public static int diameterOfBinaryTree(Tree tree) {depth(tree);return max; }public static int depth(Tree tree) {if (tree == null) {return 0;}int leftDepth = tree.left != null ? depth(tree.left) + 1 : 0;int rightDepth = tree.right != null ? depth(tree.right) + 1 : 0;max = Math.max(max, leftDepth + rightDepth);return Math.max(leftDepth, rightDepth); }
-
572、另一棵树的子树(深)
给定两颗二叉树,判断第二颗是否为第一颗的子树。// 深 public static boolean isSubtree(Tree, tree1, Tree tree2) {if (tree1 == null) {return false;}return isSame(tree1, tree2) || isSame(tree1.left, tree2) || isSame(tree1.right, tree2); }public static boolean isSame(Tree tree1, Tree tree2) {if (tree1 == null && tree2 == null) {return treu;}if (tree1 == null || tree2 == null) {return false;}return tree1.value == tree2.value && isSame(tree1.left, tree2.left) && isSame(tree1.right, tree2.right); }
-
Offer55-II、平衡二叉树(深)
给定一颗二叉树,若其任意节点的左右子树的深度差不超过 1,则称为平衡二叉树。// 深(自顶向下递归) public static boolean isBalanced(Tree tree) {if (tree == null) {return treu;}if (Math.abs(depth(tree.left) - depth(tree.right)) > 1) {return false;}return isBalanced(tree.left) && isBalanced(tree.right);// 自底向上递归return depth1(tree) >= 0; }// 自底向上递归 public static int depth1(Tree tree) {if (tree == null) {return 0;}int leftDepth = depth1(tree.left);int rightDepth = depth1(tree.right);if (leftDepth == -1 || rightDepth == -1 || Math.abs(leftDepth - rightDepth) > 1) {return -1;}return Math.max(leftDepth, rightDepth) + 1; }public static int depth(Tree) {return tree == null ? 0 : Math.max(tree.left, tree.right) + 1; }
-
637、二叉树的层平均值(广)
给定一颗二叉树,返回其层平均值。// 广 // 广度优先遍历 求每一层平均值 代码过于简单 不予展示
-
Offer54、二叉搜索树的第 k 大节点(反中序)
给定一颗二叉搜索树,返回其第 k 大节点。// 反中序 int count = 0, value = 0; public static int k(Tree tree, int k) {if (tree == null) {return -1;}middle(tree, k);return value; }public static void middle(Tree tree, int k) {if (tree.right != null) {middle(tree.right, k);}if (++count == k) {value = tree.value;break;}if (tree.left != null) {middle(tree.left, k);} }
-
559、N 叉树的最大深度(深、广)
给定一颗 n 叉树,返回其最大深度。// 深/广 // 深 public static int dfs(Tree tree) {if (tree == null) {return 0;}int depth = 0;for (Tree item : tree.children) {depth = Math.max(depth, dfs(item));}return depth + 1; }// 广 public static int bfs(Tree tree) {if (tree == null) {return 0;}if (tree.children.size == 0) {return 1;}int depth = 0;Queue<Tree> queue = new LinkedList<>();queue.add(tree);while (!queue.isEmpty()) {depth++;int size = queue.size();while (size > 0) {Tree temp = queue.poll();if (temp.chiildren,.size > 0) {queue.addAll(temp.children);}size--;}}return depth; }
9、排序法
9.1、数组
-
88、合并有序数组
给定 两个升序数组,合并数组,并使元素保持升序顺序。// 双指针法、排序法 // 排序法(归并合并) public static int[] merge(int[] m, int[] n) {int[] res = new int[m.length + n.length];int i = 0, j = 0, index = 0;while (i < m.length && j < n.length) {res[index++] = m[i] < n[j] ? m[i++] : n[j++];}if (i < m.length) {res[index++] = m[i++];}if (j < n.length) {res[index++] = n[j++];}return res; }
-
Offer40、最小的 k 个数(快排)
给定一个整数数组和一个整数 k,k 小于数组的长度,返回数组中最小的 k 个数。// 排序法(快排思想) public static int[] getLeastNumbers(int[] nums, int k) {if (nums.length == 0) {return new int[0];}return min(nums, 0, nums..length - 1, k); }public static int[] min(int[] nums, int left, int right, int k) {int index = quick(nums, left, right);if (index + 1 == k) {return Arrays.copyOf(nums, 0, k);}return index + 1 < k ? min(nums, index + 1, right, k) : min(nums, left, index - 1, k); }public static int quick(int[] nums, int left, int right) {int key = nums[left];int i = left, j = right;while (i < j) {while (i < j && nums[j] >= key) {j--;}while (i < j && nums[i] <= key) {i++;}if (i < j) {int temp = nums[i];nums[i] = nums[j];nums[j] = temp;}}nums[left] = nums[i];nums[i] = key;return i; }
9.2、链表
-
21、Offer25、合并有序链表
合并两个有序链表。// 排序法(归并合并思想) public static Node mergeTwoLists(Node node1, Node node2) {if (node1 == null) {return node2;}if (node2 == null) {return node1;}Node root = new Node(-1);Node node = root;while (node1 != null && node2 != null) {if (node1.value <= node2.value) {node.next = node1;node1 = nnode1.next;} else {node.next = node2;node2 = node2.next;}node = node.next;}if (node1 != null) {node.next = node1;}if (node2 != null) {node.next = node2;}return root.next; }
10、匹配法
-
28、strStr()
实现 strStr() 方法。// 字符串匹配 直接参考五大匹配算法(BF、RK、KMP、BM、Sunday)
11、记忆化法
// 记忆化法皆可用动态规划解决
12、二分法
-
35、搜索插入位置
给定一个有序数组和一个整数,返回该整数在数组中的索引,若不存在于数组,则返回其插入位置。// 二分法 public static int searchInsert(int[] nums, int key) {if (key < nums[0]) {return 0;} else if (key > nums[nums.length - 1]) {return nums.length;} ele {return binary(nums, 0, nums.length - 1, key);} }public static int binary(int[] nums, int left, int right, int key) {if (left == right) {if (key <= nums[left]) {return left;} else {return left + 1;}} else if (left < right) {int mid = left + (right - left) / 2;if (key == nums[mid]) {return mid;} else if (key < nums[mid]) {return binary(nums, left, mid - 1, key);} else {return bianry(nums, mid + 1, right, key);}} else {return left;} }
-
69、x 的平方根
给定一个整数 x,在不使用任何库函数的情况下,返回 x 的算数平方根。// 二分法 public static int mySqrt(int x) {int left = 0, right = x, res = -1;while (left <= right) {int mid = left + (right - left) / 2;if ((long) mid * mid <= x) {res = mid;left = mid + 1;} else {right = mid - 1;}}return res; }
-
704、二分查找
二分查找。// 二分查找 代码见七大查找算法之二分查找
-
852、山脉数组的峰顶索引
给定一个山脉数组,返回其峰顶索引值,即返回最大值索引。public static int peakIndexInMountainArray(int[] nums) {int left = 0, right = arr.length - 1;while (left < right) {int mid = left + (right - left) / 2;if (nums[mid] > nums[mid - 1] && nums[mid] > nums[mid + 1]) {return mid;} else if (nums[mid] < nums[mid - 1]) {right = mid - 1;} else {left = mid + 1;}}return - 1; }
13、分治法
// 皆可用其它方法解决
14、摩尔投票法
-
169、Offer39、多数元素
给定一个数组,求出现次数超过一半元素。// 计数法、哈希表、分治法、摩尔投票法 // 摩尔投票法 public static int majorityElement(int[] nums) {int count = 1, curr = nums[0];for (int i = 1; i < nums.length; i++) {if (nums[i] == curr) {count++;} else {count--;if (count == 0) {if (i< nums.length - 1) {curr = nums[i + 1];} else {return -1;}}}}return count; }
15、前缀和
-
303、区域检索-数组不可变
利用前缀和来作为结果。// 代码被扣了
16、模拟法
-
867、转置矩阵
转置矩阵,即将矩阵的行换成列,列换成行。// 模拟法 public static int[][] transpose(int[][] nums) {if (nums.length == 0) {return null;}int[][] res = new int[nums[0].length][nums.length];for (int i = 0; i < nums.length; i++) {for (int j = 0; j < nums[i].length; j++) {res[j][i] = nums[i][j];}}return res; }
-
Offer29、顺时针打印矩阵
给定一个矩阵,顺时针打印矩阵内元素。// 模拟法 public static int[] spiralOrder(int[][] nums) {if (nums.length == 0) {return new int[] {};}int high = nums.length, width = nums[0].length;int[] res = new int[high * width];int right = width - 1, down = high - 1, left = 0, up = 0;int index = 0, i = 0, j = 0;while (left <= right && up <= down) {// 对应存在以最中心元素中心对称的情况if ((right == left) && (down == up) && (right == down)) {res[index++] = nums[i][j];break;}while (j < right) {res[index++] = nums[i][j++];}right--;while (i < down) {res[index++] = nums[i++][j];}down--;while (j > left && index < res.length) {res[index++] = nums[i][j--];}left++;while (i > up && index < res.length) {res[index++] = nums[i--][j];}up++;i++;j++;}return res; }
17、动态规划
17.1、整数
-
118、杨辉三角
杨辉三角,在杨辉三角中,每个数字的值等于它左上方和右上方的和。给定一个整数 n,返回 n 行杨辉三角。// 动态规划 public static int[][] generate(int n) {int[][] dp = new int[n][0];for (int i = 0; i < n; i++) {int[] temp = new int[i + 1];dp[i] = temp;for (int j = 0; j <= i; j++) {if (i == 0 || j == 0) {dp[i][j] = 1;} else {if (j <= i / 2) {dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j];} else {dp[i][j] = dp[i][i - j];}}}}return dp; }
-
509、Offer10I、斐波那契数列
斐波那契数列 f(n) = f(n - 2) + f(n + 1)。// 递归/迭代、动态规划 // 动态规划 public static int fibonacci(int n) {if (n < 2) {return n;}int prePre = 0, pre = 1, fn = 0;for (int i = 1; i < n; i++) {fn = (prePre + pre) % 1000000007;prePre = pre;pre = fn;}return fn; }
-
70、爬楼梯;Offer10II、跳台阶
小丸子爬楼梯与跳台阶,可以一次爬一个台阶,也可以一次爬两个台阶,求对于有 n 个台阶的楼梯,小丸子有多少中爬楼梯方案。// 动态规划 public static int climbStairs(int n) {// 若是跳台阶 小丸子会原地蹦一下// if (n == 0) {// return 1;// }if (n <= 2) {return n;}int a = 1, b = 2, temp = 0;for (int i = 3; i <= n; i++) {temp = (a + b) % 1000000007;a = b;b = temp;}return temp; }
-
interview-08-01、三步问题
小丸子上楼梯,小丸子长大了,可以一次上一个,也可以一次上两个,也可以一次上三个。对于有 n 个台阶的楼梯,小丸子有多少中爬楼梯方案。// 动态规划 public static int waysToStep(int n) {if (n < 3) {return n;}if (n == 3) {return 4;}int mod = 1000000007;int[] dp = new int[n + 1];dp[1] = 1;dp[2] = 2;dp[3] = 4;for (int i = 4; i <= n; i++) {dp[i] = (dp[i - 3] + dp[i - 2]) % mod + dp[i - 1];dp[i] %= mod;}return dp[n]; }
17.2、数组
-
53、Offer42、最大连续子段和
给定一个数组,求其最大连续子段和。// 动态规划 public static int maxSubArray(int[] nums) {int max = nums[0];for (int i = 1; i < nums.length; i++) {nums[i] += Math.max(nums[i], 0);max = Math.max(max, nums[i]);}return max; }
-
121、买卖股票问题
给定一个数组,nums[i] 表示第 i 天股票的价格。求股票买卖的最大利润。// 动态规划 public static int maxProfit(int[] nums) {int max = 0, minPrice = nums[0];for (int i = 1; i < nums.length; i++) {max = Math.max(max, nums[i] - minPrice);minPrice = Math.min(minPrice, nums[i]);}return max; }
-
392、判断子序列
给定两个字符串 s 和 t,判断 s 是否为 t 的子序列。// 双指针、动态规划 // 动态规划 // 转化为最短编辑距离问题,最短编辑距离问题中 s => t 可以经过修改、插入、删除来完成,而在这个问题中 s => t 只能通过插入 public static boolean isSubsequence(String s, String t) {char[] a = s.toCharArray();char[] b = t.toCharArray();int[][] dp = new int[a.length + 1][b.length + 1];for (int i = 1; i < a.length + 1; i++) {for (int j = 1; j < b.length + 1; j++) {if (a[i - 1] == b[j - 1]) {dp[i][j] = dp[i - 1][j - 1] + 1;} else {dp[i][j] = dp[i][j - 1];}}}return dp[a.length][b.length] == s.length(); }
-
LCP07、传递信息
给定一个整数 n,表示 n 个小朋友,编号从 0 ~ n - 1;给定一个二维数组,其中第二维 [2, 6] 表示信息可以从 2 传到 6;给定一个整数 k 表示传递的次数。求信息经过 k 次传播传到 n - 1 处的方案数。// 动态规划 public static int numWays(int n, int[][] relation, int k) {int[][] dp = new int[k + 1][n];dp[0][0] = 1; // 可以理解为刚开始信息的持有者for (int i = 1; i < k + 1; i++) {for (int[] temp : relation) {dp[i][temp[1]] += dp[i - 1][temp[0]];}}return dp[k][n - 1]; }
@XGLLHZ - 吴奇隆 -《祝你一路顺风》.mp3