diff --git a/notes/Leetcode 题解.md b/notes/Leetcode 题解.md index d1407e2a..990145c2 100644 --- a/notes/Leetcode 题解.md +++ b/notes/Leetcode 题解.md @@ -59,7 +59,7 @@ 1. 在计算 mid 时不能使用 mid = (l + h) / 2 这种方式,因为 l + h 可能会导致加法溢出,应该使用 mid = l + (h - l) / 2。 2. 对 h 的赋值和循环条件有关,当循环条件为 l <= h 时,h = mid - 1;当循环条件为 l < h 时,h = mid。 -解释如下:在循环条件为 l <= h 时,如果 h = mid,会出现循环无法退出的情况,例如 l = 1,h = 1,此时 mid 也等于 1,如果此时继续执行 h = mid,那么就会无限循环;在循环条件为 l < h,如果 h = mid - 1,会错误跳过查找的数,例如对于数组 [1, 2, 3],要查找 1,最开始 l = 0,h = 2,mid = 1,判断 key < arr[mid] 执行 h = mid - 1 = 0,此时循环退出,直接把查找的数跳过了。 +解释如下:在循环条件为 l <= h 时,如果 h = mid,会出现循环无法退出的情况,例如 l = 1,h = 1,此时 mid 也等于 1,如果此时继续执行 h = mid,那么就会无限循环;在循环条件为 l < h,如果 h = mid - 1,会错误跳过查找的数,例如对于数组 [1,2,3],要查找 1,最开始 l = 0,h = 2,mid = 1,判断 key < arr[mid] 执行 h = mid - 1 = 0,此时循环退出,直接把查找的数跳过了。 3. l 的赋值一般都为 l = mid + 1。 @@ -196,7 +196,7 @@ public int findContentChildren(int[] g, int[] s) { ``` Input: -[[10, 16], [2, 8], [1, 6], [7, 12]] +[[10,16], [2,8], [1,6], [7,12]] Output: 2 @@ -212,7 +212,7 @@ Output: ```java public int findMinArrowShots(int[][] points) { if(points.length == 0) return 0; - Arrays.sort(points,(a, b) -> (a[1] - b[1])); + Arrays.sort(points,(a,b) -> (a[1] - b[1])); int curPos = points[0][1]; int ret = 1; for (int i = 1; i < points.length; i++) { @@ -249,7 +249,7 @@ public int maxProfit(int[] prices) { [Leetcode : 605. Can Place Flowers (Easy)](https://leetcode.com/problems/can-place-flowers/description/) ```html -Input: flowerbed = [1, 0, 0, 0, 1], n = 1 +Input: flowerbed = [1,0,0,0,1], n = 1 Output: True ``` @@ -318,7 +318,7 @@ public boolean isSubsequence(String s, String t) { ```java Input: S = "ababcbacadefegdehijhklij" -Output: [9, 7, 8] +Output: [9,7,8] Explanation: The partition is "ababcbaca", "defegde", "hijhklij". This is a partition so that each letter appears in at most one part. @@ -351,10 +351,10 @@ public List partitionLabels(String S) { ```html Input: -[[7, 0], [4, 4], [7, 1], [5, 0], [6, 1], [5, 2]] +[[7,0], [4,4], [7,1], [5,0], [6,1], [5,2]] Output: -[[5, 0], [7, 0], [5, 2], [6, 1], [4, 4], [7, 1]] +[[5,0], [7,0], [5,2], [6,1], [4,4], [7,1]] ``` 题目描述:一个学生用两个分量 (h, k) 描述,h 表示身高,k 表示排在前面的有 k 个学生的身高比他高或者和他一样高。 @@ -373,13 +373,13 @@ public int[][] reconstructQueue(int[][] people) { return b[0] - a[0]; } }); - + int n = people.length; List tmp = new ArrayList<>(); for(int i = 0; i < n; i++) { tmp.add(people[i][1], new int[]{people[i][0], people[i][1]}); } - + int[][] ret = new int[n][2]; for(int i = 0; i < n; i++) { ret[i][0] = tmp.get(i)[0]; @@ -677,7 +677,7 @@ public List topKFrequent(int[] nums, int k) { } bucket[frequency].add(key); } - + for(int i = bucket.length - 1; i >= 0 && ret.size() < k; i--) { if(bucket[i] != null) { ret.addAll(bucket[i]); @@ -711,10 +711,10 @@ public List topKFrequent(int[] nums, int k) { **计算在网格中从原点到特定点的最短路径长度** ```html -[[1, 1, 0, 1], -[1, 0, 1, 0], -[1, 1, 1, 1], -[1, 0, 1, 1]] +[[1,1,0,1], +[1,0,1,0], +[1,1,1,1], +[1,0,1,1]] ``` ```java @@ -766,14 +766,14 @@ private class Position { [Leetcode : 695. Max Area of Island (Easy)](https://leetcode.com/problems/max-area-of-island/description/) ```html -[[0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0], -[0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0], -[0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0], -[0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0], -[0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0], -[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0], -[0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0], -[0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0]] +[[0,0,1,0,0,0,0,1,0,0,0,0,0], +[0,0,0,0,0,0,0,1,1,1,0,0,0], +[0,1,1,0,1,0,0,0,0,0,0,0,0], +[0,1,0,0,1,1,0,0,1,0,1,0,0], +[0,1,0,0,1,1,0,0,1,1,1,0,0], +[0,0,0,0,0,0,0,0,0,0,1,0,0], +[0,0,0,0,0,0,0,1,1,1,0,0,0], +[0,0,0,0,0,0,0,1,1,0,0,0,0]] ``` ```java @@ -803,9 +803,9 @@ private int dfs(int[][] grid, int i, int j){ ```html Input: -[[1, 1, 0], - [1, 1, 0], - [0, 0, 1]] +[[1,1,0], + [1,1,0], + [0,0,1]] Output: 2 Explanation:The 0th and 1st students are direct friends, so they are in a friend circle. The 2nd student himself is in a friend circle. So return 2. @@ -974,7 +974,7 @@ private void dfs(char[][] board, int r, int c) { ```html Given the following 5x5 matrix: - Pacific ~ ~ ~ ~ ~ + Pacific ~ ~ ~ ~ ~ ~ 1 2 2 3 (5) * ~ 3 2 3 (4) (4) * ~ 2 4 (5) 3 1 * @@ -1042,11 +1042,11 @@ private void dfs(int r, int c, boolean[][] canReach) { 一行一行地摆放,在确定一行中的那个皇后应该摆在哪一列时,需要用三个标记数组来确定某一列是否合法,这三个标记数组分别为:列标记数组、45 度对角线标记数组和 135 度对角线标记数组。 -45 度对角线标记数组的维度为 2\*n - 1,通过下图可以明确 (r, c) 的位置所在的数组下标为 r + c。 +45 度对角线标记数组的维度为 2\*n - 1,通过下图可以明确 (r,c) 的位置所在的数组下标为 r + c。 ![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//85583359-1b45-45f2-9811-4f7bb9a64db7.jpg) -135 度对角线标记数组的维度也是 2\*n - 1,(r, c) 的位置所在的数组下标为 n - 1 - (r - c)。 +135 度对角线标记数组的维度也是 2\*n - 1,(r,c) 的位置所在的数组下标为 n - 1 - (r - c)。 ![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//9e80f75a-b12b-4344-80c8-1f9ccc2d5246.jpg) @@ -1230,14 +1230,14 @@ private void doRestore(int k, String path, String s) { [Leetcode : 46. Permutations (Medium)](https://leetcode.com/problems/permutations/description/) ```html -[1, 2, 3] have the following permutations: +[1,2,3] have the following permutations: [ - [1, 2, 3], - [1, 3, 2], - [2, 1, 3], - [2, 3, 1], - [3, 1, 2], - [3, 2, 1] + [1,2,3], + [1,3,2], + [2,1,3], + [2,3,1], + [3,1,2], + [3,2,1] ] ``` @@ -1272,8 +1272,8 @@ private void backtracking(List permuteList, boolean[] visited, int[] nu [Leetcode : 47. Permutations II (Medium)](https://leetcode.com/problems/permutations-ii/description/) ```html -[1, 1, 2] have the following unique permutations: -[[1, 1, 2], [1, 2, 1], [2, 1, 1]] +[1,1,2] have the following unique permutations: +[[1,1,2], [1,2,1], [2,1,1]] ``` 题目描述:数组元素可能含有相同的元素,进行排列时就有可能出先重复的排列,要求重复的排列只返回一个。 @@ -1315,12 +1315,12 @@ private void backtracking(List permuteList, boolean[] visited, int[] nu ```html If n = 4 and k = 2, a solution is: [ - [2, 4], - [3, 4], - [2, 3], - [1, 2], - [1, 3], - [1, 4], + [2,4], + [3,4], + [2,3], + [1,2], + [1,3], + [1,4], ] ``` @@ -1337,7 +1337,7 @@ private void backtracking(int start, int n, int k, List combineList, Li ret.add(new ArrayList(combineList)); // 这里要重新构造一个 List return; } - + for(int i = start; i <= n - k + 1; i++){ // 剪枝 combineList.add(i); // 把 i 标记为已访问 @@ -1386,8 +1386,8 @@ A solution set is: [Leetcode : 40. Combination Sum II (Medium)](https://leetcode.com/problems/combination-sum-ii/description/) ```html -For example, given candidate set [10, 1, 2, 7, 6, 1, 5] and target 8, -A solution set is: +For example, given candidate set [10, 1, 2, 7, 6, 1, 5] and target 8, +A solution set is: [ [1, 7], [1, 2, 5], @@ -1463,14 +1463,14 @@ private void backtracking(int startIdx, int size, int[] nums) { ```html For example, -If nums = [1, 2, 2], a solution is: +If nums = [1,2,2], a solution is: [ [2], [1], - [1, 2, 2], - [2, 2], - [1, 2], + [1,2,2], + [2,2], + [1,2], [] ] ``` @@ -1792,7 +1792,7 @@ public int climbStairs(int n) { **母牛生产** -[ 程序员代码面试指南 -P181](#) +[程序员代码面试指南-P181](#) 题目描述:假设农场中成熟的母牛每年都会生 1 头小母牛,并且永远不会死。第一年有 1 只小母牛,从第二年开始,母牛开始生小母牛。每只小母牛 3 年之后成熟又可以生小母牛。给定整数 N,求 N 年后牛的数量。 @@ -1896,11 +1896,11 @@ dp[N] 即为所求。 ### 最长递增子序列 -已知一个序列 {S1, S2,..., Sn} ,取出若干数组成新的序列 {Si1, Si2,..., Sim},其中 i1、i2 ... im 保持递增,即新序列中各个数仍然保持原数列中的先后顺序,称新序列为原序列的一个**子序列**。 +已知一个序列 {S1, S2,...,Sn} ,取出若干数组成新的序列 {Si1, Si2,..., Sim},其中 i1、i2 ... im 保持递增,即新序列中各个数仍然保持原数列中的先后顺序,称新序列为原序列的一个**子序列**。 如果在子序列中,当下标 ix > iy 时,Six > Siy,称子序列为原序列的一个**递增子序列**。 -定义一个数组 dp 存储最长递增子序列的长度,dp[n] 表示以 Sn 结尾的序列的最长递增子序列长度。对于一个递增子序列 {Si1, Si2,..., Sim},如果 im < n 并且 Sim < Sn ,此时 {Si1, Si2,..., Sim, Sn} 为一个递增子序列,递增子序列的长度增加 1。满足上述条件的递增子序列中,长度最长的那个递增子序列就是要找的,在长度最长的递增子序列上加上 Sn 就构成了以 Sn 为结尾的最长递增子序列。因此 dp[n] = max{ dp[i]+1 | Si < Sn && i < n} 。 +定义一个数组 dp 存储最长递增子序列的长度,dp[n] 表示以 Sn 结尾的序列的最长递增子序列长度。对于一个递增子序列 {Si1, Si2,...,Sim},如果 im < n 并且 Sim < Sn ,此时 {Si1, Si2,..., Sim, Sn} 为一个递增子序列,递增子序列的长度增加 1。满足上述条件的递增子序列中,长度最长的那个递增子序列就是要找的,在长度最长的递增子序列上加上 Sn 就构成了以 Sn 为结尾的最长递增子序列。因此 dp[n] = max{ dp[i]+1 | Si < Sn && i < n} 。 因为在求 dp[n] 时可能无法找到一个满足条件的递增子序列,此时 {Sn} 就构成了递增子序列,因此需要对前面的求解方程做修改,令 dp[n] 最小为 1,即: @@ -1931,7 +1931,7 @@ public int lengthOfLIS(int[] nums) { } ``` -以上解法的时间复杂度为 O(n2) ,可以使用二分查找使得时间复杂度降低为 O(nlogn)。定义一个 tails 数组,其中 tails[i] 存储长度为 i + 1 的最长递增子序列的最后一个元素,例如对于数组 [4, 5, 6, 3],有 +以上解法的时间复杂度为 O(n2) ,可以使用二分查找使得时间复杂度降低为 O(nlogn)。定义一个 tails 数组,其中 tails[i] 存储长度为 i + 1 的最长递增子序列的最后一个元素,例如对于数组 [4,5,6,3],有 ```html len = 1 : [4], [5], [6], [3] => tails[0] = 3 @@ -2150,9 +2150,9 @@ public boolean wordBreak(String s, List wordDict) { [Leetcode : 494. Target Sum (Medium)](https://leetcode.com/problems/target-sum/description/) ```html -Input: nums is [1, 1, 1, 1, 1], S is 3. +Input: nums is [1, 1, 1, 1, 1], S is 3. Output: 5 -Explanation: +Explanation: -1+1+1+1+1 = 3 +1-1+1+1+1 = 3 @@ -2199,7 +2199,7 @@ private int subsetSum(int[] nums, int targetSum) { } ``` -**01 字符构成最多的字符串** +**01字符构成最多的字符串** [Leetcode : 474. Ones and Zeroes (Medium)](https://leetcode.com/problems/ones-and-zeroes/description/) @@ -2242,7 +2242,7 @@ public int findMaxForm(String[] strs, int m, int n) { 题目描述:给一些面额的硬币,要求用这些硬币来组成给定面额的钱数,并且使得硬币数量最少。硬币可以重复使用。 -这是一个完全背包问题,完全背包问题和 0-1 背包问题在实现上唯一的不同是,第二层循环是从 0 开始的,而不是从尾部开始。 +这是一个完全背包问题,完全背包问题和 0-1背包问题在实现上唯一的不同是,第二层循环是从 0 开始的,而不是从尾部开始。 ```java public int coinChange(int[] coins, int amount) { @@ -2356,15 +2356,15 @@ public int maxProfit(int k, int[] prices) { ```java class NumArray { - + int[] nums; - + public NumArray(int[] nums) { for(int i = 1; i < nums.length; i++) nums[i] += nums[i - 1]; this.nums = nums; } - + public int sumRange(int i, int j) { return i == 0 ? nums[j] : nums[j] - nums[i - 1]; } @@ -2415,7 +2415,7 @@ A = [1, 2, 3, 4] return: 3, for 3 arithmetic slices in A: [1, 2, 3], [2, 3, 4] and [1, 2, 3, 4] itself. ``` -对于 (1, 2, 3, 4),它有三种组成递增子区间的方式,而对于 (1, 2, 3, 4, 5),它组成递增子区间的方式除了 (1, 2, 3, 4) 的三种外还多了一种,即 (1, 2, 3, 4, 5),因此 dp[i] = dp[i - 1] + 1。 +对于 (1,2,3,4),它有三种组成递增子区间的方式,而对于 (1,2,3,4,5),它组成递增子区间的方式除了 (1,2,3,4) 的三种外还多了一种,即 (1,2,3,4,5),因此 dp[i] = dp[i - 1] + 1。 ```java public int numberOfArithmeticSlices(int[] A) { @@ -2538,7 +2538,7 @@ public int findLongestChain(int[][] pairs) { } } } - + int ret = 0; for(int num : dp) { ret = Math.max(ret, num); @@ -2614,9 +2614,9 @@ public int minSteps(int n) { 如果 x 整除 y(y mod x == 0),则对于所有 i,mi <= ni。 -x 和 y 的 **最大公约数** 为:gcd(x, y) = 2min(m0, n0) \* 3min(m1, n1) \* 5min(m2, n2) \* ... +x 和 y 的 **最大公约数** 为:gcd(x,y) = 2min(m0,n0) \* 3min(m1,n1) \* 5min(m2,n2) \* ... -x 和 y 的 **最小公倍数** 为:lcm(x, y) = 2max(m0, n0) \* 3max(m1, n1) \* 5max(m2, n2) \* ... +x 和 y 的 **最小公倍数** 为:lcm(x,y) = 2max(m0,n0) \* 3max(m1,n1) \* 5max(m2,n2) \* ... **生成素数序列** @@ -2868,8 +2868,8 @@ public int majorityElement(int[] nums) { [Leetcode : 367. Valid Perfect Square (Easy)](https://leetcode.com/problems/valid-perfect-square/description/) -平方序列:1, 4, 9, 16,.. -间隔:3, 5, 7,... +平方序列:1,4,9,16,.. +间隔:3,5,7,... 间隔为等差数列,使用这个特性可以得到从 1 开始的平方序列。 @@ -2992,7 +2992,7 @@ class MyQueue { class MyQueue { private Stack in = new Stack(); private Stack out = new Stack(); - + public void push(int x) { in.push(x); } @@ -3006,7 +3006,7 @@ class MyQueue { in2out(); return out.peek(); } - + private void in2out(){ if(out.isEmpty()){ while(!in.isEmpty()){ @@ -3027,28 +3027,28 @@ class MyQueue { ```java class MyStack { - + private Queue queue; public MyStack() { queue = new LinkedList<>(); } - + public void push(int x) { queue.add(x); for(int i = 1; i < queue.size(); i++){ // 翻转 queue.add(queue.remove()); } } - + public int pop() { return queue.remove(); } - + public int top() { return queue.peek(); } - + public boolean empty() { return queue.isEmpty(); } @@ -3063,7 +3063,7 @@ class MyStack { ```java class MinStack { - + private Stack dataStack; private Stack minStack; private int min; @@ -3073,7 +3073,7 @@ class MinStack { minStack = new Stack<>(); min = Integer.MAX_VALUE; } - + public void push(int x) { dataStack.add(x); if(x < min) { @@ -3081,7 +3081,7 @@ class MinStack { } minStack.add(min); } - + public void pop() { dataStack.pop(); minStack.pop(); @@ -3091,11 +3091,11 @@ class MinStack { min = Integer.MAX_VALUE; } } - + public int top() { return dataStack.peek(); } - + public int getMin() { return min; } @@ -3166,8 +3166,8 @@ public int[] dailyTemperatures(int[] temperatures) { [Leetcode : 496. Next Greater Element I (Easy)](https://leetcode.com/problems/next-greater-element-i/description/) ```html -Input: nums1 = [4, 1, 2], nums2 = [1, 3, 4, 2]. -Output: [-1, 3,-1] +Input: nums1 = [4,1,2], nums2 = [1,3,4,2]. +Output: [-1,3,-1] ``` 在遍历数组时用 Stack 把数组中的数存起来,如果当前遍历的数比栈顶元素来的大,说明栈顶元素的下一个比它大的数就是当前元素。 @@ -3421,11 +3421,11 @@ s1 进行循环移位的结果是 s1s1 的子字符串,因此只要判断 s2 例如 abcd123 向右移动 3 位 得到 123abcd -将 abcd123 中的 abcd 和 123 单独逆序,得到 dcba321,然后对整个字符串进行逆序,得到 123abcd。 +将 abcd123 中的 abcd 和 123 单独逆序,得到 dcba321,然后对整个字符串进行逆序,得到123abcd。 **字符串中单词的翻转** -[ 程序员代码面试指南 ](#) +[程序员代码面试指南](#) 例如将 "I am a student" 翻转成 "student a am I" @@ -3470,11 +3470,11 @@ public int[] findErrorNums(int[] nums) { for(int i = 0; i < nums.length; i++){ while(nums[i] != i + 1 && nums[i] != nums[nums[i] - 1]) swap(nums, i, nums[i] - 1); } - + for(int i = 0; i < nums.length; i++){ if(i + 1 != nums[i]) return new int[]{nums[i], i + 1}; } - + return null; } @@ -3766,7 +3766,7 @@ private boolean isEqual(ListNode l1, ListNode l2){ **从链表中删除节点** -[ 编程之美:3.4]() +[编程之美:3.4]() ![](https://github.com/CyC2018/InterviewNotes/blob/master/pics//2c968ec5-0967-49ce-ac06-f8f5c9ab33bc.jpg) @@ -4022,7 +4022,7 @@ private TreeNode toBST(int[] nums, int sIdx, int eIdx){ / \ 4 5 -Return 3, which is the length of the path [4, 2, 1, 3] or [5, 2, 1, 3]. +Return 3, which is the length of the path [4,2,1,3] or [5,2,1,3]. ``` ```java @@ -4494,24 +4494,24 @@ Trie,又称前缀树或字典树,用于判断字符串是否存在或者是 ```java class Trie { - + private class Node{ Node[] childs = new Node[26]; boolean isLeaf; } - + private Node root = new Node(); - + /** Initialize your data structure here. */ public Trie() { } - + /** Inserts a word into the trie. */ public void insert(String word) { int idx = word.charAt(0) - 'a'; insert(word, root); } - + private void insert(String word, Node node){ int idx = word.charAt(0) - 'a'; if(node.childs[idx] == null){ @@ -4520,12 +4520,12 @@ class Trie { if(word.length() == 1) node.childs[idx].isLeaf = true; else insert(word.substring(1), node.childs[idx]); } - + /** Returns if the word is in the trie. */ public boolean search(String word) { - return search(word, root); + return search(word, root); } - + private boolean search(String word, Node node){ if(node == null) return false; int idx = word.charAt(0) - 'a'; @@ -4533,12 +4533,12 @@ class Trie { if(word.length() == 1) return node.childs[idx].isLeaf; return search(word.substring(1), node.childs[idx]); } - + /** Returns if there is any word in the trie that starts with the given prefix. */ public boolean startsWith(String prefix) { return startWith(prefix, root); } - + private boolean startWith(String prefix, Node node){ if(node == null) return false; if(prefix.length() == 0) return true; @@ -4558,18 +4558,18 @@ class MapSum { int val; Map childs; boolean isWord; - + Trie() { childs = new HashMap<>(); } } - + private Trie root; public MapSum() { root = new Trie(); } - + public void insert(String key, int val) { Trie cur = root; for(char c : key.toCharArray()) { @@ -4582,7 +4582,7 @@ class MapSum { cur.val = val; cur.isWord = true; } - + public int sum(String prefix) { Trie cur = root; for(char c : prefix.toCharArray()) { @@ -4591,7 +4591,7 @@ class MapSum { } return dfs(cur); } - + private int dfs(Trie cur) { int sum = 0; if(cur.isWord) { @@ -4745,7 +4745,7 @@ public int reverseBits(int n) { **不用额外变量交换两个整数** -[ 程序员代码面试指南 :P317](#) +[程序员代码面试指南 :P317](#) ```java a = a ^ b; @@ -4949,9 +4949,9 @@ public int maxProduct(String[] words) { # 参考资料 - [Leetcode](https://leetcode.com/problemset/algorithms/?status=Todo) -- Weiss M A, 冯舜玺 . 数据结构与算法分析——C 语言描述 [J]. 2004. +- Weiss M A, 冯舜玺. 数据结构与算法分析——C 语言描述[J]. 2004. - Sedgewick R. Algorithms[M]. Pearson Education India, 1988. -- 何海涛 , 软件工程师 . 剑指 Offer: 名企面试官精讲典型编程题 [M]. 电子工业出版社 , 2014. -- 《编程之美》小组 . 编程之美 [M]. 电子工业出版社 , 2008. -- 左程云 . 程序员代码面试指南 [M]. 电子工业出版社 , 2015. +- 何海涛, 软件工程师. 剑指 Offer: 名企面试官精讲典型编程题[M]. 电子工业出版社, 2014. +- 《编程之美》小组. 编程之美[M]. 电子工业出版社, 2008. +- 左程云. 程序员代码面试指南[M]. 电子工业出版社, 2015. diff --git a/notes/Linux.md b/notes/Linux.md index 2f5d5ad9..2981c0cd 100644 --- a/notes/Linux.md +++ b/notes/Linux.md @@ -118,7 +118,7 @@ info 与 man 类似,但是 info 将文档分成一个个页面,每个页面 **2. shutdown** ```html -# /sbin/shutdown [-krhc] [ 时间 ] [ 警告讯息 ] +# /sbin/shutdown [-krhc] [时间] [警告讯息] -k : 不会关机,只是发送警告讯息,通知所有在线的用户 -r : 将系统的服务停掉后就重新启动 -h : 将系统的服务停掉后就立即关机 @@ -153,7 +153,7 @@ netstat -anp | grep 80 ## 运行等级 - 0:关机模式 -- 1:单用户模式(可用于破解 root 密码) +- 1:单用户模式(可用于破解root密码) - 2:无网络支持的多用户模式 - 3:有网络支持的多用户模式(文本模式,工作中最常用的模式) - 4:保留,未使用 @@ -210,7 +210,7 @@ MBR 中,第一个扇区最重要,里面有:主要开机记录(Master boo 分区表只有 64 bytes,最多只能存储 4 个分区,这 4 个分区为主分区(Primary)和扩展分区(Extended)。其中扩展分区只有一个,它将其它空间用来记录分区表,可以记录更多的分区,因此通过扩展分区可以分出更多区分,这些分区称为逻辑分区。 -Linux 也把分区当成文件,分区文件的命名方式为:磁盘文件名 + 编号,例如 /dev/sda1。注意,逻辑分区的编号从 5 开始。 +Linux 也把分区当成文件,分区文件的命名方式为:磁盘文件名+编号,例如 /dev/sda1。注意,逻辑分区的编号从 5 开始。 ### 2. GPT @@ -282,7 +282,7 @@ UEFI 相比于 BIOS 来说功能更为全面,也更为安全。 不仅可以修改文件拥有者,也可以修改文件所属群组。 ```html -# chown [-R] 用户名 : 群组名 dirname/filename +# chown [-R] 用户名:群组名 dirname/filename ``` ### 3. 修改权限 @@ -335,7 +335,7 @@ UEFI 相比于 BIOS 来说功能更为全面,也更为安全。 为了使不同 Linux 发行版本的目录结构保持一致性,Filesystem Hierarchy Standard (FHS) 规定了 Linux 的目录结构。最基础的三个目录如下: -- / (root, 根目录 ) +- / (root, 根目录) - /usr (unix software resource):所有系统默认软件都会安装到这个目录; - /var (variable):存放系统或程序运行过程中的数据文件。 @@ -378,7 +378,7 @@ cp [-adfilprsu] source destination -p :连同文件的属性一起复制过去 -r :递归持续复制 -u :destination 比 source 旧才更新 destination,或 destination 不存在的情况下才复制 ---preserve=all :除了 -p 的权限相关参数外,还加入 SELinux 的属性 , links, xattr 等也复制了 +--preserve=all :除了 -p 的权限相关参数外,还加入 SELinux 的属性, links, xattr 等也复制了 ``` ### 3. rm @@ -449,8 +449,8 @@ cp [-adfilprsu] source destination -a : 更新 atime -c : 更新 ctime,若该文件不存在则不建立新文件 -m : 更新 mtime --d : 后面可以接欲更新的日期而不用当前的日期,也可以使用 --date=" 日期或时间 " --t :后面可以接欲更新的时间而不用当前的时间,格式为 [YYYYMMDDhhmm] +-d : 后面可以接欲更新的日期而不用当前的日期,也可以使用 --date="日期或时间" +-t :后面可以接欲更新的时间而不用当前的时间,格式为[YYYYMMDDhhmm] ``` ## 指令与文件搜索 @@ -495,8 +495,8 @@ find 可以使用文件的属性和权限进行搜索。 ```html -mtime n :列出在 n 天前的那一天修改过内容的文件 --mtime +n :列出在 n 天之前 ( 不含 n 天本身 ) 修改过内容的文件 --mtime -n :列出在 n 天之内 ( 含 n 天本身 ) 修改过内容的文件 +-mtime +n :列出在 n 天之前(不含 n 天本身)修改过内容的文件 +-mtime -n :列出在 n 天之内(含 n 天本身)修改过内容的文件 -newer file : 列出比 file 更新的文件 ``` @@ -519,7 +519,7 @@ find 可以使用文件的属性和权限进行搜索。 ```html -name filename --size [+-] SIZE:搜寻比 SIZE 还要大 (+) 或小 (-) 的文件。这个 SIZE 的规格有:c: 代表 byte,k: 代表 1024bytes。所以,要找比 50KB 还要大的文件,就是 -size +50k +-size [+-]SIZE:搜寻比 SIZE 还要大(+)或小(-)的文件。这个 SIZE 的规格有:c: 代表 byte,k: 代表 1024bytes。所以,要找比 50KB 还要大的文件,就是 -size +50k -type TYPE -perm mode :搜索权限等于 mode 的文件 -perm -mode :搜索权限包含 mode 的文件 @@ -556,13 +556,13 @@ inode 中记录了文件内容所在的 block,但是每个 block 非常小, inode 具体包含以下信息: -- 该文件的存取模式 (read/write/excute); -- 该文件的拥有者与群组 (owner/group); +- 该文件的存取模式(read/write/excute); +- 该文件的拥有者与群组(owner/group); - 该文件的容量; -- 该文件建立或状态改变的时间 (ctime); -- 最近一次的读取时间 (atime); -- 最近修改的时间 (mtime); -- 定义文件特性的旗标 (flag),如 SetUID...; +- 该文件建立或状态改变的时间(ctime); +- 最近一次的读取时间(atime); +- 最近修改的时间(mtime); +- 定义文件特性的旗标(flag),如 SetUID...; - 该文件真正内容的指向 (pointer)。 ## 目录的 inode 与 block @@ -636,7 +636,7 @@ $ gzip [-cdtv#] filename -d :解压缩 -t :检验压缩文件是否出错 -v :显示压缩比等信息 --# : # 为数字的意思,代表压缩等级,数字越大压缩比越高,默认为 6 +-# : # 为数字的意思,代表压缩等级,数字越大压缩比越高,默认为6 ``` ### 2. bzip2 @@ -667,16 +667,16 @@ $ xz [-dtlkc#] filename 压缩指令只能对一个文件进行压缩,而打包能够将多个文件打包成一个大文件。tar 不仅可以用于打包,也可以使用 gip、bzip2、xz 将打包文件进行压缩。 ```html -$ tar [-z|-j|-J] [cv] [-f 新建的 tar 文件 ] filename... == 打包压缩 -$ tar [-z|-j|-J] [tv] [-f 已有的 tar 文件 ] == 查看 -$ tar [-z|-j|-J] [xv] [-f 已有的 tar 文件 ] [-C 目录 ] == 解压缩 --z :使用 zip; --j :使用 bzip2; --J :使用 xz; +$ tar [-z|-j|-J] [cv] [-f 新建的tar文件] filename... ==打包压缩 +$ tar [-z|-j|-J] [tv] [-f 已有的tar文件] ==查看 +$ tar [-z|-j|-J] [xv] [-f 已有的tar文件] [-C 目录] ==解压缩 +-z :使用zip; +-j :使用bzip2; +-J :使用xz; -c :新建打包文件; -t :查看打包文件里面有哪些文件; -x :解打包或解压缩的功能; --v :在压缩 / 解压缩的过程中,显示正在处理的文件名; +-v :在压缩/解压缩的过程中,显示正在处理的文件名; -f : filename:要处理的文件; -C 目录 : 在特定目录解压缩。 ``` @@ -724,7 +724,7 @@ $ echo $var $ echo ${var} ``` -变量内容如果有空格,需要使用双引号或者单引号。双引号内的特殊字符可以保留原本特性,例如 var="lang is \(uname -r),则 version 的值为 3.10.0-229.el7.x86_64。 @@ -738,7 +738,7 @@ $ declare [-aixr] variable -a : 定义为数组类型 -i : 定义为整数类型 -x : 定义为环境变量 --r : 定义为 readonly 类型 +-r : 定义为readonly类型 ``` 使用 [ ] 来对数组进行操作: @@ -761,9 +761,9 @@ $ echo ${array[1]} 重定向就是使用文件代替标准输入、标准输出和标准错误输出。 -1. 标准输入 (stdin)       :代码为 0 ,使用 < 或 << ; -2. 标准输出 (stdout)     :代码为 1 ,使用 > 或 >> ; -3. 标准错误输出 (stderr):代码为 2 ,使用 2> 或 2>> ; +1. 标准输入(stdin)       :代码为 0 ,使用 < 或 << ; +2. 标准输出(stdout)     :代码为 1 ,使用 > 或 >> ; +3. 标准错误输出(stderr):代码为 2 ,使用 2> 或 2>> ; 其中,有一个箭头的表示以覆盖的方式重定向,而有两个箭头的表示以追加的方式重定向。 @@ -815,7 +815,7 @@ declare -x HISTCONTROL="ignoredups" declare -x HISTSIZE="1000" declare -x HOME="/home/dmtsai" declare -x HOSTNAME="study.centos.vbird" -.....( 其他省略 )..... +.....(其他省略)..... $ export | cut -c 12 ``` @@ -961,7 +961,7 @@ $ grep -n 'the' regular_express.txt 因为 { 与 } 的符号在 shell 是有特殊意义的,因此必须要使用使用转义字符进行转义。 ```html -$ grep -n 'go\{2, 5\} g' regular_express.txt +$ grep -n 'go\{2,5\}g' regular_express.txt ``` ## printf @@ -980,7 +980,7 @@ $ printf '%10s %5i %5i %5i %8.2f \n' $(cat printf.txt) ## awk ```html -$ awk ' 条件类型 1{ 动作 1} 条件类型 2{ 动作 2} ...' filename +$ awk '条件类型1{动作1} 条件类型2{动作2} ...' filename ``` awk 每次处理一行,处理的最小单位是字段,每个字段的命名方式为:\0 表示一整行。 @@ -1036,16 +1036,16 @@ daemon 2 | 命令 | 作用 | | -- | -- | -| :w | 写入磁盘 | +| :w | 写入磁盘| | :w! | 当文件为只读时,强制写入磁盘。到底能不能写入,与用户对该文件的权限有关 | -| :q | 离开 | -| :q! | 强制离开不保存 | -| :wq | 写入磁盘后离开 | -| :wq!| 强制写入磁盘后离开 | +| :q | 离开| +| :q! | 强制离开不保存| +| :wq | 写入磁盘后离开| +| :wq!| 强制写入磁盘后离开| # 参考资料 -- 鸟哥 . 鸟 哥 的 Linux 私 房 菜 基 础 篇 第 三 版 [J]. 2009. -- [Linux 平台上的软件包管理 ](https://www.ibm.com/developerworks/cn/linux/l-cn-rpmdpkg/index.html) +- 鸟哥. 鸟 哥 的 Linux 私 房 菜 基 础 篇 第 三 版[J]. 2009. +- [Linux 平台上的软件包管理](https://www.ibm.com/developerworks/cn/linux/l-cn-rpmdpkg/index.html) diff --git a/notes/计算机操作系统.md b/notes/计算机操作系统.md index 02f25dd5..a1189d84 100644 --- a/notes/计算机操作系统.md +++ b/notes/计算机操作系统.md @@ -43,7 +43,7 @@ * [5. 共享内存](#5-共享内存) * [6. 套接字](#6-套接字) * [经典同步问题](#经典同步问题) - * [1. 读者 - 写者问题](#1-读者---写者问题) + * [1. 读者-写者问题](#1-读者-写者问题) * [2. 哲学家进餐问题](#2-哲学家进餐问题) * [第三章 死锁](#第三章-死锁) * [死锁的条件](#死锁的条件) @@ -121,7 +121,7 @@ ### 1. 外中断 -由 CPU 执行指令以外的事件引起,如 I/O 结束中断,表示设备输入 / 输出处理已经完成,处理器能够发送下一个输入 / 输出请求。此外还有时钟中断、控制台中断等。 +由 CPU 执行指令以外的事件引起,如 I/O 结束中断,表示设备输入/输出处理已经完成,处理器能够发送下一个输入/输出请求。此外还有时钟中断、控制台中断等。 ### 2. 异常 @@ -163,7 +163,7 @@ - 系统开销:由于创建或撤销进程时,系统都要为之分配或回收资源,如内存空间、I/O 设备等,因此操作系统所付出的开销远大于创建或撤销线程时的开销。类似地,在进行进程切换时,涉及当前执行进程 CPU 环境的保存及新调度进程 CPU 环境的设置。而线程切换时只需保存和设置少量寄存器内容,开销很小。 -- 通信方面:进程间通信 (IPC) 需要进程同步和互斥手段的辅助,以保证数据的一致性,而线程间可以通过直接读 / 写同一进程中的数据段(如全局变量)来进行通信。 +- 通信方面:进程间通信 (IPC) 需要进程同步和互斥手段的辅助,以保证数据的一致性,而线程间可以通过直接读/写同一进程中的数据段(如全局变量)来进行通信。 举例:QQ 和浏览器是两个进程,浏览器进程里面有很多线程,例如 HTTP 请求线程、事件响应线程、渲染线程等等,线程的并发执行使得在浏览器中点击一个新链接从而发起 HTTP 请求时,浏览器还可以响应用户的其它事件。 @@ -207,7 +207,7 @@ shortest remaining time next(SRTN)。 除了可以手动赋予优先权之外,还可以把响应比作为优先权,这种调度方式叫做高响应比优先调度算法。 -响应比 = ( 等待时间 + 要求服务时间 ) / 要求服务时间 = 响应时间 / 要求服务时间 +响应比 = (等待时间 + 要求服务时间) / 要求服务时间 = 响应时间 / 要求服务时间 这种调度算法主要是为了解决 SJF 中长作业可能会饿死的问题,因为随着等待时间的增长,响应比也会越来越高。 @@ -269,7 +269,7 @@ down 和 up 操作需要被设计成原语,不可分割,通常的做法是 如果信号量的取值只能为 0 或者 1,那么就成为了**互斥量(Mutex)**,0 表示临界区已经加锁,1 表示临界区解锁。 ```c -typedef int semaphore; +typedef int semaphore ; semaphore mutex = 1; void P1() { down(mutex); @@ -284,7 +284,7 @@ void P2() { } ``` -**使用信号量实现生产者 - 消费者问题** +**使用信号量实现生产者-消费者问题** 使用一个互斥量 mutex 来对临界资源进行访问;empty 记录空缓冲区的数量,full 记录满缓冲区的数量。 @@ -292,7 +292,7 @@ void P2() { ```c #define N 100 -typedef int semaphore; +typedef int semaphore ; semaphore mutex = 1; semaphore empty = N; semaphore full = 0; @@ -324,21 +324,21 @@ void consumer() { 使用信号量机制实现的生产者消费者问题需要客户端代码做很多控制,而管程把控制的代码独立出来,不仅不容易出错,也使得客户端代码调用更容易。 -c 语言不支持管程,下面的示例代码使用了类 Pascal 语言来描述管程。示例代码中的管程提供了 insert() 和 remove() 方法,客户端代码通过调用这两个方法来解决生产者 - 消费者问题。 +c 语言不支持管程,下面的示例代码使用了类 Pascal 语言来描述管程。示例代码中的管程提供了 insert() 和 remove() 方法,客户端代码通过调用这两个方法来解决生产者-消费者问题。 ```pascal monitor ProducerConsumer integer i; condition c; - + procedure insert(); begin - + end; - + procedure remove(); begin - + end; end monitor; ``` @@ -347,7 +347,7 @@ end monitor; 管程引入了 **条件变量** 以及相关的操作:**wait()** 和 **signal()** 来实现同步操作。对条件变量执行 wait() 操作会导致调用进程阻塞,把管程让出来让另一个进程持有。signal() 操作用于唤醒被阻塞的进程。 -**使用管程实现生成者 - 消费者问题** +**使用管程实现生成者-消费者问题** ```pascal monitor ProducerConsumer @@ -433,7 +433,7 @@ Linux 中管道是通过空文件来实现。 生产者和消费者问题前面已经讨论过。 -### 1. 读者 - 写者问题 +### 1. 读者-写者问题 允许多个进程同时对数据进行读操作,但是不允许读和写以及写和写操作同时发生。 @@ -677,7 +677,7 @@ void philosopher(int i) { 7,0,1,2,0,3,0,4,2,3,0,3,2,1,2,0,1,7,0,1 -进程运行时,先将 7, 0, 1 三个页面装入内存。当进程要访问页面 2 时,产生缺页中断,会将页面 7 换出,因为页面 7 再次被访问的时间最长。 +进程运行时,先将 7,0,1 三个页面装入内存。当进程要访问页面 2 时,产生缺页中断,会将页面 7 换出,因为页面 7 再次被访问的时间最长。 ### 2. 先进先出(FIFO) @@ -730,6 +730,6 @@ CSCAN 对 SCAN 进行了改动,要求磁头始终沿着一个方向移动。 # 参考资料 - Tanenbaum A S, Bos H. Modern operating systems[M]. Prentice Hall Press, 2014. -- 汤子瀛 , 哲凤屏 , 汤小丹 . 计算机操作系统 [M]. 西安电子科技大学出版社 , 2001. -- Bryant, R. E., & O’Hallaron, D. R. (2004). 深入理解计算机系统 . -- [ 进程间的几种通信方式 ](http://blog.csdn.net/yufaw/article/details/7409596) +- 汤子瀛, 哲凤屏, 汤小丹. 计算机操作系统[M]. 西安电子科技大学出版社, 2001. +- Bryant, R. E., & O’Hallaron, D. R. (2004). 深入理解计算机系统. +- [进程间的几种通信方式](http://blog.csdn.net/yufaw/article/details/7409596) diff --git a/notes/计算机网络.md b/notes/计算机网络.md index bf3b8cbd..a870f774 100644 --- a/notes/计算机网络.md +++ b/notes/计算机网络.md @@ -116,7 +116,7 @@ ## 主机之间的通信方式 -**1. 客户 - 服务器(C/S)** +**1. 客户-服务器(C/S)** 客户是服务的请求方,服务器是服务的提供方。