diff --git a/Week1/README.md b/Week1/README.md index 50de3041..e9799ac8 100644 --- a/Week1/README.md +++ b/Week1/README.md @@ -1 +1,274 @@ -学习笔记 \ No newline at end of file +## 心得体会 +1.注意中间状态和最终状态的关系,如果能直接到达最终状态显然可以极大的降低算法的成本。比如直接推导出通项公式。
+2.对于暴力算法复杂度超过$O(n^2)$的题目,可以考虑是否可以先排序,因为排序的时间复杂度为O$(nlogn)$。
+3.动态规划其实是一种高级暴力算法,遇到暴力算法时间复杂度较高时候第一时间想到的就应该是有没有重复计算,能不能记忆化,能不能自底向上迭代。
+4.链表题目很多时候添加一个空的头结点会方便很多。
+5.双指针甚至多指针也是一种记忆化,很多时候可以对空间复杂度进行进一步优化
+## 作业部分 +### 旋转数组 +#### 1.临时数组 +使用一个临时数组存储,时间复杂度$O(n)$,空间复杂度$O(n)$
+但是这个代码比较清晰,实际工程可以使用这种方式
+```java +public class SolutionTempArray { + public void rotate(int[] nums, int k) { + if(nums.length == 0) return; + //这个取余数是一个关键点 + k = k % nums.length; + int[] temp = new int[k]; + //将前k个元素储存在临时数组 + for(int i = 0;i < k;i++) { + temp[i] = nums[nums.length-k+i]; + } + //将最后k个元素移动到前面 + for(int i = nums.length - k - 1;i >= 0 ;i--) { + nums[i+k] = nums[i]; + } + //移动临时数组到最后k个 + for(int i = 0;i < k;i++){ + nums[i] = temp[i]; + } + } +} + +``` +#### 2.三次反转 +标准解法,$O(n)$复杂度,只是不太好想,非常巧妙,是一个非常不错的解法! +```java +public class SolutionReverse { + public void rotate(int[] nums, int k) { + k = k % nums.length; + reverse(nums, 0, nums.length-1); + reverse(nums, 0, k-1); + reverse(nums, k, nums.length-1); + } + void reverse(int[] arr, int start, int end){ + while(start < end) { + int temp = arr[start]; + arr[start++] = arr[end]; + arr[end--] = temp; + } + } +} + +``` +#### 3.双端队列 +用一个双端队列来进行移动
+时间复杂度也是$O(n)$,虽然使用了辅助队列造成了$O(n)$的空间复杂度,但是在工程中这种问题明显**在最开始建模的时候就应该使用双端队列而不是数组** +```java +import java.util.*; + +public class SolutionDeque { + if(nums.length == 0) return ; + Deque queue = new LinkedList(); + for(int i:nums){ + queue.addLast(i); + } + while(k > 0){ + queue.offerFirst(queue.removeLast()); + k--; + } + for(int i =0; i < nums.length;i++){ + nums[i] = queue.pollFirst(); + } + +} + +``` +#### 4.循环置换 +另外一种原地算法,作为一种正确性还需要证明一下的算法,可读性实在是堪忧,时间和空间复杂度没有明显的优势,不推荐使用。 +```java +public class SolutionCycSwap { + public void rotate(int[] nums, int k) { + if (nums.length == 0) return; + int count = 0; + for(int i = 0; count < nums.length; i++){ + int pos = i; + int temp = nums[i]; + while(true) { + int target = (pos + k) % nums.length; + int targetValue = nums [target]; + nums[target] = temp; + temp = targetValue; + count++; + if(target == i) break; + pos = target; + } + } + + } +} + +``` +### 接雨水 +非常不错的题目啊 +#### 1.按行计算 +假设height数组的最大值为m,则时间复杂度为$O(m*n)$。
+乍看上去和按列计算没多大区别,但
+n == height.length
+0 <= n <= 3 * 104
+0 <= height[i] <= 105
+m的值更大。按行计算无法通过最后一个测试用例,超出时间限制
+```java +class Solution { + public int trap(int[] height) { + int level = 1; + int waterCount = 0; + while(true){ + List trapIndexs=new ArrayList<>(); + for (int i = 0;i < height.length;i++){ + if(height[i] >= level){ + trapIndexs.add(i); + } + } + if (trapIndexs.size() == 1 || trapIndexs.size() == 0){ + break; + } + for (int i = 0;i < trapIndexs.size() - 1;i++){ + waterCount += trapIndexs.get(i + 1)-trapIndexs.get(i)-1; + } + level++; + } + return waterCount; + } + } +``` +#### 2.按列计算 +时间复杂度为$O(n^2)$,按列计算不仅时间复杂度略低于按行计算。而且可以进行多次优化!
+其根本原因在于:**height数组是按列分布的,根据位置找高度是$O(1)$复杂度,而根据高度查位置却是$O(n)$,牛排横切和纵切的难度自然是不同的!** +```java +public class SolutionSumColumn { + public int trap(int[] height) { + int level = 1; + int waterCount = 0; + while(true){ + List trapIndexs =new ArrayList<>(); + for (int i = 0;i < height.length;i++){ + if(height[i] >= level){ + trapIndexs.add(i); + } + } + if (trapIndexs.size() == 1 || trapIndexs.size() == 0){ + break; + } + for (int i = 0;i < trapIndexs.size() - 1;i++){ + waterCount += trapIndexs.get(i + 1)-trapIndexs.get(i)-1; + } + level++; + } + return waterCount; + } +} +``` +#### 3.动态规划 +按列计算的算法中,每次去左边最高和右边最高的都要重新遍历一边数组, +我们将计算结果储存在数组之中,这样就可以避免一些重复遍历。但是本题有一个特殊之处,就是max_right[]需要从后向前计算。用了三次遍历,但是没有嵌套,时间复杂度为$O(n)$,使用了两个辅助数组,空间复杂度为$O(n)$。 +```java +public class SolutionDp { + public int trap(int[] height) { + if(height.length == 0) return 0; + int sum = 0; + int[] max_left = new int[height.length]; + int[] max_right = new int[height.length]; + max_left[0] = height[0]; + max_right[height.length - 1] = height[height.length - 1]; + for( int i = 1;i < height.length - 1;i++){ + max_left[i] = Math.max(max_left[i-1], height[i]); + } + for( int i = height.length - 2;i > 0;i--){ + max_right[i] = Math.max(max_right[i+1], height[i]); + } + for(int i = 1;i < height.length - 1;i++){ + //这是一个关键点: + //1.某处可以接雨水需要左右均有比当前节点高的柱子 + //2.接雨水的量取决于较低的柱子 + int min = Math.min(max_left[i],max_right[i]); + if(min > height[i]){ + sum += min - height[i]; + } + } + return sum; + } +} +``` +#### 4.双指针 +我们发现对于每一个max_left[n]和max_right[n]都是用过两次:
+1.求max_left[n+1]或者max_right[n-1]
+2.求接雨水的数量
+这说明DP算法的空间复杂度还有优化成常数的余地。
+这个算法理解的关键就是:
+1.maxLeftCurrent是从左到右更新,而maxRightCurrent是从又到左更新
+2.未更新部分的区间为(left,right),在这个范围内,因为是求最大值么,maxLeftCurrent和maxRightCurrent的值只可能比当前大,不可能比当前小。也就是如果n在区间(left,right)内,有maxLeftCurrent <= maxLeft[n] 和 maxRight[n]
+3.对于left节点maxLeftCurrent是等效与上面的max_left,而maxRightCurrent则不一定。反之亦然。
+4.如果maxLeftCurrent <= maxRightCurrent,那么根据 maxRightCurrent <= maxRight[n],根据不等式的传递性 maxLeftCurrent <= maxRight[n];反之maxLeftCurrent > maxRightCurrent则有maxRightCurrent >= maxLeft[n];
+5.根据上面算法,我们需要知道的是maxLeft和maxRight的最小值,而不是一定要直接确定这两个值那么根据4的结论,maxLeftCurrent <= maxRightCurrent时,可以根据maxLeftCurrent处理left节点,反之处理right节点。
+ + +```java +public class SolutionDoublePoint { + class Solution { + public int trap(int[] height) { + if(height.length < 2) return 0; + int sum = 0; + int maxLeftCurrent = 0; + int maxRightCurrent = 0; + int left = 0; + int right = height.length - 1; + while( left <= right){ + if(maxLeftCurrent <= maxRightCurrent){ + if(maxLeftCurrent > height[left]){ + sum += (maxLeftCurrent-height[left]); + } + maxLeftCurrent = Math.max(maxLeftCurrent,height[left]); + left++; + } + else{ + if(maxRightCurrent > height[right]){ + sum += (maxRightCurrent - height[right]) ; + } + maxRightCurrent = Math.max(maxRightCurrent, height[right]); + right--; + } + } + + return sum; + } + } +} + +``` +#### 5.栈 +反正我是想不出这方法...
+这个方法计算的是两根匹配柱子之间的水,一次计算一个矩形。
+https://leetcode-cn.com/problems/trapping-rain-water/solution/dan-diao-zhan-jie-jue-jie-yu-shui-wen-ti-by-sweeti/
+说不清楚,直接粘贴别人题解 + +```java + public int trap(int[] height) { + if(height.length <= 2) return 0; + int sum = 0; + Deque stack = new LinkedList<>(); + stack.push(0); + for( int i = 1;i < height.length; i++){ + if(height[i] < height[stack.peek()]){ + stack.push(i); + } + else if(height[i] == height[stack.peek()]){ + stack.pop(); + stack.push(i); + } + else{ + while(!stack.isEmpty() && height[i] > height[stack.peek()]){ + int bottom = stack.pop(); + if(!stack.isEmpty()){ + int rainHeight = Math.min(height[i],height[stack.peek()])-height[bottom]; + int rainWidth = i - stack.peek() - 1; + sum += rainHeight*rainWidth; + } + } + stack.push(i); + } + } + return sum; + } +``` diff --git a/Week1/code/design_circular_deque/MyCircularDeque.java b/Week1/code/design_circular_deque/MyCircularDeque.java new file mode 100644 index 00000000..6e09a801 --- /dev/null +++ b/Week1/code/design_circular_deque/MyCircularDeque.java @@ -0,0 +1,91 @@ +package code.design_circular_deque; + +class MyCircularDeque { + private int[] data; + private int count; + private int front; + private int rear; + private int size; + /** Initialize your data structure here. Set the size of the deque to be k. */ + public MyCircularDeque(int k) { + data = new int[k]; + count = 0; + front = 0; + rear = k-1; + size = k; + } + + /** Adds an item at the front of Deque. Return true if the operation is successful. */ + public boolean insertFront(int value) { + if(count == size){ + return false; + } + count++; + data[front%size] = value; + front = (front+1)%size; + return true; + } + + /** Adds an item at the rear of Deque. Return true if the operation is successful. */ + public boolean insertLast(int value) { + if(count == size){ + return false; + } + count++; + data[rear%size] = value; + rear = (rear+size-1)%size; + return true; + } + + /** Deletes an item from the front of Deque. Return true if the operation is successful. */ + public boolean deleteFront() { + if(count == 0) return false; + count--; + front = (front+size-1)%size; + return true; + } + + /** Deletes an item from the rear of Deque. Return true if the operation is successful. */ + public boolean deleteLast() { + if(count == 0) return false; + count--; + rear = (rear+1)%size; + return true; + + } + + /** Get the front item from the deque. */ + public int getFront() { + if (count==0) return -1; + return data[(front+size-1)%size]; + } + + /** Get the last item from the deque. */ + public int getRear() { + if (count==0) return -1; + return data[(rear+1)%size]; + } + + /** Checks whether the circular deque is empty or not. */ + public boolean isEmpty() { + return count==0; + } + + /** Checks whether the circular deque is full or not. */ + public boolean isFull() { + return count==size; + } +} + +/** + * Your MyCircularDeque object will be instantiated and called as such: + * MyCircularDeque obj = new MyCircularDeque(k); + * boolean param_1 = obj.insertFront(value); + * boolean param_2 = obj.insertLast(value); + * boolean param_3 = obj.deleteFront(); + * boolean param_4 = obj.deleteLast(); + * int param_5 = obj.getFront(); + * int param_6 = obj.getRear(); + * boolean param_7 = obj.isEmpty(); + * boolean param_8 = obj.isFull(); + */ diff --git a/Week1/code/merge_two_sorted_lists/Solution.java b/Week1/code/merge_two_sorted_lists/Solution.java new file mode 100644 index 00000000..0149e2cc --- /dev/null +++ b/Week1/code/merge_two_sorted_lists/Solution.java @@ -0,0 +1,26 @@ +package code.merge_two_sorted_lists; +public class Solution { + public ListNode mergeTwoLists(ListNode l1, ListNode l2) { + ListNode dummy = new ListNode(Integer.MIN_VALUE); + ListNode prev = dummy; + while(l1!= null && l2!= null){ + if(l1.val < l2.val){ + prev.next = l1; + l1 = l1.next; + } + else { + prev.next = l2; + l2 = l2.next; + } + prev = prev.next; + } + prev.next = l1 == null ? l2 : l1; + return dummy.next; + } +} +class ListNode { + int val; + ListNode next;ListNode() {} + ListNode(int val) { this.val = val; } + ListNode(int val, ListNode next) { this.val = val; this.next = next; } +} \ No newline at end of file diff --git a/Week1/code/move_zeroes/Solution.java b/Week1/code/move_zeroes/Solution.java new file mode 100644 index 00000000..24432735 --- /dev/null +++ b/Week1/code/move_zeroes/Solution.java @@ -0,0 +1,16 @@ +package code.move_zeroes; + +public class Solution { + public void moveZeroes(int[] nums) { + int countZero = 0; + for(int i = 0;i < nums.length;i++) { + if(nums[i] == 0){ + countZero++; + } + else if(countZero > 0){ + nums[i-countZero] = nums[i]; + nums[i] = 0; + } + } + } +} diff --git a/Week1/code/puls_one/Solution.java b/Week1/code/puls_one/Solution.java new file mode 100644 index 00000000..43b653e3 --- /dev/null +++ b/Week1/code/puls_one/Solution.java @@ -0,0 +1,16 @@ +package code.puls_one; + +public class Solution { + public int[] plusOne(int[] digits) { + for(int i = digits.length-1 ;i >= 0;i--){ + digits[i]++; + digits[i] = digits[i]%10; + if(digits[i] != 0){ + return digits; + } + } + int[] result = new int[digits.length+1]; + result[0] = 1; + return result; + } +} diff --git a/Week1/code/remove_duplicates_from_sorted_array/SolutionDoublePoint.java b/Week1/code/remove_duplicates_from_sorted_array/SolutionDoublePoint.java new file mode 100644 index 00000000..99c16545 --- /dev/null +++ b/Week1/code/remove_duplicates_from_sorted_array/SolutionDoublePoint.java @@ -0,0 +1,12 @@ +package code.remove_duplicates_from_sorted_array; +public class SolutionDoublePoint { + public int removeDuplicates(int[] nums) { + int pos = 0; + for (int i = 0;i < nums.length ; i++){ + if(nums[i] > nums[pos]) { + nums[pos++] = nums[i]; + } + } + return pos+1; + } +} diff --git a/Week1/code/rotate_array/SolutionCycSwap.java b/Week1/code/rotate_array/SolutionCycSwap.java new file mode 100644 index 00000000..6b76e8ea --- /dev/null +++ b/Week1/code/rotate_array/SolutionCycSwap.java @@ -0,0 +1,21 @@ +package code.rotate_array; +public class SolutionCycSwap { + public void rotate(int[] nums, int k) { + if (nums.length == 0) return; + int count = 0; + for(int i = 0; count < nums.length; i++){ + int pos = i; + int temp = nums[i]; + while(true) { + int target = (pos + k) % nums.length; + int targetValue = nums [target]; + nums[target] = temp; + temp = targetValue; + count++; + if(target == i) break; + pos = target; + } + } + + } +} diff --git a/Week1/code/rotate_array/SolutionDeque.java b/Week1/code/rotate_array/SolutionDeque.java new file mode 100644 index 00000000..2bd73e15 --- /dev/null +++ b/Week1/code/rotate_array/SolutionDeque.java @@ -0,0 +1,20 @@ +package code.rotate_array; + +import java.util.*; + +public class SolutionDeque { + public void rotate(int[] nums, int k) { + if(nums.length == 0) return ; + Deque queue = new LinkedList(); + for(int i:nums){ + queue.addLast(i); + } + while(k > 0){ + queue.offerFirst(queue.removeLast()); + k--; + } + for(int i =0; i < nums.length;i++){ + nums[i] = queue.pollFirst(); + } + } +} diff --git a/Week1/code/rotate_array/SolutionReverse.java b/Week1/code/rotate_array/SolutionReverse.java new file mode 100644 index 00000000..a75fcc4a --- /dev/null +++ b/Week1/code/rotate_array/SolutionReverse.java @@ -0,0 +1,16 @@ +package code.rotate_array; +public class SolutionReverse { + public void rotate(int[] nums, int k) { + k = k % nums.length; + reverse(nums, 0, nums.length-1); + reverse(nums, 0, k-1); + reverse(nums, k, nums.length-1); + } + void reverse(int[] arr, int start, int end){ + while(start < end) { + int temp = arr[start]; + arr[start++] = arr[end]; + arr[end--] = temp; + } + } +} diff --git a/Week1/code/rotate_array/SolutionTempArray.java b/Week1/code/rotate_array/SolutionTempArray.java new file mode 100644 index 00000000..0c8f3ff1 --- /dev/null +++ b/Week1/code/rotate_array/SolutionTempArray.java @@ -0,0 +1,17 @@ +package code.rotate_array; +public class SolutionTempArray { + public void rotate(int[] nums, int k) { + if(nums.length == 0) return; + k = k % nums.length; + int[] temp = new int[k]; + for(int i = 0;i < k;i++) { + temp[i] = nums[nums.length-k+i]; + } + for(int i = nums.length-k-1;i >= 0 ;i--) { + nums[i+k] = nums[i]; + } + for(int i = 0;i < k;i++){ + nums[i] = temp[i]; + } + } +} diff --git a/Week1/code/trapping_rain_water/SolutionDoublePoint.java b/Week1/code/trapping_rain_water/SolutionDoublePoint.java new file mode 100644 index 00000000..14b259ac --- /dev/null +++ b/Week1/code/trapping_rain_water/SolutionDoublePoint.java @@ -0,0 +1,32 @@ +package code.trapping_rain_water; + +public class SolutionDoublePoint { + class Solution { + public int trap(int[] height) { + if(height.length < 2) return 0; + int sum = 0; + int maxLeftCurrent = 0; + int maxRightCurrent = 0; + int left = 0; + int right = height.length - 1; + while( left <= right){ + if(maxLeftCurrent <= maxRightCurrent){ + if(maxLeftCurrent > height[left]){ + sum += (maxLeftCurrent-height[left]); + } + maxLeftCurrent = Math.max(maxLeftCurrent,height[left]); + left++; + } + else{ + if(maxRightCurrent > height[right]){ + sum += (maxRightCurrent - height[right]) ; + } + maxRightCurrent = Math.max(maxRightCurrent, height[right]); + right--; + } + } + + return sum; + } + } +} diff --git a/Week1/code/trapping_rain_water/SolutionDp.java b/Week1/code/trapping_rain_water/SolutionDp.java new file mode 100644 index 00000000..7e394711 --- /dev/null +++ b/Week1/code/trapping_rain_water/SolutionDp.java @@ -0,0 +1,25 @@ +package code.trapping_rain_water; + +public class SolutionDp { + public int trap(int[] height) { + if(height.length == 0) return 0; + int sum = 0; + int[] max_left = new int[height.length]; + int[] max_right = new int[height.length]; + max_left[0] = height[0]; + max_right[height.length - 1] = height[height.length - 1]; + for( int i = 1;i < height.length - 1;i++){ + max_left[i] = Math.max(max_left[i-1], height[i]); + } + for( int i = height.length - 2;i > 0;i--){ + max_right[i] = Math.max(max_right[i+1], height[i]); + } + for(int i = 1;i < height.length - 1;i++){ + int min = Math.min(max_left[i],max_right[i]); + if(min > height[i]){ + sum += min - height[i]; + } + } + return sum; + } +} diff --git a/Week1/code/trapping_rain_water/SolutionStack.java b/Week1/code/trapping_rain_water/SolutionStack.java new file mode 100644 index 00000000..7360c882 --- /dev/null +++ b/Week1/code/trapping_rain_water/SolutionStack.java @@ -0,0 +1,34 @@ +package code.trapping_rain_water; + +import java.util.Deque; +import java.util.LinkedList; + +public class SolutionStack { + public int trap(int[] height) { + if(height.length <= 2) return 0; + int sum = 0; + Deque stack = new LinkedList<>(); + stack.push(0); + for( int i = 1;i < height.length; i++){ + if(height[i] < height[stack.peek()]){ + stack.push(i); + } + else if(height[i] == height[stack.peek()]){ + stack.pop(); + stack.push(i); + } + else{ + while(!stack.isEmpty() && height[i] > height[stack.peek()]){ + int bottom = stack.pop(); + if(!stack.isEmpty()){ + int rainHeight = Math.min(height[i],height[stack.peek()])-height[bottom]; + int rainWidth = i - stack.peek() - 1; + sum += rainHeight*rainWidth; + } + } + stack.push(i); + } + } + return sum; + } +} diff --git a/Week1/code/trapping_rain_water/SolutionSumColumn.java b/Week1/code/trapping_rain_water/SolutionSumColumn.java new file mode 100644 index 00000000..d364afb8 --- /dev/null +++ b/Week1/code/trapping_rain_water/SolutionSumColumn.java @@ -0,0 +1,27 @@ +package code.trapping_rain_water; + +import java.util.ArrayList; +import java.util.List; + +public class SolutionSumColumn { + public int trap(int[] height) { + int level = 1; + int waterCount = 0; + while(true){ + List trapIndexs =new ArrayList<>(); + for (int i = 0;i < height.length;i++){ + if(height[i] >= level){ + trapIndexs.add(i); + } + } + if (trapIndexs.size() == 1 || trapIndexs.size() == 0){ + break; + } + for (int i = 0;i < trapIndexs.size() - 1;i++){ + waterCount += trapIndexs.get(i + 1)-trapIndexs.get(i)-1; + } + level++; + } + return waterCount; + } +} diff --git a/Week1/code/trapping_rain_water/SolutionSumRow.java b/Week1/code/trapping_rain_water/SolutionSumRow.java new file mode 100644 index 00000000..de70fa20 --- /dev/null +++ b/Week1/code/trapping_rain_water/SolutionSumRow.java @@ -0,0 +1,29 @@ +package code.trapping_rain_water; + +import java.util.ArrayList; +import java.util.List; + +public class SolutionSumRow { + class Solution { + public int trap(int[] height) { + int level = 1; + int waterCount = 0; + while(true){ + List trapIndexs=new ArrayList<>(); + for (int i = 0;i < height.length;i++){ + if(height[i] >= level){ + trapIndexs.add(i); + } + } + if (trapIndexs.size() == 1 || trapIndexs.size() == 0){ + break; + } + for (int i = 0;i < trapIndexs.size() - 1;i++){ + waterCount += trapIndexs.get(i + 1)-trapIndexs.get(i)-1; + } + level++; + } + return waterCount; + } + } +} diff --git a/Week1/code/two_sum/Solution.java b/Week1/code/two_sum/Solution.java new file mode 100644 index 00000000..4f0c782c --- /dev/null +++ b/Week1/code/two_sum/Solution.java @@ -0,0 +1,23 @@ +package code.two_sum; + +import java.util.HashMap; +import java.util.Map; + +public class Solution { + public int[] twoSum(int[] nums, int target) { + int[] result = new int[2]; + Map history = new HashMap<>(); + for(int i = 0;i < nums.length;i++) { + int remain = target - nums[i]; + if(history.containsKey(nums[i])){ + result[1] = i; + result[0] = history.get(nums[i]); + return result; + } + else { + history.put(remain,i); + } + } + return result; + } +} diff --git a/Week2/README.md b/Week2/README.md index 50de3041..66e43617 100644 --- a/Week2/README.md +++ b/Week2/README.md @@ -1 +1,72 @@ -学习笔记 \ No newline at end of file +# HashMap笔记 + +### 私有属性 +```java +public class HashMap extends AbstractMap implements Map, Cloneable, Serializable { + // 序列号 + private static final long serialVersionUID = 362498820763181265L; + // 默认的初始容量是16 + static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; + // 最大容量 + static final int MAXIMUM_CAPACITY = 1 << 30; + // 默认的填充因子 + static final float DEFAULT_LOAD_FACTOR = 0.75f; + // 当桶(bucket)上的结点数大于这个值时会转成红黑树 + static final int TREEIFY_THRESHOLD = 8; + // 当桶(bucket)上的结点数小于这个值时树转链表 + static final int UNTREEIFY_THRESHOLD = 6; + // 桶中结构转化为红黑树对应的table的最小大小 + static final int MIN_TREEIFY_CAPACITY = 64; + // 存储元素的数组,总是2的幂次倍 + transient Node[] table; + // 存放具体元素的集 + transient Set> entrySet; + // 存放元素的个数,注意这个不等于数组的长度。 + transient int size; + // 每次扩容和更改map结构的计数器 + transient int modCount; + // 临界值 当实际大小(容量*填充因子)超过临界值时,会进行扩容 + int threshold; + // 加载因子 + final float loadFactor; +} +``` +##### loadFactor加载因子 +loadFactor加载因子是控制数组存放数据的疏密程度,loadFactor越趋近于1,那么 数组中存放的数据(entry)也就越多,也就越密,也就是会让链表的长度增加,loadFactor越小,也就是趋近于0,数组中存放的数据(entry)也就越少,也就越稀疏。 + +**loadFactor太大导致查找元素效率低,太小导致数组的利用率低,存放的数据会很分散。loadFactor的默认值为0.75f是官方给出的一个比较好的临界值。** + +给定的默认容量为 16,负载因子为 0.75。Map 在使用过程中不断的往里面存放数据,当数量达到了 16 * 0.75 = 12 就需要将当前 16 的容量进行扩容,而扩容这个过程涉及到 rehash、复制数据等操作,所以非常消耗性能。 +##### capacity +Returns a power of two size for the given target capacity. +当HashMap初始化的时候会初始化为比给定capacity更大的一个2的n次幂 +比如给定7,则初始化为8,给9则初始化为16 + +### hash +```java +static final int hash(Object key) { + int h; + return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); + } +``` +### put +1. 如果定位到的数组位置没有元素就直接插入。 +2. 果定位到的数组位置有元素就和要插入的key比较,如果key相同就直接覆盖,如果key不相同,就判断p是否是一个树节点,如果是就调用putTreeVal将元素添加进入。如果不是就遍历链表插入(插入的是链表尾部)。 +3. 如果插入链表后发现链表的长度大于TREEIFY_THRESHOLD会将链表转化为红黑树。 +4. 如果putTreeVal发现容量小于MIN_TREEIFY_CAPACITY则会直接扩容而不是创建红黑树。 +### get +1. 如果定位到的元素的key和hash值都相等,则直接返回 +2. 如果定位到的元素是TreeNode,则在红黑树中查找,否则则遍历链表 +### rehash +1. 进行扩容,会伴随着一次重新hash分配,并且会遍历hash表中所有的元素,是非常耗时的。在编写程序中,要尽量避免resize。 +2. 每次扩容的容量是扩容前的二倍 +### jdk1.7与jdk1.8区别 +1.hash函数不同 jdk1.7会进行四次扰动,而jdk1.8仅进行了一次。扰动是为了防止写的不太好的hashCode函数带来过多的碰撞 +2.jdk1.7是纯粹的拉链法解决冲突,而jdk1.8则在链表长度超过TREEIFY_THRESHOLD并且容量大于MIN_TREEIFY_CAPACITY时使用红黑树来代替链表,提升了冲突时的查询效率 + +# 心得体会 +1. 递归不代表效率低,只要没有重复计算,递归是完全没有问题的,而且代码很整洁。 + + + + diff --git a/Week2/code/binary_tree_inorder_traversal/SolutionIteration.java b/Week2/code/binary_tree_inorder_traversal/SolutionIteration.java new file mode 100644 index 00000000..f94e9f2c --- /dev/null +++ b/Week2/code/binary_tree_inorder_traversal/SolutionIteration.java @@ -0,0 +1,43 @@ +package code.binary_tree_inorder_traversal; + +import java.util.ArrayList; +import java.util.Deque; +import java.util.LinkedList; +import java.util.List; + +public class SolutionIteration { + public List inorderTraversal(TreeNode root) { + List result = new ArrayList(); + Deque stack = new LinkedList(); + while (root != null || !stack.isEmpty()) { + while (root != null) { + stack.push(root); + root = root.left; + } + root = stack.pop(); + result.add(root.val); + root = root.right; + } + return result; + } + + private class TreeNode { + int val; + TreeNode left; + TreeNode right; + + TreeNode() { + } + + TreeNode(int val) { + this.val = val; + } + + TreeNode(int val, TreeNode left, TreeNode right) { + this.val = val; + this.left = left; + this.right = right; + } + } +} + diff --git a/Week2/code/binary_tree_inorder_traversal/SolutionRecursion.java b/Week2/code/binary_tree_inorder_traversal/SolutionRecursion.java new file mode 100644 index 00000000..9fb76f9f --- /dev/null +++ b/Week2/code/binary_tree_inorder_traversal/SolutionRecursion.java @@ -0,0 +1,40 @@ +package code.binary_tree_inorder_traversal; + +import java.util.ArrayList; +import java.util.List; + +public class SolutionRecursion { + List result = new ArrayList(); + + public List inorderTraversal(TreeNode root) { + visit(root); + return result; + } + + public void visit(TreeNode node) { + if (node == null) return; + visit(node.left); + result.add(node.val); + visit(node.right); + } + + private class TreeNode { + int val; + TreeNode left; + TreeNode right; + + TreeNode() { + } + + TreeNode(int val) { + this.val = val; + } + + TreeNode(int val, TreeNode left, TreeNode right) { + this.val = val; + this.left = left; + this.right = right; + } + } + +} diff --git a/Week2/code/binary_tree_preorder_traversal/SolutionIteration.java b/Week2/code/binary_tree_preorder_traversal/SolutionIteration.java new file mode 100644 index 00000000..cc6698da --- /dev/null +++ b/Week2/code/binary_tree_preorder_traversal/SolutionIteration.java @@ -0,0 +1,38 @@ +package code.binary_tree_preorder_traversal; +import java.util.*; +public class SolutionIteration { + public List preorderTraversal(TreeNode root) { + List result = new ArrayList(); + Deque stack = new LinkedList(); + TreeNode node = root; + while (!stack.isEmpty() || node != null) { + while (node != null) { + result.add(node.val); + stack.push(node); + node = node.left; + } + node = stack.pop(); + node = node.right; + } + + return result; + } + private class TreeNode { + int val; + TreeNode left; + TreeNode right; + + TreeNode() { + } + + TreeNode(int val) { + this.val = val; + } + + TreeNode(int val, TreeNode left, TreeNode right) { + this.val = val; + this.left = left; + this.right = right; + } + } +} diff --git a/Week2/code/binary_tree_preorder_traversal/SolutionRecursion.java b/Week2/code/binary_tree_preorder_traversal/SolutionRecursion.java new file mode 100644 index 00000000..2200b55f --- /dev/null +++ b/Week2/code/binary_tree_preorder_traversal/SolutionRecursion.java @@ -0,0 +1,34 @@ +package code.binary_tree_preorder_traversal; +import java.util.*; + +public class SolutionRecursion { + List result = new ArrayList(); + public List preorderTraversal(TreeNode root) { + visit(root); + return result; + } + public void visit(TreeNode node){ + if(node == null) return; + result.add(node.val); + visit(node.left); + visit(node.right); + } + private class TreeNode { + int val; + TreeNode left; + TreeNode right; + + TreeNode() { + } + + TreeNode(int val) { + this.val = val; + } + + TreeNode(int val, TreeNode left, TreeNode right) { + this.val = val; + this.left = left; + this.right = right; + } + } +} diff --git a/Week2/code/group_anagrams/SolutionHashTable.java b/Week2/code/group_anagrams/SolutionHashTable.java new file mode 100644 index 00000000..f88b7bc1 --- /dev/null +++ b/Week2/code/group_anagrams/SolutionHashTable.java @@ -0,0 +1,20 @@ +package code.group_anagrams; +import java.util.*; +public class SolutionHashTable { + public List> groupAnagrams(String[] strs) { + Map> map = new HashMap(strs.length); + for(String str : strs){ + char[] alphaCount = new char[26]; + for(char c : str.toCharArray()){ + alphaCount[c-'a']++; + } + String hashKey = String.valueOf(alphaCount); + if(!map.containsKey(hashKey)){ + map.put(hashKey,new ArrayList()); + } + List list = map.get(hashKey); + list.add(str); + } + return new ArrayList(map.values()); + } +} diff --git a/Week2/code/n_ary_tree_level_order_traversal/SolutionDFS.java b/Week2/code/n_ary_tree_level_order_traversal/SolutionDFS.java new file mode 100644 index 00000000..73fc6a86 --- /dev/null +++ b/Week2/code/n_ary_tree_level_order_traversal/SolutionDFS.java @@ -0,0 +1,36 @@ +package code.n_ary_tree_level_order_traversal; +import java.util.*; +public class SolutionDFS { + private List> result; + public List> levelOrder(Node root) { + result = new ArrayList(); + dfs(root,0); + return result; + } + private void dfs(Node node,int depth){ + if(node == null) return; + if(result.size() < depth+1){ + result.add(new ArrayList()); + } + List level = result.get(depth); + level.add(node.val); + for (Node child : node.children) { + dfs(child,depth+1); + } + } + private class Node { + public int val; + public List children; + + public Node() {} + + public Node(int _val) { + val = _val; + } + + public Node(int _val, List _children) { + val = _val; + children = _children; + } + }; +} diff --git a/Week2/code/n_ary_tree_level_order_traversal/SolutionQueue.java b/Week2/code/n_ary_tree_level_order_traversal/SolutionQueue.java new file mode 100644 index 00000000..02d9e83a --- /dev/null +++ b/Week2/code/n_ary_tree_level_order_traversal/SolutionQueue.java @@ -0,0 +1,48 @@ +package code.n_ary_tree_level_order_traversal; +import java.util.*; +public class SolutionQueue { + class Solution { + public List> levelOrder(Node root) { + Queue queue = new LinkedList(); + int levelCount = 1; + int nextLevelCount = 0; + queue.offer(root); + List> result = new ArrayList(); + if(root == null) return result; + List level = new ArrayList(levelCount); + while(!queue.isEmpty()){ + Node current = queue.poll(); + level.add(current.val); + if(current.children != null){ + for(Node n : current.children){ + queue.offer(n); + } + nextLevelCount += current.children.size(); + } + levelCount--; + if(levelCount == 0) { + result.add(level); + levelCount = nextLevelCount; + level = new ArrayList(levelCount); + nextLevelCount = 0; + } + } + return result; + } + } + private class Node { + public int val; + public List children; + + public Node() {} + + public Node(int _val) { + val = _val; + } + + public Node(int _val, List _children) { + val = _val; + children = _children; + } + }; +} diff --git a/Week2/code/top_k_frequent_elements/SolutionHeap.java b/Week2/code/top_k_frequent_elements/SolutionHeap.java new file mode 100644 index 00000000..c843e81b --- /dev/null +++ b/Week2/code/top_k_frequent_elements/SolutionHeap.java @@ -0,0 +1,49 @@ +package code.top_k_frequent_elements; +import java.util.*; +public class SolutionHeap { + class Solution { + public int[] topKFrequent(int[] nums, int k) { + Map map = new HashMap<>(nums.length); + for(int num : nums){ + if(map.containsKey(num)){ + Freq currentFreq = map.get(num); + currentFreq.inc(); + } + else{ + Freq currentFreq = new Freq(num); + map.put(num,currentFreq); + } + } + PriorityQueue freqQueue = new PriorityQueue<>(k); + for (Map.Entry entry : map.entrySet()){ + if(freqQueue.size() freqQueue.peek().freq){ + freqQueue.poll(); + freqQueue.add(entry.getValue()); + } + } + int[] result = new int[k]; + for(int i = 0;i < k;i++){ + result [i] = freqQueue.poll().key; + } + return result; + } + public class Freq implements Comparable{ + int freq; + int key; + Freq(int key){ + this.key = key; + this.freq = 1; + } + public void inc(){ + this.freq++; + } + @Override + public int compareTo(Freq o) { + return this.freq - o.freq; + } + } + } +} diff --git a/Week2/code/ugly_number_ii/SolutionDP.java b/Week2/code/ugly_number_ii/SolutionDP.java new file mode 100644 index 00000000..e3f165b4 --- /dev/null +++ b/Week2/code/ugly_number_ii/SolutionDP.java @@ -0,0 +1,18 @@ +package code.ugly_number_ii; + +public class SolutionDP { + public int nthUglyNumber(int n) { + int[] dp = new int[n]; + dp[0] = 1; + int a = 0; + int b = 0; + int c = 0; + for(int i = 1;i < n;i++){ + dp[i] = Math.min(dp[a]*2,Math.min(dp[b]*3,dp[c]*5)); + if(dp[i] == dp[a]*2) a++; + if(dp[i] == dp[b]*3) b++; + if(dp[i] == dp[c]*5) c++; + } + return dp[n-1]; + } +} diff --git a/Week2/code/ugly_number_ii/SolutionDPCache.java b/Week2/code/ugly_number_ii/SolutionDPCache.java new file mode 100644 index 00000000..6b2eb2f3 --- /dev/null +++ b/Week2/code/ugly_number_ii/SolutionDPCache.java @@ -0,0 +1,25 @@ +package code.ugly_number_ii; + +public class SolutionDPCache { + static int[] dp = new int[1690]; + static int a = 0; + static int b = 0; + static int c = 0; + static int count = 1; + public int nthUglyNumber(int n) { + if( n<= count){ + return dp[n-1]; + } + for(int i = count; i < n; i++){ + dp[i] = Math.min(Math.min(dp[a]*2, dp[b]*3),dp[c]*5); + if(dp[i]==dp[a]*2) a++; + if(dp[i]==dp[b]*3) b++; + if(dp[i]==dp[c]*5) c++; + count++; + } + return dp[n-1]; + } + static{ + dp[0] = 1; + } +}