# 面试题 这部分内容是算法问题合集,题目大多来自网络和书籍。我做了下简单的整理,很多题做了一些思路标记。 ## 小结 面试中如何更好的写算法题 * ide 工具 & 文本框 ;文本框环境写算法是通常没有智能提示,有些基础数据结构可能要自己定义 * 语言基础语法:各常用集合的api,要能够默写 * 题目:熟悉各种题目,避免在题目理解上花太多时间跟面试官拉齐 * 编程思路和框架:拿到题目以后能快速套思路和代码框架 * 编程细节:多练习,总结 ## 常用解题套路工具 * 数组,字符串问题:二分查找、 快慢指针、 左右指针、 滑动窗口、 前缀和数组、 差分数组。 * 二叉树问题:递归 * [动态规划问题](../8%20Algorithms%20Analysis/动态规划.md) * [常见算法题目Java实现](https://github.com/nonstriater/deep-in-java/tree/master/src/main/java/com/nonstriater/deepinjava/algo) ## 刷题框架套路 ### 遍历 ``` # 数组遍历框架 void traverse(int[] arr) { for (int i = 0; i < arr.length; i++) { // 迭代访问 arr[i] } } # 链表遍历框架 void traverse(ListNode head) { ListNode p = head; while(p.next != null) ... p = p.next } ``` ### 递归 ```Java # 链表递归 void traverse(ListNode head) { // 递归访问 head.val traverse(head.next); } # 二叉树递归 void traverse(TreeNode root) { traverse(root.left); traverse(root.right); } # 多叉树递归 void traverse(TreeNode root) { for (TreeNode child : root.children) traverse(child); } # 图的递归:,用个布尔数组 visited 做标记就行了 ``` 比如,二叉树的最近公共祖先 ```Java TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { // base case if (root == null) return null; if (root == p || root == q) return root; TreeNode left = lowestCommonAncestor(root.left, p, q); TreeNode right = lowestCommonAncestor(root.right, p, q); // 情况 1 :p, q 在 root 为根的树中 if (left != null && right != null) { return root; } // 情况 2 :p, q 不在 在 root 为根的树中 if (left == null && right == null) { return null; } // 情况 3 : p, q 只有1个在root 为根的树中 return left == null ? right : left; } ``` ### 二分查找 [查找算法](../7%20Search/README.md) ```Java // 1, 2, 2, 2, 2, 3 public int bsearch(int[] nums, int target){ if(nums == null) { return -1; } int low = 0; int high = nums.length;// 注意 while(low < high){ middle = (high + low ) / 2; if(nums[middle] < target){ low = middle + 1; } else if (nums[middle] == target) { high = middle;//继续向左早 } else { high = middle; // 注意 , 这里没有 -1 } } return low; } ``` ### 快慢指针 如下判断链表是否有环 ``` public static boolean hasCycle(LinkNode head) { if(head == null) { return false; } LinkNode p = head, q = head; while(p.next != null && p.next.next != null && q.next != null) { p = p.next.next; q = q.next; if(p == q) { return true; } } return false; } ``` ### 左右指针 ``` ``` ### 滑动窗口 滑动窗口: 无重复字符的最长子串 ```Java //如 ”abcabbcbb“ 输出 3 public static int longestSubString(char[] s){ int left = 0, right = 0; int res = 0; // 记录最长结果 Map window = new HashMap(); while (right < s.length) { Character c = s[right]; //窗口变大 right++; window.put(c, window.getOrDefault(c, 0) + 1); //java写的麻烦,不一定记得这个api if (window.get(c) > 1) { //判断左侧窗口是否要收缩 char d = s[left]; left ++; window.put(d, window.get(d)-1); } // 在这里更新答案 res = res > (right-left) ? res: (right-left); } return res; } ``` ### 排序算法 [排序算法](../6%20Sort/README.md) ```Java #快排 quickSort void quicksort(int[] nums, int left, int right){ if (left