publicstaticvoidquickSort(int[] arr, int l, int r){ if (l >= r) { return; } int pivot = arr[l], i = l - 1, j = r + 1; while (i < j) { do i++; while(arr[i] < pivot); do j--; while(arr[j] > pivot); // 注意:重点在这里,要i < j的时候才需要swap,否则不需要!!! if (i < j) swap(arr, i, j); }
// 这种写法应该更加亲民一点,只是while循环多了一点内容。 publicstaticvoidquickSort(int[] arr, int l, int r){ if (l >= r) { return; } int i = l, j = r; while (i < j) { // 注意,这里一定得是j在前,i在后 while (i < j && arr[j] >= arr[l]) j--; while (i < j && arr[i] <= arr[l]) i++; swap(arr, i, j); } swap(arr, i, l); quickSort(arr, l, i - 1); quickSort(arr, i + 1, r); }
Quick Select
和quick sort基本一致吧,就是找出top k元素。其实对于top k元素,找到k或者k-1均可,这里方便起见,直接80行就不换乘 i < k - 1了。
privatevoidquickSelect(int[] nums, int l, int r, int k){ Map<Integer, Integer> temp = map; if (l >= r) { return; } int pivot = nums[l], i = l, j = r; while (i < j) { while (i < j && nums[j] <= pivot) j--; while (i < j && nums[i] >= pivot) i++; swap(nums, i, j); } swap(nums, i, l); if (i > k) { quickSelect(nums, l, i - 1, k); } elseif (i < k) { quickSelect(nums, i + 1, r, k); } }
// 找左边界 publicstaticvoidbinarySearch1(int l, int r){ int mid = l + r >> 1; if (check(mid)){ r = mid; } else { l = mid + 1; } }
区间被分为[l, mid - 1]和[mid, r]
道理和上面类似,只是此时需要mid = (l + r + 1)/2。原因在于除法是向下取整,存在精读缺失,有可能无限死循环。
1 2 3 4 5 6 7 8 9
// 找右边界,注意l=mid的时候,要+1 publicvoidbinarySearch2(int l, int r){ int mid = (l + r + 1)/2; if (check(mid)) { l = mid; } else { r = mid - 1; } }
取模
这样为了防止负数!!!一定要 +mod 再 % mod
1 2 3
privateintmod(int a){ return (a % mod + mod) % mod; }
快速幂
快速幂就是求大数字a的大数字b次方对p取模。极其重要!!!
1 2 3 4 5 6 7 8 9 10 11
privatestaticintprocess(int a, int b, int p){ int ans = 1 % p; while (b > 0) { if ((b & 1) == 1) { ans = (int)((ans * 1L * a) % p); } a = (int)((a * 1L * a) % p); b = b >> 1; } return ans; }
最大公约数
1 2 3 4 5 6
intgcd(int a, int b){ if (b == 0) { return a; } return gcd(b, a % b); }
publicvoidmontonousStack(int[] nums){ Stack<Integer> stack = new Stack();
for (int i = nums.length; i >= 0; i--) { while (!stack.isEmpty() && stack.peek() < nums[i]) { System.out.printf("index %d left greater element is %d\n", stack.pop(), nums[i]); } stack.push(i); } while (!stack.isEmpty()) { System.out.printf("index %d left greater element is %d\n", stack.pop(), -1); } }
publicint[] minSlidingWindow(int[] nums, int k) { Deque<Integer> deque = new LinkedList(); int n = nums.length; // 这里用res数组来存储结果 int[] res = newint[n - k + 1]; for (int i = 0; i < n; i++) { // 如果当前队列里面存的数字过多,则将最前面的数字弹出,其实就是边界情况,当window里面数字全部都是升序的时候。注意判断是否为空! if (!deque.isEmpty() && i - k + 1 > deque.peekFirst()) { deque.pollFirst(); } // 将队尾的所有比当前元素大的全部pop出去,因为它们不可能为解。注意,是队尾!!!不是队首!!!而且要注意有等于的情况!!! while (!deque.isEmpty() && nums[deque.peekLast()] <= nums[i]) { deque.pollLast(); }
// 这里用数组来模拟双端队列,q就是这个队列,里面存的也是index int N = 100010, hh = 0, tt = -1; int[] q = newint[N];
publicint[] minSlidingWindow(int[] nums, int k) { int[] res = newint[nums.length - k + 1]; for (int i = 0; i < nums.length; i++) { // if (hh <= tt && i - k + 1 > q[hh]) hh++; while (hh <= tt && nums[q[tt]] >= nums[i]) tt--; q[++tt] = i; if (i >= k - 1) { res[i - k + 1] = nums[q[hh]]; } } return res; }
classSolution{ public List<Integer> preorderTraversal(TreeNode root){ Stack<TreeNode> stack = new Stack<TreeNode>(); List<Integer> list = new ArrayList<Integer>(); TreeNode node = root; stack.push(node);
while (!stack.isEmpty() && node != null) { node = stack.pop(); list.add(node.val); if (node.right != null) { stack.push(node.right); } if (node.left != null) { stack.push(node.left); } }
return list; } }
压栈的目的只是为了回溯找右节点,不是压左右子树,而是访问过的节点。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
classSolution{ public List<Integer> inorderTraversal(TreeNode root){ Stack<TreeNode> stack = new Stack<TreeNode>(); List<Integer> list = new ArrayList<Integer>(); TreeNode node = root;
classSolution{ public List<Integer> inorderTraversal(TreeNode root){ Stack<TreeNode> stack = new Stack<TreeNode>(); List<Integer> list = new ArrayList<Integer>(); TreeNode node = root;
classSolution{ public List<Integer> inorderTraversal(TreeNode root){ Stack<TreeNode> stack = new Stack<TreeNode>(); List<Integer> list = new ArrayList<Integer>(); TreeNode node = root;
classTrieNode{ TrieNode[] sons; boolean isWord; TrieNode() { sons = new TrieNode[26]; isWord = false; } public TrieNode get(char c){ int idx = c - 'a'; return sons[idx]; } publicbooleancontainsKey(char c){ int idx = c - 'a'; return sons[idx] != null; } publicvoidadd(char c){ int idx = c - 'a'; sons[idx] = new TrieNode(); } }
infra + cloud
front-side, visual team 25-30 people Seattle, 20 engineers, backend engineer
3 teams: bidding backend system, SRE team
google cloud,Big Data,
确认输入输出,是否会有异常;确认输出输出。比如输入如果没有k个咋办。以及先说明定义的函数。
一边说一边说明每一段代码的逻辑,不用念代码;说代码是干啥的就行。
可以问面试官要一下hint,要一下example。写完以后主动.
Given the root of a binary tree and an integer targetSum, return all root-to-leaf paths where the sum of the node values in the path equals targetSum. Each path should be returned as a list of the node values, not node references.
A root-to-leaf path is a path starting from the root and ending at any leaf node. A leaf is a node with no children.
Given an integer array nums, return the length of the longest strictly increasing subsequence.
A subsequence is a sequence that can be derived from an array by deleting some or no elements without changing the order of the remaining elements. For example, [3,6,2,7] is a subsequence of the array [0,3,1,6,2,2,7].