diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..485dee64b --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.idea diff --git a/Week 01/id_011/design-circular-deque.go b/Week 01/id_011/design-circular-deque.go new file mode 100644 index 000000000..f2c3d901b --- /dev/null +++ b/Week 01/id_011/design-circular-deque.go @@ -0,0 +1,125 @@ +package algorithm00401 + +type MyCircularDeque struct { + len, cap int + front, rear *node +} + +type node struct { + val int + prev, next *node +} + +/** Initialize your data structure here. Set the size of the deque to be k. */ +func Constructor(k int) MyCircularDeque { + return MyCircularDeque{ + cap: k, + } +} + +/** Adds an item at the front of Deque. Return true if the operation is successful. */ +func (this *MyCircularDeque) InsertFront(value int) bool { + if this.IsFull() { + return false + } + n := &node{ + val: value, + } + if this.IsEmpty() { + this.front, this.rear = n, n + } else { + n.next = this.front + this.front.prev = n + this.front = n + } + this.len++ + return true +} + +/** Adds an item at the rear of Deque. Return true if the operation is successful. */ +func (this *MyCircularDeque) InsertLast(value int) bool { + if this.IsFull() { + return false + } + n := &node{ + val: value, + } + if this.IsEmpty() { + this.front, this.rear = n, n + } else { + n.prev = this.rear + this.rear.next = n + this.rear = n + } + this.len++ + return true +} + +/** Deletes an item from the front of Deque. Return true if the operation is successful. */ +func (this *MyCircularDeque) DeleteFront() bool { + if this.IsEmpty() { + return false + } + if this.len == 1 { + this.front, this.rear = nil, nil + } else { + this.front = this.front.next + this.front.prev = nil + } + this.len-- + return true +} + +/** Deletes an item from the rear of Deque. Return true if the operation is successful. */ +func (this *MyCircularDeque) DeleteLast() bool { + if this.IsEmpty() { + return false + } + if this.len == 1 { + this.front, this.rear = nil, nil + } else { + this.rear = this.rear.prev + this.rear.next = nil + } + this.len-- + return true +} + +/** Get the front item from the deque. */ +func (this *MyCircularDeque) GetFront() int { + if this.IsEmpty() { + return -1 + } + return this.front.val +} + +/** Get the last item from the deque. */ +func (this *MyCircularDeque) GetRear() int { + if this.IsEmpty() { + return -1 + } + return this.rear.val +} + +/** Checks whether the circular deque is empty or not. */ +func (this *MyCircularDeque) IsEmpty() bool { + return this.len == 0 +} + +/** Checks whether the circular deque is full or not. */ +func (this *MyCircularDeque) IsFull() bool { + return this.len == this.cap +} + +/** + * Your MyCircularDeque object will be instantiated and called as such: + * obj := Constructor(k); + * param_1 := obj.InsertFront(value); + * param_2 := obj.InsertLast(value); + * param_3 := obj.DeleteFront(); + * param_4 := obj.DeleteLast(); + * param_5 := obj.GetFront(); + * param_6 := obj.GetRear(); + * param_7 := obj.IsEmpty(); + * param_8 := obj.IsFull(); + */ diff --git a/Week 01/id_011/merge-sorted-array.go b/Week 01/id_011/merge-sorted-array.go new file mode 100644 index 000000000..215f05c78 --- /dev/null +++ b/Week 01/id_011/merge-sorted-array.go @@ -0,0 +1,22 @@ +package algorithm00401 + +func merge(nums1 []int, m int, nums2 []int, n int) { + i := m + n - 1 + m-- + n-- + + for m >= 0 && n >= 0 { + if nums1[m] > nums2[n] { + nums1[i] = nums1[m] + m-- + } else { + nums1[i] = nums2[n] + n-- + } + i-- + } + for n >= 0 { + nums1[n] = nums2[n] + n-- + } +} diff --git a/Week 01/id_011/merge-two-sorted-lists.go b/Week 01/id_011/merge-two-sorted-lists.go new file mode 100644 index 000000000..1277d78d5 --- /dev/null +++ b/Week 01/id_011/merge-two-sorted-lists.go @@ -0,0 +1,11 @@ +package algorithm00401 + +func mergeTwoLists(l1, l2 *ListNode) *ListNode { + if l1 == nil || (l2 != nil && l1.Val > l2.Val) { + l1, l2 = l2, l1 + } + if l1 != nil { + l1.Next = mergeTwoLists(l1.Next, l2) + } + return l1 +} diff --git a/Week 01/id_011/move-zeroes.go b/Week 01/id_011/move-zeroes.go new file mode 100644 index 000000000..3e40444aa --- /dev/null +++ b/Week 01/id_011/move-zeroes.go @@ -0,0 +1,13 @@ +package algorithm00401 + +func moveZeroes(nums []int) { + k := 0 + for i := 0; i < len(nums); i++ { + if nums[i] != 0 { + if k != i { + nums[i], nums[k] = nums[k], nums[i] + } + k++ + } + } +} diff --git a/Week 01/id_011/plus-one.go b/Week 01/id_011/plus-one.go new file mode 100644 index 000000000..2c56abb49 --- /dev/null +++ b/Week 01/id_011/plus-one.go @@ -0,0 +1,15 @@ +package algorithm00401 + +func plusOne(digits []int) []int { + for i := len(digits); i >= 0; i-- { + digits[i]++ + digits[i] %= 10 + if digits[i] != 0 { + return digits + } + } + + digits = make([]int, len(digits)+1) + digits[0] = 1 + return digits +} diff --git a/Week 01/id_011/remove-duplicates-from-sorted-array.go b/Week 01/id_011/remove-duplicates-from-sorted-array.go new file mode 100644 index 000000000..c30882402 --- /dev/null +++ b/Week 01/id_011/remove-duplicates-from-sorted-array.go @@ -0,0 +1,12 @@ +package algorithm00401 + +func removeDuplicates(nums []int) int { + i := 0 + for j := 0; j < len(nums); j++ { + if nums[i] != nums[j] { + i++ + nums[i] = nums[j] + } + } + return i + 1 +} diff --git a/Week 01/id_011/rotate-array.go b/Week 01/id_011/rotate-array.go new file mode 100644 index 000000000..7ce591706 --- /dev/null +++ b/Week 01/id_011/rotate-array.go @@ -0,0 +1,16 @@ +package algorithm00401 + +func rotate(nums []int, k int) { + k %= len(nums) + reverse(nums, 0, len(nums)-1) + reverse(nums, 0, k-1) + reverse(nums, k, len(nums)-1) +} + +func reverse(nums []int, i, j int) { + for i < j { + nums[i], nums[j] = nums[j], nums[i] + i++ + j-- + } +} diff --git a/Week 01/id_011/two-sum.go b/Week 01/id_011/two-sum.go new file mode 100644 index 000000000..0a6006dca --- /dev/null +++ b/Week 01/id_011/two-sum.go @@ -0,0 +1,30 @@ +package algorithm00401 + +// 对撞指针解法 +func twoSum2(numbers []int, target int) []int { + l, r := 0, len(numbers)-1 + for l < r { + if numbers[l]+numbers[r] == target { + return []int{l, r} + } else if numbers[l]+numbers[r] > target { + r-- + } else { + l++ + } + } + return nil +} + +// hash 解法 +func twoSum(numbers []int, target int) []int { + memo := make(map[int]int) + for i := 0; i < len(numbers); i++ { + sub := target - nums[i] + if j, ok := memo[sub]; ok { + return []int{j, i} + } else { + memo[nums[i]] = i + } + } + return nil +} diff --git a/Week 01/id_016/LeetCode_15_016.js b/Week 01/id_016/LeetCode_15_016.js new file mode 100644 index 000000000..69f322810 --- /dev/null +++ b/Week 01/id_016/LeetCode_15_016.js @@ -0,0 +1,63 @@ +/* + * @Description: This is a description + * @Author: Ask + * @LastEditors: Ask + * @Date: 2019-10-19 10:09:38 + * @LastEditTime: 2019-10-19 15:40:33 +1.暴力破解 3层循环 O(n^3) -- 存在执行时间过长的问题 +2.模拟两数之和-双指针进行求解O(n^2) -- 代码过于冗余 +3.参考网上代码进行修复O(n^2) -- 修复了数组重复的问题,优化代码18行 + */ +/* + * @lc app=leetcode id=15 lang=javascript + * + * [15] 3Sum + */ +// @lc code=start +/** + * @param {number[]} nums + * @return {number[][]} + */ +// var threeSum = function(nums) { +// let length = nums.length; +// let arr = []; +// let map = new Map(); +// for (let i = 0; i < length - 2; i++) { +// for (let j = i + 1; j < length - 1; j++) { +// for (let k = j + 1; k < length; k++) { +// if (nums[i] + nums[j] + nums[k] === 0) { +// arr.push([nums[i], nums[j], nums[k]]); +// } +// } +// } +// } +// arr.forEach(item => { +// item.sort((a, b) => a - b); +// map.set(item.join(), item); +// }); +// return Array.from(map.values()); +// }; +var threeSum = function(nums) { + nums.sort((a, b) => a - b); + let arr = []; + for (let i = 0; i < nums.length - 2; i++) { + if (i > 0 && nums[i] === nums[i - 1]) continue; + for (let l = i + 1, r = nums.length - 1; l < r; ) { + let sum = nums[i] + nums[l] + nums[r]; + if (sum === 0) { + arr.push([nums[i], nums[l++], nums[r--]]); + while (l < r && nums[l] === nums[l - 1]) l++; + while (l < r && nums[r] === nums[r + 1]) r--; + } else if (sum < 0) { + l++; + } else if (sum > 0) { + r--; + } + } + } + return arr; +}; +// @lc code=end +// console.log(threeSum([0, 0, 0, 0])); +console.log(threeSum([-4, -2, -2, -2, 0, 1, 2, 2, 2, 3, 3, 4, 4, 6, 6])); +// console.log(threeSum([-4, -2, -2, -2, 0, 1, 2, 2, 2, 3, 3, 4, 4, 6, 6])); diff --git a/Week 01/id_016/LeetCode_189_016.js b/Week 01/id_016/LeetCode_189_016.js new file mode 100644 index 000000000..3b7a3e0af --- /dev/null +++ b/Week 01/id_016/LeetCode_189_016.js @@ -0,0 +1,85 @@ +/* + * @lc app=leetcode id=189 lang=javascript + * + * [189] Rotate Array + * + * https://leetcode.com/problems/rotate-array/description/ + * + * algorithms + * Easy (31.69%) + * Likes: 1718 + * Dislikes: 670 + * Total Accepted: 357.5K + * Total Submissions: 1.1M + * Testcase Example: '[1,2,3,4,5,6,7]\n3' + * + * Given an array, rotate the array to the right by k steps, where k is + * non-negative. + * + * Example 1: + * + * + * Input: [1,2,3,4,5,6,7] and k = 3 + * Output: [5,6,7,1,2,3,4] + * Explanation: + * rotate 1 steps to the right: [7,1,2,3,4,5,6] + * rotate 2 steps to the right: [6,7,1,2,3,4,5] + * rotate 3 steps to the right: [5,6,7,1,2,3,4] + * + * + * Example 2: + * + * + * Input: [-1,-100,3,99] and k = 2 + * Output: [3,99,-1,-100] + * Explanation: + * rotate 1 steps to the right: [99,-1,-100,3] + * rotate 2 steps to the right: [3,99,-1,-100] + * + * + * Note: + * + * + * Try to come up as many solutions as you can, there are at least 3 different + * ways to solve this problem. + * Could you do it in-place with O(1) extra space? + * + 1.队列一样出队入队 -- 时间O(n) 空间O(1) + 2.一次性计算完成进行移动 -- 时间O(1) 空间O(n) + 3.预先计算好每个数的位置,一趟循环走完 -- 时间O(n) 空间O(n) + */ + +// @lc code=start +/** + * @param {number[]} nums + * @param {number} k + * @return {void} Do not return anything, modify nums in-place instead. + */ +// var rotate = function(nums, k) { +// while (k) { +// let res = nums.pop(); +// nums.unshift(res); +// k--; +// } +// return nums; +// }; +// var rotate = function(nums, k) { +// let length = nums.length; +// k = k % length; +// let t = length - k; +// let tempArr = nums.slice(t); +// console.log(tempArr); +// nums.splice(k, t, ...nums.slice(0, t)); +// nums.splice(0, k, ...tempArr); +// return nums; +// }; +var rotate = function(nums, k) { + let temp = [...nums]; + let length = nums.length; + for (let i = 0; i < length; i++) { + nums[(i + k) % length] = temp[i]; + } + return nums; +}; +// @lc code=end +console.log(rotate([-1, -100, 3, 99], 2)); diff --git a/Week 01/id_016/LeetCode_206_016.js b/Week 01/id_016/LeetCode_206_016.js new file mode 100644 index 000000000..01c368e02 --- /dev/null +++ b/Week 01/id_016/LeetCode_206_016.js @@ -0,0 +1,100 @@ +/* + * @lc app=leetcode id=206 lang=javascript + * + * [206] Reverse Linked List + * + * https://leetcode.com/problems/reverse-linked-list/description/ + * + * algorithms + * Easy (57.23%) + * Likes: 2935 + * Dislikes: 73 + * Total Accepted: 712.9K + * Total Submissions: 1.2M + * Testcase Example: '[1,2,3,4,5]' + * + * Reverse a singly linked list. + * + * Example: + * + * + * Input: 1->2->3->4->5->NULL + * Output: 5->4->3->2->1->NULL + * + * + * Follow up: + * + * A linked list can be reversed either iteratively or recursively. Could you + * implement both? + 1.第一个是迭代的方式-从头到尾迭代 时间O(n) 空间O(1) + 2.考虑递归的方式 -从头到尾递,尾到头归(此时指向链接操作) 时间O(n) 空间O(n) ---思想太奇妙了 + * + */ +// @lc code=start +/** + * Definition for singly-linked list. + * function ListNode(val) { + * this.val = val; + * this.next = null; + * } + */ +/** + * @param {ListNode} head + * @return {ListNode} + */ +// var reverseList = function(head) { +// let temp = null; +// let newHead = null; +// while (head !== null) { +// temp = head; +// head = head.next; +// temp.next = newHead; +// newHead = temp; +// } +// return newHead; +// }; +var reverseList = function(head) { + // head === null:兼容空链表的情况 + if (head === null || head.next === null) return head; // find tail node,开始递归 + let h = reverseList(head.next); // 归的时候拿到每一个值 + head.next.next = head; // 把当前的节点指向下一个的next + head.next = null; // 相当于尾节点置空 + return h; +}; +// @lc code=end + +//=====================================test===================================== +/** + * @Description: 构造一个简单链表 + * @param {Array} + * @return: ListNode + */ +// 构造一个简单链表 +function createLinkedList(arr) { + let list = null; + for (let index = arr.length - 1; index >= 0; index--) { + if (list === null) { + list = new ListNode(arr[index]); + } else { + let temp = new ListNode(arr[index]); + temp.next = list; + list = temp; + } + } + return list; +} + +/** + * @Description: 链表类 + * @param {any} + * @return: ListNode + */ +function ListNode(val) { + this.val = val; + this.next = null; +} +// 构造简单链表 +let list = createLinkedList([1, 2, 3, 4]); +// console.log(list); +// 反转 +console.log(reverseList(list)); diff --git a/Week 01/id_016/LeetCode_26_016.js b/Week 01/id_016/LeetCode_26_016.js new file mode 100644 index 000000000..091a25a46 --- /dev/null +++ b/Week 01/id_016/LeetCode_26_016.js @@ -0,0 +1,83 @@ +/* + * @lc app=leetcode id=26 lang=javascript + * + * [26] Remove Duplicates from Sorted Array + * + * https://leetcode.com/problems/remove-duplicates-from-sorted-array/description/ + * + * algorithms + * Easy (42.10%) + * Likes: 1778 + * Dislikes: 3855 + * Total Accepted: 713.6K + * Total Submissions: 1.7M + * Testcase Example: '[1,1,2]' + * + * Given a sorted array nums, remove the duplicates in-place such that each + * element appear only once and return the new length. + * + * Do not allocate extra space for another array, you must do this by modifying + * the input array in-place with O(1) extra memory. + * + * Example 1: + * + * + * Given nums = [1,1,2], + * + * Your function should return length = 2, with the first two elements of nums + * being 1 and 2 respectively. + * + * It doesn't matter what you leave beyond the returned length. + * + * Example 2: + * + * + * Given nums = [0,0,1,1,1,2,2,3,3,4], + * + * Your function should return length = 5, with the first five elements of nums + * being modified to 0, 1, 2, 3, and 4 respectively. + * + * It doesn't matter what values are set beyond the returned length. + * + * + * Clarification: + * + * Confused why the returned value is an integer but your answer is an array? + * + * Note that the input array is passed in by reference, which means + * modification to the input array will be known to the caller as well. + * + * Internally you can think of this: + * + * + * // nums is passed in by reference. (i.e., without making a copy) + * int len = removeDuplicates(nums); + * + * // any modification to nums in your function would be known by the caller. + * // using the length returned by your function, it prints the first len + * elements. + * for (int i = 0; i < len; i++) { + * print(nums[i]); + * } + 1.顺序查找,找到相邻相同的值删除掉 时间O(n) 空间O(1) + + * + */ + +// @lc code=start +/** + * @param {number[]} nums + * @return {number} + */ +var removeDuplicates = function(nums) { + for (let i = 1; i < nums.length; i++) { + if (nums[i] === nums[i - 1]) { + nums.splice(i, 1); + i--; + } + } + return nums.length; +}; +// @lc code=end + +console.log(removeDuplicates([0, 0, 1, 1, 1, 2, 2, 3, 3, 4])); diff --git a/Week 01/id_016/LeetCode_283_016.js b/Week 01/id_016/LeetCode_283_016.js new file mode 100644 index 000000000..dc4e812c8 --- /dev/null +++ b/Week 01/id_016/LeetCode_283_016.js @@ -0,0 +1,30 @@ +/* + * @Description: This is a description + * @Author: Ask + * @LastEditors: Ask + * @Date: 2019-10-18 09:05:04 + * @LastEditTime: 2019-10-18 09:14:21 + +给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。 +必须在原数组上操作,不能拷贝额外的数组。 +尽量减少操作次数。 + case + 输入: [0,1,0,3,12] + 输出: [1,3,12,0,0] + */ + +var moveZeroes = function(nums) { + if (!nums.length) return; + let length = nums.length; + for (let i = 0; i < length; i++) { + if (nums[i] === 0) { + let temp = nums[i]; + nums.splice(i--, 1); + nums.push(temp); + length--; + } + } + return nums; +}; + +console.log(moveZeroes([0, 1, 0, 3, 12])); \ No newline at end of file diff --git a/Week 01/id_016/NOTE.md b/Week 01/id_016/NOTE.md index a6321d6e2..cfa244204 100644 --- a/Week 01/id_016/NOTE.md +++ b/Week 01/id_016/NOTE.md @@ -1,4 +1,36 @@ + # NOTE - +# 第一周,感觉进度有点慢,时间不够,还是自己的时间分配有问题 +- 目前的总结知识为了完成作业的感觉,题目太多,时间不是很充足 + +### 数组 + + +### 链表 + +单链表的相关问题: +1. 链表插入,删除,查找 +2. 链表反转 done +3. 链表中环的判断 + +双向链表相关: + + +### 栈 -LIFO +应用: +1. 浏览器的前进后退 + + +### 队列-FIFO + + + +### 跳表 -- 了解了基本的操作流程 \ No newline at end of file diff --git a/Week 01/id_021/algorithm.zip b/Week 01/id_021/algorithm.zip new file mode 100644 index 000000000..dafb2d929 Binary files /dev/null and b/Week 01/id_021/algorithm.zip differ diff --git "a/Week 01/id_021/\346\200\273\347\273\223\345\222\214\345\210\206\346\236\220" "b/Week 01/id_021/\346\200\273\347\273\223\345\222\214\345\210\206\346\236\220" new file mode 100644 index 000000000..75d5be343 --- /dev/null +++ "b/Week 01/id_021/\346\200\273\347\273\223\345\222\214\345\210\206\346\236\220" @@ -0,0 +1,8 @@ +PriorityQueue源码分析https://juejin.im/post/5dac84ce6fb9a04e0b0dbc6d +Queue源码分析https://juejin.im/post/5dac7b1c6fb9a04de7735bd5 + +总结: +周一至周五未对此课程进行安排,导致周六周日两天时间对课程比较紧张。 +将其课堂上讲到的例题理解,对其进行编写,对不同的解法进行比较,得出时间复杂度和空间复杂度。 +使用五毒神掌对讲到的知识点和不清楚的题目进行专项训练。 + diff --git a/Week 01/id_026/026-Week 01/Merge.java b/Week 01/id_026/026-Week 01/Merge.java new file mode 100644 index 000000000..5a289d0d9 --- /dev/null +++ b/Week 01/id_026/026-Week 01/Merge.java @@ -0,0 +1,31 @@ +//ϲ鲢 +public class Merge { + public void merge(int[] nums1, int m, int[] nums2, int n) { + //int[] nums = new int[m+n]; + for (int i = 0; i < m; i++) { + nums1[i] = nums1[i]; + } + for (int i = 0; i < n; i++) { + nums1[m++] = nums2[i]; + } + for (int i = 0; i < nums1.length; i++) { + for (int j = i+1; j < nums1.length; j++) { + if (nums1[i] > nums1[j]) { + int temp = nums1[j]; + nums1[j] = nums1[i]; + nums1[i] = temp; + } + } + } + } + + public static void main(String[] args) { + int[] a = {1,2,3,0,0,0}; + int[] b = {2,5,6}; + int m = 3; + int n = 3; + Solution s = new Solution(); + s.merge(a,m,b, n); + } + +} diff --git a/Week 01/id_026/026-Week 01/MergeNew.java b/Week 01/id_026/026-Week 01/MergeNew.java new file mode 100644 index 000000000..71ab3c962 --- /dev/null +++ b/Week 01/id_026/026-Week 01/MergeNew.java @@ -0,0 +1,23 @@ +//ϲ鲢 +public class Merge { + public void merge(int[] nums1, int m, int[] nums2, int n) { + int pointer = m + n - 1; //ʼָλΪϲĵĩβλ + while (n > 0) { //nums2û꣬ѭ + if (m > 0 && nums1[m - 1] > nums2[n - 1]) { //nums1û£nums1[m-1]nums2[n-1]1ʵ±꣩ + nums1[pointer--] = nums1[--m]; //Ƚnums1[--m]Լmõʵ±ֵ꣩nums[pointer]Ȼָǰƶ + } else { + nums1[pointer--] = nums2[--n]; //nums1nums1[m-1]Сnums2[n-1]ֵnums2[--n]nums[pointer] + } + } + } + + public static void main(String[] args) { + int[] a = {1,2,3,0,0,0}; + int[] b = {2,5,6}; + int m = 3; + int n = 3; + Solution s = new Solution(); + s.merge(a,m,b, n); + } + +} diff --git a/Week 01/id_026/026-Week 01/RemoveDuplicates.java b/Week 01/id_026/026-Week 01/RemoveDuplicates.java new file mode 100644 index 000000000..433cf8b04 --- /dev/null +++ b/Week 01/id_026/026-Week 01/RemoveDuplicates.java @@ -0,0 +1,27 @@ +// 删除排序数组中的重复项 +public class RemoveDuplicates { + public int removeDuplicates(int[] nums) { + int j = 0; + int length = nums.length; + for (int i = 0; i < length; i++) { + for (j = i + 1; j < length; j++) { + if (nums[i] == nums[j]) { + for(int k = j; k < length-1; k++){ + nums[k] = nums[k+1]; + } + j--; + length--; + } + } + } + return length; + + } + + public static void main(String[] args) { + int[] a = {1,1,2}; + RemoveDuplicates r = new RemoveDuplicates(); + r.removeDuplicates(a); + } + +} diff --git a/Week 01/id_026/026-Week 01/RemoveDuplicatesNew.java b/Week 01/id_026/026-Week 01/RemoveDuplicatesNew.java new file mode 100644 index 000000000..87f178eae --- /dev/null +++ b/Week 01/id_026/026-Week 01/RemoveDuplicatesNew.java @@ -0,0 +1,20 @@ +// 删除排序数组中的重复项 +public class RemoveDuplicates { + public int removeDuplicates(int[] nums) { + int i = 0; + for (int j = 1; j < nums.length; j++) { + if (nums[j] != nums[i]) { + i++; + nums[i] = nums[j]; + } + } + return i + 1; + } + + public static void main(String[] args) { + int[] a = {1,1,2}; + RemoveDuplicates r = new RemoveDuplicates(); + r.removeDuplicates(a); + } + +} diff --git "a/Week 01/id_026/026-Week 01/\345\255\246\344\271\240\346\200\273\347\273\223.docx" "b/Week 01/id_026/026-Week 01/\345\255\246\344\271\240\346\200\273\347\273\223.docx" new file mode 100644 index 000000000..f93711a62 Binary files /dev/null and "b/Week 01/id_026/026-Week 01/\345\255\246\344\271\240\346\200\273\347\273\223.docx" differ diff --git a/Week 01/id_031/LeetCode_11_031.java b/Week 01/id_031/LeetCode_11_031.java new file mode 100644 index 000000000..c7f08a166 --- /dev/null +++ b/Week 01/id_031/LeetCode_11_031.java @@ -0,0 +1,65 @@ +package id_031; + +/** + * + * 给定 n 个非负整数 a1,a2,...,an,每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0)。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。 + * + * 说明:你不能倾斜容器,且 n 的值至少为 2。 + * + * + * + * 图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。 + * + * + * + * 示例: + * + * 输入: [1,8,6,2,5,4,8,3,7] + * 输出: 49 + * + * 来源:力扣(LeetCode) + * 链接:https://leetcode-cn.com/problems/container-with-most-water + * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + * + * @author xuhaojie created on 2019-10-20 + */ +public class LeetCode_11_031 { + // 1. 计算每一个面积并比较最大值 + // 2. 夹逼法 + + /** + * 计算每一个面积并比较最大值 双重循环,第一层从首位开始,第二层从第二位(第二位后一位)开始 + */ + public int maxArea(int[] height) { + int maxArea = 0; + // i < height.length - 1 保证 i 与 j 不相遇 + // int j = i + 1 保证 j 永远在 i 后面 + for (int i = 0; i < height.length - 1 ; i++) { + for (int j = i + 1; j < height.length; j++) { + int nowHeight = Math.min(height[i], height[j]); + int area = nowHeight * (j - i); + maxArea = Math.max(maxArea, area); + } + } + + return maxArea; + } + + + /** + * 夹逼法,不断往中间靠 + */ + public int maxArea1(int[] height) { + int maxArea = 0; + int i = 0; + int j = height.length - 1; + for (; i map = new HashMap<>(nums.length); + + for (int i = 0; i < nums.length; i++) { + map.put(nums[i], i); + } + + for (int i = 0; i < nums.length; i++) { + int matchNum = target - nums[i]; + Integer matchKey = map.get(matchNum); + //确保存在且与当前值不为同一位置的值 + if (matchKey != null && matchKey != i) { + return new int[]{i, matchKey}; + } + } + return new int[]{0, 0}; + } + + /** + * 暴力法 + */ + public int[] twoSum2(int[] nums, int target) { + for (int i = 0; i < nums.length; i++) { + for (int j = i + 1; j < nums.length; j++) { + if ((nums[i] + nums[j]) == target) { + return new int[]{i, j}; + } + } + } + + //找不到答案 + return new int[]{0, 0}; + } + + // + + public static void main(String[] args) { + int[] nums = new int[]{3, 2, 4}; + int target = 6; + int[] result = new LeetCode_1_031().twoSum(nums, target); + System.out.println(Arrays.toString(result)); + + } +} \ No newline at end of file diff --git a/Week 01/id_031/LeetCode_283_031.java b/Week 01/id_031/LeetCode_283_031.java new file mode 100644 index 000000000..b97ef75e3 --- /dev/null +++ b/Week 01/id_031/LeetCode_283_031.java @@ -0,0 +1,79 @@ +package id_031; + +/** + * @author xuhaojie created on 2019-10-20 + */ +public class LeetCode_283_031 { + // 1. 暴力解法 两个循环 + // 2. 使用新数组 + // 3. 使用下标记录索引 + + // 使用两个数组方式 + public void moveZeroes2(int[] nums) { + + //元素移动的起始位置 + int j = 0; + //0的个数 + int zeroCount = 0; + + for (int index = 0; index < nums.length; index++) { + //累计 0 的个数 + if (nums[index] == 0) { + zeroCount++; + } + //将元素置换,并将位置往后移动一位 + else { + nums[j] = nums[index]; + j++; + } + } + + //将尾部需要改为 0 的修改为 0 + for (; zeroCount > 0; zeroCount--) { + nums[nums.length - zeroCount] = 0; + } + } + + + //使用新数组解法 + public void moveZeroes(int[] nums) { + int[] newNumbers = new int[nums.length]; + + int j = 0; + for (int index = 0; index < nums.length; index++) { + if (nums[index] != 0) { + newNumbers[j] = nums[index]; + j++; + } + } + + for (; j < nums.length - 1; j++) { + newNumbers[j] = 0; + } + System.arraycopy(newNumbers, 0, nums, 0, nums.length); + } + + + //使用索引 + public void moveZeroes3(int[] nums) { + int number0Index = 0; + for (int index = 0; index < nums.length; index++) { + if (nums[index] != 0) { + nums[number0Index] = nums[index]; + if (index != number0Index) { + nums[index] = 0; + } + number0Index++; + } + } + + } + + + public static void main(String[] args) { + new LeetCode_283_031().moveZeroes(new int[]{0, 1, 0, 3, 12}); + new LeetCode_283_031().moveZeroes2(new int[]{0, 1, 0, 3, 12}); + new LeetCode_283_031().moveZeroes3(new int[]{0, 1, 0, 3, 12}); + } + +} \ No newline at end of file diff --git a/Week 01/id_041/MyCircularDeque.java b/Week 01/id_041/MyCircularDeque.java new file mode 100644 index 000000000..9fc502b62 --- /dev/null +++ b/Week 01/id_041/MyCircularDeque.java @@ -0,0 +1,98 @@ +class MyCircularDeque { + int[] myDeque ; + int front;//队头指针 + int last;//队尾指针 + int count;//队列当前的大小 + int capacity;//队列的容量 + + /** Initialize your data structure here. Set the size of the deque to be k. */ + public MyCircularDeque(int k) { + this.myDeque = new int[k]; + this.front = 0; + this.last = 0; + this.count = 0; + this.capacity = k; + } + + /** Adds an item at the front of Deque. Return true if the operation is successful. */ + public boolean insertFront(int value) { + if(last == front && count == capacity){ + return false; + }else { + myDeque[front] = value; + front = (front+capacity-1) % capacity; + count++; + return true; + } + } + + /** Adds an item at the rear of Deque. Return true if the operation is successful. */ + public boolean insertLast(int value) { + if(last == front && count == capacity){ + return false; + }else { + myDeque[last] = value; + last = (last+capacity+1) % capacity; + count++; + return true; + } + } + + /** Deletes an item from the front of Deque. Return true if the operation is successful. */ + public boolean deleteFront() { + if(last == front && count == 0){ + return false; + }else { + front = (front+1) % capacity; + count--; + return true; + } + } + + /** Deletes an item from the rear of Deque. Return true if the operation is successful. */ + public boolean deleteLast() { + if(last == front && count == 0){ + return false; + }else { + last = (last+capacity-1) % capacity; + count--; + return true; + } + } + + /** Get the front item from the deque. */ + public int getFront() { + if(last == front && count == 0){ + return -1; + }else { + return myDeque[front]; + } + } + + /** Get the last item from the deque. */ + public int getRear() { + if(last == front && count == 0){ + return -1; + }else { + return myDeque[(last+capacity-1) % capacity]; + } + } + + /** Checks whether the circular deque is empty or not. */ + public boolean isEmpty() { + if(last == front && count == 0){ + return true; + }else { + return false; + } + } + + /** Checks whether the circular deque is full or not. */ + public boolean isFull() { + if(last == front && count == capacity){ + return true; + }else { + return false; + } + } +} \ No newline at end of file diff --git a/Week 01/id_041/NOTE.md b/Week 01/id_041/NOTE.md deleted file mode 100644 index a6321d6e2..000000000 --- a/Week 01/id_041/NOTE.md +++ /dev/null @@ -1,4 +0,0 @@ -# NOTE - - - diff --git a/Week 01/id_041/Trap.java b/Week 01/id_041/Trap.java new file mode 100644 index 000000000..cbc1d3f2b --- /dev/null +++ b/Week 01/id_041/Trap.java @@ -0,0 +1,31 @@ +public class Trap { + /* + * 运用双指针夹逼的方式实现 + * */ + public int trap(int[] height) { + int left = 0; + int right = height.length -1; + int left_max = 0,right_max = 0 ; + int result = 0; + while (left< right){ + if(height[left] < height[right]){ + if (height[left] >= left_max){ + left_max = height[left]; + }else { + result += (left_max-height[left]); + } + ++left; + }else { + if (height[right] >= right_max){ + right_max = height[right]; + + }else { + result += (right_max-height[right]); + } + --right; + } + } + return result; + } + +} diff --git a/Week 01/id_046/LeetCode_1_046.java b/Week 01/id_046/LeetCode_1_046.java new file mode 100755 index 000000000..b95f02b32 --- /dev/null +++ b/Week 01/id_046/LeetCode_1_046.java @@ -0,0 +1,29 @@ +// 暴力解法 +class Solution { + public int[] twoSum(int[] nums, int target) { + for(int i=0 ;i < nums.length ;i++){ + for(int j=i+1; j map = new HashMap<>(); + for(int i = 0; i < nums.length; i++){ + if(map.containsKey(target - nums[i])){ + return new int []{map.get(target - nums[i]),i}; + } + map.put(nums[i],i); + } + return null; + } + +} + diff --git a/Week 01/id_046/LeetCode_21_046.java b/Week 01/id_046/LeetCode_21_046.java new file mode 100755 index 000000000..107721a1d --- /dev/null +++ b/Week 01/id_046/LeetCode_21_046.java @@ -0,0 +1,24 @@ +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode(int x) { val = x; } + * } + */ + // 递归 +class Solution { + public ListNode mergeTwoLists(ListNode l1, ListNode l2) { + if(l1 == null){ + return l2; + }else if(l2 == null){ + return l1; + }else if(l1.val > l2.val){ + l2.next = mergeTwoLists(l2.next,l1); + return l2; + }else{ + l1.next = mergeTwoLists(l1.next,l2); + return l1; + } + } +} \ No newline at end of file diff --git a/Week 01/id_046/LeetCode_26_046.java b/Week 01/id_046/LeetCode_26_046.java new file mode 100755 index 000000000..123b82148 --- /dev/null +++ b/Week 01/id_046/LeetCode_26_046.java @@ -0,0 +1,31 @@ +// 双指针思路 +class Solution { + public int removeDuplicates(int[] nums) { + int i = 0; + for(int j = 1; j < nums.length; j++){ + if(nums[i] != nums[j]){ + nums[i+1] = nums[j]; + i++; + } + } + return i+1; + } +} + + +// 优化解法 +// 完全无重复的时候减少元素移动 +class Solution { + public int removeDuplicates(int[] nums) { + int i = 0; + for(int j = 1; j < nums.length; j++){ + if(nums[i] != nums[j]){ + if(j - i > 1){ + nums[i+1] = nums[j]; + } + i++; + } + } + return i+1; + } +} \ No newline at end of file diff --git a/Week 01/id_046/LeetCode_42_046.java b/Week 01/id_046/LeetCode_42_046.java new file mode 100644 index 000000000..0bb4b1802 --- /dev/null +++ b/Week 01/id_046/LeetCode_42_046.java @@ -0,0 +1,27 @@ +import java.lang.Math; +class Solution { + public int trap(int[] height) { + if(height == null || height.length == 0){ + return 0; + } + int ans = 0; + int size = height.length; + int[] left_max = new int[size]; + int[] right_max = new int[size]; + left_max[0] = height[0]; + // 左侧条形块高度 + for (int i = 1; i < size; i++) { + left_max[i] = Math.max(height[i], left_max[i - 1]); + } + right_max[size - 1] = height[size - 1]; + // 右侧条形块高度 + for (int i = size - 2; i >= 0; i--) { + right_max[i] = Math.max(height[i], right_max[i + 1]); + } + // 相对i而言,左右侧条形高度最小的决定储水高度 + for (int i = 1; i < size - 1; i++) { + ans += Math.min(left_max[i], right_max[i]) - height[i]; + } + return ans; + } +} \ No newline at end of file diff --git a/Week 01/id_071/LeetCode_01_071.go b/Week 01/id_071/LeetCode_01_071.go new file mode 100644 index 000000000..f68f4637a --- /dev/null +++ b/Week 01/id_071/LeetCode_01_071.go @@ -0,0 +1,33 @@ +package week01/id_071 + +// array https://leetcode-cn.com/problems/two-sum/ +func twoSumes(nums []int, target int) []int { + + var new []int + if len(nums) < 2{ + return new + } + + for i := 0; i < len(nums); i++ { + for j := i+1; j < len(nums); j++ { + if nums[i] + nums[j] == target { + new = []int{i,j} + break + } + } + } + return new +} + +//map key => nums values; value => nums key +func twoSum(nums []int, target int) []int { + + mp := make(map[int]int) + for i, v := range nums { + if idx,ok := mp[target - v]; ok { + return []int{idx,i} + } + mp[v] = i + } + return nil +} \ No newline at end of file diff --git a/Week 01/id_071/LeetCode_11_071.go b/Week 01/id_071/LeetCode_11_071.go new file mode 100644 index 000000000..179cd0a16 --- /dev/null +++ b/Week 01/id_071/LeetCode_11_071.go @@ -0,0 +1,76 @@ +package week01/id_071 + +// array https://leetcode-cn.com/problems/container-with-most-water/ +func maxAreaes(height []int) int { + + if len(height) < 2 { + return 0 + } + + if len(height) == 2 { + if height[0] > height[1]{ + return height[0] + } + + return height[1] + } + + var ( + min int + max int + temp int + ) + + for i := 0;i < len(height); i++ { + for j := i+1; j < len(height); j++ { + if height[i] > height[j]{ + min = height[j] + } + min = height[i] + temp = (j-i)*min + if max < temp { + max = temp + } + } + } + + return max +} + +func maxArea(height []int) int { + + if len(height) < 2 { + return 0 + } + + if len(height) == 2{ + if height[0] > height[1]{ + return height[0] + } + return height[1] + } + + var ( + min int + temp int + num int + max = len(height)-1 + ) + + for min < max { + if height[min] < height[max]{ + temp = height[min] + } + temp = height[max] + if (max - min)*temp > num { + num = (max - min)*temp + } + if height[min] < height[max] { + min++ + }else{ + max-- + } + } + + return num +} \ No newline at end of file diff --git a/Week 01/id_071/LeetCode_15_071.go b/Week 01/id_071/LeetCode_15_071.go new file mode 100644 index 000000000..58a02eaba --- /dev/null +++ b/Week 01/id_071/LeetCode_15_071.go @@ -0,0 +1,49 @@ +package week01/id_071 + +import "sort" + +// array https://leetcode-cn.com/problems/3sum/ +// O(n^2) new array for +func threeSumes(nums []int) [][]int { + + var result [][]int + sort.Ints(nums) + for i := 0; i < len(nums); i++ { + if i > 0 && nums[i] == nums[i-1] { + continue //To prevent the repeat + } + target,l,r := -nums[i],i+1,len(nums)-1 + for l < r { + sum := nums[l] + nums[r] + if sum == target { + result = append(result,[]int{nums[i],nums[l],nums[r]}) + l++ + r-- + for l < r && nums[l] == nums[l-1]{ + l++ + } + for l < r && nums[r] == nums[r+1]{ + r-- + } + }else if sum > target { + r-- + }else if sum < target { + l++ + } + } + } + + return result +} + +// O(nlogn) 排序 双指针 +func threeSum(nums []int) [][]int { + + var result [][]int + sort.Ints(nums) + for i := 0; i < len(nums); i++ { + + } + + return result +} diff --git a/Week 01/id_071/LeetCode_189_071.go b/Week 01/id_071/LeetCode_189_071.go new file mode 100644 index 000000000..f804c4d0b --- /dev/null +++ b/Week 01/id_071/LeetCode_189_071.go @@ -0,0 +1,29 @@ +package week01/id_071 + +func rotatees(nums []int, k int) { + + var n int = len(nums) + var new []int + for i := 0; i < n; i++ { + a[(i+k) % n] = nums[i] + } + for j := o; j < n; j++ { + nums[i] = a[i] + } +} + +func rotate(nums []int, k int){ + k = k % len(nums) + reverse(nums,0,len(nums)-1) + reverse(nums,0,k - 1) + reverse(nums,k,len(nums)-1) +} + +func reverse(nums []int ,start int, end int){ + + for start < end { + nums[start],nums[end] = nums[end],nums[start] + start++ + end-- + } +} \ No newline at end of file diff --git a/Week 01/id_071/LeetCode_42_071.go b/Week 01/id_071/LeetCode_42_071.go new file mode 100644 index 000000000..0550d112f --- /dev/null +++ b/Week 01/id_071/LeetCode_42_071.go @@ -0,0 +1,31 @@ +package week01/id_071 + +func trap(height []int) int { + + if len(height) == 0 { + return 0 + } + + var max,maxIndex int + for i, h := range height { + if h > max { + max = h + maxIndex = i + } + } + var total, leftMax, rightMax int + for i := 0; i < maxIndex; i++ { + if leftMax < height[i]{ + leftMax = height[i] + } + total += leftMax - height[i] + } + + for i := len(height)-1; i > maxIndex; i-- { + if rightMax < height[i]{ + rightMax = height[i] + } + total += rightMax - height[i] + } + return total +} \ No newline at end of file diff --git a/Week 01/id_071/LeetCode_641_071.go b/Week 01/id_071/LeetCode_641_071.go new file mode 100644 index 000000000..95d5d9fd2 --- /dev/null +++ b/Week 01/id_071/LeetCode_641_071.go @@ -0,0 +1,94 @@ +package week01 + +type MyCircularDeque struct { + q []int + capacity int + head int + tail int +} + + +/** Initialize your data structure here. Set the size of the deque to be k. */ +func Constructor(k int) MyCircularDeque { + + return MyCircularDeque{make([]int, k), k, 0, 0} +} + +/** Adds an item at the front of Deque. Return true if the operation is successful. */ +func (this *MyCircularDeque) InsertFront(value int) bool { + if this.IsFull() { + return false + } + + this.head = (this.head-1 + this.capacity) % this.capacity + this.q[this.head] = value + + return true +} + +/** Adds an item at the rear of Deque. Return true if the operation is successful. */ +func (this *MyCircularDeque) InsertLast(value int) bool { + if this.IsFull() { + return false + } + + this.q[this.tail] = value + this.tail = (this.tail + 1) % this.capacity + + return true +} + + +/** Deletes an item from the front of Deque. Return true if the operation is successful. */ +func (this *MyCircularDeque) DeleteFront() bool { + + if (this.IsEmpty()) { + return false; + } + + this.head = (this.head + 1) % this.capacity; + return true +} + + +/** Deletes an item from the rear of Deque. Return true if the operation is successful. */ +func (this *MyCircularDeque) DeleteLast() bool { + if (this.IsEmpty()) { + return false; + } + + this.tail = (this.tail - 1 + this.capacity) % this.capacity; + return true; +} + + +/** Get the front item from the deque. */ +func (this *MyCircularDeque) GetFront() int { + if (this.IsEmpty()) { + return -1 + } + + return this.q[this.head] +} + + +/** Get the last item from the deque. */ +func (this *MyCircularDeque) GetRear() int { + if (this.IsEmpty()) { + return -1 + } + + return this.q[(this.tail - 1 + this.capacity) % this.capacity] +} + +/** Checks whether the circular deque is empty or not. */ +func (this *MyCircularDeque) IsEmpty() bool { + + return this.head == this.tail; +} + +/** Checks whether the circular deque is full or not. */ +func (this *MyCircularDeque) IsFull() bool { + + return (this.tail + 1) % this.capacity == this.head; +} \ No newline at end of file diff --git a/Week 01/id_071/NOTE.md b/Week 01/id_071/NOTE.md index a6321d6e2..c2fe19838 100644 --- a/Week 01/id_071/NOTE.md +++ b/Week 01/id_071/NOTE.md @@ -1,4 +1,92 @@ # NOTE - +### 数组、链表、队列、栈都是线性表结构。 + + 线性表 linear list + + 数据排成像一条线一样的结构。每个线性表上的数据最多只有前和后两个方向。 + +> 数组 array 内存管理 + + + 数组 :是一种线性表数据结构,它用一组连续的内存空间来存储一组具有相同类型的数据。 + + 数组 最大的特点就是支持随机访问,但插入、删除操作比较低效。平均情况实际复杂度为O(n)。 + + var arr = [3]int{1,2,3} + arr := [3]int{2,3,4} + mul := [2][3]int{{1,2,3},{4,5,6}} + +> 链表 linked list LRU Cache + +##### 单链表 + + next + +##### 双向链表 + + next + previous + +##### 循环链表 + + 尾指针(Tail) 指向 头指针 (Head) + +> 跳表 skip list Redis + + 通过添加 索引 来实现空间换时间的方式,提高查询速度。 + + +> 栈 stack + + + 最近相关性 + 先进后出 + +> 对列 queue + + + 先进先出 + +> 双端对列 deque Double-End Queue + + + 头部和尾部都可以进行 push/pop 操作 + + +> 优先队列 priority queue + + 按照 优先级取出 + 插入操作 O(1) + 查找操作 O(logn) + + +### 思维方式 + + +> 1、升维(一维 到 二维 到多维) + + +> 2、空间换时间 + + +> 3、双指针 就是利用两个指针去遍历数组。一般来说,遍历数组采用的是单指针(index)去遍历,两个指针一般是在有序数组中使用,一个放首,一个放尾,同时向中间遍历,直到两个指针相交,完成遍历。时间复杂度也是O(n)。 + + + 两数之和满足某条件 + 先对数组排序,再采用两个指针,分别从前和后往中间遍历,front增大,tail减小,通过对条件的判断,可以在O(n)内遍历,而非使用双重循环。 + in place交换 + 一个指针正常遍历,另一个指针去找可以用来交换的元素。 + + +action | array | linked list | skip list +---|--- |--- |--- +prepend | O(1) | O(1) | O(1) +append | O(1) | O(1) | O(1) +lookup | O(1) | O(n) | O(logn) +insert | O(n) | O(1) | O(1) +delete | O(1) | O(1) | O(1) + + +[双指针](https://linzhenglearn.github.io/2017/03/29/TwoPointer/#remove-duplicates-from-sorted-array) diff --git a/Week 01/id_071/week01_test.go b/Week 01/id_071/week01_test.go new file mode 100644 index 000000000..3825c87dc --- /dev/null +++ b/Week 01/id_071/week01_test.go @@ -0,0 +1,65 @@ +package week01/id_071 + +import ( + _ "fmt" + "testing" +) + +func TestMoveZero(t *testing.T) { + var nums = []int{0, 8, 0, 0, 0, 4, 8, 3, 7} + + // moveZero(nums) + // t.Log(nums) + moveZeroes(nums) + t.Log(nums) +} + +func TestMaxArea(t *testing.T) { + var nums = []int{1, 8, 6, 2, 5, 4, 8, 3, 7} + + max := maxArea(nums) + t.Log(max) +} + +func TestThreeSum(t *testing.T) { + var nums = []int{-1, 0, 1, 2, -1, -4, 4, 0, -2} + + n := threeSumes(nums) + t.Log(n) +} + +func TestTwoSum(t *testing.T) { + // target := 6 + // nums := []int{3,2,4} + + target := 9 + nums := []int{2, 7, 11, 15} + + s := twoSum(nums, target) + t.Log(s) +} + +func TestRotate(t *testing.T) { + arr := []int{1, 2, 4, 5, 7, 8, 0} + rotate(arr, 2) + t.Log(arr) +} + +func TestInsertFront(t *testing.T) { + + circularDeque := Constructor(3) + + circularDeque.InsertLast(1) + circularDeque.InsertLast(2) + t.Log(circularDeque.InsertLast(3)) + t.Log(circularDeque) + circularDeque.InsertLast(4) + circularDeque.InsertLast(5) + t.Log(circularDeque) +} + +func TestTrap(t *testing.T) { + arr := []int{0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1} + + t.Log(trap(arr)) +} diff --git a/Week 01/id_076/LeetCode_42_076.java b/Week 01/id_076/LeetCode_42_076.java new file mode 100644 index 000000000..fd5a39024 --- /dev/null +++ b/Week 01/id_076/LeetCode_42_076.java @@ -0,0 +1,52 @@ +/** + * 采用双指针方法,此题没什么思路 + * 只考虑使用双指针进行增加或减少 + * 看了leetCode 题解,基础不好需要多刷题 + * + * @author tangzhenhua + * @date 2019/10/20 20:15 + */ +public class LeetCode_42_076 { + + public static int trap(int[] height) { + + if (height == null || height.length == 0) { + return 0; + } + + int ans = 0; + + int leftMax = 0; + int rightMax = 0; + + int left = 0; + int right = height.length - 1; + + while (left < right) { + if (height[left] < height[right]) { + if (height[left] >= leftMax) { + leftMax = height[left]; + } else { + ans += leftMax - height[left]; + } + ++left; + } else { + if (height[right] >= rightMax) { + rightMax = height[right]; + } else { + ans += rightMax - height[right]; + } + --right; + } + } + + return ans; + } + + public static void main(String[] args) { + int[] height = {0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1}; + int size = trap(height); + System.out.println(size); + } + +} \ No newline at end of file diff --git a/Week 01/id_076/LeetCode_641_076.java b/Week 01/id_076/LeetCode_641_076.java new file mode 100644 index 000000000..341148698 --- /dev/null +++ b/Week 01/id_076/LeetCode_641_076.java @@ -0,0 +1,154 @@ +/** + * 采用数组实现双端队列 + * 参考 java Queue,Stack + * + * @author tangzhenhua + * @date 2019/10/20 20:15 + */ +public class LeetCode_641_076 { + + //使用数组实现双端队列 + int[] dqueue = {}; + //头指针 + int front = 0; + //尾指针 + int tail = 0; + //当前大小 + int size = 0; + //队列容量 + int capacity = 0; + + /** Initialize your data structure here. Set the size of the deque to be k. */ + public LeetCode_641_076(int k) { + + if(k < 0){ + throw new IllegalArgumentException("param k mast >= 0"); + } + + if(k > 0){ + this.dqueue = new int[k]; + this.capacity = k; + } + + } + + /** Adds an item at the front of Deque. Return true if the operation is successful. */ + public boolean insertFront(int value) { + + if(isFull()){ + return false; + } + + front = (front - 1 + capacity) % capacity; + dqueue[front] = value; + size ++; + + if(size == 1){ + tail = front; + } + return true; + } + + /** Adds an item at the rear of Deque. Return true if the operation is successful. */ + public boolean insertLast(int value) { + if(isFull()) { + return false; + } + tail = (tail + 1) % capacity; + dqueue[tail] = value; + size ++; + if(size == 1){ + front = tail; + } + return true; + } + + /** Deletes an item from the front of Deque. Return true if the operation is successful. */ + public boolean deleteFront() { + if(isEmpty()){ + return false; + } + front = (front + 1) % capacity; + size --; + return true; + } + + /** Deletes an item from the rear of Deque. Return true if the operation is successful. */ + public boolean deleteLast() { + if(isEmpty()) { + return false; + } else { + tail = (tail - 1 + capacity) % capacity; + size --; + return true; + } + } + + /** Get the front item from the deque. */ + public int getFront() { + if(isEmpty()) { + return -1; + } else { + return dqueue[front]; + } + } + + /** Get the last item from the deque. */ + public int getRear() { + if(isFull()) { + return -1; + } + if(isEmpty()){ + return -1; + } + return dqueue[tail]; + } + + /** Checks whether the circular deque is empty or not. */ + public boolean isEmpty() { + if(size == 0){ + return true; + } else { + return false; + } + } + + /** Checks whether the circular deque is full or not. */ + public boolean isFull() { + if(size == capacity){ + return true; + } else { + return false; + } + } + + + /** + * 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(); + */ + public static void main(String[] args) { + int k = 4; + int value = 5; + LeetCode_641_076 obj = new LeetCode_641_076(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/Week 01/id_076/NOTE.md b/Week 01/id_076/NOTE.md index a6321d6e2..d31c95ff6 100644 --- a/Week 01/id_076/NOTE.md +++ b/Week 01/id_076/NOTE.md @@ -1,4 +1,7 @@ # NOTE - - - +1.经过本周学习,对于了解了 循环的经典处理方式 + (front - 1 + maxSize) % maxSize +2.队列,栈 的实现方式有所了解,但是还需继续学习 +3.通过分析java 代码,了解了java 队列内部实现方式,更加理解了边界的处理,扩容的考量,内存回收的注意。 +4.对于双端队列解决问题的思路稍微了解了一些,还需继续学习。 +5.通过编写代码发现,想正确实现对应的算法目前很困难,努力吧。 diff --git a/Week 01/id_081/MoveZero.java b/Week 01/id_081/MoveZero.java new file mode 100644 index 000000000..cd4cb01fd --- /dev/null +++ b/Week 01/id_081/MoveZero.java @@ -0,0 +1,16 @@ +/** + * MoveZero + */ +public class MoveZero { + public static void moveZeroes(int[] nums) { + int p1 = 0; + for (int i = 0; i < nums.length; i++){ + if(nums[i] != 0){ + int temp = nums[p1]; + nums[p1] = nums[i]; + nums[i] = temp; + p1++; + } + } + } +} \ No newline at end of file diff --git a/Week 01/id_081/PlusOne.java b/Week 01/id_081/PlusOne.java new file mode 100644 index 000000000..1f50e4dfe --- /dev/null +++ b/Week 01/id_081/PlusOne.java @@ -0,0 +1,53 @@ +/** + * PlusOne + *

+ * 方法名为-> plusOne 为最终解法 + * 除此以外为独立完成时,自己的解法,主要在于对比 + */ +public class PlusOne { + + public static int[] plusOne(int[] digits) { + for (int i = digits.length - 1; i >= 0; i--) { + if (digits[i] < 9) { + digits[i]++; + return digits; + } + digits[i] = 0; + } + int[] res = new int[digits.length + 1]; + res[0] = 1; + return res; + } + + public static int[] plusOneOriginal(int[] digits) { + boolean addSpace = true; + for (int i = 0; i < digits.length; i++) + if (digits[i] != 9) { + addSpace = false; + break; + } + + int[] res; + if (addSpace) { + res = new int[digits.length + 1]; + for (int i = 1; i < digits.length + 1; i++) + res[i] = digits[i - 1]; + } else { + res = new int[digits.length]; + for (int i = 0; i < digits.length; i++) + res[i] = digits[i]; + } + + boolean carry = true; + for (int i = res.length - 1; i >= 0; i--) { + if (carry) { + int temp = res[i]; + res[i] += 1; + res[i] %= 10; + carry = res[i] < temp; + } else + break; + } + return res; + } +} \ No newline at end of file diff --git a/Week 01/id_081/TwoSum.java b/Week 01/id_081/TwoSum.java new file mode 100644 index 000000000..4be17c644 --- /dev/null +++ b/Week 01/id_081/TwoSum.java @@ -0,0 +1,20 @@ +import java.util.HashMap; +import java.util.Map; + +/** + * TowSum + */ +public class TwoSum { + + public static int[] twoSum(int[] nums, int target) { + Map map = new HashMap<>(); + for (int i = 0; i < nums.length; i++) { + int n = target - nums[i]; + if(map.containsKey(n)){ + return new int[] {map.get(n), i}; + } + map.put(nums[i], i); + } + return null; + } +} \ No newline at end of file diff --git a/Week 01/id_086/LeetCode_01_086.java b/Week 01/id_086/LeetCode_01_086.java new file mode 100644 index 000000000..9ec1a997a --- /dev/null +++ b/Week 01/id_086/LeetCode_01_086.java @@ -0,0 +1,14 @@ +// 求两数之和,输出数组中两个元素之和等于目标数据的元素 + +class Solution { + public int[] twoSum(int[] nums, int target) { + for (int i=0; i 从下周开始合理安排学习时间,把学习任务合理分布到每天;花时间弥补基础,用讲述的`五毒神掌`、`自顶向下`等方式学习 + + +### 学习收获 + +一直以来总觉得算法、数据结构都是一些很高深的知识,很多次也想攻破这道`难关`,最终都到在门前。这周的视频学习,让我明白了`算法`并不是很复杂、高深的东西,而是一些比较基础,看起来变化性多,确实一种类型比较固定的知识。只要掌握这些已经存在的,能熟练的运用它们,也就是`掌握`了。**学算法,学习的是使用,并不是发明创造!** + + +### 思考 + +计算机是一个相对简单的世界,所有看起来很复杂的东西`算法`都是由`ifelse`、`for`、`while`、`recursion`组合而成。计算机是没办法像人类一样去理解、使用数学公式,而是需要把数学公式转化成一些`ifelse`、`for`、`while`、`recursion`再做组合。花费的时间越少,消耗的资源越少,还能成功实现功能的组合,就是最优的`算法`。 + + diff --git "a/Week 01/id_086/\345\255\246\344\271\240\346\200\273\347\273\223.md" "b/Week 01/id_086/\345\255\246\344\271\240\346\200\273\347\273\223.md" new file mode 100644 index 000000000..e86fd3d09 --- /dev/null +++ "b/Week 01/id_086/\345\255\246\344\271\240\346\200\273\347\273\223.md" @@ -0,0 +1,26 @@ +# 学习总结 + +## 第一周学习总结 + +### 学习情况 + +1、学习情况 + * 没有学习计划、安排 + * 临近周日快要提交作业才急忙赶工,学习效果差 + +2、课程情况 + * 很多算法的概念都不熟悉,尽管视频中有不少讲解,再看课后题还是会出现懵逼情况 + + **改进:** + > 从下周开始合理安排学习时间,把学习任务合理分布到每天;花时间弥补基础,用讲述的`五毒神掌`、`自顶向下`等方式学习 + + +### 学习收获 + +一直以来总觉得算法、数据结构都是一些很高深的知识,很多次也想攻破这道`难关`,最终都到在门前。这周的视频学习,让我明白了`算法`并不是很复杂、高深的东西,而是一些比较基础,看起来变化性多,确实一种类型比较固定的知识。只要掌握这些已经存在的,能熟练的运用它们,也就是`掌握`了。**学算法,学习的是使用,并不是发明创造!** + + +### 思考 + +计算机是一个相对简单的世界,所有看起来很复杂的东西`算法`都是由`ifelse`、`for`、`while`、`recursion`组合而成。计算机是没办法像人类一样去理解、使用数学公式,而是需要把数学公式转化成一些`ifelse`、`for`、`while`、`recursion`再做组合。花费的时间越少,消耗的资源越少,还能成功实现功能的组合,就是最优的`算法`。 + diff --git a/Week 01/id_091/Leetcode_1_091.py b/Week 01/id_091/Leetcode_1_091.py new file mode 100644 index 000000000..dd9ea8211 --- /dev/null +++ b/Week 01/id_091/Leetcode_1_091.py @@ -0,0 +1,10 @@ +from typing import List + + +class Solution: + def moveZeroes(self, nums: List[int]) -> None: + i = j = 0 + for i in range(len(nums)): + if nums[i] != 0: + nums[j], nums[i] = nums[i], nums[j] + j += 1 diff --git a/Week 01/id_091/Leetcode_26_091.py b/Week 01/id_091/Leetcode_26_091.py new file mode 100644 index 000000000..2e1f04687 --- /dev/null +++ b/Week 01/id_091/Leetcode_26_091.py @@ -0,0 +1,36 @@ +from typing import List + + +class Solution(object): + # 可用一遍遍历,即根据当前遍历得到的元素index, + # 查找target-index是否在剩余数组里出现 + # 如果找得到,则返回其下标值;反之则说明没有该答案 + def twoSum(self, nums: List[int], target: int) -> List[int]: + """ + :type nums: List[int] + :type target: int + :rtype: List[int] + """ + answer = [] + for left_index in range(len(nums)): + right = target - nums[left_index] + if right in nums[left_index + 1:]: + nums_right = nums[left_index + 1:] + right_index = nums_right.index(right) + left_index + 1 + answer.extend([left_index, right_index]) + break + return answer + + def tow_sum_with_dict(self, nums: List[int], target: int) -> List[int]: + _dict = {} + for i, m in enumerate(nums): + if _dict.get(target - m) is not None: + return [i, _dict.get(target - m)] + _dict[m] = i + + +if __name__ == "__main__": + nums = [-1, -2, -3, -4, -5] + target = -3 + answer = Solution().tow_sum_with_dict(nums, target) + print(answer) diff --git a/Week 01/id_091/Leetcode_283_091.py b/Week 01/id_091/Leetcode_283_091.py new file mode 100644 index 000000000..e18fb3b1f --- /dev/null +++ b/Week 01/id_091/Leetcode_283_091.py @@ -0,0 +1,13 @@ +from typing import List + + +class Solution: + def moveZeroes(self, nums: List[int]) -> None: + """ + Do not return anything, modify nums in-place instead. + """ + i = j = 0 + for i in range(len(nums)): + if nums[i] != 0: + nums[j], nums[i] = nums[i], nums[j] + j += 1 diff --git a/Week 01/id_091/NOTE.md b/Week 01/id_091/NOTE.md index a6321d6e2..98be3e888 100644 --- a/Week 01/id_091/NOTE.md +++ b/Week 01/id_091/NOTE.md @@ -1,4 +1,22 @@ # NOTE +###数组Array: +#####适用于查找,插入/删除:最坏情况移动n个数,最好情况移动1个数,平均复杂度O(n) +###链表LinkList: +#####适用于添加和删除元素,添加、修改和删除平均时间复杂度O(1),查找的平均时间复杂度O(n) +###跳跃表: +#####在链表的基础上升纬,时间复杂度O(log2n) (2为底数),空间复杂度O(n) ;Redis中用的比较多 +##优化思想:升纬思想+空间换时间 - +###栈 +#####先入后出,添加、删除的时间复杂度O(1) +###队列 +#####先入先出,添加、删除的时间复杂度O(1) +###Deque + +###个人总结 +1.实在没有任何想法时考虑用暴力破解 +2.类似斐波那契那种的最近重复法,如爬楼梯那题 +3.看LeetCode上别人的思路和算法觉得好牛逼 +4.自己还需多看视频和LeetCode上别人的解法,看一两遍当时能动,易忘记或默写不完整 +5.把学习分摊到每天,留在周末的一天去学习很匆忙 \ No newline at end of file diff --git a/Week 01/id_106/1.two-sum.java b/Week 01/id_106/1.two-sum.java new file mode 100644 index 000000000..fa8afaa83 --- /dev/null +++ b/Week 01/id_106/1.two-sum.java @@ -0,0 +1,52 @@ +/* + * @lc app=leetcode id=1 lang=java + * + * [1] Two Sum + * + * https://leetcode.com/problems/two-sum/description/ + * + * algorithms + * Easy (44.62%) + * Likes: 12133 + * Dislikes: 423 + * Total Accepted: 2.2M + * Total Submissions: 4.9M + * Testcase Example: '[2,7,11,15]\n9' + * + * Given an array of integers, return indices of the two numbers such that they + * add up to a specific target. + * + * You may assume that each input would have exactly one solution, and you may + * not use the same element twice. + * + * Example: + * + * + * Given nums = [2, 7, 11, 15], target = 9, + * + * Because nums[0] + nums[1] = 2 + 7 = 9, + * return [0, 1]. + * + * + */ + +// @lc code=start +class Solution { + public int[] twoSum(int[] nums, int target) { + Map numsMap = new HashMap<>(); + for(int i = 0; i < nums.length; i++){ + int temp = target - nums[i]; + if(numsMap.containsKey(temp) && numsMap.get(temp) != i){ + return new int[]{numsMap.get(temp), i}; + } + numsMap.put(nums[i], i); + } + return null; + } +} +// @lc code=end + +/** + * 通过求值来寻找索引,建立索引与值的关系,使用map + * 其中对target的转换的思想需要学习 + */ \ No newline at end of file diff --git a/Week 01/id_106/189.rotate-array.java b/Week 01/id_106/189.rotate-array.java new file mode 100644 index 000000000..09f8a73e2 --- /dev/null +++ b/Week 01/id_106/189.rotate-array.java @@ -0,0 +1,40 @@ +/* + * @lc app=leetcode id=189 lang=java + * + * [189] Rotate Array + */ + +// @lc code=start +class Solution { + public void rotate(int[] nums, int k) { + int[] newNums = new int[nums.length]; + for (int i = 0; i < nums.length; i++) { + newNums[(i+k) % nums.length] = nums[i]; + } + for (int j = 0; j < nums.length; j++) { + nums[j] = newNums[j]; + } + } +} +// @lc code=end + + + +/** + * 给定步数将数组的所有的元素向右移动 + * 1 创建一个新数组 + * 当小于K时,遍历数组,创建一个新的数组,当i通过(i+k)%length位移到新的位置 + * 完成后将新数组拷贝回原数组,关于这个计算公式的想法:每个下标被下令右移时有超出 + * 数组长度的可能,超出的位置回到数组头部重新计算,因此比数组长度长多少就是解, + * 所以用取余的方式获得. 时O(2n) 空O(n) + * + * 2 暴力解法 + * 旋转k次就挪动k次,不创建新的数组时就要保存元素,否则会被覆盖 + * 时O(n*k) 空O(1) + * + * 3 环状替代 + * 在同一个数组中移动替换元素,相当于执行length次将要替换的元素放到(i+k)%length的位置上去 + * 当n%k=0的时候,n/k个数字的下标会重复循环移动的过程,这n/k个数字是一组,为了遍历所有数字 + * 需要相同的操作去操作k个组 + * + */ diff --git a/Week 01/id_106/21.merge-two-sorted-lists.java b/Week 01/id_106/21.merge-two-sorted-lists.java new file mode 100644 index 000000000..265aa6448 --- /dev/null +++ b/Week 01/id_106/21.merge-two-sorted-lists.java @@ -0,0 +1,67 @@ +/* + * @lc app=leetcode id=21 lang=java + * + * [21] Merge Two Sorted Lists + * + * https://leetcode.com/problems/merge-two-sorted-lists/description/ + * + * algorithms + * Easy (49.36%) + * Likes: 2769 + * Dislikes: 405 + * Total Accepted: 716.3K + * Total Submissions: 1.4M + * Testcase Example: '[1,2,4]\n[1,3,4]' + * + * Merge two sorted linked lists and return it as a new list. The new list + * should be made by splicing together the nodes of the first two lists. + * + * Example: + * + * Input: 1->2->4, 1->3->4 + * Output: 1->1->2->3->4->4 + * + * + */ + +// @lc code=start +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode(int x) { val = x; } + * } + */ +class Solution { + public ListNode mergeTwoLists(ListNode l1, ListNode l2) { + if(l1 == null){ + return l2; + }else if (l2 == null){ + return l1; + }else if(l1.val < l2.val){ + l1.next = mergeTwoLists(l1.next, l2); + return l1; + }else{ + l2.next = mergeTwoLists(l2.next, l1); + return l2; + } + } +} +// @lc code=end + + +/** + * 1-使用递归 + * l1 + * 1 → 2 → 5 + * l2 + * 0 → 3 → 4 + * + * 1. 0→_ 1→2→5 3→4 + * 2. 0→1→_ 2→5 3→4 + * 3. 0→1→2→_ 5 3→4 + * 4. 0→1→2→3→_ 5 4 + * 5. 0→1→2→3→4→_ 5 null return 5 + * + */ \ No newline at end of file diff --git a/Week 01/id_106/26.remove-duplicates-from-sorted-array.java b/Week 01/id_106/26.remove-duplicates-from-sorted-array.java new file mode 100644 index 000000000..9c2bbaacd --- /dev/null +++ b/Week 01/id_106/26.remove-duplicates-from-sorted-array.java @@ -0,0 +1,32 @@ +/* + * @lc app=leetcode id=26 lang=java + * + * [26] Remove Duplicates from Sorted Array + */ + +// @lc code=start +class Solution { + public int removeDuplicates(int[] nums) { + if (nums.length == 0) return 0; + int dup = 0; + for (int i = 1; i < nums.length; i++){ + if (nums[i] != nums[dup]) { + dup++; + nums[dup] = nums[i]; + } + } + return dup+1; + } +} +// @lc code=end + + +/* +[0,0,1,1,1,2,2,3,3,4] +[0,1,2,3,4] +1 遍历,记录当前指针,定义一个比当前指针快一步的指针,进行遍历,遇到与当前数不同的数字就复制到当前数字的后面 +相同就跨过(前提是数组必须排序) +*/ +//2 或者如果允许用另一个数组,当遇到不同的数字就放在另一数组中,直接返回新数组就可以,O(n) +//if (nums.length == 0) return 0; 当数组为空时返回0 + diff --git a/Week 01/id_106/283-Move Zeroes.java b/Week 01/id_106/283-Move Zeroes.java new file mode 100644 index 000000000..084a69944 --- /dev/null +++ b/Week 01/id_106/283-Move Zeroes.java @@ -0,0 +1,15 @@ +class Solution { + public void moveZeroes(int[] nums) { + int count = 0; + for(int i=0;i= 0; j--) { //寻找左边最大值 + max_left = Math.max(max_left, height[j]); + } + for (int j = i; j < size; j++) { //寻找右边最大值 + max_right = Math.max(max_right, height[j]); + } + v += Math.min(max_left, max_right) - height[i]; + } + return v; + } +} +// @lc code=end + +/** + * 每个位置左右最大值中较小值为水的高度,同时还要减去在这范围中元素本身的高度 + */ \ No newline at end of file diff --git a/Week 01/id_106/NOTE.md b/Week 01/id_106/NOTE.md index a6321d6e2..3302482f2 100644 --- a/Week 01/id_106/NOTE.md +++ b/Week 01/id_106/NOTE.md @@ -1,4 +1,102 @@ # NOTE +### 20191014-1020第一周学习总结 +**一、主要内容** +1.学习了数组,链表,栈,队列,双端队列的给基本数据结构预期基本原理 +2.通过练习题目加深了对上述数据结构的理解与使用熟练度;同时,通过题目的练习了解了一些常用解题思路与代码处理方式。 - +**二、代码改写** + public static void main(String[] args) { + Deque deque = new LinkedList(); + deque.addFirst("a"); + deque.addLast("b"); + deque.addLast("c"); + System.out.println(deque); + + String str = deque.peek(); + System.out.println(str); + System.out.println(deque); + + while ( deque.size() > 0){ + System.out.println(deque.removeFirst());//pop + } + System.out.println(deque); + } + //output + /* + [a, b, c] + a + [a, b, c] + a + b + c + [] + */ + +**三、关于java PriorityQueue的源码分析** +java中PriorityQueue由平衡二进制堆实现(balanced binary heap) +堆(heap)是一种有数组实现的二叉树数据结构,通过堆属性来排列元素,分为最大堆与最小堆两种类型。所谓最大堆指的就是父节点大于所有的子节点;最小堆是指父节点小于所有子节点。根据api描述,PriorityQueue类型为最小堆,queue[0]位置将会保存最小的元素。 + +_1.add方法_ +add方法内部直接调用offer方法,其中先判断插入元素是否为null,长度是否超出等类似操作之后,执行主要的siftUp(index,e)方法将元素加入。 + + private void siftUp(int k, E x) { + if (comparator != null) + siftUpUsingComparator(k, x);//使用Comparator + else + siftUpComparable(k, x);//使用Comparable + } + + private void siftUpComparable(int k, E x) { + Comparable key = (Comparable) x; + while (k > 0) { + int parent = (k - 1) >>> 1;//取要insert元素的索引位置的上一层元素索引,即当前节点的父节点索引 + Object e = queue[parent]; + if (key.compareTo((E) e) >= 0)//判断插入值是否不小于父节点的值 + break; + queue[k] = e;//插入值不父节点的值小,向上移动一层 + k = parent; + } + queue[k] = key; + } + +通过此方法add保证了队列中queue[0]为最小节点,但没有按照优先级进行严格排序。 + +_2.poll出列方法_ +前将最小的第一个元素出列,后面的元素进行重排序。 + + public E poll() { + if (size == 0) + return null; + int s = --size; + modCount++; + E result = (E) queue[0]; + E x = (E) queue[s]; + queue[s] = null; + if (s != 0) + siftDown(0, x); + return result; + } + 排序方法如下: + + private void siftDownComparable(int k, E x) { + Comparable key = (Comparable)x; + int half = size >>> 1; // loop while a non-leaf + while (k < half) { + int child = (k << 1) + 1; // 获取左子的索引,假设坐姿左子最小 + Object c = queue[child];//获取左子的值 + int right = child + 1;//获取右子的key + if (right < size && + ((Comparable) c).compareTo((E) queue[right]) > 0) + c = queue[child = right];//如果左子的值大于右子,取两者最小 + if (key.compareTo((E) c) <= 0) + break;//判断当前元素是否小于最小子 + queue[k] = c;//如果不是,将最小子放置在当前元素 + k = child;//将下表替换为左子下标,继续便利,直到叶子节点的上一层 + } + queue[k] = key; + } + +可以看出,当第一个元素出队列之后,对剩下的元素进行再排序,挑选出最小的元素排在数组第一个位置。 + +以上是对add和poll的简要分析,还有些没有看完,如有错误请老师和同学们指出,欢迎大家交流。 diff --git a/Week 01/id_111/NOTE.md b/Week 01/id_111/NOTE.md index a6321d6e2..12d5fcd78 100644 --- a/Week 01/id_111/NOTE.md +++ b/Week 01/id_111/NOTE.md @@ -1,4 +1,29 @@ -# NOTE +# NOTE by 111-黑化肥 +## 数组、链表、跳表的基本实现和特性 + +### 数组 + +- 一种线性表数据结构 +- 内存管理器中开辟出连续的内存空间 +- 访问数组内任一元素,时间复杂度均为1(常数级时间复杂度) +- 插入操作 O(n) +- 删除操作 +### 链表 +- 元素定义之后有value 和 next 能指向到下一个元素,串成一个链表 +- 一个next 指针 单链表 ,含Pre 指针为双链表 +- 最后元素指向空,若最后的指针指向头则循环链表 +- 增加删除节点,时间复杂度O(n) +- 访问链表中任意位置O(n) +### 跳表 +- 链表的优化,redis中有运用 +- 升维(空间换时间) +- 添加一级索引指向next + 1 +- 添加二级索引指向(next + 1)*2 +- 增加多级索引 增加log(2n) 索引 +- 查询时间复杂度O(logn) +- 维护成本高 +- 增加/删除时间复杂度 logn +- 空间复杂度 O(n) diff --git a/Week 01/id_111/leetcode_26_111.py b/Week 01/id_111/leetcode_26_111.py new file mode 100644 index 000000000..4119cc9ea --- /dev/null +++ b/Week 01/id_111/leetcode_26_111.py @@ -0,0 +1,68 @@ +#有序数组去重 +""" +给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。 +不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。 +示例 1: +给定数组 nums = [1,1,2], +函数应该返回新的长度 2, 并且原数组 nums 的前两个元素被修改为 1, 2。 +你不需要考虑数组中超出新长度后面的元素。 +""" + +# 解题思路:查看他人解法后理解写出: +# 有序数组,重复项必相邻 +""" + 双指针法采用前后两个指针,a b + a起始下标为0 ,b起始下标为1 + 1. 比较 a b 两数是否相等 + 如相等,a 不动, b向后移动一位 + 如不相等,a 先不动, 复制 b位置的元素到 a+1 的位置, a 后移一位 ,b后移一位 + 2. 重复上述过程,直到b 等于数组的长度 + 3. 返回 a+1 即为新数组的长度 + 这样不用剔除数组中的元素,时间复杂度应该是 O(n)? +""" +class Solution: + def removeDuplicates(self, nums: List[int]) -> int: + a,b=0,1 + while b int: + """ + 1. 定义 len_ + 2. 如果数组长度为 0 则 0 + 用i 作下标遍历数组,遇到n[i]不等于相邻元素时,将值赋给 len_ + 最后返回 len_ 值 + 3. 时间复杂度 O(n) 一样是需要遍历完整个数组 + + """ + len_ = 1 + if len(nums)==0: + return 0 + for i in range(1,len(nums)): + if nums[i] != nums[i-1]: + nums[len_] = nums[i] + len_ += 1 + return len_ + +#优化项: +#假设极端情况,数组中没有重复元素,则每次判断a!=b 都会将数值复制一遍 +# 可以对复制值前先作一个判断 b-a>1 即 中间存在重复值时,才进行复制: + +class Solution: + def removeDuplicates(self, nums: List[int]) -> int: + a,b=0,1 + while b 1: + nums[a+1]=nums[b] + a,b=a+1,b+1 #这里好像执行有问题 + return a+1 diff --git "a/Week 01/id_116/[21]\345\220\210\345\271\266\344\270\244\344\270\252\346\234\211\345\272\217\351\223\276\350\241\250.py" "b/Week 01/id_116/[21]\345\220\210\345\271\266\344\270\244\344\270\252\346\234\211\345\272\217\351\223\276\350\241\250.py" new file mode 100644 index 000000000..8e41ea22f --- /dev/null +++ "b/Week 01/id_116/[21]\345\220\210\345\271\266\344\270\244\344\270\252\346\234\211\345\272\217\351\223\276\350\241\250.py" @@ -0,0 +1,40 @@ +#将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 +# +# 示例: +# +# 输入:1->2->4, 1->3->4 +#输出:1->1->2->3->4->4 +# +# Related Topics 链表 + + + +#leetcode submit region begin(Prohibit modification and deletion) +# Definition for singly-linked list. +# class ListNode(object): +# def __init__(self, x): +# self.val = x +# self.next = None + +class Solution(object): + def mergeTwoLists(self, l1, l2): + """ + :type l1: ListNode + :type l2: ListNode + :rtype: ListNode + """ + prehead = ListNode(-1) + prev = prehead + while l1 and l2: + if l1.val= 0 and p2 >= 0: + if nums1[p1] < nums2[p2]: + nums1[p] = nums2[p2] + p2 -= 1 + else: + nums1[p] = nums1[p1] + p1 -= 1 + p -= 1 + nums1[:p2 + 1] = nums2[:p2+1] + # print(nums1) + # print(nums2) + # leetcode submit region end(Prohibit modification and deletion) + + +# Solution().merge([1, 2, 3, 0, 0, 0], 3, [2, 5, 6], 3) +# Solution().merge([1], 1, [], 0) + +l1 = [1,2,2,3,5,6] +l2 = [2,5,6] +print(l1[:0]) +print(l2[:0]) +print(l1) \ No newline at end of file diff --git a/Week 01/id_131/LeetCode_15_131.java b/Week 01/id_131/LeetCode_15_131.java new file mode 100644 index 000000000..4db0fa0bc --- /dev/null +++ b/Week 01/id_131/LeetCode_15_131.java @@ -0,0 +1,62 @@ +//给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组。 +// +// 注意:答案中不可以包含重复的三元组。 +// +// 例如, 给定数组 nums = [-1, 0, 1, 2, -1, -4], +// +//满足要求的三元组集合为: +//[ +// [-1, 0, 1], +// [-1, -1, 2] +//] +// +// Related Topics 数组 双指针 + + +//leetcode submit region begin(Prohibit modification and deletion) + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +public class ThreeSum { + public List> threeSum(int[] nums) { + if (nums == null || nums.length < 2) return Collections.emptyList(); + + Arrays.sort(nums); + + List> list = new ArrayList<>(); + for (int i = 0; i < nums.length - 2; i++) { + if (nums[i] > 0) return list; + + // duplicate in i + if (i > 0 && nums[i] == nums[i - 1]) continue; + + // left, right + int left = i + 1; + int right = nums.length - 1; + if (nums[right] < 0) return list; + + while (left < right) { + int sum = nums[i] + nums[left] + nums[right]; + if (sum < 0) { + left++; + } else if (sum > 0) { + right--; + } else { + list.add(Arrays.asList(nums[i], nums[left], nums[right])); + + // duplicate in left, right + while (left < right && nums[left] == nums[left + 1]) left++; + while (left < right && nums[right] == nums[right - 1]) right--; + + left++; + right--; + } + } + } + return list; + } +} +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 01/id_131/LeetCode_1_131.java b/Week 01/id_131/LeetCode_1_131.java new file mode 100644 index 000000000..41ad3eba3 --- /dev/null +++ b/Week 01/id_131/LeetCode_1_131.java @@ -0,0 +1,30 @@ +//给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。 +// +// 你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。 +// +// 示例: +// +// 给定 nums = [2, 7, 11, 15], target = 9 +// +//因为 nums[0] + nums[1] = 2 + 7 = 9 +//所以返回 [0, 1] +// +// Related Topics 数组 哈希表 + +import java.util.HashMap; +import java.util.Map; + +//leetcode submit region begin(Prohibit modification and deletion) +public class TwoSum { + public int[] twoSum(int[] nums, int target) { + Map map = new HashMap<>(); + for (int i = 0; i < nums.length; i++) { + if (map.containsKey(target - nums[i])) { + return new int[]{map.get(target - nums[i]), i}; + } + map.put(nums[i], i); + } + return null; + } +} +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 01/id_131/LeetCode_26_131.java b/Week 01/id_131/LeetCode_26_131.java new file mode 100644 index 000000000..97152b00f --- /dev/null +++ b/Week 01/id_131/LeetCode_26_131.java @@ -0,0 +1,56 @@ +//给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。 +// +// 不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。 +// +// 示例 1: +// +// 给定数组 nums = [1,1,2], +// +//函数应该返回新的长度 2, 并且原数组 nums 的前两个元素被修改为 1, 2。 +// +//你不需要考虑数组中超出新长度后面的元素。 +// +// 示例 2: +// +// 给定 nums = [0,0,1,1,1,2,2,3,3,4], +// +//函数应该返回新的长度 5, 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4。 +// +//你不需要考虑数组中超出新长度后面的元素。 +// +// +// 说明: +// +// 为什么返回数值是整数,但输出的答案是数组呢? +// +// 请注意,输入数组是以“引用”方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。 +// +// 你可以想象内部操作如下: +// +// // nums 是以“引用”方式传递的。也就是说,不对实参做任何拷贝 +//int len = removeDuplicates(nums); +// +//// 在函数里修改输入数组对于调用者是可见的。 +//// 根据你的函数返回的长度, 它会打印出数组中该长度范围内的所有元素。 +//for (int i = 0; i < len; i++) { +//    print(nums[i]); +//} +// +// Related Topics 数组 双指针 + + +//leetcode submit region begin(Prohibit modification and deletion) +public class RemoveDuplicatesFromSortedArray { + public int removeDuplicates(int[] nums) { + if (nums == null) return 0; + if (nums.length < 2) return nums.length; + int count = 0; + for (int i = 1; i < nums.length; i++) { + if (nums[i - 1] == nums[i]) count++; + else nums[i - count] = nums[i]; + } + return nums.length - count; + } +} +//leetcode submit region end(Prohibit modification and deletion) + diff --git a/Week 01/id_131/LeetCode_283_131.java b/Week 01/id_131/LeetCode_283_131.java new file mode 100644 index 000000000..8c9631939 --- /dev/null +++ b/Week 01/id_131/LeetCode_283_131.java @@ -0,0 +1,32 @@ +//给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。 +// +// 示例: +// +// 输入: [0,1,0,3,12] +//输出: [1,3,12,0,0] +// +// 说明: +// +// +// 必须在原数组上操作,不能拷贝额外的数组。 +// 尽量减少操作次数。 +// +// Related Topics 数组 双指针 + + +//leetcode submit region begin(Prohibit modification and deletion) +class Solution { + public void moveZeroes(int[] nums) { + if (nums == null || nums.length == 0) return; + for (int i = 0, nonZero = 0; i < nums.length; i++) { + if (nums[i] != 0) { + // 直接交换则无需判断,减少程序判断的停留 + int temp = nums[nonZero]; + nums[nonZero] = nums[i]; + nums[i] = temp; + nonZero++; + } + } // for + } // moveZeroes +} +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 01/id_141/LeetCode_1_141.swift b/Week 01/id_141/LeetCode_1_141.swift new file mode 100644 index 000000000..abd3cef2e --- /dev/null +++ b/Week 01/id_141/LeetCode_1_141.swift @@ -0,0 +1,46 @@ +// +// TwoSum.swift +// algorithm +// +// Created by pingan on 2019/10/16. +// Copyright © 2019 pingan. All rights reserved. +// + +import Foundation + +//func twoSum(nums: [Int],target: Int) -> [Int] { +// for i in 0.. [Int] { +// var dic: [Int: Int] = [Int: Int]() +// for i in 0.. [Int] { + var dic: [Int: Int] = [Int: Int]() + for i in 0.. Int { + if nums.count == 0 { + return 0 + } + var i: Int = 0 + for j in i+1..& nums, int k) { + deque d(nums.begin(), nums.end()); + for (int i = 0; i < k; ++i) { + int tmp = d.back(); + d.pop_back(); + d.push_front(tmp); + } + for (int i = 0; i < d.size(); ++i) { + nums[i] = d[i]; + } + } +}; diff --git a/Week 01/id_151/LeetCode_1_151.cpp b/Week 01/id_151/LeetCode_1_151.cpp new file mode 100644 index 000000000..d9787ec29 --- /dev/null +++ b/Week 01/id_151/LeetCode_1_151.cpp @@ -0,0 +1,13 @@ +class Solution { +public: + vector twoSum(vector& nums, int target) { + map m; + for (int i = 0; i < nums.size(); ++i) { + if (m.count(target - nums[i])) { + return {i, m[target - nums[i]]}; + } + m[nums[i]] = i; + } + return {}; + } +}; diff --git a/Week 01/id_151/LeetCode_21_151.cpp b/Week 01/id_151/LeetCode_21_151.cpp new file mode 100644 index 000000000..a3eb3b2c2 --- /dev/null +++ b/Week 01/id_151/LeetCode_21_151.cpp @@ -0,0 +1,27 @@ +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode(int x) : val(x), next(NULL) {} + * }; + */ +class Solution { +public: + ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) { + ListNode dummy(0); + ListNode* head = &dummy; + while (l1 && l2) { + if (l1->val > l2->val) { + head->next = l2; + l2 = l2->next; + } else { + head->next = l1; + l1 = l1->next; + } + head = head->next; + } + head->next = l1 ? l1 : l2; + return dummy.next; + } +}; diff --git a/Week 01/id_151/LeetCode_26_151.cpp b/Week 01/id_151/LeetCode_26_151.cpp new file mode 100644 index 000000000..faa0e157a --- /dev/null +++ b/Week 01/id_151/LeetCode_26_151.cpp @@ -0,0 +1,15 @@ +class Solution { +public: + int removeDuplicates(vector& nums) { + if (nums.empty()) return 0; + + int idx = 0; + for (int i = 1; i < nums.size(); ++i) { + if (nums[i] == nums[i - 1]) { + continue; + } + nums[++idx] = nums[i]; + } + return idx + 1; + } +}; diff --git a/Week 01/id_151/LeetCode_283_151.cpp b/Week 01/id_151/LeetCode_283_151.cpp new file mode 100644 index 000000000..b568a9238 --- /dev/null +++ b/Week 01/id_151/LeetCode_283_151.cpp @@ -0,0 +1,16 @@ +class Solution { +public: + void moveZeroes(vector& nums) { + int j = 0; + for (int i = 0; i != nums.size(); ++i) { + if (nums[i] != 0) { + nums[j] = nums[i]; + // 防止[1], [1, 0]这种输入 + if (i != j) { + nums[i] = 0; + } + ++j; + } + } + } +}; diff --git a/Week 01/id_151/LeetCode_42_151.cpp b/Week 01/id_151/LeetCode_42_151.cpp new file mode 100644 index 000000000..22de62415 --- /dev/null +++ b/Week 01/id_151/LeetCode_42_151.cpp @@ -0,0 +1,23 @@ +class Solution { +public: + int trap(vector& height) { + stack s; + s.push(0); + int ret = 0; + for (int i = 1; i < height.size(); ++i) { + while (! s.empty() && height[i] >= height[s.top()]) { + int top = s.top(); + s.pop(); + + if (s.empty()) + break; + + int distance = i - s.top() - 1; + int min_height = min(height[i], height[s.top()]) - height[top]; + ret += distance * min_height; + } + s.push(i); + } + return ret; + } +}; diff --git a/Week 01/id_151/LeetCode_641_151.cpp b/Week 01/id_151/LeetCode_641_151.cpp new file mode 100644 index 000000000..038502291 --- /dev/null +++ b/Week 01/id_151/LeetCode_641_151.cpp @@ -0,0 +1,98 @@ +class MyCircularDeque { +public: + /** Initialize your data structure here. Set the size of the deque to be k. */ + MyCircularDeque(int k) { + capacity_ = k; + allocBuffer(); + } + + /** Adds an item at the front of Deque. Return true if the operation is successful. */ + bool insertFront(int value) { + if (size_ == capacity_) { + return false; + } + ++size_; + buffer_[--front_idx_] = value; + return true; + } + + /** Adds an item at the rear of Deque. Return true if the operation is successful. */ + bool insertLast(int value) { + if (size_ == capacity_) { + return false; + } + ++size_; + buffer_[++back_idx_] = value; + return true; + } + + /** Deletes an item from the front of Deque. Return true if the operation is successful. */ + bool deleteFront() { + if (size_ == 0) { + return false; + } + --size_; + ++front_idx_; + return true; + } + + /** Deletes an item from the rear of Deque. Return true if the operation is successful. */ + bool deleteLast() { + if (size_ == 0) { + return false; + } + --size_; + --back_idx_; + return true; + } + + /** Get the front item from the deque. */ + int getFront() { + if (size_ == 0) + return -1; + return buffer_[front_idx_]; + } + + /** Get the last item from the deque. */ + int getRear() { + if (size_ == 0) + return -1; + return buffer_[back_idx_]; + } + + /** Checks whether the circular deque is empty or not. */ + bool isEmpty() { + return size_ == 0; + } + + /** Checks whether the circular deque is full or not. */ + bool isFull() { + return size_ == capacity_; + } +private: + void allocBuffer() { + buffer_ = (int*)malloc(sizeof(int) * (capacity_ + 1) * 2); + front_idx_ = capacity_; + back_idx_ = front_idx_ - 1; + size_ = 0; + } +private: + int* buffer_; + int capacity_; + int size_; + int back_idx_; + int front_idx_; +}; + +/** + * Your MyCircularDeque object will be instantiated and called as such: + * MyCircularDeque* obj = new MyCircularDeque(k); + * bool param_1 = obj->insertFront(value); + * bool param_2 = obj->insertLast(value); + * bool param_3 = obj->deleteFront(); + * bool param_4 = obj->deleteLast(); + * int param_5 = obj->getFront(); + * int param_6 = obj->getRear(); + * bool param_7 = obj->isEmpty(); + * bool param_8 = obj->isFull(); + */ diff --git a/Week 01/id_151/LeetCode_66_151.cpp b/Week 01/id_151/LeetCode_66_151.cpp new file mode 100644 index 000000000..ecf8392be --- /dev/null +++ b/Week 01/id_151/LeetCode_66_151.cpp @@ -0,0 +1,21 @@ +class Solution { +public: + vector plusOne(vector& digits) { + int carry = 1; + int count = 0; + for (int i = digits.size() - 1; i >= 0; --i, ++count) { + int& n = digits[i]; + n += carry; + if (n % 10 == 0) { + n = 0; + continue; + } + break; + } + if (count == digits.size()) { + digits.push_back(0); + digits[0] = 1; + } + return digits; + } +}; diff --git a/Week 01/id_151/LeetCode_88_151.cpp b/Week 01/id_151/LeetCode_88_151.cpp new file mode 100644 index 000000000..020be02b8 --- /dev/null +++ b/Week 01/id_151/LeetCode_88_151.cpp @@ -0,0 +1,10 @@ +class Solution { +public: + void merge(vector& nums1, int m, vector& nums2, int n) { + if (n <= 0) + return; + + memcpy(nums1.data() + m, nums2.data(), n * sizeof(int)); + sort(nums1.begin(), nums1.begin() + m + n); + } +}; diff --git a/Week 01/id_166/1.cpp b/Week 01/id_166/1.cpp new file mode 100644 index 000000000..f24e8db7b --- /dev/null +++ b/Week 01/id_166/1.cpp @@ -0,0 +1,11 @@ +class Solution { +public: + vector twoSum(vector& nums, int target) { + unordered_map hashmap; + for(int i = 0; i < nums.size(); i++){ + if(hashmap.count(target - nums[i])) return {hashmap[target - nums[i]], i}; + hashmap[nums[i]] = i; + } + return {-1, -1}; + } +}; diff --git a/Week 01/id_166/189.cpp b/Week 01/id_166/189.cpp new file mode 100644 index 000000000..24e20e8ff --- /dev/null +++ b/Week 01/id_166/189.cpp @@ -0,0 +1,20 @@ +class Solution { +public: + void rotate(vector& nums, int k) { + + k = k % nums.size(); + int len = nums.size(); + + while (k > 0 && len > 1 && len != k) { + for (int i = len - 1; i > k - 1; i--) { + swap(nums[i], nums[i - k]); + } + + int tmp = k; + k = k - len % k; + len = tmp; + } + + } + +}; diff --git a/Week 01/id_166/21.cpp b/Week 01/id_166/21.cpp new file mode 100644 index 000000000..3f1617ced --- /dev/null +++ b/Week 01/id_166/21.cpp @@ -0,0 +1,28 @@ +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode(int x) : val(x), next(NULL) {} + * }; + */ +class Solution { +public: + ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) { + if(l1 == NULL) { + return l2; + } + else if(l2 == NULL) { + return l1; + } + if(l1->val < l2->val) { + l1->next = mergeTwoLists(l1->next, l2); + return l1; + } + else{ + l2->next = mergeTwoLists(l2->next, l1); + return l2; + } + + } +}; diff --git a/Week 01/id_166/26.cpp b/Week 01/id_166/26.cpp new file mode 100644 index 000000000..40db30271 --- /dev/null +++ b/Week 01/id_166/26.cpp @@ -0,0 +1,15 @@ +class Solution { +public: + int removeDuplicates(vector& nums) { + if (nums.size() < 2) { + return nums.size(); + } + int j=0; + for(int i=1;i& nums) { + for (int lastNZeroFoundAt = 0, cur = 0; cur < nums.size(); cur++) { + if (nums[cur] != 0) { + swap(nums[lastNZeroFoundAt++], nums[cur]); + } + } + } +}; diff --git a/Week 01/id_166/42.cpp b/Week 01/id_166/42.cpp new file mode 100644 index 000000000..466c0e6d8 --- /dev/null +++ b/Week 01/id_166/42.cpp @@ -0,0 +1,19 @@ +class Solution { +public: + int trap(vector& height) { + int n = height.size(); + vector left(n), right(n); + for (int i = 1; i < n; i++) { + left[i] = max(left[i - 1], height[i - 1]); + } + for (int i = n - 2; i >= 0; i--) { + right[i] = max(right[i + 1], height[i + 1]); + } + int water = 0; + for (int i = 0; i < n; i++) { + int level = min(left[i], right[i]); + water += max(0, level - height[i]); + } + return water; + } +}; diff --git a/Week 01/id_166/66.cpp b/Week 01/id_166/66.cpp new file mode 100644 index 000000000..42c2f496d --- /dev/null +++ b/Week 01/id_166/66.cpp @@ -0,0 +1,23 @@ +class Solution { +public: + vector plusOne(vector& digits) { + vector ret(digits); + if (digits[0] == 0) { + ret[0] = 1; + return ret; + } + + int index = digits.size() - 1; + int mod = 0; + + while (index >= 0 && mod == 0) { + ret[index] += 1; + mod = ret[index--] % 10; + } + + if (mod == 0) { + ret.insert(ret.begin(), 1); + } + return ret; + } +}; diff --git a/Week 01/id_166/88.go b/Week 01/id_166/88.go new file mode 100644 index 000000000..b9254c2eb --- /dev/null +++ b/Week 01/id_166/88.go @@ -0,0 +1,25 @@ +func merge(nums1 []int, m int, nums2 []int, n int) { + k := n+m-1 + i := m-1 + j:= n-1 + + if i < 0 && j < 0 { + return + } + for j >= 0&&i>=0 { + if nums1[i]>=nums2[j] { + nums1[k] = nums1[i] + k-- + i-- + }else { + nums1[k] = nums2[j] + j-- + k-- + } + } + for j>=0 { + nums1[k] = nums2[j] + k-- + j-- + } +} diff --git a/Week 01/id_166/MyCircularDeque.hpp b/Week 01/id_166/MyCircularDeque.hpp new file mode 100644 index 000000000..7d6c6da96 --- /dev/null +++ b/Week 01/id_166/MyCircularDeque.hpp @@ -0,0 +1,60 @@ +class MyCircularDeque { +public: + MyCircularDeque(int k) { + start = 0, end = 1, cap = k; + } + + bool insertFront(int value) { + if(mp.size() == cap) return false; + mp[start--] = value; + return true; + } + + bool insertLast(int value) { + if(mp.size() == cap) return false; + mp[end++] = value; + return true; + } + + bool deleteFront() { + if(!mp.size()) return false; + mp.erase(++start); + return true; + } + + bool deleteLast() { + if(!mp.size()) return false; + mp.erase(--end); + return true; + } + + int getFront() { + if(!mp.size()) return -1; + return mp[start + 1]; + } + + int getRear() { + if(!mp.size()) return -1; + return mp[end - 1]; + } + + bool isEmpty() { return !mp.size(); } + + bool isFull() { return mp.size() == cap; } +private: + unordered_map mp; + int start, end, cap; +}; + +/** + * Your MyCircularDeque object will be instantiated and called as such: + * MyCircularDeque* obj = new MyCircularDeque(k); + * bool param_1 = obj->insertFront(value); + * bool param_2 = obj->insertLast(value); + * bool param_3 = obj->deleteFront(); + * bool param_4 = obj->deleteLast(); + * int param_5 = obj->getFront(); + * int param_6 = obj->getRear(); + * bool param_7 = obj->isEmpty(); + * bool param_8 = obj->isFull(); + */ diff --git a/Week 01/id_171/MergeSortedArraySol.cs b/Week 01/id_171/MergeSortedArraySol.cs new file mode 100644 index 000000000..ec6de4784 --- /dev/null +++ b/Week 01/id_171/MergeSortedArraySol.cs @@ -0,0 +1,66 @@ +using System; + +namespace Poplar.Algorithm.WeekOne +{ + ///

+ /// 合并两个有序数组 + /// https://leetcode.com/problems/merge-sorted-array/ + /// https://leetcode-cn.com/problems/merge-sorted-array/ + /// + public class MergeSortedArraySol + { + public void Merge(int[] nums1, int m, int[] nums2, int n) + { + //this.MergeOne(nums1, m, nums2, n); + //this.MergeTwo(nums1, m, nums2, n); + this.MergeThree(nums1, m, nums2, n); + } + + private void MergeThree(int[] nums1, in int m, int[] nums2, int n) + { + int i = m - 1, j = n - 1, k = m + n - 1; + while (i > -1 && j > -1) + { + if (nums1[i] >= nums2[j]) + { + nums1[k--] = nums1[i--]; + } + else + { + nums1[k--] = nums2[j--]; + } + } + if (j > -1) + { + Array.Copy(nums2, 0, nums1, 0, j + 1); + } + } + + private void MergeTwo(int[] nums1, in int m, int[] nums2, int n) + { + var arr = new int[nums1.Length]; + Array.Copy(nums1, 0, arr, 0, m); + var k = 0; + int i = 0, j = 0; + while (i < m && j < n) + { + nums1[k++] = arr[i] <= nums2[j] ? arr[i++] : nums2[j++]; + } + if (i < m) + { + Array.Copy(arr, i, nums1, k, m - i); + } + else + { + Array.Copy(nums2, j, nums1, k, n - j); + } + + } + + private void MergeOne(int[] nums1, in int m, int[] nums2, int n) + { + Array.Copy(nums2, 0, nums1, m, n); + Array.Sort(nums1, 0, m + n); + } + } +} diff --git a/Week 01/id_171/MergeTwoSortedListsSol.cs b/Week 01/id_171/MergeTwoSortedListsSol.cs new file mode 100644 index 000000000..12a8c207e --- /dev/null +++ b/Week 01/id_171/MergeTwoSortedListsSol.cs @@ -0,0 +1,82 @@ +using Poplar.Algorithm.Models; + +namespace Poplar.Algorithm.WeekOne +{ + /// + /// 合并两个有序链表 + /// https://leetcode.com/problems/merge-two-sorted-lists/ + /// https://leetcode-cn.com/problems/merge-two-sorted-lists/ + /// + public class MergeTwoSortedListsSol + { + public ListNode MergeTwoLists(ListNode l1, ListNode l2) + { + //return MergeTwoListsOne(l1, l2); + return MergeTwoListTwo(l1, l2); + } + + /// + /// 递归 + /// + /// + /// + /// + private ListNode MergeTwoListTwo(ListNode l1, ListNode l2) + { + if (l1 == null) + { + return l2; + } + if (l2 == null) + { + return l1; + } + if (l1.val <= l2.val) + { + l1.next = MergeTwoListTwo(l1.next, l2); + return l1; + } + else + { + l2.next = MergeTwoListTwo(l2.next, l1); + return l2; + } + } + + /// + /// 迭代 + /// + /// + /// + /// + private ListNode MergeTwoListsOne(ListNode l1, ListNode l2) + { + if (l1 == null) + { + return l2; + } + if (l2 == null) + { + return l1; + } + var head = new ListNode(-1); + var prev = head; + 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 head; + } + } +} diff --git a/Week 01/id_171/MoveZeroesSol.cs b/Week 01/id_171/MoveZeroesSol.cs new file mode 100644 index 000000000..38f31161d --- /dev/null +++ b/Week 01/id_171/MoveZeroesSol.cs @@ -0,0 +1,31 @@ +namespace Poplar.Algorithm.WeekOne +{ + /// + /// 移动零 + /// https://leetcode.com/problems/move-zeroes/ + /// https://leetcode-cn.com/problems/move-zeroes/ + /// + public class MoveZeroesSol + { + public void MoveZeroes(int[] nums) + { + if (nums == null || nums.Length < 2) + { + return; + } + int j = 0; + for (int i = 0; i < nums.Length; i++) + { + if (nums[i] != 0) + { + nums[j] = nums[i]; + if (i != j) + { + nums[i] = 0; + } + j++; + } + } + } + } +} diff --git a/Week 01/id_171/PlusOneSol.cs b/Week 01/id_171/PlusOneSol.cs new file mode 100644 index 000000000..007d23780 --- /dev/null +++ b/Week 01/id_171/PlusOneSol.cs @@ -0,0 +1,61 @@ +using System; + +namespace Poplar.Algorithm.WeekOne +{ + /// + /// 加一 + /// https://leetcode.com/problems/plus-one/ + /// https://leetcode-cn.com/problems/plus-one/ + /// + public class PlusOneSol + { + public int[] PlusOne(int[] digits) + { + //return this.PlusOneOne(digits); + return this.PlusOneTwo(digits); + } + + private int[] PlusOneTwo(int[] digits) + { + for (int i = digits.Length - 1; i > -1; i--) + { + digits[i] = digits[i] + 1; + digits[i] = digits[i] % 10; + if (digits[i] != 10) + { + return digits; + } + } + digits = new int[digits.Length + 1]; + digits[0] = 1; + return digits; + } + + private int[] PlusOneOne(int[] digits) + { + var step = 1; + for (int i = digits.Length - 1; i > -1; i--) + { + var sum = digits[i] + step; + if (sum > 9) + { + step = 1; + sum = sum - 10; + } + else + { + step = 0; + } + digits[i] = sum; + } + if (step == 0) + { + return digits; + } + var arr = new int[digits.Length + 1]; + arr[0] = step; + Array.Copy(digits, 0, arr, 1, digits.Length); + return arr; + } + } +} diff --git a/Week 01/id_171/RemoveDuplicatesFromSortedArraySol.cs b/Week 01/id_171/RemoveDuplicatesFromSortedArraySol.cs new file mode 100644 index 000000000..86a7541ec --- /dev/null +++ b/Week 01/id_171/RemoveDuplicatesFromSortedArraySol.cs @@ -0,0 +1,37 @@ +namespace Poplar.Algorithm.WeekOne +{ + /// + /// 删除排序数组中的重复项 + /// https://leetcode.com/problems/remove-duplicates-from-sorted-array/ + /// https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array/ + /// + public class RemoveDuplicatesFromSortedArraySol + { + /// + /// 双指针法,第一个指针j指向最后一个不重复的值,另外一个指针i遍历数组, + /// 开始的时候,j指向0,i指向j + 1也就是1。 + /// i从1开始遍历数组,当i指向的值和j指向的值相等,就继续向前遍历, + /// 当i指向的值和j指向的值不相等,让j先往前近一格(因为当前j指向的是最后一个不重复的值,此时要将另外一个不重复的值放进来,所以j要前进一格), + /// 将i指向的值赋给j指向的位置。 + /// 整个数组遍历完成之后,j还是最后一个不重复的值的索引,因为返回的是数量,所以需要将j + 1再返回 + /// + /// + /// + public int RemoveDuplicates(int[] nums) + { + if (nums.Length < 2) + { + return nums.Length; + } + var j = 0; + for (int i = 1; i < nums.Length; i++) + { + if (nums[i] != nums[j]) + { + nums[++j] = nums[i]; + } + } + return j + 1; + } + } +} diff --git a/Week 01/id_171/RotateArraySol.cs b/Week 01/id_171/RotateArraySol.cs new file mode 100644 index 000000000..db7643039 --- /dev/null +++ b/Week 01/id_171/RotateArraySol.cs @@ -0,0 +1,67 @@ +using System; + +namespace Poplar.Algorithm.WeekOne +{ + /// + /// 旋转数组 + /// https://leetcode.com/problems/rotate-array/ + /// https://leetcode-cn.com/problems/rotate-array/ + /// + public class RotateArraySol + { + public void Rotate(int[] nums, int k) + { + //RotateOne(nums, k); + RotateTwo(nums, k); + } + + /// + /// 循环交换 + /// + /// + /// + private void RotateTwo(int[] nums, int k) + { + var length = nums.Length; + k = k % length; + if (k == length) + { + return; + } + var count = 0; + for (var start = 0; count < nums.Length; start++) + { + var curIndex = start; + var cur = nums[curIndex]; + do + { + var temp = cur; + var nextIndex = (curIndex + k) % length; + cur = nums[nextIndex]; + nums[nextIndex] = temp; + curIndex = nextIndex; + count++; + } while (start != curIndex); + } + } + + /// + /// 第一种方法,使用额外的数组 + /// + /// + /// + public void RotateOne(int[] nums, int k) + { + var length = nums.Length; + k = k % length; + if (k == length) + { + return; + } + var arr = new int[length]; + Array.Copy(nums, 0, arr, 0, length); + Array.Copy(arr, 0, nums, 0 + k, length - k); + Array.Copy(arr, nums.Length - k, nums, 0, k); + } + } +} diff --git a/Week 01/id_171/ThreeNumSol.cs b/Week 01/id_171/ThreeNumSol.cs new file mode 100644 index 000000000..d78428891 --- /dev/null +++ b/Week 01/id_171/ThreeNumSol.cs @@ -0,0 +1,97 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Poplar.Algorithm.WeekOne +{ + /// + /// 三数之和 + /// https://leetcode.com/problems/3sum/ + /// https://leetcode-cn.com/problems/3sum/ + /// + public class ThreeNumSol + { + public IList> ThreeSum(int[] nums) + { + //return this.ThreeSumOne(nums); + return this.ThreeSumTwo(nums); + } + + /// + /// 双指针 + /// + /// + /// + public IList> ThreeSumTwo(int[] nums) + { + Array.Sort(nums); + var result = new List>(); + for (int k = 0; k < nums.Length; k++) + { + if (k == 0 || nums[k] != nums[k - 1]) + { + var cur = nums[k]; + var i = k + 1; + var j = nums.Length - 1; + while (i < j) + { + var sum = nums[i] + nums[j] + cur; + if (sum == 0) + { + result.Add(new List() { nums[i++], nums[j--], nums[k] }); + while (i < j && nums[i] == nums[i - 1]) + { + i++; + } + while (i < j && nums[j] == nums[j + 1]) + { + j--; + } + } + else if (sum < 0) + { + i++; + } + else + { + j--; + } + } + } + } + return result; + } + + /// + /// 暴力破解,三层循环嵌套,时间复杂度是O(n³),空间复杂度是O(1),没有消耗额外空间 + /// + /// + /// + public IList> ThreeSumOne(int[] nums) + { + var temp = nums.ToList(); + temp.Sort(); + nums = temp.ToArray(); + var result = new List>(); + for (int i = 0; i < nums.Length - 2; i++) + { + for (int j = i + 1; j < nums.Length - 1; j++) + { + if (j > i + 1 && nums[j] == nums[j] - 1) + { + continue; + } + for (int k = j + 1; k < nums.Length; k++) + { + if (nums[i] + nums[j] + nums[k] == 0) + { + result.Add(new List() { nums[i], nums[j], nums[k] }); + break; + } + } + } + } + return result; + } + } +} diff --git a/Week 01/id_176/LeetCode_189_176.swift b/Week 01/id_176/LeetCode_189_176.swift new file mode 100644 index 000000000..4602487f9 --- /dev/null +++ b/Week 01/id_176/LeetCode_189_176.swift @@ -0,0 +1,99 @@ +/* + * @lc app=leetcode.cn id=189 lang=swift + * + * [189] 旋转数组 + * + * https://leetcode-cn.com/problems/rotate-array/description/ + * + * algorithms + * Easy (38.99%) + * Likes: 387 + * Dislikes: 0 + * Total Accepted: 72.7K + * Total Submissions: 186.3K + * Testcase Example: '[1,2,3,4,5,6,7]\n3' + * + * 给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数。 + * + * 示例 1: + * + * 输入: [1,2,3,4,5,6,7] 和 k = 3 + * 输出: [5,6,7,1,2,3,4] + * 解释: + * 向右旋转 1 步: [7,1,2,3,4,5,6] + * 向右旋转 2 步: [6,7,1,2,3,4,5] + * 向右旋转 3 步: [5,6,7,1,2,3,4] + * + * + * 示例 2: + * + * 输入: [-1,-100,3,99] 和 k = 2 + * 输出: [3,99,-1,-100] + * 解释: + * 向右旋转 1 步: [99,-1,-100,3] + * 向右旋转 2 步: [3,99,-1,-100] + * + * 说明: + * + * + * 尽可能想出更多的解决方案,至少有三种不同的方法可以解决这个问题。 + * 要求使用空间复杂度为 O(1) 的 原地 算法。 + * + * + */ + +// @lc code=start +class Solution { + + + /*//环状替换解法 + func rotate(_ nums: inout [Int], _ k: Int) { + + let k = k % nums.count; + var start = 0, count = 0 + + while (count < nums.count) { + + var current = start + var prev = nums[start] + + repeat { + let next = (current + k) % nums.count + let temp = nums[next] + nums[next] = prev + prev = temp + current = next + count += 1 + } while (start != current) + + start += 1 + } + } + */ + + //反转解法 + func rotate(_ nums: inout [Int], _ k: Int) { + let k = k % nums.count + guard k != 0 else { + return + } + reverse(&nums, 0, nums.count - 1); + reverse(&nums, 0, k - 1); + reverse(&nums, k, nums.count - 1); + + } + + func reverse(_ nums: inout [Int], _ start: Int, _ end: Int) { + var start = start, end = end + while (start < end) { + let temp = nums[start] + nums[start] = nums[end] + nums[end] = temp + start += 1 + end -= 1 + } + } +} + +// @lc code=end + diff --git a/Week 01/id_176/LeetCode_26_176.swift b/Week 01/id_176/LeetCode_26_176.swift new file mode 100644 index 000000000..fcbcf96a9 --- /dev/null +++ b/Week 01/id_176/LeetCode_26_176.swift @@ -0,0 +1,76 @@ +/* + * @lc app=leetcode.cn id=26 lang=swift + * + * [26] 删除排序数组中的重复项 + * + * https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array/description/ + * + * algorithms + * Easy (46.83%) + * Likes: 1131 + * Dislikes: 0 + * Total Accepted: 182.4K + * Total Submissions: 389.4K + * Testcase Example: '[1,1,2]' + * + * 给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。 + * + * 不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。 + * + * 示例 1: + * + * 给定数组 nums = [1,1,2], + * + * 函数应该返回新的长度 2, 并且原数组 nums 的前两个元素被修改为 1, 2。 + * + * 你不需要考虑数组中超出新长度后面的元素。 + * + * 示例 2: + * + * 给定 nums = [0,0,1,1,1,2,2,3,3,4], + * + * 函数应该返回新的长度 5, 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4。 + * + * 你不需要考虑数组中超出新长度后面的元素。 + * + * + * 说明: + * + * 为什么返回数值是整数,但输出的答案是数组呢? + * + * 请注意,输入数组是以“引用”方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。 + * + * 你可以想象内部操作如下: + * + * // nums 是以“引用”方式传递的。也就是说,不对实参做任何拷贝 + * int len = removeDuplicates(nums); + * + * // 在函数里修改输入数组对于调用者是可见的。 + * // 根据你的函数返回的长度, 它会打印出数组中该长度范围内的所有元素。 + * for (int i = 0; i < len; i++) { + * print(nums[i]); + * } + * + * + */ + +// @lc code=start +class Solution { + func removeDuplicates(_ nums: inout [Int]) -> Int { + if nums.count == 0 { + return 0; + } + + var i = 0, j = 1; + while j < nums.count { + if nums[i] != nums[j] { + i += 1; + nums[i] = nums[j]; + } + j += 1; + } + return i + 1; + } +} +// @lc code=end + diff --git a/Week 01/id_176/NOTE.md b/Week 01/id_176/NOTE.md index a6321d6e2..110e053e5 100644 --- a/Week 01/id_176/NOTE.md +++ b/Week 01/id_176/NOTE.md @@ -1,4 +1,18 @@ -# NOTE +#NOTE - +数组(Array):连续的内存空间,insert、delete O(n) + +单链表(Linked List):next指针,lookup O(n) + +双链表(Double Linked List):previous、next指针,lookup O(n) + +跳表(Skip List):在链表的基础上增加多级索引,lookup O(logn),升维思想 + 空间换时间 + +栈(Stack):Last in - First out + +队列(Queue):First in - First out + +双端队列(Deque):两端都可以添加、删除元素 + +优先级队列(Priority Queue):按照元素的优先级取出 diff --git a/Week 01/id_181/189.rotate-array.js b/Week 01/id_181/189.rotate-array.js new file mode 100644 index 000000000..b462148c4 --- /dev/null +++ b/Week 01/id_181/189.rotate-array.js @@ -0,0 +1,54 @@ +// 给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数。 +// [189. 旋转数组 - 力扣(LeetCode)](https://leetcode-cn.com/problems/rotate-array/) + +/** + * @param {number[]} nums + * @param {number} k + * @return {void} Do not return anything, modify nums in-place instead. + + */ +// 暴力解法 +var rotate = function(nums, k) { + var len = nums.length; + var temp,previous; + var realOffset = k % len; + for(var i = 0;i 优先级队列的元素按照其自然顺序进行排序,或者根据构造队列时提供的 Comparator 进行排序 +> PriorityQueue 是一个无界队列,但是初始的容量(实际是一个Object[]),随着不断向优先级队列添加元素,其容量会自动扩容,无需指定容量增加策略的细节。 \ No newline at end of file diff --git a/Week 01/id_196/LeetCode_189_196.py b/Week 01/id_196/LeetCode_189_196.py new file mode 100644 index 000000000..29cd4c0a5 --- /dev/null +++ b/Week 01/id_196/LeetCode_189_196.py @@ -0,0 +1,22 @@ +class Solution: + def rotate(self, nums: List[int], k: int) -> None: + """ + Do not return anything, modify nums in-place instead. + """ + n = len(nums) + k %= n + if k == 0:return + start = 0 + tmp = nums[start] + cnt = 0 + while cnt < n: + nxt = (start + k) % n + while nxt != start: + nums[nxt], tmp = tmp, nums[nxt] + nxt = (nxt+k) % n + cnt += 1 + nums[nxt] = tmp + start += 1 + tmp = nums[start] + cnt += 1 + diff --git a/Week 01/id_196/LeetCode_26_196.py b/Week 01/id_196/LeetCode_26_196.py new file mode 100644 index 000000000..a5b433d5a --- /dev/null +++ b/Week 01/id_196/LeetCode_26_196.py @@ -0,0 +1,10 @@ +class Solution: + def removeDuplicates(self, nums: [int]) -> int: + if not nums: return 0 + k = 1 + for i in range(1, len(nums)): + if nums[i] != nums[i - 1]: + nums[k] = nums[i] + k += 1 + return k + diff --git a/Week 01/id_201/leetcode_1_twoSum b/Week 01/id_201/leetcode_1_twoSum new file mode 100644 index 000000000..c4f6ffe0b --- /dev/null +++ b/Week 01/id_201/leetcode_1_twoSum @@ -0,0 +1,80 @@ +//给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。 +// +// 你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。 +// +// 示例: +// +// 给定 nums = [2, 7, 11, 15], target = 9 +// +//因为 nums[0] + nums[1] = 2 + 7 = 9 +//所以返回 [0, 1] +// +// Related Topics 数组 哈希表 + + +import java.sql.Array; +import java.util.Arrays; +import java.util.HashMap; + +//leetcode submit region begin(Prohibit modification and deletion) +class Solution { + /** + * use hashMap O(n) // or use array int[target] instead use hashMap if target is small + * @param nums + * @param target + * @return + */ + public int[] twoSum(int[] nums, int target) { + int diffNum; + HashMap numKeyValue = new HashMap(); + for ( int i = 0; i < nums.length; i++ ) { + if ( numKeyValue.get(nums[i]) != null) { + return new int[]{numKeyValue.get(nums[i]), i}; + } + numKeyValue.put(target - nums[i], i); + } + return new int[2]; + } + + /** + * o(n^2) + * @param nums + * @param target + * @return + */ + public int[] twoSum1(int[] nums, int target) { + for (int i = 0; i < nums.length - 1; i++ ) { + for (int j = i + 1; j < nums.length; j ++) { + if (nums[i] + nums[j] == target) { + return new int[]{i, j}; + } + } + } + return new int[2]; + } + + /** + * use two pointer (left/ right) in sorted array 假设每种输入只会对应一个答案 + * lose old index (changed index) + * @param nums + * @param target + * @return + */ + /*public int[] twoSum2(int[] nums, int target) { + int left = 0, right = nums.length - 1, sum; + int[] numsCopy = Arrays.copyOf(nums, nums.length); + Arrays.sort(numsCopy); + while (left < right) { + sum = nums[left] + nums[right]; + if (sum > target) { + right--; + } elseif (sum < target) { + left++; + } else { + return new int[]{left, right}; + } + } + return new int[2]; + }*/ +} +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 01/id_201/leetcode_66_plusOne b/Week 01/id_201/leetcode_66_plusOne new file mode 100644 index 000000000..a43d58392 --- /dev/null +++ b/Week 01/id_201/leetcode_66_plusOne @@ -0,0 +1,64 @@ +//给定一个由整数组成的非空数组所表示的非负整数,在该数的基础上加一。 +// +// 最高位数字存放在数组的首位, 数组中每个元素只存储单个数字。 +// +// 你可以假设除了整数 0 之外,这个整数不会以零开头。 +// +// 示例 1: +// +// 输入: [1,2,3] +//输出: [1,2,4] +//解释: 输入数组表示数字 123。 +// +// +// 示例 2: +// +// 输入: [4,3,2,1] +//输出: [4,3,2,2] +//解释: 输入数组表示数字 4321。 +// +// Related Topics 数组 + + + +//leetcode submit region begin(Prohibit modification and deletion) +class Solution { + public int[] plusOne(int[] digits) { + int j = digits.length, + length = j; + while (j > 0) { + if ( 9 > digits[j - 1]) + break; + j--; + } + if ( 0 == j ) { + int[] result = new int[++length]; + result[0] = 1; + return result; + } else { + digits[j - 1] = digits[j - 1] + 1; + while (j < length) { + digits[j++] = 0; + } + return digits; + } + } + + public int[] plusOne1(int[] digits) { + for (int i = digits.length; i > 0; ) { + if (9 == digits[--i]) { + continue; + } + digits[i]++; + return digits; + } + int[] result = new int[digits.length + 1]; + result[0] = 1; + return result; + } + + public int[] plusOne2(int[] digits) { + + } +} +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 01/id_201/leetcode_88_merge_array b/Week 01/id_201/leetcode_88_merge_array new file mode 100644 index 000000000..54ca97e41 --- /dev/null +++ b/Week 01/id_201/leetcode_88_merge_array @@ -0,0 +1,37 @@ +//给定两个有序整数数组 nums1 和 nums2,将 nums2 合并到 nums1 中,使得 num1 成为一个有序数组。 +// +// 说明: +// +// +// 初始化 nums1 和 nums2 的元素数量分别为 m 和 n。 +// 你可以假设 nums1 有足够的空间(空间大小大于或等于 m + n)来保存 nums2 中的元素。 +// +// +// 示例: +// +// 输入: +//nums1 = [1,2,3,0,0,0], m = 3 +//nums2 = [2,5,6], n = 3 +// +//输出: [1,2,2,3,5,6] +// Related Topics 数组 双指针 + + + +//leetcode submit region begin(Prohibit modification and deletion) +class Solution { + public void merge(int[] nums1, int m, int[] nums2, int n) { + if (p2 < 0) + break; + if (p1 < 0) { + System.arraycopy(nums2, 0, nums1, 0, p2 + 1); + break; + } + if (nums1[p1] >= nums2[p2]) { + nums1[i] = nums1[p1--]; + } else { + nums1[i] = nums2[p2--]; + } + } +} +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 01/id_211/LeedCode_1_211.cpp b/Week 01/id_211/LeedCode_1_211.cpp new file mode 100644 index 000000000..2eb6d2a39 --- /dev/null +++ b/Week 01/id_211/LeedCode_1_211.cpp @@ -0,0 +1,17 @@ +class Solution { +public: + vector twoSum(vector& nums, int target) { + std::unordered_map mp; + + for (int i = 0; i < nums.size(); ++i) { + int diff = target - nums[i]; + if (mp.count(diff) == 1) { + return std::vector({mp[diff], i}); + } + + mp[nums[i]] = i; + } + + return vector({-1, -1}); + } +}; diff --git a/Week 01/id_211/LeedCode_21_211.cpp b/Week 01/id_211/LeedCode_21_211.cpp new file mode 100644 index 000000000..4bbce07b5 --- /dev/null +++ b/Week 01/id_211/LeedCode_21_211.cpp @@ -0,0 +1,56 @@ +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode(int x) : val(x), next(NULL) {} + * }; + */ +class Solution { +public: + ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) { + if (!l1 && l2) + return l2; + if (!l2 && l1) + return l1; + + if (!l1 && !l2) + return nullptr; + + ListNode *lc, *tail, *p1, *p2; + lc = tail = l1; + p1 = l1; + p2 = l2; + + if (p1->val > p2->val) { + lc = tail = p2; + p2 = p2->next; + } else { + p1 = p1->next; + } + + while (p1 != nullptr && p2 != nullptr) { + if (p1->val > p2->val) { + tail->next = p2; + tail = p2; + p2 = p2->next; + } else { + tail->next = p1; + tail = p1; + p1 = p1->next; + } + } + + if (p1 == nullptr) { + tail->next = p2; + tail = p2; + } + + if (p2 == nullptr) { + tail->next = p1; + tail = p1; + } + + return lc; + } +}; diff --git a/Week 01/id_216/Week01.java b/Week 01/id_216/Week01.java new file mode 100644 index 000000000..df7442945 --- /dev/null +++ b/Week 01/id_216/Week01.java @@ -0,0 +1,81 @@ +import java.util.Stack; + +/** + * Created by liuyp on 2019/10/16. + */ +public class Week01 { + + public Week01() { + } + + //旋转数组 + public void rotate(int[] nums, int k) { + + int base = 0; + int temp = 0; + + for (int j = 0; j < k; j++) { + base = nums[nums.length - 1]; + for (int i = 0; i < nums.length; i++) { + temp = nums[i]; + nums[i] = base; + base = temp; +// System.out.println(nums.toString()); + } + } +// System.out.println(nums); + } + + public void rotate0(int[] nums, int k) { + k = k % nums.length; + + int cnt = 0; + for (int i = 0; cnt < nums.length; i++) { + + int cur = 0; + int target = 0; + int base = nums[i]; + int copy = 0; + do { + target = (cur + k) % nums.length; + copy = nums[target]; + nums[target] = base; + base = copy; + cnt = cnt + 1; + cur = target; + } while (i != cur); + + } + } + + //接雨水 + public int trap(int[] height) { + int res = 0; + Stack stack = new Stack(); + int index = 0; + + while (index < height.length) { + while (stack.size() > 0 && height[index] > height[stack.peek()]) { + int top = stack.pop(); + if (stack.empty()) { + break; + } + int h = Math.min(height[index], height[stack.peek()]) - height[top]; + System.out.println("h====" + h); + int d = index - stack.peek() - 1; + System.out.println("d====" + d); + System.out.println("------------------------------------"); + + res = res + h * d; + } + stack.push(index++); + } + return res; + } + + + public static void main(String[] args) { + } + +} + diff --git a/Week 01/id_226/leetCode_226.py b/Week 01/id_226/leetCode_226.py new file mode 100644 index 000000000..dd61ef173 --- /dev/null +++ b/Week 01/id_226/leetCode_226.py @@ -0,0 +1,15 @@ +class Solution(object): + def moveZeroes(self, nums): + """ + :type nums: List[int] + :rtype: None Do not return anything, modify nums in-place instead. + """ + snowBall = 0 + index = 0 + while index < len(nums): + if nums[index] == 0: + snowBall += 1 + elif snowBall > 0: + nums[index] , nums[index - snowBall] = nums[index - snowBall],nums[index] + index += 1 + diff --git a/Week 01/id_226/leetCode_88_226.py b/Week 01/id_226/leetCode_88_226.py new file mode 100644 index 000000000..bc1597de8 --- /dev/null +++ b/Week 01/id_226/leetCode_88_226.py @@ -0,0 +1,24 @@ +class Solution(object): + def merge(self, nums1, m, nums2, n): + """ + :type nums1: List[int] + :type m: int + :type nums2: List[int] + :type n: int + :rtype: None Do not return anything, modify nums1 in-place instead. + """ + if m == 0: + nums1[:] = nums2 + tail1 = m - 1 + tail2 = n - 1 + tail = m + n -1 + while tail1 >= 0 and tail2 >=0: + if nums1[tail1] < nums2[tail2]: + nums1[tail] = nums2[tail2] + tail2 -= 1 + else: + nums1[tail] = nums1[tail1] + tail1 -= 1 + tail -= 1 + if tail2 >= 0: + nums1[:tail2 + 1] = nums2[:tail2 + 1] diff --git a/Week 01/id_236/LeetCode_1_236.go b/Week 01/id_236/LeetCode_1_236.go new file mode 100644 index 000000000..668cc223f --- /dev/null +++ b/Week 01/id_236/LeetCode_1_236.go @@ -0,0 +1,39 @@ +package main + +import "fmt" + +// Solution 1: Brute-Force +// Use two loops to search the right pair. +// Time Complexity : O(n^2) +// Space Complexity: O(1) + +// Solution 2: Sort and Search +// Sort the copied nums[O(NlogN)], and use two pointers start/end to search the pair[O(N)]. +// And search the indices in the original array. +// Time Complexity : O(NlogN) +// Space Complexity: O(N) + +// Solution 3: Hash Record +// Use hash map to record number and index in iterating the nums to finding the pair. +// Time Complexity : O(N) +// Space Complexity: O(N) +func twoSum(nums []int, target int) []int { + // num index + m := make(map[int]int) + + for i, num := range nums { + j, exists := m[target-num] + + if exists { + return []int{i, j} + } + + m[num] = i + } + + return nil +} + +func main() { + fmt.Println(twoSum([]int{2, 7, 11, 15}, 9)) +} diff --git a/Week 01/id_236/LeetCode_21_236.go b/Week 01/id_236/LeetCode_21_236.go new file mode 100644 index 000000000..45c679f45 --- /dev/null +++ b/Week 01/id_236/LeetCode_21_236.go @@ -0,0 +1,103 @@ +package main + +import ( + "fmt" + "strings" +) + +// Solution 1: Recursive Assignment. +// The code is much cleaner but not recommended in production code, +// which will cause stack overflow if the list is too long. +// Time Complexity : O(M+N) +// Space Complexity: O(1) +func mergeTwoListsRecursion(l1 *ListNode, l2 *ListNode) *ListNode { + if l1 == nil { + return l2 + } + if l2 == nil { + return l1 + } + + if l1.Val < l2.Val { + l1.Next = mergeTwoListsRecursion(l1.Next, l2) + return l1 + } else { + l2.Next = mergeTwoListsRecursion(l1, l2.Next) + return l2 + } +} + +// Solution 2: Interative Loop. +// Use a dummy node to simplify the interactive loop. +// Time Complexity : O(M+N) +// Space Complexity: O(1) +func mergeTwoLists(l1 *ListNode, l2 *ListNode) *ListNode { + dummy := &ListNode{} + curr := dummy + + for l1 != nil && l2 != nil { + if l1.Val < l2.Val { + curr.Next = l1 + l1 = l1.Next + } else { + curr.Next = l2 + l2 = l2.Next + } + + curr = curr.Next + } + + if l1 == nil { + curr.Next = l2 + } else { + curr.Next = l1 + } + + return dummy.Next +} + +type ListNode struct { + Val int + Next *ListNode +} + +func (l *ListNode) String() string { + if l == nil { + return "" + } + + var b strings.Builder + if l != nil { + b.WriteString(fmt.Sprintf("%d", l.Val)) + } + + for node := l.Next; node != nil; node = node.Next { + b.WriteString(fmt.Sprintf("->%d", node.Val)) + } + + return b.String() +} + +func main() { + l1 := &ListNode{ + Val: 1, + Next: &ListNode{ + Val: 2, + Next: &ListNode{ + Val: 4, + }, + }, + } + + l2 := &ListNode{ + Val: 1, + Next: &ListNode{ + Val: 3, + Next: &ListNode{ + Val: 4, + }, + }, + } + + fmt.Println(mergeTwoLists(l1, l2)) +} diff --git a/Week 01/id_251/LeetCode_11_251.py b/Week 01/id_251/LeetCode_11_251.py new file mode 100644 index 000000000..8f2ee311a --- /dev/null +++ b/Week 01/id_251/LeetCode_11_251.py @@ -0,0 +1,48 @@ +# 给定 n 个非负整数 a1,a2,...,an,每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0)。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。 +# +# 说明:你不能倾斜容器,且 n 的值至少为 2。 +# +# +# +# 图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。 +# +# +# +# 示例: +# +# 输入: [1,8,6,2,5,4,8,3,7] +# 输出: 49 +# Related Topics 数组 双指针 + +""" +1 暴力法 +2 双指针前后逼近 +""" + + +# leetcode submit region begin(Prohibit modification and deletion) +class Solution(object): + def maxArea(self, height): + """ + :type height: List[int] + :rtype: int + """ + + def force_max_area(self, height): + max_area = 0 + for i in range(len(height) - 1): + for j in range(i + 1, len(height)): + max_area = max(max_area, min(height[i], height[j]) * (j - i)) + return max_area + + def index_max_area(self, height): + max_area, l, r = 0, 0, len(height) - 1 + while l < r: + max_area = max(max_area, min(height[l], height[r]) * (r - l)) + if height[l] < height[r]: + l += 1 + else: + r -= 1 + return max_area + +# leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 01/id_251/LeetCode_141_251.py b/Week 01/id_251/LeetCode_141_251.py new file mode 100644 index 000000000..a83ce8a55 --- /dev/null +++ b/Week 01/id_251/LeetCode_141_251.py @@ -0,0 +1,82 @@ +# 给定一个链表,判断链表中是否有环。 +# +# 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。 +# +# +# +# 示例 1: +# +# 输入:head = [3,2,0,-4], pos = 1 +# 输出:true +# 解释:链表中有一个环,其尾部连接到第二个节点。 +# +# +# +# +# 示例 2: +# +# 输入:head = [1,2], pos = 0 +# 输出:true +# 解释:链表中有一个环,其尾部连接到第一个节点。 +# +# +# +# +# 示例 3: +# +# 输入:head = [1], pos = -1 +# 输出:false +# 解释:链表中没有环。 +# +# +# +# +# +# +# 进阶: +# +# 你能用 O(1)(即,常量)内存解决此问题吗? +# Related Topics 链表 双指针 + + +# leetcode submit region begin(Prohibit modification and deletion) +# Definition for singly-linked list. +# class ListNode(object): +# def __init__(self, x): +# self.val = x +# self.next = None + +""" +提示不要看官方这个head 等于一个list 的举例,严重误导人,看图就行了。 +# 输入:head = [1,2], pos = 0 +# 输出:true +1 哈希表 +2 快慢指针法 很巧妙 记住就行 +""" + + +class Solution(object): + def hasCycle(self, head): + """ + :type head: ListNode + :rtype: bool + """ + hash_set = set() + while head: + if head in hash_set: + return True + hash_set.add(head) + head = head.next + return False + + # 快慢指针法 + def hasCycleSlowFastIndex(self, head): + slow = fast = head + while fast and fast.next: + slow = slow.next + fast = fast.next.next + if slow == fast: + return True + return False + +# leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 01/id_251/LeetCode_155_251.py b/Week 01/id_251/LeetCode_155_251.py new file mode 100644 index 000000000..95b6fd164 --- /dev/null +++ b/Week 01/id_251/LeetCode_155_251.py @@ -0,0 +1,179 @@ +# 设计一个支持 push,pop,top 操作,并能在常数时间内检索到最小元素的栈。 +# +# +# push(x) -- 将元素 x 推入栈中。 +# pop() -- 删除栈顶的元素。 +# top() -- 获取栈顶元素。 +# getMin() -- 检索栈中的最小元素。 +# +# +# 示例: +# +# MinStack minStack = new MinStack(); +# minStack.push(-2); +# minStack.push(0); +# minStack.push(-3); +# minStack.getMin(); --> 返回 -3. +# minStack.pop(); +# minStack.top(); --> 返回 0. +# minStack.getMin(); --> 返回 -2. +# +# Related Topics 栈 设计 + +""" +方法一:辅助栈和数据栈同步 +方法二:辅助栈和数据栈不同步 +2 二元组同步栈 +""" + + +# leetcode submit region begin(Prohibit modification and deletion) +class MinStack(object): + """ + # 辅助栈和数据栈同步 + # 思路简单不容易出错 + """ + + def __init__(self): + """ + initialize your data structure here. + """ + # 数据栈 + self.data = [] + # 辅助栈 + self.helper = [] + + def push(self, x): + """ + :type x: int + :rtype: None + """ + self.data.append(x) + if len(self.helper) == 0 or x <= self.helper[-1]: + self.helper.append(x) + else: + self.helper.append(self.helper[-1]) + + def pop(self): + """ + :rtype: None + """ + if self.data: + del self.helper[-1] + return self.data.pop() + + def top(self): + """ + :rtype: int + """ + if self.data: + return self.data[-1] + + def getMin(self): + """ + :rtype: int + """ + if self.helper: + return self.helper[-1] + + +class MinStackNoSync(object): + """ + # 辅助栈和数据栈不同步 + # 关键 1:辅助栈的元素空的时候,必须放入新进来的数 + # 关键 2:新来的数小于或者等于辅助栈栈顶元素的时候,才放入(特别注意这里等于要考虑进去) + # 关键 3:出栈的时候,辅助栈的栈顶元素等于数据栈的栈顶元素,才出栈,即"出栈保持同步"就可以了 + """ + + def __init__(self): + """ + initialize your data structure here. + """ + # 数据栈 + self.data = [] + # 辅助栈 + self.helper = [] + + def push(self, x): + """ + :type x: int + :rtype: None + """ + self.data.append(x) + # 关键1 和 关键2 + if len(self.helper) == 0 or x <= self.helper[-1]: + self.helper.append(x) + + def pop(self): + """ + :rtype: None + """ + if self.data: + if self.data[-1] == self.helper[-1]: + del self.helper[-1] + return self.data.pop() + + def top(self): + """ + :rtype: int + """ + if self.data: + return self.data[-1] + + def getMin(self): + """ + :rtype: int + """ + if self.helper: + return self.helper[-1] + + +class MinStackTuple(object): + def __init__(self): + self.stack = [] + + def push(self, x): + if self.stack: + self.stack.append((x, min(x, self.stack[-1][1]))) + else: + self.stack.append((x, x)) + + def pop(self): + if self.stack: + del self.stack[-1] + + def top(self): + if self.stack: + return self.stack[-1][0] + + def getMin(self): + if self.stack: + return self.stack[-1][1] + + +# 方法3 升级 +class MinStack4(object): + def __init__(self): + self.data = [(None, float('inf'))] + + def push(self, x): + self.data.append((x, min(x, self.data[-1][1]))) + + def pop(self): + if len(self.data) > 1: + self.data.pop() + # del self.data[-1] + + def top(self): + return self.data[-1][0] + + def getMin(self): + return self.data[-1][1] + +# Your MinStack object will be instantiated and called as such: +# obj = MinStack() +# obj.push(x) +# obj.pop() +# param_3 = obj.top() +# param_4 = obj.getMin() +# leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 01/id_251/LeetCode_15_251.py b/Week 01/id_251/LeetCode_15_251.py new file mode 100644 index 000000000..f26b1782f --- /dev/null +++ b/Week 01/id_251/LeetCode_15_251.py @@ -0,0 +1,81 @@ +# 给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组。 +# +# 注意:答案中不可以包含重复的三元组。 +# +# 例如, 给定数组 nums = [-1, 0, 1, 2, -1, -4], +# +# 满足要求的三元组集合为: +# [ +# [-1, 0, 1], +# [-1, -1, 2] +# ] +# +# Related Topics 数组 双指针 + +""" +1 暴力解法 三层循环 O(n^3) +2 排序 + 双指针 +3 排序 hash 转换为两数之和问题 +""" + + +# leetcode submit region begin(Prohibit modification and deletion) +class Solution(object): + def threeSum(self, nums): + """ + :type nums: List[int] + :rtype: List[List[int]] + """ + + def force_three_sum(self, nums): + nums.sort() + res = set() + for i in range(len(nums) - 2): + for j in range(i + 1, len(nums) - 1): + for k in range(j + 1, len(nums)): + if nums[i] + nums[j] + nums[k] == 0: + res.add((nums[i], nums[j], nums[k])) + return list(map(list, res)) + + def sort_towIndex_three_sum(self, nums): + nums.sort() + res = [] + for k in range(len(nums) - 2): + if nums[k] > 0: break # 因为 nums[r] > nums[l] > nums[k] + if k > 0 and nums[k] == nums[k - 1]: continue # skip 重复项 + + l, r = k + 1, len(nums) - 1 + while l < r: + s = nums[k] + nums[l] + nums[r] + if s < 0: + while l < r and nums[l] == nums[l + 1]: l += 1 # skip 重复项 + l += 1 + elif s > 0: + while l < r and nums[r] == nums[r - 1]: r -= 1 # skip 重复项 + r -= 1 + else: + res.append([nums[k], nums[l], nums[r]]) + while l < r and nums[l] == nums[l + 1]: l += 1 # skip 重复项 + while l < r and nums[r] == nums[r - 1]: r -= 1 # skip 重复项 + l += 1 + r -= 1 + return res + + def hash_three_sum(self, nums): + if len(nums) < 3: + return [] + + nums.sort() + res = set() + for i, v in enumerate(nums[:-2]): + if v > 0: break + if i > 0 and v == nums[i - 1]: continue # skip 重复项 + + vist = {} + for x in nums[i + 1:]: + if x not in vist: + vist[-v - x] = 1 + else: + res.add((v, -v - x, x)) + return list(map(list, res)) +# leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 01/id_251/LeetCode_189_251.py b/Week 01/id_251/LeetCode_189_251.py new file mode 100755 index 000000000..42d4229a7 --- /dev/null +++ b/Week 01/id_251/LeetCode_189_251.py @@ -0,0 +1,119 @@ +# 给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数。 +# +# 示例 1: +# +# 输入: [1,2,3,4,5,6,7] 和 k = 3 +# 输出: [5,6,7,1,2,3,4] +# 解释: +# 向右旋转 1 步: [7,1,2,3,4,5,6] +# 向右旋转 2 步: [6,7,1,2,3,4,5] +# 向右旋转 3 步: [5,6,7,1,2,3,4] +# +# +# 示例 2: +# +# 输入: [-1,-100,3,99] 和 k = 2 +# 输出: [3,99,-1,-100] +# 解释: +# 向右旋转 1 步: [99,-1,-100,3] +# 向右旋转 2 步: [3,99,-1,-100] +# +# 说明: +# +# +# 尽可能想出更多的解决方案,至少有三种不同的方法可以解决这个问题。 +# 要求使用空间复杂度为 O(1) 的 原地 算法。 +# +# Related Topics 数组 + +""" +1 暴力解法 旋转 k 次,每次将数组旋转 1 个元素。 +2 使用额外的数组 +3 环形旋转 +4 三次使用反转 +""" + + +# leetcode submit region begin(Prohibit modification and deletion) +class Solution(object): + def rotate(self, nums, k): + """ + :type nums: List[int] + :type k: int + :rtype: None Do not return anything, modify nums in-place instead. + """ + + # 1 暴力解法 O(n*k) 超时 + def force_rotate(self, nums, k): + k %= len(nums) + for i in range(k): + previous = nums[-1] + for j in range(len(nums)): + previous, nums[j] = nums[j], previous + + # 2 使用额外的数组 时间空间:O(n) + def new_arr_rotate(self, nums, k): + new_list = [None] * len(nums) + k %= len(nums) + for i in range(len(nums)): + new_list[(i + k) % len(nums)] = nums[i] + + for i in range(len(nums)): + nums[i] = new_list[i] + + # nums[:] = new_list 这样赋值也行 + + # 3 环形旋转 ? + def ring_rotation(self, nums, k): + size = len(nums) + k %= size + count = start = 0 # start是当出现循环时最开始的点 + while count < size: + target = start + prev = nums[target] + while True: + target = (target + k) % size + prev, nums[target] = nums[target], prev + count += 1 + if target == start: + break # 次数到了或者出现循环则跳出 + start += 1 + + # 4 三次使用反转 + def three_reverse_rotation(self, nums, k): + k %= len(nums) + """ + self.reverse(nums, 0, len(nums) - 1) + self.reverse(nums, 0, k - 1) + self.reverse(nums, k, len(nums) - 1) + """ + nums[:] = nums[::-1] + nums[:k] = nums[:k][::-1] + nums[k:] = nums[k:][::-1] + + # 反转list + def reverse(self, nums, start, end): + while start < end: + nums[start], nums[end] = nums[end], nums[start] + start += 1 + end -= 1 + + # other 1 Python语言特性解法 性能一般 + def p_rotate(self, nums, k): + k %= len(nums) + for _ in range(k): + nums.insert(0, nums.pop()) + + # other 2 Python语言特性解法 + def p_rotate1(self, nums, k): + k %= len(nums) + nums[:] = nums[-k:] + nums[:-k] + + +# leetcode submit region end(Prohibit modification and deletion) + +if __name__ == '__main__': + s = Solution() + l = [1, 2, 3, 4] + s.reverse(l, 1, 3) + print(l) diff --git a/Week 01/id_251/LeetCode_1_251.py b/Week 01/id_251/LeetCode_1_251.py new file mode 100644 index 000000000..3cefde3c7 --- /dev/null +++ b/Week 01/id_251/LeetCode_1_251.py @@ -0,0 +1,42 @@ +# 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。 +# +# 你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。 +# +# 示例: +# +# 给定 nums = [2, 7, 11, 15], target = 9 +# +# 因为 nums[0] + nums[1] = 2 + 7 = 9 +# 所以返回 [0, 1] +# +# Related Topics 数组 哈希表 + +""" +1 两重循环暴力解法 O(n^2) +2 hash/set 存储 O(n) +""" + + +# leetcode submit region begin(Prohibit modification and deletion) +class Solution(object): + def twoSum(self, nums, target): + """ + :type nums: List[int] + :type target: int + :rtype: List[int] + """ + + def hash_two_sum(self, nums, target): + hash_map = {} + for i, num in enumerate(nums): + if target - num in hash_map: + return [hash_map[target - num], i] + hash_map[num] = i # 这里容易写错 + + def force_two_Sum(self, nums, target): + for i in range(len(nums) - 1): + for j in range(i + 1, len(nums)): + if nums[i] + nums[j] == target: + return [i, j] + +# leetcode submit region end(Prohibit modification and deletion) diff --git "a/Week 01/id_251/LeetCode_206. \345\217\215\350\275\254\351\223\276\350\241\250\350\277\207\347\250\213\345\233\276\350\247\243.jpeg" "b/Week 01/id_251/LeetCode_206. \345\217\215\350\275\254\351\223\276\350\241\250\350\277\207\347\250\213\345\233\276\350\247\243.jpeg" new file mode 100644 index 000000000..60cf75286 Binary files /dev/null and "b/Week 01/id_251/LeetCode_206. \345\217\215\350\275\254\351\223\276\350\241\250\350\277\207\347\250\213\345\233\276\350\247\243.jpeg" differ diff --git a/Week 01/id_251/LeetCode_206_251.py b/Week 01/id_251/LeetCode_206_251.py new file mode 100644 index 000000000..e8a2d578c --- /dev/null +++ b/Week 01/id_251/LeetCode_206_251.py @@ -0,0 +1,54 @@ +# 反转一个单链表。 +# +# 示例: +# +# 输入: 1->2->3->4->5->NULL +# 输出: 5->4->3->2->1->NULL +# +# 进阶: +# 你可以迭代或递归地反转链表。你能否用两种方法解决这道题? +# Related Topics 链表 + + +# leetcode submit region begin(Prohibit modification and deletion) +# Definition for singly-linked list. +# class ListNode(object): +# def __init__(self, x): +# self.val = x +# self.next = None +""" +1 迭代 +2 递归 + # 参考资料: https://www.cnblogs.com/kubixuesheng/p/4394509.html + (1) 结束条件:已经反转的链表为空或者链表中只有一个元素 head = None or head.next = None + (2) 递推公式:只要画一下第一层就行head + ! 先反转后面的链表,走到链表的末端结点 new_pre = f(head.next), + !! 再将当前节点设置为后面节点的后续节点 head.next.next = head; head.next = None +""" + + +class Solution(object): + def reverseList(self, head): + """ + :type head: ListNode + :rtype: ListNode + """ + pre, curr = None, head + while curr: + curr.next, pre, curr = pre, curr, curr.next + return pre + # 或者 + # head = pre + # return head + + def reverseList1(self, head): + # 已经反转的链表为空或者链表中只有一个元素 + if head is None or head.next is None: + return head + # 先反转后面的链表,走到链表的末端结点 + new_pre = self.reverseList1(head.next) + # 再将当前节点设置为后面节点的后续节点 + head.next.next = head # 防止出现环 + head.next = None # 防止出现环 + return new_pre # 走到链表的末端结点 +# leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 01/id_251/LeetCode_20_251.py b/Week 01/id_251/LeetCode_20_251.py new file mode 100644 index 000000000..abacbb0fb --- /dev/null +++ b/Week 01/id_251/LeetCode_20_251.py @@ -0,0 +1,113 @@ +# 给定一个只包括 '(',')','{','}','[',']' 的字符串,判断字符串是否有效。 +# +# 有效字符串需满足: +# +# +# 左括号必须用相同类型的右括号闭合。 +# 左括号必须以正确的顺序闭合。 +# +# +# 注意空字符串可被认为是有效字符串。 +# +# 示例 1: +# +# 输入: "()" +# 输出: true +# +# +# 示例 2: +# +# 输入: "()[]{}" +# 输出: true +# +# +# 示例 3: +# +# 输入: "(]" +# 输出: false +# +# +# 示例 4: +# +# 输入: "([)]" +# 输出: false +# +# +# 示例 5: +# +# 输入: "{[]}" +# 输出: true +# Related Topics 栈 字符串 + +""" +1 replace 替换解法 +2 stack解法 +""" + + +# leetcode submit region begin(Prohibit modification and deletion) +class Solution(object): + def isValid(self, s): + """ + :type s: str + :rtype: bool + """ + + def isValid1(self, s): + if len(s) & 1 == 1: # 位运算判断奇偶 + return False + + while len(s): + tmp = s + s = s.replace('[]', '').replace('()', '').replace('{}', '') + if s == tmp: + return False + return True + + # LeetCode中文官方题解不推荐 + def isValid2(self, s): + if len(s) & 1 == 1: # 位运算判断奇偶 + return False + + stack = [] + hash_map = {')': '(', ']': '[', '}': '{'} + for char in s: + if char in hash_map: + top_element = stack.pop() if stack else '#' + if hash_map[char] != top_element: + return False + else: + stack.append(char) + return not stack + + # 栈方法 正向思维 推荐 + def isValid3(self, s): + if len(s) & 1 == 1: # 位运算判断奇偶 + return False + + stack = [] + hash_map = {'(': ')', '[': ']', '{': '}'} + for c in s: + if c in hash_map: + stack.append(c) + continue + elif stack and hash_map[stack[-1]] == c: + del stack[-1] + else: + return False + return not stack + + # 栈方法 + def isValid3_1(self, s): + if len(s) & 1 == 1: # 位运算判断奇偶 + return False + + stack = ['#'] + hash_map = {'(': ')', '[': ']', '{': '}', '#': '#'} + for c in s: + if c in hash_map: + stack.append(c) + elif hash_map[stack.pop()] != c: + return False + return len(stack) == 1 +# leetcode submit region end(Prohibit modification and deletion) diff --git "a/Week 01/id_251/LeetCode_24. \344\270\244\344\270\244\344\272\244\346\215\242\351\223\276\350\241\250\344\270\255\347\232\204\350\212\202\347\202\271\350\277\255\344\273\243\346\263\225\345\233\276\350\247\243.jpeg" "b/Week 01/id_251/LeetCode_24. \344\270\244\344\270\244\344\272\244\346\215\242\351\223\276\350\241\250\344\270\255\347\232\204\350\212\202\347\202\271\350\277\255\344\273\243\346\263\225\345\233\276\350\247\243.jpeg" new file mode 100644 index 000000000..312ae1966 Binary files /dev/null and "b/Week 01/id_251/LeetCode_24. \344\270\244\344\270\244\344\272\244\346\215\242\351\223\276\350\241\250\344\270\255\347\232\204\350\212\202\347\202\271\350\277\255\344\273\243\346\263\225\345\233\276\350\247\243.jpeg" differ diff --git a/Week 01/id_251/LeetCode_24_251.py b/Week 01/id_251/LeetCode_24_251.py new file mode 100644 index 000000000..3b573819e --- /dev/null +++ b/Week 01/id_251/LeetCode_24_251.py @@ -0,0 +1,69 @@ +# 给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。 +# +# 你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。 +# +# +# +# 示例: +# +# 给定 1->2->3->4, 你应该返回 2->1->4->3. +# +# Related Topics 链表 + + +# leetcode submit region begin(Prohibit modification and deletion) +# Definition for singly-linked list. +class ListNode(object): + def __init__(self, x): + self.val = x + self.next = None + + +""" +1 迭代法 pre --> a --> b --> b.next to pre --> b --> a --> b.next 同时修改,然后pre 移到 a +2 递归 + (1) 结束条件:后面已经反转的链表为空或者链表中只有一个元素 head = None or head.next = None + (2) second = head.next 递推公式:head --> second --> f(second.next) to second --> head --> (second.next) + ! head.next = f(second.next) # 调转完新的第二个结点,指向后面已经反转完的头结点 + !! second.next = head # 调转 + :return second # 返回新头结点 +""" + + +class Solution(object): + # 1 迭代法 + def swapPairs(self, head): + """ + :type head: ListNode + :rtype: ListNode + """ + pre, pre.next = self, head + while pre.next and pre.next.next: + a = pre.next + b = a.next + pre.next, b.next, a.next = b, a, b.next + pre = a + return self.next + + # 好理解 + def swapPairs1(self, head): + dummy = pre = ListNode(0) + pre.next = head + while pre.next and pre.next.next: + a = pre.next + b = a.next + pre.next, b.next, a.next = b, a, b.next + pre = a + return dummy.next + + # 2 递归 + def swapPairs2(self, head): + if not head or not head.next: + return head + second = head.next + # head --> second --> f(second.next) to second --> head --> f(second.next) + head.next = self.swapPairs2(second.next) + second.next = head + return second + +# leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 01/id_251/LeetCode_26_251.py b/Week 01/id_251/LeetCode_26_251.py new file mode 100644 index 000000000..517a80191 --- /dev/null +++ b/Week 01/id_251/LeetCode_26_251.py @@ -0,0 +1,81 @@ +# 给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。 +# +# 不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。 +# +# 示例 1: +# +# 给定数组 nums = [1,1,2], +# +# 函数应该返回新的长度 2, 并且原数组 nums 的前两个元素被修改为 1, 2。 +# +# 你不需要考虑数组中超出新长度后面的元素。 +# +# 示例 2: +# +# 给定 nums = [0,0,1,1,1,2,2,3,3,4], +# +# 函数应该返回新的长度 5, 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4。 +# +# 你不需要考虑数组中超出新长度后面的元素。 +# +# +# 说明: +# +# 为什么返回数值是整数,但输出的答案是数组呢? +# +# 请注意,输入数组是以“引用”方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。 +# +# 你可以想象内部操作如下: +# +# // nums 是以“引用”方式传递的。也就是说,不对实参做任何拷贝 +# int len = removeDuplicates(nums); +# +# // 在函数里修改输入数组对于调用者是可见的。 +# // 根据你的函数返回的长度, 它会打印出数组中该长度范围内的所有元素。 +# for (int i = 0; i < len; i++) { +#     print(nums[i]); +# } +# +# Related Topics 数组 双指针 +""" +和移动零还是稍微有些区别 +1 双指针法 记录非重复元素个数 和移动0 类似 +2 统计重复 的个数 +3 统计非重复 的个数 +""" + + +# leetcode submit region begin(Prohibit modification and deletion) +class Solution(object): + def removeDuplicates(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + + def count_dup(self, nums): + count_dup = 0 + for i in range(1, len(nums)): + if nums[i] == nums[i - 1]: + count_dup += 1 + else: + nums[i - count_dup] = nums[i] + return len(nums) - count_dup + + def two_index(self, nums): + j = 0 + for i in range(len(nums)): + if nums[i] != nums[j]: + j += 1 + nums[j] = nums[i] + return j + 1 + + def count_non_dup(self, nums): + count_ndup = 0 + for i in range(1, len(nums)): + if nums[i] != nums[i - 1]: + count_ndup += 1 + nums[count_ndup] = nums[i] + return count_ndup + 1 + + # leetcode submit region end(Prohibit modification and deletion) diff --git "a/Week 01/id_251/LeetCode_26_\345\277\253\346\205\242\346\214\207\351\222\210\345\233\276\350\247\243.jpg" "b/Week 01/id_251/LeetCode_26_\345\277\253\346\205\242\346\214\207\351\222\210\345\233\276\350\247\243.jpg" new file mode 100644 index 000000000..cc4fb4a3f Binary files /dev/null and "b/Week 01/id_251/LeetCode_26_\345\277\253\346\205\242\346\214\207\351\222\210\345\233\276\350\247\243.jpg" differ diff --git "a/Week 01/id_251/LeetCode_26_\345\277\253\346\205\242\346\214\207\351\222\210\345\233\276\350\247\243\344\270\244\347\247\215\347\211\271\344\276\213\346\203\205\345\206\265.jpg" "b/Week 01/id_251/LeetCode_26_\345\277\253\346\205\242\346\214\207\351\222\210\345\233\276\350\247\243\344\270\244\347\247\215\347\211\271\344\276\213\346\203\205\345\206\265.jpg" new file mode 100644 index 000000000..12d41d044 Binary files /dev/null and "b/Week 01/id_251/LeetCode_26_\345\277\253\346\205\242\346\214\207\351\222\210\345\233\276\350\247\243\344\270\244\347\247\215\347\211\271\344\276\213\346\203\205\345\206\265.jpg" differ diff --git a/Week 01/id_251/LeetCode_283_251.py b/Week 01/id_251/LeetCode_283_251.py new file mode 100644 index 000000000..f1336b0d6 --- /dev/null +++ b/Week 01/id_251/LeetCode_283_251.py @@ -0,0 +1,113 @@ +# 给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。 +# +# 示例: +# +# 输入: [0,1,0,3,12] +# 输出: [1,3,12,0,0] +# +# 说明: +# +# +# 必须在原数组上操作,不能拷贝额外的数组。 +# 尽量减少操作次数。 +# +# Related Topics 数组 双指针 + + +# leetcode submit region begin(Prohibit modification and deletion) +class Solution(object): + """ + # 1 loop 两层循环统计 0 + # 2 一个新数组,遍历非零存入新数组,最后len(old array) - len(new array)个0 + # 3 index 统计非零 + 1 和 3 本质上差别不到,无非就是 一个统计0 一个统计非0 + """ + + def moveZeroes(self, nums): + """ + :type nums: List[int] + :rtype: None Do not return anything, modify nums in-place instead. + """ + # 双指针法优化版本 + # 速度比two_index 好,0越多越明显 + j = 0 + for i in range(len(nums)): + if nums[i] != 0: + nums[j] = nums[i] + if i != j: + nums[i] = 0 + j += 1 + + # 双指针交换版 和 上面优化版复杂度一样 + def swap_index(self, nums): + j = 0 + for i in range(len(nums)): + if nums[i] != 0: + """ + # 减少无用的操作,只有在没有0的情况下才生效,意义不大 + if i != j: + nums[j], nums[i] = nums[i], nums[j] + """ + nums[j], nums[i] = nums[i], nums[j] + j += 1 + + def two_index(self, nums): + # 双指针法好理解的版本 + j = 0 + for i in range(len(nums)): + if nums[i] != 0: + nums[j] = nums[i] + j += 1 + + for i in range(j, len(nums)): + nums[i] = 0 + + # 1 count 0 + def count_zeros(self, nums): + zeros_count = 0 + for i in range(len(nums)): + if nums[i] == 0: + zeros_count += 1 + else: + """ + # 减少无用的赋值操作,只有在没有0的情况下才生效,意义不大 + if i - zeros_count != i: + nums[i - zeros_count] = nums[i] + """ + nums[i - zeros_count] = nums[i] + + for j in range(len(nums) - zeros_count, len(nums)): + nums[j] = 0 + + # 1.2 count 0 改进版 + def count_zeros_(self, nums): + zeros_count = 0 + for i in range(len(nums)): + if nums[i] == 0: + zeros_count += 1 + else: + """ + # 减少无用的赋值操作,只有在没有0的情况下才生效,意义不大 + if i - zeros_count != i: + nums[i - zeros_count], nums[i] = nums[i], nums[i - zeros_count] + """ + nums[i - zeros_count], nums[i] = nums[i], nums[i - zeros_count] + + # 笨方法 LeetCode + def newArray(self, nums): + new_list = [] + for i in nums: + if i != 0: + new_list.append(i) + zeros_count = len(nums) - len(new_list) + if zeros_count: + new_list.extend([0] * zeros_count) + nums[:] = new_list # 不改变指针赋值 + + +# leetcode submit region end(Prohibit modification and deletion) +if __name__ == '__main__': + # 笨方法测试 + s = Solution() + print(s.newArray([0, 1, 0, 3, 12, 0])) + print(s.newArray([0])) diff --git a/Week 01/id_251/LeetCode_641_251.py b/Week 01/id_251/LeetCode_641_251.py new file mode 100644 index 000000000..c07f129ce --- /dev/null +++ b/Week 01/id_251/LeetCode_641_251.py @@ -0,0 +1,330 @@ +# 设计实现双端队列。 +# 你的实现需要支持以下操作: +# +# +# MyCircularDeque(k):构造函数,双端队列的大小为k。 +# insertFront():将一个元素添加到双端队列头部。 如果操作成功返回 true。 +# insertLast():将一个元素添加到双端队列尾部。如果操作成功返回 true。 +# deleteFront():从双端队列头部删除一个元素。 如果操作成功返回 true。 +# deleteLast():从双端队列尾部删除一个元素。如果操作成功返回 true。 +# getFront():从双端队列头部获得一个元素。如果双端队列为空,返回 -1。 +# getRear():获得双端队列的最后一个元素。 如果双端队列为空,返回 -1。 +# isEmpty():检查双端队列是否为空。 +# isFull():检查双端队列是否满了。 +# +# +# 示例: +# +# MyCircularDeque circularDeque = new MycircularDeque(3); // 设置容量大小为3 +# circularDeque.insertLast(1); // 返回 true +# circularDeque.insertLast(2); // 返回 true +# circularDeque.insertFront(3); // 返回 true +# circularDeque.insertFront(4); // 已经满了,返回 false +# circularDeque.getRear(); // 返回 2 +# circularDeque.isFull(); // 返回 true +# circularDeque.deleteLast(); // 返回 true +# circularDeque.insertFront(4); // 返回 true +# circularDeque.getFront(); // 返回 4 +#   +# +# +# +# 提示: +# +# +# 所有值的范围为 [1, 1000] +# 操作次数的范围为 [1, 1000] +# 请不要使用内置的双端队列库。 +# +# Related Topics 设计 队列 + +""" +1、list硬解,简单易懂 +2、环状操作list +""" + + +# leetcode submit region begin(Prohibit modification and deletion) +class MyCircularDequeForceList(object): + + def __init__(self, k): + """ + Initialize your data structure here. Set the size of the deque to be k. + :type k: int + """ + self.k = k + self.q = [] + + def insertFront(self, value): + """ + Adds an item at the front of Deque. Return true if the operation is successful. + :type value: int + :rtype: bool + """ + if self.isFull(): + return False + self.q.insert(0, value) + return True + + def insertLast(self, value): + """ + Adds an item at the rear of Deque. Return true if the operation is successful. + :type value: int + :rtype: bool + """ + if self.isFull(): + return False + self.q.append(value) + return True + + def deleteFront(self): + """ + Deletes an item from the front of Deque. Return true if the operation is successful. + :rtype: bool + """ + if self.isEmpty(): + return False + del self.q[0] + return True + + def deleteLast(self): + """ + Deletes an item from the rear of Deque. Return true if the operation is successful. + :rtype: bool + """ + if self.isEmpty(): + return False + del self.q[-1] + return True + + def getFront(self): + """ + Get the front item from the deque. + :rtype: int + """ + if self.isEmpty(): + return -1 + return self.q[0] + + def getRear(self): + """ + Get the last item from the deque. + :rtype: int + """ + if self.isEmpty(): + return -1 + return self.q[-1] + + def isEmpty(self): + """ + Checks whether the circular deque is empty or not. + :rtype: bool + """ + return len(self.q) == 0 + + def isFull(self): + """ + Checks whether the circular deque is full or not. + :rtype: bool + """ + return len(self.q) == self.k + + +class MyCircularDequeCycleList(object): + + def __init__(self, k): + """ + Initialize your data structure here. Set the size of the deque to be k. + :type k: int + """ + self._size = 0 + self._front, self._rear = 0, 0 + self._capacity = k + self._data = [-1] * k + + def insertFront(self, value): + """ + Adds an item at the front of Deque. Return true if the operation is successful. + :type value: int + :rtype: bool + """ + if self.isFull(): + return False + if self.isEmpty(): + self._data[self._front] = value + else: + self._front = (self._front - 1) % self._capacity + self._data[self._front] = value + self._size += 1 + return True + + def insertLast(self, value): + """ + Adds an item at the rear of Deque. Return true if the operation is successful. + :type value: int + :rtype: bool + """ + if self.isFull(): + return False + if self.isEmpty(): + self._data[self._rear] = value + else: + self._rear = (self._rear + 1) % self._capacity + self._data[self._rear] = value + self._size += 1 + return True + + def deleteFront(self): + """ + Deletes an item from the front of Deque. Return true if the operation is successful. + :rtype: bool + """ + if self.isEmpty(): + return False + self._data[self._front] = -1 + self._front = (self._front + 1) % self._capacity + self._size -= 1 + if self.isEmpty(): + self._rear = self._front + return True + + def deleteLast(self): + """ + Deletes an item from the rear of Deque. Return true if the operation is successful. + :rtype: bool + """ + if self.isEmpty(): + return False + self._data[self._rear] = -1 + self._rear = (self._rear - 1) % self._capacity + self._size -= 1 + if self.isEmpty(): + self._front = self._rear + return True + + def getFront(self): + """ + Get the front item from the deque. + :rtype: int + """ + return self._data[self._front] + + def getRear(self): + """ + Get the last item from the deque. + :rtype: int + """ + return self._data[self._rear] + + def isEmpty(self): + """ + Checks whether the circular deque is empty or not. + :rtype: bool + """ + return self._size == 0 + + def isFull(self): + """ + Checks whether the circular deque is full or not. + :rtype: bool + """ + return self._size == self._capacity + + +# k+1 cycle优化 牺牲一个存储单元 +class MyCircularDeque(object): + + def __init__(self, k): + """ + Initialize your data structure here. Set the size of the deque to be k. + :type k: int + """ + self._size = k + self._front, self._rear = 0, 0 + self._capacity = k + 1 + self._data = [-1] * (k + 1) + + def insertFront(self, value): + """ + Adds an item at the front of Deque. Return true if the operation is successful. + :type value: int + :rtype: bool + """ + if self.isFull(): + return False + self._front = (self._front - 1 + self._capacity) % self._capacity + self._data[self._front] = value + return True + + def insertLast(self, value): + """ + Adds an item at the rear of Deque. Return true if the operation is successful. + :type value: int + :rtype: bool + """ + if self.isFull(): + return False + self._data[self._rear] = value + self._rear = (self._rear + 1) % self._capacity + return True + + def deleteFront(self): + """ + Deletes an item from the front of Deque. Return true if the operation is successful. + :rtype: bool + """ + if self.isEmpty(): + return False + self._data[self._front] = -1 + self._front = (self._front + 1) % self._capacity + return True + + def deleteLast(self): + """ + Deletes an item from the rear of Deque. Return true if the operation is successful. + :rtype: bool + """ + if self.isEmpty(): + return False + self._rear = (self._rear - 1 + self._capacity) % self._capacity + self._data[self._rear] = -1 + return True + + def getFront(self): + """ + Get the front item from the deque. + :rtype: int + """ + return self._data[self._front] + + def getRear(self): + """ + Get the last item from the deque. + :rtype: int + """ + return self._data[(self._rear - 1 + self._capacity) % self._capacity] + + def isEmpty(self): + """ + Checks whether the circular deque is empty or not. + :rtype: bool + """ + return self._front == self._rear + + def isFull(self): + """ + Checks whether the circular deque is full or not. + :rtype: bool + """ + return (self._rear - self._front + self._capacity) % self._capacity == self._size +# Your MyCircularDeque object will be instantiated and called as such: +# obj = MyCircularDeque(k) +# param_1 = obj.insertFront(value) +# param_2 = obj.insertLast(value) +# param_3 = obj.deleteFront() +# param_4 = obj.deleteLast() +# param_5 = obj.getFront() +# param_6 = obj.getRear() +# param_7 = obj.isEmpty() +# param_8 = obj.isFull() +# leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 01/id_251/LeetCode_66_251.py b/Week 01/id_251/LeetCode_66_251.py new file mode 100644 index 000000000..5833e32a3 --- /dev/null +++ b/Week 01/id_251/LeetCode_66_251.py @@ -0,0 +1,56 @@ +# 给定一个由整数组成的非空数组所表示的非负整数,在该数的基础上加一。 +# +# 最高位数字存放在数组的首位, 数组中每个元素只存储单个数字。 +# +# 你可以假设除了整数 0 之外,这个整数不会以零开头。 +# +# 示例 1: +# +# 输入: [1,2,3] +# 输出: [1,2,4] +# 解释: 输入数组表示数字 123。 +# +# +# 示例 2: +# +# 输入: [4,3,2,1] +# 输出: [4,3,2,2] +# 解释: 输入数组表示数字 4321。 +# +# Related Topics 数组 + + +# leetcode submit region begin(Prohibit modification and deletion) +class Solution(object): + def plusOne(self, digits): + """ + :type digits: List[int] + :rtype: List[int] + """ + for i in range(len(digits) - 1, -1, -1): + digits[i] += 1 + digits[i] %= 10 + if digits[i] != 0: + return digits + digits.insert(0, 1) + return digits + + # 最优解法 + def plusOne_(self, digits): + for i in range(len(digits) - 1, -1, -1): + if digits[i] < 9: + digits[i] += 1 + return digits + digits[i] = 0 + digits.insert(0, 1) + return digits + + def tricky(self, digits): + return list(map(int, list(str(int("".join(map(str, digits))) + 1)))) + + +# leetcode submit region end(Prohibit modification and deletion) + +if __name__ == '__main__': + s = Solution() + print(s.tricky([9, 9, 9])) diff --git a/Week 01/id_251/LeetCode_70_251.py b/Week 01/id_251/LeetCode_70_251.py new file mode 100644 index 000000000..22d4f9d36 --- /dev/null +++ b/Week 01/id_251/LeetCode_70_251.py @@ -0,0 +1,75 @@ +# 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 +# +# 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢? +# +# 注意:给定 n 是一个正整数。 +# +# 示例 1: +# +# 输入: 2 +# 输出: 2 +# 解释: 有两种方法可以爬到楼顶。 +# 1. 1 阶 + 1 阶 +# 2. 2 阶 +# +# 示例 2: +# +# 输入: 3 +# 输出: 3 +# 解释: 有三种方法可以爬到楼顶。 +# 1. 1 阶 + 1 阶 + 1 阶 +# 2. 1 阶 + 2 阶 +# 3. 2 阶 + 1 阶 +# +# Related Topics 动态规划 + +""" +1 朴素递归 (1) 递归终止条件 f(1) = 1, f(2) = 2; (2) 递归公式 f(n) = f(n - 1) + f(n - 2) + 时间空间O(2^n) +2 递推公式 时间(1) 空间O(n) +3 递归 + 记忆化 空间时间O(n) +""" + + +# leetcode submit region begin(Prohibit modification and deletion) +class Solution(object): + def climbStairs(self, n): + """ + :type n: int + :rtype: int + """ + + # 1 朴素递归 + def simple_recursion(self, n): + if n == 1: + return 1 + if n == 2: + return 2 + return self.simple_recursion(n - 1) + self.simple_recursion(n - 2) + + # 2 递推 + def iteration(self, n): + if n == 1: + return 1 + first, second = 1, 2 + for _ in range(2, n): + second, first = first + second, second + return second + + # 斐波那契 + def iteration1(self, n): + a, b = 0, 1 + for _ in range(n): + b, a = a + b, b + return b + + # 3 递归 + 记忆化 + def __init__(self): + self.dic = {1: 1, 2: 2} + + def memorization_recursion(self, n): + if n not in self.dic: + self.dic[n] = self.memorization_recursion(n - 1) + self.memorization_recursion(n - 2) + return self.dic[n] + +# leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 01/id_251/LeetCode_84_251.py b/Week 01/id_251/LeetCode_84_251.py new file mode 100644 index 000000000..bf8f969af --- /dev/null +++ b/Week 01/id_251/LeetCode_84_251.py @@ -0,0 +1,103 @@ +# 给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。 +# +# 求在该柱状图中,能够勾勒出来的矩形的最大面积。 +# +# +# +# +# +# 以上是柱状图的示例,其中每个柱子的宽度为 1,给定的高度为 [2,1,5,6,2,3]。 +# +# +# +# +# +# 图中阴影部分为所能勾勒出的最大矩形面积,其面积为 10 个单位。 +# +# +# +# 示例: +# +# 输入: [2,1,5,6,2,3] +# 输出: 10 +# Related Topics 栈 数组 + +""" +1 暴力解法 两重循环 一个取min操作 O(n*3) +2 遍历一遍 左右边界 O(n^2) +3 栈 O(n) +""" + + +# leetcode submit region begin(Prohibit modification and deletion) +class Solution(object): + def largestRectangleArea(self, heights): + """ + :type heights: List[int] + :rtype: int + """ + + def largestRectangleArea1(self, heights): + max_area = 0 + for i in range(len(heights)): + for j in range(i, len(heights)): + min_high = min(heights[i: j + 1]) + max_area = max(max_area, min_high * (j - i + 1)) + return max_area + + # 暴力法优化 O(n^2) + def largestRectangleArea1_1(self, heights): + max_area = 0 + for i in range(len(heights)): + min_high = heights[i] + for j in range(i, len(heights)): + min_high = min(min_high, heights[j]) + max_area = max(max_area, min_high * (j - i + 1)) + return max_area + + def largestRectangleArea2(self, heights): + max_area = 0 + for i in range(len(heights)): + l = r = i + while l >= 0 and heights[l] >= heights[i]: + l -= 1 + while r < len(heights) and heights[r] >= heights[i]: + r += 1 + max_area = max(max_area, heights[i] * (r - l - 1)) + return max_area + + def largestRectangleArea3(self, heights): + max_area = 0 + stack = [-1] + for i in range(len(heights)): + while stack[-1] != -1 and heights[i] < heights[stack[-1]]: + max_area = max(max_area, heights[stack.pop()] * (i - stack[-1] - 1)) + stack.append(i) + while stack[-1] != -1: + max_area = max(max_area, heights[stack.pop()] * (len(heights) - stack[-1] - 1)) + return max_area + + # 栈 优化版 + def largestRectangleArea3_1(self, heights): + max_area = 0 + """ + heights.append(0) 这里很巧妙有2点 + 1:将第一个while的stack[-1] != -1判断省掉 + 因为当stack[-1] == -1时,height[i] > 0, heights[stack[-1]] = heights[-1] = 0 + 从而 heights[i] < heights[stack[-1]] 包含 stack[-1= != -1 的判断 + 2:讲上一方法的最后for循环提升到前面来实现 + while stack[-1] != -1: + max_area = max(max_area, heights[stack.pop()] * (len(heights) - stack[-1] - 1)) + 当 i 迭代到最后 + 正好是 i = 原长度 + 最后一次刚好把优化前的第二while替代掉 + """ + heights.append(0) + stack = [-1] + for i in range(len(heights)): + while heights[i] < heights[stack[-1]]: + max_area = max(max_area, heights[stack.pop()] * (i - stack[-1] - 1)) + stack.append(i) + return max_area + +# leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 01/id_251/LeetCode_88_251.py b/Week 01/id_251/LeetCode_88_251.py new file mode 100644 index 000000000..81fe8051f --- /dev/null +++ b/Week 01/id_251/LeetCode_88_251.py @@ -0,0 +1,103 @@ +# 给定两个有序整数数组 nums1 和 nums2,将 nums2 合并到 nums1 中,使得 num1 成为一个有序数组。 +# +# 说明: +# +# +# 初始化 nums1 和 nums2 的元素数量分别为 m 和 n。 +# 你可以假设 nums1 有足够的空间(空间大小大于或等于 m + n)来保存 nums2 中的元素。 +# +# +# 示例: +# +# 输入: +# nums1 = [1,2,3,0,0,0], m = 3 +# nums2 = [2,5,6], n = 3 +# +# 输出: [1,2,2,3,5,6] +# Related Topics 数组 双指针 +""" +1 合并后排序 +2 双指针 / 从前往后 +3 双指针 / 从后往前 +""" + + +# leetcode submit region begin(Prohibit modification and deletion) +class Solution(object): + def merge(self, nums1, m, nums2, n): + """ + :type nums1: List[int] + :type m: int + :type nums2: List[int] + :type n: int + :rtype: None Do not return anything, modify nums1 in-place instead. + """ + + # 1 合并后排序 + # 时间复杂度: O((n + m)log(n + m)) + # 空间复杂度: O(1) + def merege_sort(self, nums1, m, nums2, n): + nums1[:] = sorted(nums1[:m] + nums2) + + # 2 双指针 / 从前往后 + # 时间复杂度: O(n + m) + # 空间复杂度: O(m) + def two_index1(self, nums1, m, nums2, n): + nums1_copy, nums1[:] = nums1[:m], [] + p1, p2 = 0, 0 + + while p1 < m and p2 < n: + if nums1_copy[p1] < nums2[p2]: + nums1.append(nums1_copy[p1]) + p1 += 1 + else: + nums1.append(nums2[p2]) + p2 += 1 + + if p1 < m: + nums1[p1 + p2:] = nums1_copy[p1:] + if p2 < n: + nums1[p1 + p2:] = nums2[p2:] + + # 3 双指针 / 从后往前 + # 时间复杂度: O(n + m) + # 空间复杂度: O(1) + def two_index2(self, nums1, m, nums2, n): + p1, p2, p = m - 1, n - 1, m + n - 1 + + while p1 >= 0 and p2 >= 0: + if nums1[p1] > nums2[p2]: + nums1[p] = nums1[p1] + p1 -= 1 + else: + nums1[p] = nums2[p2] + p2 -= 1 + p -= 1 + + if p2 != -1: # if p2 left + nums1[:p2 + 1] = nums2[:p2 + 1] + + # 方法3 改进版 + def two_index3(self, nums1, m, nums2, n): + m, n = m - 1, n - 1 + + while m >= 0 and n >= 0: + if nums1[m] > nums2[n]: + nums1[m + n + 1] = nums1[m] + m -= 1 + else: + nums1[m + n + 1] = nums2[n] + n -= 1 + + if n != -1: # nums2 is still left + nums1[:n + 1] = nums2[:n + 1] + + +# leetcode submit region end(Prohibit modification and deletion) + +if __name__ == '__main__': + n1 = [1, 2, 3, 0, 0, 0] + n2 = [2, 5, 6] + s = Solution() + s.two_index2(n1, 3, n2, 3) + print(n1) diff --git a/Week 01/id_256/LeetCode_189_256.js b/Week 01/id_256/LeetCode_189_256.js new file mode 100644 index 000000000..9b58928c7 --- /dev/null +++ b/Week 01/id_256/LeetCode_189_256.js @@ -0,0 +1,54 @@ +/* + * @lc app=leetcode.cn id=189 lang=javascript + * + * [189] 旋转数组 + */ + +// @lc code=start +/** + * @param {number[]} nums + * @param {number} k + * @return {void} Do not return anything, modify nums in-place instead. + */ +var rotate = function(nums, k) { + // 暴力解 + // if(nums.length === 0 || nums.length === k) { + // return nums; + // } + // while (k > 0) { + // let previous = nums[nums.length - 1]; + // for (let i = 0; i < nums.length; i++) { + // let temp = nums[i]; + // nums[i] = previous; + // previous = temp; + // } + // k--; + // } + // return nums; + + // 绝起反转 + // let len = nums.length; + // k = k % len; + // if (k == len || len == 1 || len == 0) return nums; + // nums = nums.splice(len - k, k).concat(nums); + // return nums; + + // 分段截取 + let n = nums.length; + k %= n; + let tmp = 0; + if (n == 1 || k == n) return; + myRevese(0, n - 1); + myRevese(0, k - 1); + myRevese(k, n - 1); + function myRevese(start, end) { + while (start < end) { + tmp = nums[start]; + nums[start] = nums[end]; + nums[end] = tmp; + start++; + end--; + } + } +}; +// @lc code=end diff --git a/Week 01/id_256/LeetCode_1_256.js b/Week 01/id_256/LeetCode_1_256.js new file mode 100644 index 000000000..0db981ab0 --- /dev/null +++ b/Week 01/id_256/LeetCode_1_256.js @@ -0,0 +1,28 @@ +/* + * @lc app=leetcode.cn id=1 lang=javascript + * + * [1] 两数之和 + */ + +// @lc code=start +/** + * @param {number[]} nums + * @param {number} target + * @return {number[]} + */ +var twoSum = function(nums, target) { + let map = {}; + let res = []; + for (let i = 0; i < nums.length; i++) { + let tmp = target - nums[i]; + if(map[tmp+''] != undefined) { + res = [map[tmp+''], i]; + break; + } else { + map[nums[i]+''] = i; + } + } + return res; +}; +// @lc code=end + diff --git a/Week 01/id_256/LeetCode_26_256.js b/Week 01/id_256/LeetCode_26_256.js new file mode 100644 index 000000000..e9fdce544 --- /dev/null +++ b/Week 01/id_256/LeetCode_26_256.js @@ -0,0 +1,13 @@ +/** + * @param {number[]} nums + * @return {number} + */ +var removeDuplicates = function(nums) { + var i = 0; + nums.forEach(function (elem) { + if (elem !== nums[i]) { + nums[++i] = elem; + } + }); + return nums.length && i + 1; +}; \ No newline at end of file diff --git a/Week 01/id_256/LeetCode_283_256.js b/Week 01/id_256/LeetCode_283_256.js new file mode 100644 index 000000000..22ece743e --- /dev/null +++ b/Week 01/id_256/LeetCode_283_256.js @@ -0,0 +1,37 @@ +/* + * @lc app=leetcode.cn id=283 lang=javascript + * + * [283] 移动零 + */ + +// @lc code=start +/** + * @param {number[]} nums + * @return {void} Do not return anything, modify nums in-place instead. + */ +var moveZeroes = function(nums) { + // 方法一 + // let pos = 0; + // for (let i = 0; i < nums.length; i++) { + // if (nums[i] != 0) { + // nums[pos++] = nums[i]; + // } + // } + // while( pos < nums.length) { + // nums[pos++] = 0; + // } + // + //方法二 + let pos = 0; + for (let i = 0; i < nums.length; i++) { + if (nums[i] != 0) { + if (i != pos) { + nums[pos] = nums[i]; + nums[i] = 0; + } + pos++; + } + } + }; + // @lc code=end + \ No newline at end of file diff --git a/Week 01/id_256/LeetCode_88_256.js b/Week 01/id_256/LeetCode_88_256.js new file mode 100644 index 000000000..1fff378fb --- /dev/null +++ b/Week 01/id_256/LeetCode_88_256.js @@ -0,0 +1,34 @@ +/* + * @lc app=leetcode.cn id=88 lang=javascript + * + * [88] 合并两个有序数组 + */ + +// @lc code=start +/** + * @param {number[]} nums1 + * @param {number} m + * @param {number[]} nums2 + * @param {number} n + * @return {void} Do not return anything, modify nums1 in-place instead. + */ +var merge = function(nums1, m, nums2, n) { + //splice截取 合并 排序 + // nums1.splice(m, nums1.length - m); + // nums2.splice(n, nums2.length - n); + // Object.assign(nums1, [...nums1, ...nums2]).sort((a, b) => a - b); + + // 得用数组有序 + let pos = m + n - 1; + while (n > 0) { + if (m > 0 && nums1[m - 1] > nums2[n - 1]) { + nums1[pos--] = nums1[m - 1]; + m--; + } else { + nums1[pos--] = nums2[n - 1]; + n--; + } + } + }; + // @lc code=end + \ No newline at end of file diff --git a/Week 01/id_261/leetcode_189_261.go b/Week 01/id_261/leetcode_189_261.go new file mode 100644 index 000000000..274fc6e4b --- /dev/null +++ b/Week 01/id_261/leetcode_189_261.go @@ -0,0 +1,14 @@ +// leetcode - https://leetcode-cn.com/problems/rotate-array/ + +func reverse(nums []int) { + for i:= 0; i < int(len(nums) / 2); i++ { + nums[i], nums[len(nums) - i - 1] = nums[len(nums) - i - 1], nums[i] + } +} + +func rotate(nums []int, k int) { + k = k % len(nums) + reverse(nums) + reverse(nums[0: k]) + reverse(nums[k: len(nums)]) +} \ No newline at end of file diff --git a/Week 01/id_261/leetcode_1_261.go b/Week 01/id_261/leetcode_1_261.go new file mode 100644 index 000000000..29b63cd00 --- /dev/null +++ b/Week 01/id_261/leetcode_1_261.go @@ -0,0 +1,14 @@ +// leetcode - https://leetcode-cn.com/problems/two-sum/ + +func twoSum(nums []int, target int) []int { + hash := make(map[int]int) + for i:= 0; i < len(nums); i ++ { + expect := target - nums[i] + if j, ok := hash[expect]; ok { + return []int{i, j} + } else { + hash[nums[i]] = i + } + } + return nil +} \ No newline at end of file diff --git a/Week 01/id_261/leetcode_21_261.go b/Week 01/id_261/leetcode_21_261.go new file mode 100644 index 000000000..30438d0d2 --- /dev/null +++ b/Week 01/id_261/leetcode_21_261.go @@ -0,0 +1,30 @@ +// leetcode - https://leetcode-cn.com/problems/merge-two-sorted-lists/ + +/** + * Definition for singly-linked list. + * type ListNode struct { + * Val int + * Next *ListNode + * } + */ +func mergeTwoLists(l1 *ListNode, l2 *ListNode) *ListNode { + head := &ListNode{} + list := head + for l1 != nil || l2 != nil { + if l1 == nil { + list.Next = &ListNode{Val: l2.Val} + l2 = l2.Next + } else if l2 == nil { + list.Next = &ListNode{Val: l1.Val} + l1 = l1.Next + } else if l1.Val <= l2.Val { + list.Next = &ListNode{Val: l1.Val} + l1 = l1.Next + } else { + list.Next = &ListNode{Val: l2.Val} + l2 = l2.Next + } + list = list.Next + } + return head.Next +} \ No newline at end of file diff --git a/Week 01/id_261/leetcode_26_261.go b/Week 01/id_261/leetcode_26_261.go new file mode 100644 index 000000000..d5c41af0d --- /dev/null +++ b/Week 01/id_261/leetcode_26_261.go @@ -0,0 +1,17 @@ +// leetcode - https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array/ + +func removeDuplicates(nums []int) int { + if (len(nums) == 0) { + return 0 + } + prev := nums[0] + index := 1 + for i := 1; i < len(nums); i++ { + if prev != nums[i] { + nums[index] = nums[i] + prev = nums[i] + index++ + } + } + return index +} \ No newline at end of file diff --git a/Week 01/id_261/leetcode_283_261.go b/Week 01/id_261/leetcode_283_261.go new file mode 100644 index 000000000..62c068ed4 --- /dev/null +++ b/Week 01/id_261/leetcode_283_261.go @@ -0,0 +1,14 @@ +// leetcode - https://leetcode-cn.com/problems/move-zeroes/ + +func moveZeroes(nums []int) { + index := 0 + for i := 0; i < len(nums); i++ { + if nums[i] != 0 { + nums[index] = nums[i] + if i != index { + nums[i] = 0 + } + index++ + } + } +} \ No newline at end of file diff --git a/Week 01/id_261/leetcode_66_261.go b/Week 01/id_261/leetcode_66_261.go new file mode 100644 index 000000000..4075d0dc0 --- /dev/null +++ b/Week 01/id_261/leetcode_66_261.go @@ -0,0 +1,15 @@ +// leetcode - https://leetcode-cn.com/problems/plus-one/ + +func plusOne(digits []int) []int { + result := make([]int, len(digits) + 1) + digits[len(digits) - 1]++ + for i, j := len(digits)-1, len(digits); i >= 0; i,j = i-1, j-1 { + a := int((result[j] + digits[i]) / 10) + result[j] = (result[j] + digits[i]) % 10 + result[j - 1] = a + } + if result[0] == 0 { + return result[1:] + } + return result +} \ No newline at end of file diff --git a/Week 01/id_261/leetcode_88_261.go b/Week 01/id_261/leetcode_88_261.go new file mode 100644 index 000000000..bdc95c9e5 --- /dev/null +++ b/Week 01/id_261/leetcode_88_261.go @@ -0,0 +1,21 @@ +// leetcode - https://leetcode-cn.com/problems/merge-sorted-array/ + +func merge(nums1 []int, m int, nums2 []int, n int) { + index := m + n - 1 + m = m - 1 + n = n - 1 + for index >= 0 { + if n < 0 { + return + } + if m < 0 || nums1[m] < nums2[n] { + nums1[index] = nums2[n] + n-- + index-- + } else { + nums1[index] = nums1[m] + m-- + index-- + } + } +} \ No newline at end of file diff --git a/Week 01/id_266/266-Week 01 b/Week 01/id_266/266-Week 01 new file mode 100644 index 000000000..8a7641245 --- /dev/null +++ b/Week 01/id_266/266-Week 01 @@ -0,0 +1,57 @@ +1.移动零(move-zero) +// 思路: +// 首先输入的是一个数组,然后设定两个下标i和j,技巧在于以空间(两个下标)换时间。i是用来寻找非0元素(在for循环里,移动快); +// j是从来寻找非零元素应该存放的位置(移动慢)。 + +class Solution{ + public void moveZeros(int[] nums){ + int j = 0; + for (int i = 0; i < nums.length; i++){ + if (nums[i] != 0){ + int temp = nums[j]; + nums[j] = nums[i]; + nums[i] = temp; + j++; //注意此处的j++一定要在if里面,意思是当交换完成之后j就往后挪一个位置,如果放在了if的外面则每次for循环j都加1则不对。只有在交换完成之后j才加1 + } + } + } +} +// 用时0ms + +// 中间for循环部分也可以像老师的代码那样先把nums[i]放到j的位置,然后再把原来i的位置赋为0,即相当于变相的交换了一次。 +// if (nums[i] != 0){ +// nums[j] = nums[i]; +// if (i != j){ +// nums[i] = 0; +// } +// j++; +// } + +2.合并两个有序数组(merge-sorted-array) +class Solution { + public void merge(int[] nums1, int m, int[] nums2, int n) { + // 首先把数组nums1复制一个,长度为m + int [] nums1_copy = new int[m]; + System.arraycopy(nums1, 0, nums1_copy, 0, m); + + // 用两个下标p1和p2分别记录nums1_copy和nums2的下标。 + int p1 = 0; + int p2 = 0; + + // 用p记录原数组nums1的下标 + int p = 0; + + // 开始比较nums1_copy和nums2中的元素,较小的存入nums1里。 + while ((p1 < m) && (p2 < n)){ + nums1[p++] = (nums1_copy[p1] < nums2[p2]) ? nums1_copy[p1++] : nums2[p2++]; + } + + // 分别考虑nums1_copy和nums2还没处理完的情况。 + if (p1 < m) { + System.arraycopy(nums1_copy, p1, nums1, p1 + p2, m + n - p1 - p2); + } + if (p2 < n) { + System.arraycopy(nums2, p2, nums1, p1 + p2, m + n - p1 - p2); + } + } +} diff --git a/Week 01/id_276/ClimbingStairs.java b/Week 01/id_276/ClimbingStairs.java new file mode 100644 index 000000000..b5ce149f3 --- /dev/null +++ b/Week 01/id_276/ClimbingStairs.java @@ -0,0 +1,43 @@ +public class ClimbingStairs { + /*public int climbingStairs(int n) { + // fibonicicc 时间复杂副:O(2^n) + if (n <= 2) { + return n; + } else { + return climbStair(n-1)+climbStairs(n-2); + } + }*/ + + /*public int climbingStairs(int n) { + //用数组保存每一个n的方法次数 + int[] ways = new int[n]; + if (n <= 2) { + return n; + } + ways[0] = 1; + ways[1] = 2; + + for (int i=3;i= 0 && j >= 0) { + if (nums1[i] > nums2[j]) { + nums1[k--] = nums1[i--]; + } else { + nums1[k--] = nums2[j--]; + } + } + while (i >= 0) { + nums1[k--] = nums1[i--]; + } + while (j >= 0) { + nums1[k--] = nums2[j--]; + } + }*/ + // 先插入,在排序 + public void merge(int[] nums1, int m, int[] nums2, int n) { + System.arraycopy(nums2, 0, nums1, m, n); + Arrays.sort(nums1); + } + //向前排序输入,与合并链表类似 + +} diff --git a/Week 01/id_276/MergeTwoSortedList.java b/Week 01/id_276/MergeTwoSortedList.java new file mode 100644 index 000000000..1c51a0d3f --- /dev/null +++ b/Week 01/id_276/MergeTwoSortedList.java @@ -0,0 +1,48 @@ +public class MergeTwoSortedList { + /*public void mergeSortedList (List l1, List l2) { + // 用三个指针,一个保持新链表的最后一个,一个A,一个B + if (l1 == null) { + return l2; + } + if (l2 == null) { + return l1; + } + ListNode new_Head = null; + ListNode p = l1; + ListNode q = l2; + if (p.val < q.val) { + new_head = p; + p = p.next; + } else { + new_head = q; + q = q.next; + } + ListNode r = new_Head; + while (p != null && q != null) { + if (p.val < q.val) { + r.next = p; + p = p.next; + } else { + r.next = q; + q = q.next; + } + r = r.next; + } + r.next = q==null ? p : q; + return new_Head; + }*/ + /*public ListNode mergeTwoList (ListNode l1, ListNode l2) { + if (l1 == null) { + return l2; + } else if (l2 == null) { + return l1; + } else if (l1.val < l2.val) { + l1.next = mergeTwoList(l1.next, l2); + return l1; + } else { + l2.next = mergeTwoList(l1, l2.next); + return l2; + } + }*/ + +} diff --git a/Week 01/id_276/Parentheses.java b/Week 01/id_276/Parentheses.java new file mode 100644 index 000000000..a77a18b60 --- /dev/null +++ b/Week 01/id_276/Parentheses.java @@ -0,0 +1,70 @@ +public class Parentheses { + //栈的放法实现,时间复杂度O(n) + public boolean isValidParanthese (char[] str) { + if (str == null) { + return false; + } + + Deque stack = new LinkedList<>(); + + int i = 0; + while (i < str.length) { + if (str[i] == '(') { + stack.push(')'); + } else if (str[i] == '[') { + stack.push(']'); + } else if (str[i] == '{') { + stack.push('}'); + } else if (!stack.isEmpty()&&str[i] == stack.peekFirst()) { + stack.pop(); + } else { + stack.push(str[i]); + } + i ++; + } + return stack.isEmpty(); + } + + //暴力法:从左往右走,把匹配的位置换成"" + public static boolean isValid (String s) { + int i = 0; + while (i < s.length()) { + String temp = s.replace("()",""); + temp = s.replace("[]",""); + temp = s.replace("{}",""); + System.out.println(temp); + if (s.equals("")) { + return true; + } + if (s.equals(temp)) { + return false; + } + s = temp; + i ++; + } + return s.equals(""); + } + /* public static boolean isValid (String s) { + if (s == null || s == "")return false; + + Deque stack = new LinkedList<>(); + + for (char c : s.toCharArray()) { + if (c == '(') { + stack.push(')'); + } else if (c == '[') { + stack.push(']'); + } else if (c == '{') { + stack.push('}'); + } else if (stack.isEmpty() || stack.pop() != c) { + return false; + } + } + + return stack.isEmpty(); + }*/ + public static void main(String[] args) { + String s = "()"; + System.out.println(isValid(s)); + } +} diff --git a/Week 01/id_276/PlusOne.java b/Week 01/id_276/PlusOne.java new file mode 100644 index 000000000..145916853 --- /dev/null +++ b/Week 01/id_276/PlusOne.java @@ -0,0 +1,37 @@ +public class PlusOne { + public int[] plusOne(int[] digits) /*{ + int tar = 1; + + for (int i=digits.length-1;i>=0;--i) { + int sum = digits[i]+tar; + if (sum > 10) { + digits[i] = digits[i]%10; + tar = 1; + } else { + digits[i] = sum; + tar = 0; + break; + } + } + int[] temp; + if (tar == 1) { + temp = new int[digits.length+1]; + temp[0] = 1; + System.arraycopy(nums, 0, temp, 1,digits.length); + } else { + temp = new int[digits.length]; + System.arraycopy(nums, 0, temp, 0, digits.length); + } + return temp; + }*/ + /*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; + } + digits = new int[digits.length + 1];https://leetcode.com/problems/climbing-stairs/ + digits[0] = 1; + return digits; + }*/ +} diff --git a/Week 01/id_276/RemoveDuplicates.java b/Week 01/id_276/RemoveDuplicates.java new file mode 100644 index 000000000..c534dd662 --- /dev/null +++ b/Week 01/id_276/RemoveDuplicates.java @@ -0,0 +1,68 @@ +public class RemoveDuplicates { + /*public int removeDuplicates (int[] nums) { + //思路1 用两个数组,两个指针, + int[] temp = new int[nums.length]; + + int i=0,j=0; + temp[i++] = nums[j++]; + for(;j 0){ + balls[i-snowballSize] = balls[i]; + balls[i] = 0; + } + } + } +} diff --git a/Week 01/id_276/RotateArray.java b/Week 01/id_276/RotateArray.java new file mode 100644 index 000000000..6ef0a1577 --- /dev/null +++ b/Week 01/id_276/RotateArray.java @@ -0,0 +1,55 @@ +public class RotateArray { + //1.mod N,==> nums[i] = nums[(i+k)mod N] + //2.建立临时数组,保存前面的k个数,在复制到后面n-k位置上 + //3. + + /*public void rotate (int[] nums, int k) { + + int len = nums.length; + int times = k%len; //为什么k&(len-1)不行 + int[] temp = new int[times]; + System.arraycopy(nums, len-times, temp,0,times); + System.arraycopy(nums, 0, nums, times,len-times+1); + System.arraycopy(temp, 0, nums, 0,times); + }*/ + //暴力法 + /*public void rotate (int[] nums, int k) { + int temp,pre; + + for (int i=0;i maxLeft) { + maxLeft = height[left]; + } else { + sum += maxLeft- height[left]; + } + ++left; + } else { + if (height[right] < maxRight) { + maxRight = height[right]; + } else { + sum += maxRight-height[right]; + } + --right; + } + } + + return sum; + } +} diff --git a/Week 01/id_276/TwoSum.java b/Week 01/id_276/TwoSum.java new file mode 100644 index 000000000..e1a9f95ae --- /dev/null +++ b/Week 01/id_276/TwoSum.java @@ -0,0 +1,49 @@ +import java.util.Arrays; +import java.util.HashMap; + +public class TwoSum { + /*public int[] twoSum(int[] nums, int target) { + //Arrays.sort(nums); + int[] index = new int[2]; + for (int i=0;i map = new HashMap<>(); + + for (int i=0;i map = new HashMap<>(); + + for (int i=0;i map = new HashMap<>(); + for (int i = 0; i < nums.length; i++) { + if(map.containsKey(target - nums[i])){ + return new int[] { map.get(target - nums[i]), i }; + }else { + map.put(nums[i], i); + } + } + throw new IllegalArgumentException("No two sum solution"); + } +} +// @lc code=end + diff --git a/Week 01/id_281/LeetCode_21_281.java b/Week 01/id_281/LeetCode_21_281.java new file mode 100644 index 000000000..289c16268 --- /dev/null +++ b/Week 01/id_281/LeetCode_21_281.java @@ -0,0 +1,52 @@ +/* + * @lc app=leetcode.cn id=21 lang=java + * + * [21] 合并两个有序链表 + */ + +// @lc code=start +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode(int x) { val = x; } + * } + */ +class Solution { + public ListNode mergeTwoLists1(ListNode l1, ListNode l2) { + ListNode preHead = new ListNode(-1); + ListNode pre = preHead; + + while (l1 != null && l2 != null) { + if(l1.val <= l2.val){ + pre.next = l1; + l1 = l1.next; + }else { + pre.next = l2; + l2 = l2.next; + } + + pre = pre.next; + } + + pre.next = l1 == null ? l2 : l1; + + return preHead.next; + } + + public ListNode mergeTwoLists(ListNode l1, ListNode l2) { + if(l1 == null) return l2; + if(l2 == null) return l1; + + if (l1.val < l2.val) { + l1.next = mergeTwoLists(l1.next, l2); + return l1; + }else { + l2.next = mergeTwoLists(l2.next, l1); + return l2; + } + } +} +// @lc code=end + diff --git a/Week 01/id_281/LeetCode_26_281.java b/Week 01/id_281/LeetCode_26_281.java new file mode 100644 index 000000000..63a0e6cbc --- /dev/null +++ b/Week 01/id_281/LeetCode_26_281.java @@ -0,0 +1,21 @@ +/* + * @lc app=leetcode.cn id=26 lang=java + * + * [26] 删除排序数组中的重复项 + */ + +// @lc code=start +class Solution { + public int removeDuplicates(int[] nums) { + int i = 0; + for (int j = 1; j < nums.length ; j++) { + if(nums[i] != nums[j]) { + i++; + nums[i] = nums[j]; + } + } + return i+1; + } +} +// @lc code=end + diff --git a/Week 01/id_281/LeetCode_283_281.java b/Week 01/id_281/LeetCode_283_281.java new file mode 100644 index 000000000..cf7276977 --- /dev/null +++ b/Week 01/id_281/LeetCode_283_281.java @@ -0,0 +1,54 @@ +/* + * @lc app=leetcode.cn id=283 lang=java + * + * [283] 移动零 + */ + +// @lc code=start +class Solution { + public void moveZeroes1(int[] nums) { + int i = 0; + for (int j = 1; j <= nums.length - 1; j++) { + if(nums[i] == 0) { + if(nums[j] != 0) { + nums[i] = nums[j]; + nums[j] = 0; + i++; + } + }else { + i++; + } + } + + } + + // 先把非0元素填充在前面位置,后面的在补0 + public void moveZeroes2(int[] nums) { + int lastNonZerosIndex = 0; + for (int i = 0; i < nums.length; i++) { + if(nums[i] != 0) { + nums[lastNonZerosIndex++] = nums[i]; + } + } + + for (int i = lastNonZerosIndex; i < nums.length; i++) { + nums[i] = 0; + } + } + + // 递推非0指针的位置 + public void moveZeroes(int[] nums) { + int lastNonZerosIndex = 0; + for (int i = 0; i < nums.length; i++) { + if(nums[i] != 0) { + if (i > lastNonZerosIndex) { + nums[lastNonZerosIndex] = nums[i]; + nums[i] = 0; + } + lastNonZerosIndex ++; + } + } + } +} +// @lc code=end + diff --git a/Week 01/id_281/LeetCode_88_281.java b/Week 01/id_281/LeetCode_88_281.java new file mode 100644 index 000000000..e2486a472 --- /dev/null +++ b/Week 01/id_281/LeetCode_88_281.java @@ -0,0 +1,22 @@ +/* + * @lc app=leetcode.cn id=88 lang=java + * + * [88] 合并两个有序数组 + */ + +// @lc code=start +class Solution { + // O(n+m) O(1) + public void merge(int[] nums1, int m, int[] nums2, int n) { + // 指针 = 总数-1 + int p = m + n -1, p1 = m-1, p2 = n-1; + + while((p1 >= 0) && (p2 >= 0)) { + nums1[p--] = (nums1[p1] < nums2[p2]) ? nums2[p2--] : nums1[p1--]; + } + // 最后的个数就是索引+1 + System.arraycopy(nums2, 0, nums1, 0, p2 + 1); + } +} +// @lc code=end + diff --git a/Week 01/id_281/NOTE.md b/Week 01/id_281/NOTE.md index a6321d6e2..7fd5876c8 100644 --- a/Week 01/id_281/NOTE.md +++ b/Week 01/id_281/NOTE.md @@ -1,4 +1,4 @@ -# NOTE - - +# 第一周学习 +题目做的遍数还是不够,很多题目在回来写,不能一次写正确,需要五毒神掌加持。 +栈和队列的题目没有时间做了,下周再补上。 diff --git a/Week 01/id_286/LeetCode_183_286.java b/Week 01/id_286/LeetCode_183_286.java new file mode 100644 index 000000000..10b86a5d6 --- /dev/null +++ b/Week 01/id_286/LeetCode_183_286.java @@ -0,0 +1,22 @@ +package com.uanei; + +public class LeetCode_183_286 { + + public void moveZeroes(int[] nums) { + // 通过索引记录0元素的位置 + // 将非0元素移动到索引位置 + // (索引和当前元素索引相同,说明前边的元素没有0,如果索引小于当前索引,则前边有0元素,进行交换) + // 交换位置之后,0元素的索引向后移一位 + int index = 0; + for (int i = 0; i < nums.length; i++) { + if (nums[i] != 0) { + nums[index] = nums[i]; + if (index != i) { + nums[i] = 0; + } + index++; + } + } + } + +} diff --git a/Week 01/id_286/LeetCode_1_286.java b/Week 01/id_286/LeetCode_1_286.java new file mode 100644 index 000000000..75309e67c --- /dev/null +++ b/Week 01/id_286/LeetCode_1_286.java @@ -0,0 +1,26 @@ +package com.uanei; + +import java.util.HashMap; +import java.util.Map; + +public class LeetCode_1_286 { + + public int[] twoSum(int[] nums, int target) { + int[] a = new int[2]; + Map map = new HashMap<>(); + for (int i = 0; i < nums.length; i++) { + // 计算当前元素需要匹配的另一元素的值,map存储 key = 需要的值,value = 当前元素的位置 + int jValue = target - nums[i]; + if (map.containsKey(nums[i])) { + a[0] = map.get(nums[i]); + a[1] = i; + if (a[0] != a[1]) { + return a; + } + } + map.put(jValue, i); + } + return new int[0]; + } + +} diff --git a/Week 01/id_286/NOTE.md b/Week 01/id_286/NOTE.md index a6321d6e2..e8fd2c612 100644 --- a/Week 01/id_286/NOTE.md +++ b/Week 01/id_286/NOTE.md @@ -1,4 +1,75 @@ -# NOTE +# 学习总结 + +### 解题并提升兴趣 + +* 第一遍听老师讲,听的比较费劲的地方,暂停思考明白 +* 第二遍听老师讲,买一个小白板动手画思路,同时记录老师描述的关键解题思路和信息。 +* 两遍听课结束之后,动手写代码和看评论 + * 明白思路,自己写,不明白思路,直接看题解 + * 编写的过程从暴力开始,一点点优化,最后找出一个稍微好一点的解法多次复习记忆 + * leetcode-cn到leetcode国际站,很关键,国外牛人代码很精妙。 +* 通过解题过程提升兴趣 + * 解题思路 + * 性能优化 + * 自己的代码和别人的比较,以及国际站的牛人代码如何千锤百年 + +### 源码分析 + +* Queue + + ```java + public interface Queue extends Collection { + // 队尾添加元素,满了就抛出异常 + boolean add(E e); + + // 队尾添加元素,满了返回false + boolean offer(E e); + + // 出队,队空抛异常 + E remove(); + + // 出队,队空返回null + E poll(); + + // 查看队头,队空抛异常 + E element(); + + // 查看队头,队空返回null + E peek(); + } + ``` + +* PriorityQueue + + * 分析有难度,暂未分析 + + ### Deque最新api使用 + +* addFirst和addLast + + ```java + public static void main(String[] args) { + Deque deque = new LinkedList<>(); + + // 队尾添加 + deque.add(31); + deque.add(32); + deque.add(33); + + // 队头添加 + deque.addFirst(11); + deque.addFirst(12); + + // 队尾添加 + deque.addLast(91); + deque.addLast(92); + + System.out.println(deque); + } + + // console + [12, 11, 31, 32, 33, 91, 92] + ``` diff --git a/Week 01/id_296/LeetCode_42_296.java b/Week 01/id_296/LeetCode_42_296.java new file mode 100644 index 000000000..98059000b --- /dev/null +++ b/Week 01/id_296/LeetCode_42_296.java @@ -0,0 +1,32 @@ +/* + * @lc app=leetcode.cn id=42 lang=java + * + * [42] 接雨水 + */ + +// @lc code=start +class Solution { + public int trap(int[] height) { + int sum = 0; + Stack stack = new Stack<>(); + int current = 0; + while (current < height.length) { + //如果栈不空并且当前指向的高度大于栈顶高度就一直循环 + while (!stack.empty() && height[current] > height[stack.peek()]) { + int h = height[stack.peek()]; //取出要出栈的元素 + stack.pop(); //出栈 + if (stack.empty()) { // 栈空就出去 + break; + } + int distance = current - stack.peek() - 1; //两堵墙之前的距离。 + int min = Math.min(height[stack.peek()], height[current]); + sum = sum + distance * (min - h); + } + stack.push(current); //当前指向的墙入栈 + current++; //指针后移 + } + return sum; + } +} +// @lc code=end + diff --git a/Week 01/id_296/LeetCode_641_296.java b/Week 01/id_296/LeetCode_641_296.java new file mode 100644 index 000000000..0c82ca159 --- /dev/null +++ b/Week 01/id_296/LeetCode_641_296.java @@ -0,0 +1,119 @@ +/* + * @lc app=leetcode.cn id=641 lang=java + * + * [641] 设计循环双端队列 + */ + +// @lc code=start +class MyCircularDeque { + + private int[] objects; + private int head; + private int tail; + private int MAX_SIZE; + private int length; + + /** Initialize your data structure here. Set the size of the deque to be k. */ + public MyCircularDeque(int k) { + objects = new int[k]; + head = tail = -1; + MAX_SIZE = k; + length = 0; + } + + /** + * Adds an item at the front of Deque. Return true if the operation is + * successful. + */ + public boolean insertFront(int value) { + if (isFull()) + return false; + head = (head - 1 + MAX_SIZE) % MAX_SIZE; + objects[head] = value; + length++; + if (length == 1) { + tail = head; + } + return true; + } + + /** + * Adds an item at the rear of Deque. Return true if the operation is + * successful. + */ + public boolean insertLast(int value) { + if (isFull()) + return false; + tail = (tail + 1) % MAX_SIZE; + objects[tail] = value; + length++; + if (length == 1) { + head = tail; + } + return true; + } + + /** + * Deletes an item from the front of Deque. Return true if the operation is + * successful. + */ + public boolean deleteFront() { + if (isEmpty()) + return false; + head = (head + 1) % MAX_SIZE; + length--; + return true; + } + + /** + * Deletes an item from the rear of Deque. Return true if the operation is + * successful. + */ + public boolean deleteLast() { + if (isEmpty()) + return false; + tail = (tail - 1 + MAX_SIZE) % MAX_SIZE; + length--; + return true; + } + + /** Get the front item from the deque. */ + public int getFront() { + if (isEmpty()) + return -1; + return objects[head]; + } + + /** Get the last item from the deque. */ + public int getRear() { + if (isEmpty()) + return -1; + return objects[tail]; + } + + /** Checks whether the circular deque is empty or not. */ + public boolean isEmpty() { + return length == 0; + } + + /** Checks whether the circular deque is full or not. */ + public boolean isFull() { + return length == MAX_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(); + */ +// @lc code=end + diff --git a/Week 01/id_296/LeetCode_66_296.java b/Week 01/id_296/LeetCode_66_296.java new file mode 100644 index 000000000..4dbc21d01 --- /dev/null +++ b/Week 01/id_296/LeetCode_66_296.java @@ -0,0 +1,21 @@ +/* + * @lc app=leetcode.cn id=66 lang=java + * + * [66] 加一 + */ + +// @lc code=start +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; + } + digits = new int[digits.length + 1]; + digits[0] = 1; + return digits; + } +} +// @lc code=end + diff --git a/Week 01/id_301/circularDeque.go b/Week 01/id_301/circularDeque.go new file mode 100644 index 000000000..14c200e1b --- /dev/null +++ b/Week 01/id_301/circularDeque.go @@ -0,0 +1,119 @@ +package main + +import "fmt" + +type MyCircularDeque struct { + size int + length int + data []int +} + +/** Initialize your data structure here. Set the size of the deque to be k. */ +func Constructor(k int) MyCircularDeque { + var circularDeque MyCircularDeque + circularDeque = *new(MyCircularDeque) + circularDeque.size = k + circularDeque.length = 0 + return circularDeque +} + +/** Adds an item at the front of Deque. Return true if the operation is successful. */ +func (this *MyCircularDeque) InsertFront(value int) bool { + if this.IsFull() { + return false + } + this.data = append([]int{value}, this.data...) + this.length++ + return true +} + +/** Adds an item at the rear of Deque. Return true if the operation is successful. */ +func (this *MyCircularDeque) InsertLast(value int) bool { + if this.IsFull() { + return false + } + this.data = append(this.data, value) + this.length++ + return true +} + +/** Deletes an item from the front of Deque. Return true if the operation is successful. */ +func (this *MyCircularDeque) DeleteFront() bool { + if this.IsEmpty() { + return false + } + if this.length == 1 { + this.data = []int{} + } else { + this.data = this.data[1:] + } + this.length-- + return true +} + +/** Deletes an item from the rear of Deque. Return true if the operation is successful. */ +func (this *MyCircularDeque) DeleteLast() bool { + if this.IsEmpty() { + return false + } + if this.length == 1 { + this.data = []int{} + } else { + this.data = this.data[:this.length-1] + } + this.length-- + return true +} + +/** Get the front item from the deque. */ +func (this *MyCircularDeque) GetFront() int { + if this.IsEmpty() { + return -1 + } + val := this.data[0] + return val +} + +/** Get the last item from the deque. */ +func (this *MyCircularDeque) GetRear() int { + if this.IsEmpty() { + return -1 + } + val := this.data[this.length-1] + return val +} + +/** Checks whether the circular deque is empty or not. */ +func (this *MyCircularDeque) IsEmpty() bool { + if this.length == 0 { + return true + } + return false +} + +/** Checks whether the circular deque is full or not. */ +func (this *MyCircularDeque) IsFull() bool { + if this.size == this.length { + return true + } else { + return false + } +} + +func main() { + c := Constructor(3) + fmt.Println(c.size) + fmt.Println(c.InsertFront(3)) + fmt.Println(c.length) + fmt.Println(c.InsertLast(1)) + fmt.Println(c.length) + fmt.Println(c.InsertLast(10)) + fmt.Println(c.length) + fmt.Println(c.InsertLast(11)) + fmt.Println(c.length) + fmt.Println(c.InsertLast(11)) + fmt.Println(c.length) + //fmt.Println(c.DeleteFront()) + fmt.Println(c.length) + fmt.Println(c.IsFull()) +} diff --git a/Week 01/id_301/linklist/link_node.go b/Week 01/id_301/linklist/link_node.go new file mode 100644 index 000000000..28738b110 --- /dev/null +++ b/Week 01/id_301/linklist/link_node.go @@ -0,0 +1,14 @@ +package linklist + +/** +* Definition for singly-linked list. +* type ListNode struct { +* Val int +* Next *ListNode +* } + */ + +type ListNode struct { + Val int + Next *ListNode +} diff --git a/Week 01/id_301/main.go b/Week 01/id_301/main.go new file mode 100644 index 000000000..00b4a7db9 --- /dev/null +++ b/Week 01/id_301/main.go @@ -0,0 +1,262 @@ +package main + +import ( + "algo04-01/Week_01/id_301/linklist" + "fmt" +) + +func main() { + //nums := []int{1,2,3,4,5,6} + //array.RotateThree(nums,2) + //fmt.Println(nums) + //var l1 *linklist.ListNode + //var l2 *linklist.ListNode + //l1 = new(linklist.ListNode) + //l1.Val = 1 + //l1.Next = new(linklist.ListNode) + //l1.Next.Val = 4 + //l1.Next.Next = new(linklist.ListNode) + //l1.Next.Next.Val = 6 + //l2 = new(linklist.ListNode) + //l2.Val = 2 + //l2.Next = new(linklist.ListNode) + //l2.Next.Val = 3 + //l2.Next.Next = new(linklist.ListNode) + //l2.Next.Next.Val = 7 + //fmt.Println(l1.Val) + //fmt.Println(linklist.MergeTwoLists(l1, l2).Next.Next.Next.Next.Val) + //a1 := []int{1, 3, 9, 8, 7} + //fmt.Println(TwoSum(a1, 10)) + c := Constructor(3) + fmt.Println(c.InsertFront(3)) +} + +/** +移除重复元素 +*/ +func removeDuplicates(nums []int) int { + length := len(nums) + index := 0 + for i := 1; i < length; i++ { + if nums[index] != nums[i] { + index += 1 + nums[index] = nums[i] + } + } + return index + 1 +} + +/** 向右移动数组解法1 +解法思想 : 当一个数组长度为n,移动后k次,当k=n的时候,其实本质上是移动了k对n求余次数 +*/ +func RotateOne(nums []int, k int) { + length := len(nums) + if length <= 1 { + return + } + for i := 0; i < k; i++ { + tmp := nums[length-1] + for j := length - 2; j >= 0; j-- { + nums[j+1] = nums[j] + } + nums[0] = tmp + } +} + +/** 向右移动数组解法2 +解法思想 : 移动次数简化同上面分析。然后我们从最数组的第一位开始,挨个一次将元素移动到目标位置,移动n次,那么所有元素都将到达最后的位置. + 如果内层刚好移动到 +*/ +func RotateTwo(nums []int, k int) { + length := len(nums) + if length <= 1 || length == k || k == 0 { + return + } + k = k % length + count := 0 + for i := 0; count < length; i++ { + curr := i + pre := nums[i] + for { + next := (curr + k) % length + temp := nums[next] + nums[next] = pre + pre = temp + curr = next + count++ + fmt.Println(curr, "|", i, "|", count) + if curr == i { + break + } + } + } +} + +/** +向右移动数组解法三 三次反转法 +*/ +func RotateThree(nums []int, k int) { + length := len(nums) + if length <= 1 { + return + } + k = k % length + reverseArray(nums, 0, length-1) + reverseArray(nums, 0, k-1) + reverseArray(nums, k, length-1) +} + +/** +反转数组 +*/ +func reverseArray(nums []int, start, end int) { + length := len(nums) + if length <= 1 { + return + } + if start >= end { + return + } + if start > length-1 { + start = 0 + } + + if end > length-1 { + end = length - 1 + } + j := end + for i := start; i < j; i++ { + nums[i], nums[j] = nums[j], nums[i] + j-- + } +} + +/** +合并两个有序数组 双指针从尾部开始处理数据 +*/ +func Merge(nums1 []int, m int, nums2 []int, n int) { + p := m + n - 1 + p1 := m - 1 + p2 := n - 1 + for { + if p1 < 0 { + for ; p2 >= 0; p2-- { + nums1[p] = nums2[p2] + p-- + } + break + } + if p2 < 0 { + for ; p1 >= 0; p1-- { + nums1[p] = nums1[p1] + p-- + } + break + } + if nums1[p1] > nums2[p2] { + nums1[p] = nums1[p1] + p1-- + } else { + nums1[p] = nums2[p2] + p2-- + } + p-- + } +} + +/** +两数之和 +*/ +func TwoSum(nums []int, target int) []int { + var numsMap map[int]int + numsMap = make(map[int]int) + for k, v := range nums { + need := target - v + index, ok := numsMap[need] + if ok { + return []int{k, index} + break + } else { + numsMap[v] = k + } + } + return []int{} +} + +/** +移动0 +*/ +func moveZeroes(nums []int) { + curr := 0 + for k, v := range nums { + if v != 0 { + nums[curr] = v + if curr != k { + nums[k] = 0 + } + curr++ + } + } +} + +/** +加一 +*/ +func plusOne(digits []int) []int { + length := len(digits) + for i := length - 1; i >= 0; i-- { + if digits[i] != 9 { + digits[i]++ + return digits + } else { + digits[i] = 0 + } + } + return append([]int{1}, digits...) +} + +func MergeTwoLists(l1 *linklist.ListNode, l2 *linklist.ListNode) *linklist.ListNode { + currL1 := l1 + currL2 := l2 + var res *linklist.ListNode + res = new(linklist.ListNode) + if l1 == nil { + return l2 + } + if l2 == nil { + return l1 + } + if currL1.Val > currL2.Val { + res.Val = currL2.Val + currL2 = currL2.Next + } else { + res.Val = currL1.Val + currL1 = currL1.Next + } + res.Next = new(linklist.ListNode) + curr := res + for { + if currL1 == nil { + curr.Next = currL2 + break + } + if currL2 == nil { + curr.Next = currL1 + break + } + if currL1.Val > currL2.Val { + curr.Next.Val = currL2.Val + currL2 = currL2.Next + } else { + curr.Next.Val = currL1.Val + currL1 = currL1.Next + } + curr.Next.Next = new(linklist.ListNode) + curr = curr.Next + } + return res +} + +/** +收集雨水 +*/ diff --git a/Week 01/id_306/Array_RemoveDuplicates.java b/Week 01/id_306/Array_RemoveDuplicates.java new file mode 100644 index 000000000..8db345320 --- /dev/null +++ b/Week 01/id_306/Array_RemoveDuplicates.java @@ -0,0 +1,15 @@ + +public class Array_RemoveDuplicates { + public int removeDuplicates(int[] nums) { + if (0==nums.length) { + return 0; + } + int j = 0; + for (int i = 1; i< nums.length; i++) { + if (nums[i] != nums[j]) { + nums[++j] = nums[i]; + } + } + return j + 1; + } +} diff --git a/Week 01/id_306/Array_Rotate.java b/Week 01/id_306/Array_Rotate.java new file mode 100644 index 000000000..a42eba998 --- /dev/null +++ b/Week 01/id_306/Array_Rotate.java @@ -0,0 +1,18 @@ + +public class Array_Rotate { + public void rotate(int[] nums, int k) { + if(k<0){ + return; + } + int temp, previous; + for (int i = 0; i < k; i++) { + previous = nums[nums.length - 1]; + for (int j = 0; j < nums.length; j++) { + temp = nums[j]; + nums[j] = previous; + previous = temp; + } + } + + } +} diff --git a/Week 01/id_306/Linked_MergeTowLists.java b/Week 01/id_306/Linked_MergeTowLists.java new file mode 100644 index 000000000..a9da4f0d9 --- /dev/null +++ b/Week 01/id_306/Linked_MergeTowLists.java @@ -0,0 +1,25 @@ + +public class Linked_MergeTowLists { + /** + * 递归方式 + * @param l1 + * @param l2 + * @return + */ + public ListNode mergeTwoLists(ListNode l1, ListNode l2) { + if (null ==l1) { + return l2; + } + if (null==l2) { + return l1; + } + if(l1.data map = new HashMap<>(); + for (int i = 0; i < length; i++) { + if (map.containsKey(target - nums[i])) { + result[0] = map.get(target - nums[i]); + result[1] = i; + return result; + } + map.put(nums[i], i); + } + return result; + } + +} diff --git a/Week 01/id_321/LeetCode_21_321.java b/Week 01/id_321/LeetCode_21_321.java new file mode 100644 index 000000000..0f0d9f85e --- /dev/null +++ b/Week 01/id_321/LeetCode_21_321.java @@ -0,0 +1,55 @@ +package week01; + +class ListNode { + int val; + ListNode next; + + ListNode(int x) { + val = x; + } +} + +// 1.ݹ +// 2. +public class MergeTwoLists21 { + + public ListNode mergeTwoLists1(ListNode l1, ListNode l2) { + if (l1 == null) { + return l2; + } + if (l2 == null) { + return l1; + } + ListNode head; + if (l1.val < l2.val) { + head = l1; + head.next = mergeTwoLists1(l1.next, l2); + } else { + head = l2; + head.next = mergeTwoLists1(l1, l2.next); + } + return head; + } + + public ListNode mergeTwoLists2(ListNode l1, ListNode l2) { + + ListNode prehead = new ListNode(-1); + + ListNode prev = prehead; + 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 prehead.next; + } + +} diff --git a/Week 01/id_321/LeetCode_26_321.java b/Week 01/id_321/LeetCode_26_321.java new file mode 100644 index 000000000..738a65244 --- /dev/null +++ b/Week 01/id_321/LeetCode_26_321.java @@ -0,0 +1,22 @@ +package week01; + +public class RemoveDuplicates26 { + + public static void main(String[] args) { + // TODO Զɵķ + + } + public int removeDuplicates(int[] nums) { + if (nums.length == 0) { + return 0; + } + int i = 0; + for (int j = 1; j < nums.length; j++) { + if (nums[j] != nums[i]) { + i++; + nums[i] = nums[j]; + } + } + return i + 1; + } +} diff --git a/Week 01/id_321/LeetCode_66_321.java b/Week 01/id_321/LeetCode_66_321.java new file mode 100644 index 000000000..4c4f282da --- /dev/null +++ b/Week 01/id_321/LeetCode_66_321.java @@ -0,0 +1,19 @@ +package week01; + +//ֻеĩβнλʱλſܽλ +public class PlusOne66 { + + public int[] plusOne(int[] digits) { + int len = digits.length; + for (int i = len - 1; i >= 0; i--) { + digits[i]++; + digits[i] %= 10; + if (digits[i] != 0) { + return digits; + } + } + digits = new int[len + 1]; + digits[0] = 1; + return digits; + } +} diff --git a/Week 01/id_326/LeetCode_21_326.java b/Week 01/id_326/LeetCode_21_326.java new file mode 100644 index 000000000..5e47cd29e --- /dev/null +++ b/Week 01/id_326/LeetCode_21_326.java @@ -0,0 +1,39 @@ + +/** + * Description: 21. 合并两个有序链表 + * 将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 + * + * @author qinxue + * @date 2019-10-20 21:54:49 + */ + +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode(int x) { val = x; } + * } + */ +class Solution { + public ListNode mergeTwoLists(ListNode l1, ListNode l2) { + // 构造一个哨兵节点 + ListNode head = new ListNode(Integer.MIN_VALUE); + // 最开始prev指针指向哨兵节点 + ListNode prev = head; + 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 = prev.next; + } + prev.next = l1 == null ? l2 : l1; + + return head.next; + } +} \ No newline at end of file diff --git a/Week 01/id_326/LeetCode_283_326.java b/Week 01/id_326/LeetCode_283_326.java new file mode 100644 index 000000000..6996886c0 --- /dev/null +++ b/Week 01/id_326/LeetCode_283_326.java @@ -0,0 +1,26 @@ + +/** + * Description: 283.移动零 + * 给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。 + * 说明: + * 1、必须在原数组上操作,不能拷贝额外的数组。 + * 2、尽量减少操作次数。 + * + * @author qinxue + * @date 2019-10-20 21:50:31 + */ +class Solution { + public void moveZeroes(int[] nums) { + // leftMostZeroIndex永远都指向数组最左边的为零的元素的index + int leftMostZeroIndex = 0; + for (int i = 0; i < nums.length; i++) { + if (nums[i] != 0) { + if (i > leftMostZeroIndex) { + nums[leftMostZeroIndex] = nums[i]; + nums[i] = 0; + } + leftMostZeroIndex++; + } + } + } +} \ No newline at end of file diff --git a/Week 01/id_331/LeetCode_21_331.java b/Week 01/id_331/LeetCode_21_331.java new file mode 100644 index 000000000..f07e20ec8 --- /dev/null +++ b/Week 01/id_331/LeetCode_21_331.java @@ -0,0 +1,33 @@ +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode(int x) { val = x; } + * } + */ +class Solution { + public ListNode mergeTwoLists(ListNode l1, ListNode l2) { + //定义一个哨兵结点,默认值为-1 + ListNode prehead = new ListNode(-1); + + //指向哨兵结点 + ListNode prev = prehead; + + 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 prehead.next; + } +} \ No newline at end of file diff --git a/Week 01/id_331/LeetCode_26_331.java b/Week 01/id_331/LeetCode_26_331.java new file mode 100644 index 000000000..695868d36 --- /dev/null +++ b/Week 01/id_331/LeetCode_26_331.java @@ -0,0 +1,17 @@ +class Solution { + + public int removeDuplicates(int[] nums) { + + if (nums.length == 0 || nums == null) return 0; + + int i = 0; + for (int j = 1; j < nums.length; j++) { + if (nums[j] != nums[i]) { + i++; + nums[i] = nums[j]; + } + } + + return i + 1; + } +} \ No newline at end of file diff --git a/Week 01/id_331/NOTE.md b/Week 01/id_331/NOTE.md index a6321d6e2..506f88cde 100644 --- a/Week 01/id_331/NOTE.md +++ b/Week 01/id_331/NOTE.md @@ -1,4 +1,118 @@ -# NOTE +/** + * java 13 new api Deque + * @author hemiao + * @date 2019-10-20 18:00 + */ +public class NewDeque { + public static void main(String[] args) { + + Deque deque = new LinkedList(); + deque.addFirst("a"); + deque.addFirst("b"); + deque.addFirst("c"); + + System.out.println(deque); + + String str = deque.peekFirst(); + System.out.println(str); + System.out.println(deque); + + while (deque.size() > 0) { + System.out.println(deque.pollFirst()); + } + System.out.println(deque); + + } + +} + + +Queue 队列源码分析 + 特性 + 1.通常但不一定是先进先出(FIFO) + 2.不允许插入null,因为null已经作为poll方法的返回值,表示当前队列为空 + + add() 添加元素 + 1.成功返回true,失败返回异常 + 2.IllegalStateException:队列容量已满时添加元素,抛出异常 + 3.ClassCastException:添加的元素与队列的指定的类型不匹配时,抛出异常 + 4.IllegalArgumentException:添加元素中含有非法参数时,抛出异常 + 5.NullPointerException:添加的元素为null时,抛出异常 + + offer() 添加元素 + 1.成功返回true + 2.ClassCastException:添加的元素与队列的指定的类型不匹配时,抛出异常 + 3.IllegalArgumentException:添加元素中含有非法参数时,抛出异常 + 4.NullPointerException:添加的元素为null时,抛出异常 + + remove() 删除头元素 + 1.成功返回删除的元素,失败返回异常 + 2.NoSuchElementException:当队列为空时,弹出元素,抛出异常 + + poll() 删除头元素 + 1.成功返回删除的元素,当队列为空时,弹出null + + element() 检索头元素 + 1.成功返回删除的元素,失败返回异常 + 2.NoSuchElementException:当队列为空时,弹出元素,抛出异常 + + peek() 检索头元素 + 1.成功返回删除的元素,失败返回null + + +PriorityQueue 优先队列源码分析 + 特性 + 1.基于优先级取出,默认为自然顺序如输入:53214,输出:12345 + 2.线程不安全,如考虑线程安全,使用PriorityBlockingQueue类 + 3.可自定义排序规则,使用带Comparator类的构造器即可 + + comparator() 指定优先级,根据元素中的属性进行排序的比较器 + + add()/offer() 添加元素 + 1.成功返回true,失败抛异常 + 2.NullPointerException:添加的元素为null时,抛出异常 + 3.IllegalArgumentException:添加元素中含有非法参数时,抛出异常,即添加的元素与队列中的元素不能比较的时候 + + poll() 弹出元素 + 1.成功返回删除的元素,当队列为空时,弹出null + peek() 检索头元素 + 1.成功返回删除的元素,失败返回null + + remove/removeEq/removeAll 删除指定元素/集合中的元素 + + clear() 清空元素 + + size() 队列长度 + + contains​(Object o) 是否包含指定元素 + + +学习总结 + + 中心思想:升维思想空间换时间 + 最大误区:刷题只刷一遍 + + 1.数组、链表、跳表 + 空间复杂度 + 数组:插入和删除是O(n) + 链表: 查询时O(n) + 跳表: O(logn) + 实现 + 查看Java 源码 + + 题目解析 + 前后指针,i,j双指针重点,需会默写 + 左右边界,i,j双指针,j==list.length()-1重点,需会默写 + + 2.栈、队列、优先队列、双端队列 + 空间复杂度 + 栈:先入后出;添加、删除皆为O(1) + 队列:先入先出;添加、删除皆为O(1) + 双端队列:两端都可以进出的队列;添加、删除皆为O(1) + 优先队列:按照元素优先级取出;添加为O(1),删除为O(logn) + + 实现 + 查看Java源码 \ No newline at end of file diff --git a/Week 01/id_336/LeetCode_336_189.js b/Week 01/id_336/LeetCode_336_189.js new file mode 100644 index 000000000..3c7af0782 --- /dev/null +++ b/Week 01/id_336/LeetCode_336_189.js @@ -0,0 +1,54 @@ +// 解法一: + // 暴力枚举 + // 时间复杂度 O(n * k) 如果k == n && n很大 后果严重 + // 空间复杂度 O(1) + var rotate = function(nums, k) { + var n = nums.length; + var tmpEnd = 0; + var tmpPrev = 0; + for(var i = 0;i [4,5,6,7] + [1,2,3] == [4,5,6,7,1,2,3] + // [1,2,3,4,5,6,7] k = 11 => [4,5,6,7] + [1,2,3] == [4,5,6,7,1,2,3] + // [1,2,3,4,5,6,7] k = 5 => [3,4,5,6,7] +[1,2] == [3,4,5,6,7,1,2] + // 由示例可以归纳出 k%n == 后面面 n - k%n 个元素 和 前面 k%n 个元素中间交界处 重新组合成一个新的数组的分界点,此点处整体调换两部分的数组即为所求 + var rotate = function(nums, k) { + var n = nums.length; + var reversePoint = n - k%n; + reversePoint != 0 && (nums = nums.slice(reversePoint).concat(nums.slice(0,reversePoint))) + } + +// 解法三: + // 原地反转 + // 时间复杂度 O(n) 反转了3次n个元素 + // 空间复杂度 O(1) 没使用额外的空间 + var rotate = function(nums, k) { + var n = nums.length; + k %= n; + if(n == 1){ + return; + } + var tmp = 0; + myReverse(0,n-1); + myReverse(0,k-1); + myReverse(k,n-1); + function myReverse(start,end) { + while (start < end) { + tmp = nums[start]; + nums[start] = nums[end]; + nums[end] = tmp; + start++; + end--; + } + } + } \ No newline at end of file diff --git a/Week 01/id_336/LeetCode_336_26.js b/Week 01/id_336/LeetCode_336_26.js new file mode 100644 index 000000000..dad026438 --- /dev/null +++ b/Week 01/id_336/LeetCode_336_26.js @@ -0,0 +1,34 @@ +// 解法一: + /** + * @param {number[]} nums + * @return {number} + */ + var removeDuplicates = function(nums) { + var count = 0; + var n = nums.length; + for(let i = 1;inew_node->next = p->next; + p->next = new_node; + + 删除链表结点时,记得手动释放内存空间 + > p->next = p->next->next; + + 不用哨兵结点插入首结点、删除尾结点 + > if (head == null) { + head = new_node; + } + >if (head->next == null) { + head = null; + } + + 利用哨兵简化实现难度 + + 头结点为哨兵结点 + + 重点留意边界条件处理 + + 举例画图,辅助思考 + + 多写多练 ++ 常考题 + + 单链表反转 + + 链表中环的检测 + + 两个有序的链表合并 + + 删除链表倒数第n个结点 ++ 经典应用场景 + + LRU 缓存淘汰算法 ++ 缓存 + + 是一种提高数据读取性能的技术 + + 常见策略 + + LFU(Least Frequently Used) 最少使用策略 + + LRU(Least Recently Used) 最近最少使用策略 ++ 常用链表结构 + + 单链表 + + 插入与删除 + + 循环链表 + + 是一种特殊的单链表 + + 典型应用 + + 约瑟夫问题 + + 双链表 + + 双向循环链表 +#### 栈 ++ 是一种受限的线性表 ++ 先进后出 ++ 表现 + + 数组实现叫 顺序栈 + + 链表实现叫 链式栈 ++ 应用 + + 函数调用 + ```java + int main() { + int a = 1; + int ret = 0; + int res = 0; + ret = add(3, 5); + res = a + ret; + printf("%d", res); + reuturn 0; + } + int add(int x, int y) { + int sum = 0; + sum = x + y; + return sum; + } + ``` + + 表达式求值 + >34+13*9+44-12/3 + + 括号匹配 + + 用栈来保存未匹配的左括号,从左到右依次扫描字符串。当扫描到左括号时,则将其压入栈中; + + 当扫描到右括号时,从栈顶取出一个左括号。 + + 如果能够匹配,比如“(”跟“)”匹配,“[”跟“]”匹配,“{”跟“}”匹配,则继续扫描剩下的字符串。 + + 如果扫描的过程中,遇到不能配对的右括号,或者栈中没有数据,则说明为非法格式。 + + 浏览器前进后退功能 +#### 队列 ++ 是一种操作受限的线性表 ++ 先进先出 ++ 与栈区分 + + 栈只需维护一个 栈顶指针 + + 队列需要维护两个指针 + + 队首 Head 永远指向队首元素索引位置 + + 队尾 Tail 永远指向队尾元素下一个索引位置 ++ 表现 + + 用数组实现的队列叫 顺序队列 + + 用链表实现的队列叫 链式队列 ++ 循环队列 + + 队空 + + tail == head + + 队满 + + (tail+1)%n == head + ```java + public class CircularQueue { + // 数组:items,数组大小:n + private String[] items; + private int n = 0; + // head 表示队头下标,tail 表示队尾下标 + private int head = 0; + private int tail = 0; + + // 申请一个大小为 capacity 的数组 + public CircularQueue(int capacity) { + items = new String[capacity]; + n = capacity; + } + // 入队 + public boolean enqueue(String item) { + // 队列满了 + if ((tail + 1) % n == head) return false; + items[tail] = item; + tail = (tail + 1) % n; + return true; + } + // 出队 + public String dequeue() { + // 如果 head == tail 表示队列为空 + if (head == tail) return null; + String ret = items[head]; + head = (head + 1) % n; + return ret; + } + } + ``` ++ 阻塞队列 + + 在队列的基础上增加阻塞操作 + + 应用 + + 生产者 - 消费者 模型 ++ 并发队列 + + 线程安全的队列 + + 最简单直接的实现方式是直接在 enqueue()、dequeue() 方法上加锁,但是锁粒度大并发度会比较低,同一时刻仅允许一个存或者取操作。 + + 实际上,基于数组的循环队列,利用 CAS 原子操作,可以实现非常高效的并发队列。这也是循环队列比链式队列应用更加广泛的原因。 + + 实现无锁并发队列 + + cas + 数组 ++ 其它应用 + + 分布式应用中的消息队列 如 kafka diff --git a/Week 01/id_346/ClimbStairs_70.java b/Week 01/id_346/ClimbStairs_70.java new file mode 100644 index 000000000..6ad74740f --- /dev/null +++ b/Week 01/id_346/ClimbStairs_70.java @@ -0,0 +1,26 @@ +package com.yiche; + +/** + * @auther: TKQ + * @Title: ClimbStairs_70 + * @Copyright: Copyright (c) 2019 + * @Description: + * @Company: + * @Created: 2019-10-20 17:25 + */ +public class ClimbStairs_70 { + public int climbStairs(int n) { + if(n == 1){ + return 1; + } + int[] dp = new int[n]; + dp[0] = 1; + dp[1] = 2; + for (int i = 2; i < dp.length; i++) { + dp[i] = dp[i - 1] + dp[i - 2]; + } + return dp[n - 1]; + } +} +//runtime:0 ms +//memory:32.8 MB diff --git a/Week 01/id_346/InvertTree_226.java b/Week 01/id_346/InvertTree_226.java new file mode 100644 index 000000000..42df6b098 --- /dev/null +++ b/Week 01/id_346/InvertTree_226.java @@ -0,0 +1,31 @@ +package com.yiche; + +/** + * @auther: TKQ + * @Title: InvertTree_226 + * @Copyright: Copyright (c) 2019 + * @Description: + * @Company: + * @Created: 2019-10-20 17:30 + */ +public class InvertTree_226 { + public TreeNode invertTree(TreeNode root) { + if(root==null){ + return root; + } + TreeNode temp = root.left ; + root.left = root.right; + root.right = temp; + invertTree(root.left);invertTree(root.right); + return root; + } + + public class TreeNode { + int val; + TreeNode left; + TreeNode right; + TreeNode(int x) { val = x; } + } +} +//runtime:0 ms +//memory:34.2 MB diff --git a/Week 01/id_346/MaxArea_11.java b/Week 01/id_346/MaxArea_11.java new file mode 100644 index 000000000..c544648d5 --- /dev/null +++ b/Week 01/id_346/MaxArea_11.java @@ -0,0 +1,28 @@ +package com.yiche.mapi; + +/** + * @auther: TKQ + * @Title: MaxArea_11 + * @Copyright: Copyright (c) 2019 + * @Description: + * @Company: + * @Created: 2019-10-20 17:16 + */ +public class MaxArea_11 { + public int maxArea(int[] height) { + int maxArea = 0; + for (int leftIndex = 0, rightIndex = height.length - 1; leftIndex < rightIndex; ) { + int currentArea = (rightIndex-leftIndex)*Math.min(height[leftIndex],height[rightIndex]); + maxArea = Math.max(maxArea,currentArea); + if(height[leftIndex]<=height[rightIndex]){ + leftIndex++; + }else{ + rightIndex--; + } + } + return maxArea; + } +} + +//runtime:4 ms +//memory:39.5 MB diff --git a/Week 01/id_346/MergeTwoLists_21.java b/Week 01/id_346/MergeTwoLists_21.java new file mode 100644 index 000000000..575c105cd --- /dev/null +++ b/Week 01/id_346/MergeTwoLists_21.java @@ -0,0 +1,36 @@ +package com.yiche.mapi; + +/** + * @auther: TKQ + * @Title: MergeTwoLists_21 + * @Copyright: Copyright (c) 2019 + * @Description: + * @Company: + * @Created: 2019-10-20 17:23 + */ +public class MergeTwoLists_21 { + public ListNode mergeTwoLists(ListNode l1, ListNode l2) { + if (l1 == null) { + return l2; + } else if (l2 == null) { + return l1; + } else if (l1.val <= l2.val) { + l1.next = mergeTwoLists(l1.next, l2); + return l1; + } else { + l2.next = mergeTwoLists(l2.next, l1); + return l2; + } + } + + public class ListNode { + int val; + ListNode next; + + ListNode(int x) { + val = x; + } + } +} +//runtime:0 ms +//memory:37.7 MB diff --git a/Week 01/id_346/Merge_88.java b/Week 01/id_346/Merge_88.java new file mode 100644 index 000000000..d3d03b339 --- /dev/null +++ b/Week 01/id_346/Merge_88.java @@ -0,0 +1,27 @@ +package com.yiche; + +/** + * @auther: TKQ + * @Title: Merge_88 + * @Copyright: Copyright (c) 2019 + * @Description: + * @Company: + * @Created: 2019-10-20 17:27 + */ +public class Merge_88 { + public void merge(int[] nums1, int m, int[] nums2, int n) { + int i = m-1;int j = n-1;int k = m+n-1; + while(i>=0&&j>=0){ + if(nums1[i]<=nums2[j]){ + nums1[k--]= nums2[j--]; + }else{ + nums1[k--]= nums1[i--]; + } + } + while(j>=0){ + nums1[k--] = nums2[j--]; + } + } +} +//runtime:0 ms +//memory:36.1 MB diff --git a/Week 01/id_346/MoveZeroes_283.java b/Week 01/id_346/MoveZeroes_283.java new file mode 100644 index 000000000..5bfd49948 --- /dev/null +++ b/Week 01/id_346/MoveZeroes_283.java @@ -0,0 +1,27 @@ +package com.yiche; + +/** + * @auther: TKQ + * @Title: MoveZeroes_283 + * @Copyright: Copyright (c) 2019 + * @Description: + * @Company: + * @Created: 2019-10-20 17:32 + */ +public class MoveZeroes_283 { + public void moveZeroes(int[] nums) { + int zeroCount = 0; + for (int i = 0; i < nums.length; i++) { + if (nums[i] == 0) { + zeroCount++; + } else { + if (zeroCount > 0) { + nums[i - zeroCount] = nums[i]; + nums[i] = 0; + } + } + } + } +} +//runtime:0 ms +//memory:37.6 MB \ No newline at end of file diff --git a/Week 01/id_346/NOTE.md b/Week 01/id_346/NOTE.md index a6321d6e2..070172170 100644 --- a/Week 01/id_346/NOTE.md +++ b/Week 01/id_346/NOTE.md @@ -1,4 +1,5 @@ # NOTE - +一周下来唯一的感受就是, +自己的智商受到了压制!!! diff --git a/Week 01/id_346/PlusOne_66.java b/Week 01/id_346/PlusOne_66.java new file mode 100644 index 000000000..6431ce5cc --- /dev/null +++ b/Week 01/id_346/PlusOne_66.java @@ -0,0 +1,27 @@ +package com.yiche.mapi.cargoods; + +/** + * @auther: TKQ + * @Title: PlusOne_66 + * @Copyright: Copyright (c) 2019 + * @Description: + * @Company: + * @Created: 2019-10-20 17:24 + */ +public class PlusOne_66 { + public int[] plusOne(int[] digits) { + int len = digits.length; + for(int i = len-1;i>=0;i--){ + digits[i]++; + digits[i]= digits[i]%10; + if(digits[i]!=0){ + return digits; + } + } + int[] result = new int[len+1]; + result[0] = 1; + return result; + } +} +//runtime:0 ms +//memory:35 MB diff --git a/Week 01/id_346/RemoveDuplicates_26.java b/Week 01/id_346/RemoveDuplicates_26.java new file mode 100644 index 000000000..d215d5e42 --- /dev/null +++ b/Week 01/id_346/RemoveDuplicates_26.java @@ -0,0 +1,61 @@ +//给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。 +// +// 不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。 +// +// 示例 1: +// +// 给定数组 nums = [1,1,2], +// +//函数应该返回新的长度 2, 并且原数组 nums 的前两个元素被修改为 1, 2。 +// +//你不需要考虑数组中超出新长度后面的元素。 +// +// 示例 2: +// +// 给定 nums = [0,0,1,1,1,2,2,3,3,4], +// +//函数应该返回新的长度 5, 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4。 +// +//你不需要考虑数组中超出新长度后面的元素。 +// +// +// 说明: +// +// 为什么返回数值是整数,但输出的答案是数组呢? +// +// 请注意,输入数组是以“引用”方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。 +// +// 你可以想象内部操作如下: +// +// // nums 是以“引用”方式传递的。也就是说,不对实参做任何拷贝 +//int len = removeDuplicates(nums); +// +//// 在函数里修改输入数组对于调用者是可见的。 +//// 根据你的函数返回的长度, 它会打印出数组中该长度范围内的所有元素。 +//for (int i = 0; i < len; i++) { +//    print(nums[i]); +//} +// +// Related Topics 数组 双指针 + + + +//leetcode submit region begin(Prohibit modification and deletion) +class RemoveDuplicates_26 { + public int removeDuplicates(int[] nums) { + if(nums == null){ + return 0; + } + if(nums.length<2){ + return nums.length; + } + int i = 0; + for(int j = 1;j> threeSum(int[] nums) { + Arrays.sort(nums); + List> result = new ArrayList<>(); + for (int i = 0; i < nums.length-2; i++) { + if(nums[i] > 0){ break;} + if(i>0&&nums[i]==nums[i-1]){continue;} + for(int l = i+1,r = nums.length-1;l0){ + r--; + }else if(sum <0){ + l++; + }else{ + result.add(Arrays.asList(nums[i],nums[l],nums[r])); + while(l0){ + let t = nums[i]; + nums[i]=0; + nums[i-snowBallSize]=t; + } + } +}; + + diff --git a/Week 01/id_361/leetCode_42_361.js b/Week 01/id_361/leetCode_42_361.js new file mode 100644 index 000000000..0391142e4 --- /dev/null +++ b/Week 01/id_361/leetCode_42_361.js @@ -0,0 +1,43 @@ +//42 Trapping Rain Water +// 此题困扰很久,思路都很接近,就是解不出,对细节的理解需要加强 +/** + * Method 1 direct + * @param {number[]} height + * @return {number} + */ +let trap = function(height) { + let ans = 0; + let size = height.length; + for (let i = 1; i < size - 1; i++) { + let max_left = 0, max_right = 0; + for (let j = i; j >= 0; j--) { //Search the left part for max bar size + max_left = Math.max(max_left, height[j]); + } + for (let j = i; j < size; j++) { //Search the right part for max bar size + max_right = Math.max(max_right, height[j]); + } + ans += Math.min(max_left, max_right) - height[i]; + } + return ans; +}; +/** + * Method 1 double pointer + * @param {number[]} height + * @return {number} + */ +let trap = function(height) { + let left = 0, right = height.length - 1; + let ans = 0; + let left_max = 0, right_max = 0; + while (left < right) { + if (height[left] < height[right]) { + height[left] >= left_max ? (left_max = height[left]) : ans += (left_max - height[left]); + ++left; + } + else { + height[right] >= right_max ? (right_max = height[right]) : ans += (right_max - height[right]); + --right; + } + } + return ans; +}; diff --git a/Week 01/id_366/Leetcode_189_366.java b/Week 01/id_366/Leetcode_189_366.java new file mode 100644 index 000000000..95b918b8c --- /dev/null +++ b/Week 01/id_366/Leetcode_189_366.java @@ -0,0 +1,25 @@ +import java.util.Arrays; + +/* + * @lc app=leetcode.cn id=189 lang=java + * + * [189] 旋转数组 + */ + +// @lc code=start +class Solution { + public void rotate(int[] nums, int k) { + // for (int i = nums.length - 1; i >= 0; i--) { + // int index = (i + k) % nums.length; + // } + int[] res = new int[nums.length]; + int index = 0; + for (int i = nums.length - 1; i >= 0; i--) { + index = (i + k) % nums.length; + res[index] = nums[i]; + } + System.arraycopy(res, 0, nums, 0, res.length); + } +} +// @lc code=end + diff --git a/Week 01/id_366/Leetcode_1_366.java b/Week 01/id_366/Leetcode_1_366.java new file mode 100644 index 000000000..4760f92a7 --- /dev/null +++ b/Week 01/id_366/Leetcode_1_366.java @@ -0,0 +1,21 @@ +/* + * @lc app=leetcode.cn id=1 lang=java + * + * [1] 两数之和 + */ + +// @lc code=start +class Solution { + public int[] twoSum(int[] nums, int target) { + Map map = new HashMap<>(); + for (int i = 0; i < nums.length; i++){ + if (map.containsKey(target-nums[i])) { + return new int[] {map.get(target-nums[i]), i}; + } + map.put(nums[i],i); + } + throw new IllegalArgumentException("No solution"); + } +} +// @lc code=end + diff --git a/Week 01/id_366/Leetcode_283_366.java b/Week 01/id_366/Leetcode_283_366.java new file mode 100644 index 000000000..703bcd7fc --- /dev/null +++ b/Week 01/id_366/Leetcode_283_366.java @@ -0,0 +1,24 @@ +/* + * @lc app=leetcode.cn id=283 lang=java + * + * [283] 移动零 + */ + +// @lc code=start +class Solution { + public void moveZeroes(int[] nums) { + int count = 0; + for (int i = 0; i < nums.length; i++) { + if (nums[i] != 0 ) { + nums[count] = nums[i]; + count++; + } + } + for (; count < nums.length; count++) { + nums[count] = 0; + } + + } +} +// @lc code=end + diff --git a/Week 01/id_371/LeetCode_189_371.java b/Week 01/id_371/LeetCode_189_371.java new file mode 100644 index 000000000..f99a4637f --- /dev/null +++ b/Week 01/id_371/LeetCode_189_371.java @@ -0,0 +1,66 @@ +import java.util.Arrays; + +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-10-15 11:39 + **/ + +public class LeetCode_189_371 { + + public static void main(String[] args) { +// int[] nums = {1, 2, 3, 4, 5, 6, 7}; + int[] nums = {1, 2}; + int k = 3; +// rotate(nums, k); + rotate1(nums, k); + } + + /** + * 暴力法, 每次走一步 + */ + public static void rotate(int[] nums, int k) { + if (nums.length <= 1) { + return; + } + k %= nums.length; + while (k-- > 0) { + int temp = nums[nums.length - 1]; + for (int i = nums.length - 1; i > 0; i--) { + nums[i] = nums[i - 1]; + } + nums[0] = temp; + } + for (int i = 0; i < nums.length; i++) { + System.out.println("nums = " + nums[i]); + } + } + + /** + * 三次数组反转 + */ + public static void rotate1(int[] nums, int k) { + if (nums.length <= 1) { + return; + } + k %= nums.length; + reverseArray(nums, 0, nums.length - 1); + reverseArray(nums, 0, k - 1); + reverseArray(nums, k , nums.length - 1); + Arrays.stream(nums).forEach(System.out::println); + } + + /** + * 将数组中的一段反转 + */ + private static int[] reverseArray(int[] nums, int start, int end) { + while (start < end) { + int temp = nums[end]; + nums[end--] = nums[start]; + nums[start++] = temp; + } + return nums; + } + +} diff --git a/Week 01/id_371/LeetCode_1_371.java b/Week 01/id_371/LeetCode_1_371.java new file mode 100644 index 000000000..3f69a7989 --- /dev/null +++ b/Week 01/id_371/LeetCode_1_371.java @@ -0,0 +1,49 @@ +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-10-19 22:02 + **/ + +public class LeetCode_1_371 { + + public static void main(String[] args) { +// int[] nums = {2, 7, 11, 15}; + int[] nums = {3,2,4}; + int target = 6; + int[] twoSum = twoSum1(nums, target); + Arrays.stream(twoSum).forEach(System.out::println); + + } + public static int[] twoSum(int[] nums, int target) { + //遍历数组,将数组元素相加和目标值比较 + for (int i = 0; i < nums.length - 1; i++) { + for (int j = i + 1; j < nums.length; j++) { + if (nums[i] + nums[j] == target) { + return new int[]{i, j}; + } + } + } + return null; + } + + public static int[] twoSum1(int[] nums, int target) { + Map map = new HashMap<>(); + //遍历数组,将数组元素相加和目标值比较 + for (int i = 0; i < nums.length; i++) { + //判断当前元素能组成 target,不能存入 map,可以返回 + int key = target - nums[i]; + if (map.containsKey(key)) { + return new int[]{map.get(key), i}; + } else { + map.put(nums[i], i); + } + } + return null; + } + +} diff --git a/Week 01/id_371/LeetCode_21_371.java b/Week 01/id_371/LeetCode_21_371.java new file mode 100644 index 000000000..1c9d8b23e --- /dev/null +++ b/Week 01/id_371/LeetCode_21_371.java @@ -0,0 +1,86 @@ +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-10-15 20:16 + **/ + +public class LeetCode_21_371 { + class ListNode { + public ListNode() { + } + + public ListNode(int val) { + this.val = val; + } + + int val; + ListNode next; + } + + public ListNode mergeTwoLists1(ListNode l1, ListNode l2) { + //1.设置前置节点,方便返回链表 + //preHead节点不变 + ListNode head = new ListNode(-1); + + //通过tail节点来记录新链表的尾部 + ListNode tail = head; + + //2.遍历两个链表 + while (l1 != null && l2 != null) { + if (l1.val <= l2.val) { + tail.next = l1; + l1 = l1.next; + } else { + tail.next = l2; + l2 = l2.next; + } + tail = tail.next; + } + + //3.将剩下没有遍历的链表指向新链表的尾部 + tail.next = l1 == null ? l2 : l1; + + return head.next; + } + + + /** + * 原始解,没解完 + * 原因:对链表的理解没透彻,只想到一个一个节点读链表,而忘记链表最大的优势就是改变指针指向来完成数据交互 + * @return + */ + public ListNode mergeTwoLists(ListNode l1, ListNode l2) { + //1.新建一个链表 + ListNode newNode = new ListNode(); + //2.同时读读两个链表,谁小用谁 + while (l1.next != null && l2.next != null) { + if (l1.val <= l2.val) { + newNode.val = l1.val; + l1 = l1.next; + } else { + newNode.val = l2.val; + l2 = l2.next; + } + newNode = newNode.next; + } + if (l1.next == null) { + + while (l2.next != null) { + newNode.val = l2.val; + newNode = newNode.next; + } + + + } + while (l1.next != null) { + newNode.val = l1.val; + newNode = newNode.next; + } + + + return newNode; + } + + +} diff --git a/Week 01/id_371/LeetCode_26_371.java b/Week 01/id_371/LeetCode_26_371.java new file mode 100644 index 000000000..477bf2012 --- /dev/null +++ b/Week 01/id_371/LeetCode_26_371.java @@ -0,0 +1,35 @@ +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-10-15 10:52 + **/ + +public class LeetCode_26_371 { + + public static void main(String[] args) { + //1.定义一个数组 + int[] nums = {0, 0, 1, 1, 1, 2, 2, 3, 3, 4}; + //2.将数组去重,返回去重后的数组的长度 + int newLen = removeDuplicates(nums); + + } + + private static int removeDuplicates(int[] nums) {//双指针法 + //0.边界值处理 + if (nums.length <= 1) { + return nums.length; + } + //1.定义一个指针i,保存不重复元素的位置 + int i = 0; + //2.定义一个指针j,保存遍历到的元素位置 + for (int j = 1; j < nums.length; j++) { + //3.比较 + if (nums[j] > nums[i]) { + //4.交换 + nums[++i] = nums[j]; + } + } + return i + 1; + } +} diff --git a/Week 01/id_371/LeetCode_283_371.java b/Week 01/id_371/LeetCode_283_371.java new file mode 100644 index 000000000..2e67664e0 --- /dev/null +++ b/Week 01/id_371/LeetCode_283_371.java @@ -0,0 +1,46 @@ +import java.util.Arrays; + +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-10-20 07:50 + **/ + +public class LeetCode_283_371 { + public static void main(String[] args) { + // 必须在原数组上操作,不能拷贝额外的数组。 + // 尽量减少操作次数。 + int[] nums = {0, 1, 0, 3, 12};//[1,3,12,0,0] 1,0,0,3,12 ==> 1,3,0,0,12 + moveZeroes(nums); + Arrays.stream(nums).forEach(System.out::println); + } + + public static void moveZeroes(int[] nums) { + //一个指针当前为零的元素(将要被交换的元素),一个指针指向当前遍历到到的元素 + int needSwapIndex = -1; + //等待被交换的0元素的个数,用来确定下一个被交换元素的索引 + int num = 0; + for (int i = 0; i < nums.length; i++) { + if (needSwapIndex < 0 && nums[i] == 0) { + needSwapIndex = i; + num++; + } else if (needSwapIndex >= 0 && nums[i] != 0) { + swap(nums, needSwapIndex, i); + num--; + if (i - needSwapIndex > 1 && num > 0) { + needSwapIndex = i; + } else { + needSwapIndex++; + } + } + } + } + + public static void swap(int[] nums, int needSwapIndex, int i) { + int temp = nums[i]; + nums[needSwapIndex] = nums[i]; + nums[i] = 0; + + } +} diff --git a/Week 01/id_371/LeetCode_42_371.java b/Week 01/id_371/LeetCode_42_371.java new file mode 100644 index 000000000..e2facf824 --- /dev/null +++ b/Week 01/id_371/LeetCode_42_371.java @@ -0,0 +1,75 @@ +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-10-20 10:52 + **/ + +public class LeetCode_42_371 { + + public static void main(String[] args) { + int[] height = {0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1}; + int trap = trap(height); + System.out.println("trap = " + trap); + } + + /** + * 暴力法(背向双指针) + * + * @return + * @思路: 每个宽度为1的区间能接水面积=(向左的最大高度和向右的最大高度中取较小值-当前区间的高度),将所有区间接水量相加,即总接水量 + */ + public static int trap(int[] height) { + if (height.length <= 1) { + return 0; + } + int ans = 0; + for (int i = 1; i < height.length - 1; i++) { + int leftMax = 0; + int rightMax = 0; + //从当前索引位置向左扫描 + for (int j = i; j > 0; j--) { + leftMax = Math.max(leftMax, height[j]); + } + //从当前索引位置向右扫描 + for (int j = i; j < height.length; j++) { + rightMax = Math.max(rightMax, height[j]); + } + ans += Math.min(leftMax, rightMax) - height[i]; + } + return ans; + } + + /** + * 针对暴力法的优化 + * + * @param height + * @return + */ + public static int trap1(int[] height) { + if (height.length <= 1) { + return 0; + } + int ans = 0; + int size = height.length; + int[] leftMax = new int[size]; + int[] rightMax = new int[size]; + //leftMax一直是向左边比较,所以先确定leftMax[0],往右遍历时每次只需要比较依次就能确定当前位置的 leftMax ==>rightMax的确定正好相反 + leftMax[0] = height[0]; + //用数组记录下每个位置的 leftMax + for (int i = 1; i < height.length; i++) { + leftMax[i] = Math.max(leftMax[i - 1], height[i]); + } + rightMax[size - 1] = height[size - 1]; + for (int i = size - 2; i >= 0; i--) { + rightMax[i] = Math.max(rightMax[i + 1], height[i]); + } + //用数组记录下每个位置的 rightMax + for (int i = 0; i < size; i++) { + ans += Math.min(leftMax[i], rightMax[i]) - height[i]; + } + return ans; + } + + +} diff --git a/Week 01/id_371/LeetCode_641_371.java b/Week 01/id_371/LeetCode_641_371.java new file mode 100644 index 000000000..338824e46 --- /dev/null +++ b/Week 01/id_371/LeetCode_641_371.java @@ -0,0 +1,129 @@ +import java.util.Stack; + +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-10-20 09:16 + **/ + +public class LeetCode_641_371 { + + //通过两个栈实现双端队列 + class MyCircularDeque { + Stack head; + Stack tail; + int size; + + /** + * Initialize your data structure here. Set the size of the deque to be k. + */ + public MyCircularDeque(int k) { + head = new Stack<>(); + tail = new Stack<>(); + this.size = k; + } + + /** + * Adds an item at the front of Deque. Return true if the operation is successful. + */ + public boolean insertFront(int value) { + if (!isFull()) { + head.push(value); + return true; + } + return false; + } + + /** + * Adds an item at the rear of Deque. Return true if the operation is successful. + */ + public boolean insertLast(int value) { + if (!isFull()) { + tail.push(value); + return true; + } + return false; + } + + /** + * Deletes an item from the front of Deque. Return true if the operation is successful. + */ + public boolean deleteFront() { + if (head.isEmpty()) { + while (!tail.isEmpty()) { + head.push(tail.pop()); + } + } + if (head.isEmpty()) { + return false; + } else { + head.pop(); + return true; + } + } + + /** + * Deletes an item from the rear of Deque. Return true if the operation is successful. + */ + public boolean deleteLast() { + if (tail.isEmpty()) { + while (!head.isEmpty()) { + tail.push(head.pop()); + } + } + if (tail.isEmpty()) { + return false; + } else { + tail.pop(); + return true; + } + } + + /** + * Get the front item from the deque. + */ + public int getFront() { + if (head.isEmpty()) { + while (!tail.isEmpty()) { + head.push(tail.pop()); + } + } + if (head.isEmpty()) { + return -1; + } else { + return head.peek(); + } + } + + /** + * Get the last item from the deque. + */ + public int getRear() { + if (tail.isEmpty()) { + while (!head.isEmpty()) { + tail.push(head.pop()); + } + } + if (tail.isEmpty()) { + return -1; + } else { + return tail.peek(); + } + } + + /** + * Checks whether the circular deque is empty or not. + */ + public boolean isEmpty() { + return head.isEmpty() && tail.isEmpty(); + } + + /** + * Checks whether the circular deque is full or not. + */ + public boolean isFull() { + return head.size() + tail.size() >= size; + } + } +} diff --git a/Week 01/id_371/LeetCode_66_273.java b/Week 01/id_371/LeetCode_66_273.java new file mode 100644 index 000000000..28de13bad --- /dev/null +++ b/Week 01/id_371/LeetCode_66_273.java @@ -0,0 +1,43 @@ +import java.util.Arrays; + +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-10-20 08:58 + **/ + +public class LeetCode_66_273 { + public static void main(String[] args) { +// int[] nums = {9, 9, 9}; // 1,0,0,0 + int[] nums = {8, 9, 9}; // 1,0,0,0 + int[] newArr = plusOne(nums); + Arrays.stream(newArr).forEach(System.out::println); + + } + + public static int[] plusOne(int[] digits) { + //从后往前遍历,遇9就设为0,非9元素+1,跳出循环,全是9长度加1 + for (int i = digits.length - 1; i >= 0; i--) { + if (digits[i] == 9) { + digits[i] = 0; + if (i == 0) { + return incrArray(digits.length + 1); + } + } else { + digits[i]++; + break; + } + } + return digits; + } + + public static int[] incrArray(int k) { + int[] newArray = new int[k]; + newArray[0] = 1; + for (int i = 1; i < k; i++) { + newArray[i] = 0; + } + return newArray; + } +} diff --git a/Week 01/id_371/LeetCode_88_371.java b/Week 01/id_371/LeetCode_88_371.java new file mode 100644 index 000000000..ddc8f1465 --- /dev/null +++ b/Week 01/id_371/LeetCode_88_371.java @@ -0,0 +1,40 @@ +import java.util.Arrays; + +/** + * @program: algorithm004-01 + * @description: + * @author: Shaobo.Qian + * @create: 2019-10-17 10:59 + **/ + +public class LeetCode_88_371 { + + public static void main(String[] args) { + int[] nums1 = {1, 2, 3, 0, 0, 0}; + int m = 3; + int[] nums2 = {2, 5, 6}; + int n = 3; + merge(nums1, m, nums2, n); + Arrays.stream(nums1).forEach(System.out::println); + + } + + public static void merge(int[] nums1, int m, int[] nums2, int n) { + + //两个指针指向 nums1,num2的尾部,从大到小遍历两个额数组 + //n==0 --->说明nums2数组已经完全放入nums1中了 + //m==0 --->nums1先排好序了,只需要将 nums2中剩下的元素依次放入 nums1中即可 + for (int i = m + n - 1; i >= 0 && n > 0; i--) { + if (m > 0 && nums1[m - 1] >= nums2[n - 1]) { + nums1[i] = nums1[m - 1]; + m--; + } else { + nums1[i] = nums2[n - 1]; + n--; + } + + } + } + + +} diff --git "a/Week 01/id_381/189.\346\227\213\350\275\254\346\225\260\347\273\204.py" "b/Week 01/id_381/189.\346\227\213\350\275\254\346\225\260\347\273\204.py" new file mode 100644 index 000000000..f909f448d --- /dev/null +++ "b/Week 01/id_381/189.\346\227\213\350\275\254\346\225\260\347\273\204.py" @@ -0,0 +1,22 @@ +class Solution: + def rotate(self, nums: list, k: int) -> None: + """ + Do not return anything, modify nums in-place instead. + """ + k = k % len(nums) # 防止k太大 + start = 0 + # start + k 的值超出长度后循环next + next = (start + k) % len(nums) + tmp = nums[start] + for i in range(len(nums)): + nums[next], tmp = tmp, nums[next] + # 相等会陷入循环,其他数据无法挪动 + if next == start: + if i == len(nums)-1: + # 结束 + break + start += 1 + next = (start + k) % len(nums) + tmp = nums[start] + else: + next = (next + k) % len(nums) diff --git "a/Week 01/id_381/26.\345\210\240\351\231\244\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\351\207\215\345\244\215\351\241\271.py" "b/Week 01/id_381/26.\345\210\240\351\231\244\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\351\207\215\345\244\215\351\241\271.py" new file mode 100644 index 000000000..db2096927 --- /dev/null +++ "b/Week 01/id_381/26.\345\210\240\351\231\244\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\351\207\215\345\244\215\351\241\271.py" @@ -0,0 +1,11 @@ +class Solution: + def removeDuplicates(self, nums: list) -> int: + nums_len = len(nums) + if nums_len <= 1: + return nums_len + i = 0 + for j in range(1, nums_len): + if nums[j] != nums[i]: + nums[i+1] = nums[j] + i += 1 + return i + 1 diff --git a/Week 01/id_386/LeetCode_1_386.java b/Week 01/id_386/LeetCode_1_386.java new file mode 100644 index 000000000..6189d1ace --- /dev/null +++ b/Week 01/id_386/LeetCode_1_386.java @@ -0,0 +1,21 @@ +class SumOfTwoNumbers { + public int[] twoSum(int[] nums, int target) { + int[] n = new int[2]; + for (int i = 0; i < nums.length; i++) { + for (int j = 0; j < nums.length; j++) { + if (i != j && (nums[i] + nums[j] == target)) { + // System.out.println(i + ", " + j); + if (i < j) { + n[0] = i; + n[1] = j; + } else { + n[0] = j; + n[1] = i; + } + return n; + } + } + } + return new int[0]; + } +} diff --git a/Week 01/id_386/LeetCode_26_386.java b/Week 01/id_386/LeetCode_26_386.java new file mode 100644 index 000000000..453a17de2 --- /dev/null +++ b/Week 01/id_386/LeetCode_26_386.java @@ -0,0 +1,29 @@ +class RemoveDuplicates { + public int removeDuplicates(int[] nums) { + int count = 0; + + if(nums.length > 0) { + int[] arr = new int[nums.length]; + arr[0] = nums[0]; + //System.out.println("arr[0], " + arr[0]); + for(int i = 0; i < nums.length; i++) { + for(int j = i; j < nums.length; j++) { + if(i != j && nums[i] != nums[j]) { + arr[++count] = nums[j]; + nums[count] = arr[count]; + break; + } else { + i = j; + } + } + } + } else { + return 0; + } + + int[] a = new int[count+1]; + nums = a; + + return nums.length; + } +} diff --git a/Week 01/id_386/LeetCode_88_386.java b/Week 01/id_386/LeetCode_88_386.java new file mode 100644 index 000000000..281fe02ca --- /dev/null +++ b/Week 01/id_386/LeetCode_88_386.java @@ -0,0 +1,27 @@ +class Merge { + public void merge(int[] nums1, int m, int[] nums2, int n) { + for (int i = nums1.length - 1; i >= 0; i--) { + // System.out.print(nums1[i]); + if (n > 0) { + // System.out.print(nums2[n-1]); + nums1[i] = nums2[n-1]; + n--; + } + } + + int a, b = 0; + + for (int i = 0; i < nums1.length; i++) { + for (int j = 0; j < nums1.length - 1; j++) { + if (j <= nums1.length - 1 && nums1[j+1] < nums1[j]) { + a = nums1[j+1]; + b = nums1[j]; + nums1[j] = a; + nums1[j+1] = b; + + } + } + } + + } +} diff --git a/Week 01/id_421/LeetCode_42_421.java b/Week 01/id_421/LeetCode_42_421.java new file mode 100644 index 000000000..7f78a47e5 --- /dev/null +++ b/Week 01/id_421/LeetCode_42_421.java @@ -0,0 +1,104 @@ +import java.util.*; + +/** + * 接雨水问题(共三个实现方法) + */ +public class Solution { + + //初始版本(自己写出来的,没看任何提示,所以代码有点凌乱) 4ms + public static int trap(int[] height) { + LinkedList queue = new LinkedList<>(); + int left = 0; + int q = 0; + queue.push(left); + for (int i = 1; i < height.length; i++) { + if (height[left] <= height[i]) { + if (left + 1 == i) { + queue.pollFirst(); + } else { + int inner = 0; + for (int j = left; j <= i - 1; j++) { + inner += height[j]; + queue.pollFirst(); + } + q += height[left] * (i - left) - inner; + } + left = i; + } + queue.push(i); + int side = left; + if (i == height.length - 1 && !queue.isEmpty()) { + int inner = -1; + int right = 0; + for (int k = height.length - 1; k >= side; k--) { + if (right == 0 && k > 0 && height[k] <= height[k - 1]) + queue.pollLast(); + else { + if (right == 0) { + right = k; + } else { + if (height[k] < height[right]) { + if (inner == -1) + inner = 0; + inner += height[k]; + left = k; + } else { + if (inner != -1) { + q += height[right] * (right - left + 1) - inner - height[right]; + inner = 0; + right = 0; + k += 1; + } + } + } + queue.pollLast(); + } + } + } + + } + return q; + } + + //查看解析后改进版 + public static int trap2(int[] height) { + int sum = 0; + int min_left = 0; + int min_right = height.length - 1; + for (int left = 1, right = height.length - 2; left <= right; ) { + if (height[min_left] <= height[min_right]) { + if (height[min_left] < height[left]) { + min_left = left; + } else + sum += height[min_left] - height[left]; + left += 1; + } else { + if (height[min_right] < height[right]) { + min_right = right; + } else { + sum += height[min_right] - height[right]; + } + right -= 1; + } + } + return sum; + } + + //缩短行数最终版 + public static int trap3(int[] height) { + if (height.length == 0) return 0; + int sum = 0; + int min_left = height[0]; + int min_right = height[height.length - 1]; + for (int left = 1, right = height.length - 2; left <= right; ) { + if (min_left <= min_right) { + min_left = Math.max(min_left, height[left]); + sum += min_left - height[left++]; + } else { + min_right = Math.max(min_right, height[right]); + sum += min_right - height[right--]; + } + } + return sum; + } +} diff --git a/Week 01/id_421/LeetCode_641_421.java b/Week 01/id_421/LeetCode_641_421.java new file mode 100644 index 000000000..1e0ccbf9e --- /dev/null +++ b/Week 01/id_421/LeetCode_641_421.java @@ -0,0 +1,225 @@ +/** + * 设计循环双端队列(共三种实现方法) + */ +//基于数组拷贝的实现 +public class MyCircularDeque { + private int max; + private int[] obj = new int[0]; + + public MyCircularDeque(int k) { + this.max = k; + } + + public boolean insertFront(int value) { + if (!isFull()) { + int[] newObj = new int[obj.length + 1]; + if (!isEmpty()) + System.arraycopy(obj, 0, newObj, 1, obj.length); + newObj[0] = value; + this.obj = newObj; + return true; + } + return false; + } + + public boolean insertLast(int value) { + if (!isFull()) { + int[] newObj = new int[obj.length + 1]; + if (!isEmpty()) + System.arraycopy(obj, 0, newObj, 0, obj.length); + newObj[obj.length] = value; + this.obj = newObj; + return true; + } + return false; + } + + public boolean deleteFront() { + if (!isEmpty()) { + int[] newObj = new int[obj.length - 1]; + if (obj.length > 1) + System.arraycopy(obj, 1, newObj, 0, obj.length - 1); + obj = newObj; + return true; + } + return false; + } + + public boolean deleteLast() { + if (!isEmpty()) { + int[] newObj = new int[obj.length - 1]; + if (obj.length > 1) + System.arraycopy(obj, 0, newObj, 0, obj.length - 1); + obj = newObj; + return true; + } + return false; + } + + public int getFront() { + return isEmpty() ? -1 : obj[0]; + } + + public int getRear() { + return isEmpty() ? -1 : obj[obj.length - 1]; + } + + public boolean isEmpty() { + return obj.length == 0; + } + + public boolean isFull() { + return obj.length == max; + } +} + +//基于链表的实现 +class MyCircularDeque2 { + + private int capacity, size; + private Node head; + private Node tail; + + public MyCircularDeque2(int k) { + this.capacity = k; + head = new Node(0); + tail = new Node(0); + head.next = tail; + tail.prev = head; + } + + public boolean insertFront(int value) { + if (isFull()) return false; + Node newFirst = new Node(value); + Node oldFirst = head.next; + head.next = newFirst; + newFirst.prev = head; + oldFirst.prev = newFirst; + newFirst.next = oldFirst; + size++; + return true; + } + + public boolean insertLast(int value) { + if (isFull()) return false; + Node newLast = new Node(value); + Node oldLast = tail.prev; + tail.prev = newLast; + newLast.next = tail; + newLast.prev = oldLast; + oldLast.next = newLast; + size++; + return true; + } + + public boolean deleteFront() { + if (isEmpty()) return false; + Node first = head.next; + head.next = first.next; + first.next.prev = head; + size--; + return true; + } + + public boolean deleteLast() { + if (isEmpty()) return false; + Node last = tail.prev; + tail.prev = last.prev; + last.prev.next = tail; + size--; + return true; + } + + public int getFront() { + return isEmpty() ? -1 : head.next.value; + } + + public int getRear() { + return isEmpty() ? -1 : tail.prev.value; + } + + public boolean isEmpty() { + return size == 0; + } + + public boolean isFull() { + return size == capacity; + } + + static class Node { + int value; + Node prev; + Node next; + + Node(int value) { + this.value = value; + } + } +} + +//基于数组指针移动的实现 +public class MyCircularDeque3 { + + private int head; + private int tail; + private int len; + private int[] obj; + + public MyCircularDeque3(int k) { + this.obj = new int[k]; + } + + public boolean insertFront(int value) { + if (!isFull()) { + if (!isEmpty()) head = (head - 1 + obj.length) % obj.length; + obj[head] = value; + len++; + return true; + } + return false; + } + + public boolean insertLast(int value) { + if (!isFull()) { + if (!isEmpty()) tail = (tail + 1) % obj.length; + obj[tail] = value; + len++; + return true; + } + return false; + } + + public boolean deleteFront() { + if (!isEmpty()) { + if (len > 1) head = (head + 1) % obj.length; + len--; + return true; + } + return false; + } + + public boolean deleteLast() { + if (!isEmpty()) { + if (len > 1) tail = (tail - 1 + obj.length) % obj.length; + len--; + return true; + } + return false; + } + + public int getFront() { + return isEmpty() ? -1 : obj[head]; + } + + public int getRear() { + return isEmpty() ? -1 : obj[tail]; + } + + public boolean isEmpty() { + return len == 0; + } + + public boolean isFull() { + return len == obj.length; + } +} diff --git a/Week 01/id_421/NOTE.md b/Week 01/id_421/NOTE.md index a6321d6e2..bd87a319b 100644 --- a/Week 01/id_421/NOTE.md +++ b/Week 01/id_421/NOTE.md @@ -1,4 +1,24 @@ -# NOTE +### 粗略笔记 ++ 数组 + +内存管理器分配一块连续的内存地址 + ++ ArrayList + +基于数组实现,且是非并发安全的(对于内部结构的修改),通常需要外部对象同步。如果无法外部同步,则需要 +``` +List list = Collections.synchronizedList(new ArrayList(...)); +``` +其`iterators`与`listIterator`如果在创建后,修改了其内部结构(除了 iterator 自己的 remove 与 add 方法),其返回是快速失败的。 +快速失败在非同步下,不能得到保证,所以应用只能用于调试而不能依靠快速失败异常。 + +transient : 只能修饰变量,不被序列化(反序列化后,无法获得访问)。 + +O(1) : size isEmpty get set iterator listIterator +O(n) : add (and others) + + + diff --git a/Week 01/id_431/LeeCode_42_431.java b/Week 01/id_431/LeeCode_42_431.java new file mode 100644 index 000000000..016d8c5af --- /dev/null +++ b/Week 01/id_431/LeeCode_42_431.java @@ -0,0 +1,33 @@ +package hard; + +/** + * 这道暂时还没理解。。。 + * @author 潘磊明 + * @date 2019/10/20 + */ +public class TrappingRainWater { + public int trap(int[] height) { + if (height.length < 3) return 0; + + int ans = 0; + int l = 0, r = height.length - 1; + + while (l < r && height[l] <= height[l + 1]) l++; + while (l < r && height[r] <= height[r - 1]) r--; + + while (l < r) { + int left = height[l]; + int right = height[r]; + if (left <= right) { + while (l < r && left >= height[++l]) { + ans += left - height[l]; + } + } else { + while (l < r && height[--r] <= right) { + ans += right - height[r]; + } + } + } + return ans; + } +} diff --git a/Week 01/id_431/LeetCode_11_431.java b/Week 01/id_431/LeetCode_11_431.java new file mode 100644 index 000000000..aa9bd1864 --- /dev/null +++ b/Week 01/id_431/LeetCode_11_431.java @@ -0,0 +1,46 @@ +package medium; + +/** + * @author 潘磊明 + * @date 2019/10/18 + */ +public class ContainerWithMostWater { + + /** + * 进行暴力求解 + * 时间复杂度O(n^2) + * 空间复杂度O(1) + * @param height + * @return + */ +// public int maxArea(int[] height) { +// int area = 0; +// for (int i = 0; i < height.length - 1; i++) { +// for (int j = i + 1; j < height.length; j++) { +// area = Math.max(area, Math.min(height[i], height[j]) * (j - i)); +// } +// } +// return area; +// } + + /** + * 两边夹逼法 + * 时间复杂度O(n) + * 空间复杂度O(1) + * @param height + * @return + */ + public int maxArea(int[] height){ + int area = 0; + int i = 0, j = height.length - 1; + do { + area = Math.max(area, (j - i) * Math.min(height[i], height[j])); + if(height[i] > height[j]){ + j--; + }else{ + i++; + } + } while (i != j); + return area; + } +} diff --git a/Week 01/id_431/LeetCode_15_431.java b/Week 01/id_431/LeetCode_15_431.java new file mode 100644 index 000000000..028f459e8 --- /dev/null +++ b/Week 01/id_431/LeetCode_15_431.java @@ -0,0 +1,45 @@ +package medium; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * @author 潘磊明 + * @date 2019/10/20 + */ +public class ThreeSum { + public List> threeSum(int[] nums) { + //首先对数组进行排序 + Arrays.sort(nums); + //设置引用变量 + List> result = new ArrayList<>(); + for (int k = 0; k < nums.length - 2; k++) { + if (k == 0 || (k > 0 && nums[k] != nums[k-1])) { + int i = k + 1, j = nums.length - 1; + while (i < j) { + if (nums[i] + nums[j] < -nums[k]) + i++; + else if (nums[i] + nums[j] > -nums[k]) + j--; + else { + List tmp = Arrays.asList(nums[k], nums[i], nums[j]); + result.add(tmp); + while (i < j && nums[i + 1] == nums[i]) i++; + while (i < j && nums[j] == nums[j - 1]) j--; + i++; + j--; + } + } + } + } + return result; + } + + public static void main(String[] args) { + ThreeSum t = new ThreeSum(); + t.threeSum(new int[]{ + 1,-1,-1,0 + }); + } +} diff --git a/Week 01/id_431/LeetCode_1_431.java b/Week 01/id_431/LeetCode_1_431.java new file mode 100644 index 000000000..61ac143c8 --- /dev/null +++ b/Week 01/id_431/LeetCode_1_431.java @@ -0,0 +1,55 @@ +package simple; + +import java.util.Arrays; +import java.util.HashMap; + +/** + * 在一个整形数组中,找出两个数相加的和与目标值相等,返回这两个数的索引。 + * 可以确定一个整形数组中有且仅有一组符合要求的值, + */ +public class TwoSum { + + /** + * 暴力求解 + * 时间复杂度O(n^2) + * 空间复杂度O(1) + * @param nums + * @param target + * @return + */ +// public int[] twoSum(int[] nums, int target) { +// for (int i = 0; i < nums.length - 1; i++) { +// for (int j = i + 1; j < nums.length; j++) { +// if (nums[i] + nums[j] == target) { +// return new int[]{i, j}; +// } +// } +// } +// return null; +// } + + /** + * 运用hashMap进行临时存值 + * 时间复杂度O(n) + * 空间复杂度O(n) + * @param nums + * @param target + * @return + */ + public int[] twoSum(int[] nums, int target) { + //使用个Hash表进行临时存值 + //key为元素的值,value为元素的索引 + HashMap map = new HashMap<>(nums.length); + //设置初始值 + map.put(nums[0], 0); + //开始循环 + for (int i = 1; i < nums.length; i++) { + if(map.containsKey((target - nums[i]))){ + return new int[]{map.get(target - nums[i]), i}; + }else{ + map.put(nums[i], i); + } + } + return null; + } +} diff --git a/Week 01/id_431/LeetCode_26_431.java b/Week 01/id_431/LeetCode_26_431.java new file mode 100644 index 000000000..bca7da467 --- /dev/null +++ b/Week 01/id_431/LeetCode_26_431.java @@ -0,0 +1,29 @@ +package simple; + +/** + * @author 潘磊明 + * @date 2019/10/20 + */ +public class RemoveDuplicates { + public int removeDuplicates(int[] nums) { + if (nums.length < 2) { + return nums.length; + }else { + int len = 1; + for (int i = 0; i < nums.length - 1;) { + int j = i + 1; + while (j < nums.length && nums[j] == nums[i]){ + j++; + } + if(j < nums.length){ + i = j; + nums[len] = nums[i]; + len++; + }else{ + i++; + } + } + return len; + } + } +} diff --git a/Week 01/id_431/LeetCode_283_431.java b/Week 01/id_431/LeetCode_283_431.java new file mode 100644 index 000000000..2b09bf7f2 --- /dev/null +++ b/Week 01/id_431/LeetCode_283_431.java @@ -0,0 +1,22 @@ +package simple; + +/** + * @author 潘磊明 + * @date 2019/10/18 + */ +public class MoveZeros { + public void moveZeroes(int[] nums) { + int i = 0, j = -1; + while (i < nums.length) { + if (nums[i] == 0) { + j = j == -1 ? j = i : j++; + }else if (j != -1) { + int tmp = nums[i]; + nums[i] = nums[j]; + nums[j] = tmp; + j++; + } + i++; + } + } +} diff --git a/Week 01/id_431/LeetCode_641_431.java b/Week 01/id_431/LeetCode_641_431.java new file mode 100644 index 000000000..10da6db6e --- /dev/null +++ b/Week 01/id_431/LeetCode_641_431.java @@ -0,0 +1,98 @@ +package medium; + +/** + * @author 潘磊明 + * @date 2019/10/20 + */ +public class MyCircularDeque { + private int length; //最大的长度 + private int size; //当前的节点数 + private Node head; //头部节点 + private Node tail; //尾结点 + + /** Initialize your data structure here. Set the size of the deque to be k. */ + public MyCircularDeque(int k) { + length = k; + size = 0; + head = new Node(Integer.MIN_VALUE); + tail = new Node(Integer.MAX_VALUE); + head.next = tail; + tail.prev = head; + } + + /** Adds an item at the front of Deque. Return true if the operation is successful. */ + public boolean insertFront(int value) { + if(isFull()) return false; + Node node = new Node(value); + Node tmp = head.next; + tmp.prev = node; + head.next = node; + node.prev = head; + node.next = tmp; + size++; + return true; + } + + /** Adds an item at the rear of Deque. Return true if the operation is successful. */ + public boolean insertLast(int value) { + if(isFull()) return false; + Node node = new Node(value); + Node tmp = tail.prev; + tmp.next = node; + node.prev = tmp; + node.next = tail; + tail.prev = node; + size++; + return true; + } + + /** Deletes an item from the front of Deque. Return true if the operation is successful. */ + public boolean deleteFront() { + if(isEmpty()) return false; + head.next = head.next.next; + head.next.prev = head; + size--; + return true; + } + + /** Deletes an item from the rear of Deque. Return true if the operation is successful. */ + public boolean deleteLast() { + if(isEmpty()) return false; + tail.prev = tail.prev.prev; + tail.prev.next = tail; + size--; + return true; + } + + /** Get the front item from the deque. */ + public int getFront() { + if(isEmpty()) return -1; + return head.next.value; + } + + /** Get the last item from the deque. */ + public int getRear() { + if(isEmpty()) return -1; + return tail.prev.value; + } + + /** Checks whether the circular deque is empty or not. */ + public boolean isEmpty() { + return size == 0; + } + + /** Checks whether the circular deque is full or not. */ + public boolean isFull() { + return size == length; + } + + private class Node{ + Node prev; + Node next; + int value; + + private Node(int value){ + this.value = value; + } + } +} diff --git a/Week 01/id_431/LeetCode_70_431.java b/Week 01/id_431/LeetCode_70_431.java new file mode 100644 index 000000000..4b64b61d1 --- /dev/null +++ b/Week 01/id_431/LeetCode_70_431.java @@ -0,0 +1,28 @@ +package simple; + +/** + * @author 潘磊明 + * @date 2019/10/18 + */ +public class ClimbingStairs { + /** + * 使用递归思想解决问题 + * @param n + * @return + */ + public int climbStairs(int n) { + if (n < 3) { + return n; + } else { + //设置两个变量记录缓存值 + int prev = 1; + int cur = 2; + for(int i = 3; i < n; i++) { + int tmp = prev + cur; + prev = cur; + cur = tmp; + } + return prev + cur; + } + } +} diff --git a/Week 01/id_431/NOTE.md b/Week 01/id_431/NOTE.md index a6321d6e2..37778fcc3 100644 --- a/Week 01/id_431/NOTE.md +++ b/Week 01/id_431/NOTE.md @@ -1,4 +1,40 @@ -# NOTE +# 目录 + +* 刷题时间表 +* 课堂笔记 + + + +# 第一周刷题时间表 + +题目名称|难易度|第一遍时间|第二遍时间|第三遍时间|第四遍时间|第五遍时间|地址 +:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-: +Two Sum|Easy|2019-10-17|||||https://leetcode.com/problems/two-sum/ +ContainerWithMostWater|Medium|2019-10-18|||||https://leetcode.com/problems/container-with-most-water/submissions/ +Move Zeros|Easy|2019-10-18|||||https://leetcode.com/problems/move-zeroes/ +Climbing Stairs|Easy|2019-10-18|||||https://leetcode.com/problems/climbing-stairs/ +3Sum|Medium|2019-10-20|||||https://leetcode.com/problems/3sum/ +Remove Duplicates from Sorted Array|Easy|2019-10-20|||||https://leetcode.com/problems/remove-duplicates-from-sorted-array/ +Design Circular Deque|Medium|2019-10-20|||||https://leetcode.com/problems/design-circular-deque/ +Trapping Rain Water|Hard|2019-10-20|||||https://leetcode.com/problems/trapping-rain-water/ + + + +# 课堂笔记 + +## 基础思想 +        **转换多维,空间换时间** + +## 时间复杂度空间复杂度表 + +**数据结构操作** + +数据结构|访问(平均)|搜索(平均)|插入(平均)|删除(平均)|访问(最差)|搜索(最差)|插入(最差)|删除(最差)|空间复杂度 +:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:| +Array|O(1)|O(n)|O(n)|O(n)|O(1)|O(n)|O(n)|O(n)|O(n) +Singly-Linked List|O(n)|O(n)|O(1)|O(1)|O(n)|O(n)|O(1)|O(1)|O(n) +Doubly-Linked List|O(n)|O(n)|O(1)|O(1)|O(n)|O(n)|O(1)|O(1)|O(n) +Skip List|O(log(n))|O(log(n))|O(log(n))|O(log(n))|O(n)|O(n)|O(n)|O(n)|O(nlog(n)) +Stack|O(n)|O(n)|O(1)|O(1)|O(n)|O(n)|O(1)|O(1)|O(n) - diff --git a/Week 01/id_436/Leetcode_26_436.java b/Week 01/id_436/Leetcode_26_436.java new file mode 100644 index 000000000..a14498af7 --- /dev/null +++ b/Week 01/id_436/Leetcode_26_436.java @@ -0,0 +1,24 @@ + +/** + * 在这里给出对类 Leetcode_26_436 的描述。 + * + * @作者(你的名字) + * @版本(一个版本号或者一个日期) + */ +public class Leetcode_26_436 +{ + public int removeDuplicates(int[] nums) { + if(nums.length == 0) + return 0; + int result = 1; + int j = 0;// previous pointer; + for(int i = 0; i < nums.length; i++){ + if(nums[j] != nums[i]){ + result++; + j++; + nums[j] = nums[i]; + } + } + return result; + } +} diff --git a/Week 01/id_436/Leetcode_42_436.java b/Week 01/id_436/Leetcode_42_436.java new file mode 100644 index 000000000..76309d0d1 --- /dev/null +++ b/Week 01/id_436/Leetcode_42_436.java @@ -0,0 +1,28 @@ +/** + * 在这里给出对类 Leetcode_42_436 的描述。 + * + * @作者(你的名字) + * @版本(一个版本号或者一个日期) + */ +import java.util.*; +public class Leetcode_42_436 +{ + public int trap(int[] height){ + int n = height.length; + Deque stack = new ArrayDeque<>(); + int result = 0; + int index = 0; + while(index < n){ + while(!stack.isEmpty() && height[index] > height[stack.peek()]){ + int top = stack.pop(); + if(stack.isEmpty()) break; + int h = Math.min(height[stack.peek()], height[index]) - height[top]; + int dist = index - stack.peek() - 1; + result += dist * h; + } + stack.push(index); + index++; + } + return result; + } +} diff --git a/Week 01/id_441/NOTE.md b/Week 01/id_441/NOTE.md index a6321d6e2..65d4a1635 100644 --- a/Week 01/id_441/NOTE.md +++ b/Week 01/id_441/NOTE.md @@ -1,4 +1,157 @@ # NOTE +## 数据结构和算法第一周的学习内容 + +算法和数据结构解答题目的时候的两个思维: +1. 做题不要只做一遍(五毒神掌) +2. 升维,空间换时间 + +## 数组 + +数组是典型的线性结构,数组在内存中的存在方式是一段连续的内存空间。 + +### 数组的访问 + +因为是一段连续的内存空间,所以只要有数组的第一个元素的地址,就可以通过内存的寻址公式:a[i]_address = base_address + i * data_type_size,以O(1)的时间复杂度来访问数组中的任意一个元素。所以无论数组的长度是1还是一万还是一百万,访问数组中任意元素的时间复杂度都是O(1). + +### 数组的操作 +因为数组是一段连续的内存空间,所以对数组的任意元素的操作都会影响到整个数组的空间。比如往数组中添加一个元素时,最好的情况是往数组最后添加这个时候数组的时间复杂度是O(1);如果往数组第一个位置添加元素的话,数组后面所有的元素都需要在内存中后移一位,所以这个时候的时间复杂度是O(n);删除的话时间复杂度也是O(n);所以对数组的操作的时间复杂度是O(n),这也是数组这一类型的缺陷所在。 + +### js中的数组 + +js中的数组被称之为类型化数组,是一种类似数组的**对象**。js数组的长度和元素类型都是非固定的(非固定的元素类型可以理解成为泛型),js数组的length属性是可以随时改变的,在内存中也不一定是连续的内存空间,所以js的数组是非密集型的。在js中的类型数组是[TypedArray](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/TypedArray),它提供了8个类型,可以用来创造相关的类型数组。 + +### java中的数组 + +java中的数组是普通数组,需要处理边界情况,也就是当数组的size不够的时候需要扩容,一般是扩两倍原size的大小。 + +## 链表 + +链表是非连续非顺序的存储结构。访问的时间复杂度是O(n),操作的时间复杂度是O(1)。 + +### js中单链表的实现 + +```js + +class Node { + constructor (element) { + this.element = element + this.next = null + } +} + +class LinkedList { + constructor () { + this.head = new Node('head') + } + // 根据value查找节点 + findByValue (item) { + let currentNode = this.head.next + while (currentNode !== null && currentNode.element !== item) { + currentNode = currentNode.next + } + console.log(currentNode) + return currentNode === null ? -1 : currentNode + } + + // 根据index查找节点,下标从0开始 + findByIndex (index) { + let currentNode = this.head.next + let pos = 0 + while (currentNode !== null && pos !== index) { + currentNode = currentNode.next + pos++ + } + console.log(currentNode) + return currentNode === null ? -1 : currentNode + } + + // 向链表末尾追加节点 + append(newElement) { + const newNode = new Node(newElement) + let currentNode = this.head + while(currentNode.next) { + currentNode = currentNode.next + } + currentNode.next = newNode + } + + // 指定元素向后插入 + insert (newElement, element) { + const currentNode = this.findByValue(element) + if (currentNode === -1) { + console.log('未找到插入位置') + return + } + const newNode = new Node(newElement) + newNode.next = currentNode.next + currentNode.next = newNode + } + // 查找前一个 + findPrev (item) { + let currentNode = this.head + while (currentNode.next !== null && currentNode.next.element !== item) { + currentNode = currentNode.next + } + if (currentNode.next === null) { + return -1 + } + return currentNode + } + + // 根据值删除 + remove (item) { + const prevNode = this.findPrev(item) + if (prevNode === -1) { + console.log('未找到元素') + return + } + prevNode.next = prevNode.next.next + } + + // 遍历显示所有节点 + display () { + let currentNode = this.head.next // 忽略头指针的值 + while (currentNode !== null) { + console.log(currentNode.element) + currentNode = currentNode.next + } + } +} +``` + + +## 栈和队列 + +### stack + +栈是一种先进后出的数据结构(FILO),添加和删除的操作都是O(1),查询的的时间复杂度是O(n) + +### queue + +队列是一种先进先出(FIFO)的数据结构,添加和删除操作是O(1),查询的的时间复杂度是O(n) + +### 双端队列 + +deque:double-end queue,是在简单队列的基础上,头和尾都可以pop和push。插入和删除都是O(1)的操作,查询是O(n)操作的。现实中通常使用deque而不是queue。 + +### 优先队列 + +priority Queue是优先队列,是按照优先级取出的数据结构,插入操作是O(1),因为是优先级取出,所以取出操作的优先级是O(logN)。实现较为复杂和多样性,比如:heap的实现方式,bst,AVL,treap。优先级的规则通过comparator函数来定义。 + +### Java中的实现 + +1. stack +stack在java中是一个类。方法有push,pop。[stack的实现](http://developer.classpath.org/doc/java/util/Stack-source.html) + +2. queue +[queue的实现](http://fuseyism.com/classpath/doc/java/util/Queue-source.html),queue在Java中是一个interface。实现方式有很多种,比如:ArrayDeque,ConcurrentLinkedDeque(并发式链表实现的双端队列),LinkedBlickingDeque(单线程实现的双端队列),non-blocking,LinkedList.常用方法有add,remove,(offer,poll,这两个方法在异常的时候会有返回值,而add,remove会抛出异常) + +3. deque +deque在Java中比queue多了几个api比如:addLast,addFirst,等。 + +4. priority +priorit在Java中是class。[priority的源码](https://docs.oracle.com/javase/10/docs/api/java/util/PriorityQueue.html) + diff --git a/Week 01/id_441/array.km b/Week 01/id_441/array.km new file mode 100644 index 000000000..e69de29bb diff --git a/Week 01/id_441/climbing_stairs.js b/Week 01/id_441/climbing_stairs.js new file mode 100644 index 000000000..7e9ba2d71 --- /dev/null +++ b/Week 01/id_441/climbing_stairs.js @@ -0,0 +1,2 @@ +// 爬楼梯的解法 +// 懵逼的时候解法:暴力? 基本情况? diff --git a/Week 01/id_441/linked_list.js b/Week 01/id_441/linked_list.js new file mode 100644 index 000000000..bec482e97 --- /dev/null +++ b/Week 01/id_441/linked_list.js @@ -0,0 +1,11 @@ +// 经典题目汇总 +// https://leetcode.com/problems/reverse-linked-list/ +// https://leetcode.com/problems/swap-nodes-in-pairs +// https://leetcode.com/problems/linked-list-cycle/ //*** +// https://leetcode.com/problems/linked-list-cycle-ii/ +// https://leetcode.com/problems/reverse-nodes-in-k-group/ + +// linked-list-cycle +// 1暴力解法 + +// 2快慢指针 \ No newline at end of file diff --git a/Week 01/id_441/most_water.js b/Week 01/id_441/most_water.js new file mode 100644 index 000000000..d17a21cd8 --- /dev/null +++ b/Week 01/id_441/most_water.js @@ -0,0 +1,39 @@ +// 盛水最多的容器 +// O(n^2) +function Solution(arr) { + const max = 0; + for (let i = 0; i < arr.length; i++) { + for (let j = i + 1; j < arr.length; j++) { + let area; + if (arr[i] < arr[j]) { + area = arr[i] * (j - i) + } else { + area = arr[j] * (j - i) + } + max < area ? max = area : max + } + } + return max +} +// O(n) +// 此种解法其实目的就是找出宽度最宽,高度最高的两个值; +// 因为是首位指针所以宽度肯定是最宽的 +// 接下来就是循环找出高度比边界要高的值,才有可能是面积最大的(因为边界的宽度是最宽的) +// 所以通过这个方法能找出面积最大的情况,而由于每次最大的面积都会记录下来所以不会漏掉面积最大的值 +// 左右夹逼得办法 +const arr = [6, 8, 6, 2, 5, 4, 8, 3, 7] +const maxArea = (arr) => { + let max = 0; + console.log(arr) + for (let i = 0, j = arr.length - 1; i < j;) { + const minHeight = arr[i] < arr[j] ? arr[i++] : arr[j--] + console.log(i, j) + const width = j - i + 1 + console.log(width, 'width') + const area = minHeight * width + console.log(area) + max = max < area ? area : max + }; + return max +} +console.log(maxArea(arr)) \ No newline at end of file diff --git a/Week 01/id_441/stack.js b/Week 01/id_441/stack.js new file mode 100644 index 000000000..9c75c0340 --- /dev/null +++ b/Week 01/id_441/stack.js @@ -0,0 +1,7 @@ +// 最近相关性的问题 类似于洋葱结构的话 这样的问题都是用栈来解决的。 +// 先来后到的话都是采用队列来解决的 + + +// valid-parentheses https://leetcode-cn.com/problems/valid-parentheses/ +// 1. 暴力解法 不断replace匹配的括号 ->直到变成-> '' 时间复杂度 O(n^2) +// 2. 利用栈来解决 \ No newline at end of file diff --git a/Week 01/id_441/stack_queue.js b/Week 01/id_441/stack_queue.js new file mode 100644 index 000000000..e69de29bb diff --git a/Week 01/id_441/three_sum.js b/Week 01/id_441/three_sum.js new file mode 100644 index 000000000..57d52cc4b --- /dev/null +++ b/Week 01/id_441/three_sum.js @@ -0,0 +1,80 @@ +// https://leetcode-cn.com/problems/two-sum/ +// 两数之和 +// 1暴力求解 +var twoSum = function (nums, target) { + const targetArr = [] + for (let i = 0; i < nums.length - 1; i++) { + for (let j = i + 1; j < nums.length; j++) { + if (target === nums[i] + nums[j]) { + targetArr.push(i) + targetArr.push(j) + } + } + } + return targetArr +}; +// 2 哈希 +var twoSum = function (nums, target) { + const resObj = {} + for (let i = 0; i < nums.length; i++) { + resObj[target - nums[i]] = i + } + for (let k = 0; k < nums.length; k++) { + if (resObj[nums[k]] && resObj[nums[k]] !== k) { + return [k, resObj[nums[k]]] + } + } +} +// https://leetcode-cn.com/problems/3sum/ +// 三数之和 +// 暴力求解法 +var threeSum = function (nums) { + const targetArr = [] + for (let i = 0; i < nums.length - 2; i++) { + for (let j = i + 1; j < nums.length - 1; j++) { + for (let k = j + 1; k < nums.length; k++) { + if (nums[i] + nums[j] + nums[k] === 0) { + targetArr.push([nums[i], nums[j], nums[k]]) + } + } + } + } + return targetArr +}; +var threeSum = function (nums) { + // nums = sort(nums); + nums.sort((a, b) => a - b) + for (let i = 1; i < nums.length - 1; i++) { // C位人选 + let first = 0 + let last = nums.length - 1 + console.log(last, 'last') + do { + let result = nums[i] + nums[first] + nums[last] + if (result === 0) { // 如果可以组队 + res.push([nums[i], nums[first], nums[last]]) + } + if (result <= 0 && first < i) { // 实力太弱,把菜鸟那边右移一位 + while (nums[first] === nums[++first]); // 如果相等就跳过 + } else if (result > 0 && last > i) { // 实力太强,把大神那边右移一位 + while (nums[last] === nums[--last]); + } else { + break // 某一边已经没有人选了 + } + } while (1) {} + } + return res +} +// 这里是冒泡实现的,复杂度为O(n^2);应用快排,复杂度为logN +function sort(nums) { + const length = nums.length - 1 + while (length) { + for (let i = 0; i < nums.length; i++) { + if (nums[i] > nums[i + 1]) { + const num = nums[i + 1] + nums[i + 1] = nums[i] + nums[i] = num + } + } + length-- + } +} \ No newline at end of file diff --git a/Week 01/id_446/LeetCode_1_446.cpp b/Week 01/id_446/LeetCode_1_446.cpp new file mode 100644 index 000000000..118a9ef31 --- /dev/null +++ b/Week 01/id_446/LeetCode_1_446.cpp @@ -0,0 +1,28 @@ +class Solution { +public: + vector twoSum(vector& nums, int target) { + int iSize = nums.size(); + int sum1,sum2; + bool bfind = false; + for(int i=0;i result; + result.push_back(sum1); + result.push_back(sum2); + + return result; + } +}; \ No newline at end of file diff --git a/Week 01/id_446/LeetCode_26_446.cpp b/Week 01/id_446/LeetCode_26_446.cpp new file mode 100644 index 000000000..ec8d8b124 --- /dev/null +++ b/Week 01/id_446/LeetCode_26_446.cpp @@ -0,0 +1,20 @@ +#include +class Solution { +public: + int removeDuplicates(vector& nums) { + int count = 0; + int size = nums.size(); + if( size < 2){ + return size; + } + int current_num = nums[0] + 1; + for(int i = 0; i < size; i++){ + if(current_num != nums[i]){ + current_num = nums[i]; + nums[count++] = current_num; + } + } + + return count; + } +}; \ No newline at end of file diff --git a/Week 01/id_451/LeetCode_26_451.go b/Week 01/id_451/LeetCode_26_451.go new file mode 100644 index 000000000..1446ebd58 --- /dev/null +++ b/Week 01/id_451/LeetCode_26_451.go @@ -0,0 +1,19 @@ +func removeDuplicates(nums []int) int { + var pre, j int + for i, n := range nums { + if i == 0 { + pre = n + j = 1 + continue + } + if n == pre { + continue + } + + pre = n + nums[j] = n + j++ + } + return j +} + diff --git a/Week 01/id_451/LeetCode_88_451.go b/Week 01/id_451/LeetCode_88_451.go new file mode 100644 index 000000000..416a29051 --- /dev/null +++ b/Week 01/id_451/LeetCode_88_451.go @@ -0,0 +1,23 @@ +func merge(nums1 []int, m int, nums2 []int, n int) { + var i, j, k int + nums3 := make([]int, n+m) + if m == 0 || n == 0 { + copy(nums1, nums2) + return + } + for { + if k == n+m { + break + } + if j >= n || (nums1[i] < nums2[j] && i < m) { + nums3[k] = nums1[i] + k++ + i++ + continue + } + nums3[k] = nums2[j] + k++ + j++ + } + copy(nums1, nums3) +} diff --git a/Week 01/id_451/NOTE.md b/Week 01/id_451/NOTE.md index a6321d6e2..d9677f317 100644 --- a/Week 01/id_451/NOTE.md +++ b/Week 01/id_451/NOTE.md @@ -1,4 +1,14 @@ # NOTE +# 学习笔记 +# LRU 缓存 +通过hash表+链表实现 +通过hash表进行查找,通过双链表实现有序。 +# 跳跃表 +查询复杂度log(n) 插入删除复杂度log(n) +通过插入时随机选择level +# 优先队列 +抽象的数据结构,复杂度跟实现有关。(二叉堆) +# 代码点评 +通过学习256 同学的代码,学习到了合并有序数组此题的优化方法,(从尾端向前遍历,减少空间复杂度) - diff --git a/Week 01/id_461/26.remove-duplicates-from-sorted-array.cpp b/Week 01/id_461/26.remove-duplicates-from-sorted-array.cpp new file mode 100644 index 000000000..a7575c17b --- /dev/null +++ b/Week 01/id_461/26.remove-duplicates-from-sorted-array.cpp @@ -0,0 +1,82 @@ +/* + * @lc app=leetcode id=26 lang=cpp + * + * [26] Remove Duplicates from Sorted Array + * + * https://leetcode.com/problems/remove-duplicates-from-sorted-array/description/ + * + * algorithms + * Easy (42.13%) + * Likes: 1780 + * Dislikes: 3858 + * Total Accepted: 714.4K + * Total Submissions: 1.7M + * Testcase Example: '[1,1,2]' + * + * Given a sorted array nums, remove the duplicates in-place such that each + * element appear only once and return the new length. + * + * Do not allocate extra space for another array, you must do this by modifying + * the input array in-place with O(1) extra memory. + * + * Example 1: + * + * + * Given nums = [1,1,2], + * + * Your function should return length = 2, with the first two elements of nums + * being 1 and 2 respectively. + * + * It doesn't matter what you leave beyond the returned length. + * + * Example 2: + * + * + * Given nums = [0,0,1,1,1,2,2,3,3,4], + * + * Your function should return length = 5, with the first five elements of nums + * being modified to 0, 1, 2, 3, and 4 respectively. + * + * It doesn't matter what values are set beyond the returned length. + * + * + * Clarification: + * + * Confused why the returned value is an integer but your answer is an array? + * + * Note that the input array is passed in by reference, which means + * modification to the input array will be known to the caller as well. + * + * Internally you can think of this: + * + * + * // nums is passed in by reference. (i.e., without making a copy) + * int len = removeDuplicates(nums); + * + * // any modification to nums in your function would be known by the caller. + * // using the length returned by your function, it prints the first len + * elements. + * for (int i = 0; i < len; i++) { + * print(nums[i]); + * } + * + */ + +// @lc code=start +class Solution { +public: + int removeDuplicates(vector& nums) { + int dup_count = 0; + for (int i = 1; i < nums.size(); i++) { + if (nums[i] == nums[i - 1]) { + dup_count++; + } else { + //把下一个不重复的元素放到上一个不重复的元素的后面去; + nums[i - dup_count] = nums[i]; + } + } + return nums.size() - dup_count; + } +}; +// @lc code=end + diff --git a/Week 01/id_461/61.rotate-list.cpp b/Week 01/id_461/61.rotate-list.cpp new file mode 100644 index 000000000..eeb4f94cc --- /dev/null +++ b/Week 01/id_461/61.rotate-list.cpp @@ -0,0 +1,85 @@ +/* + * @lc app=leetcode id=61 lang=cpp + * + * [61] Rotate List + * + * https://leetcode.com/problems/rotate-list/description/ + * + * algorithms + * Medium (28.12%) + * Likes: 747 + * Dislikes: 894 + * Total Accepted: 218.8K + * Total Submissions: 776.8K + * Testcase Example: '[1,2,3,4,5]\n2' + * + * Given a linked list, rotate the list to the right by k places, where k is + * non-negative. + * + * Example 1: + * + * + * Input: 1->2->3->4->5->NULL, k = 2 + * Output: 4->5->1->2->3->NULL + * Explanation: + * rotate 1 steps to the right: 5->1->2->3->4->NULL + * rotate 2 steps to the right: 4->5->1->2->3->NULL + * + * + * Example 2: + * + * + * Input: 0->1->2->NULL, k = 4 + * Output: 2->0->1->NULL + * Explanation: + * rotate 1 steps to the right: 2->0->1->NULL + * rotate 2 steps to the right: 1->2->0->NULL + * rotate 3 steps to the right: 0->1->2->NULL + * rotate 4 steps to the right: 2->0->1->NULL + * + */ + +// @lc code=start +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode(int x) : val(x), next(NULL) {} + * }; + */ +class Solution { +public: + ListNode* rotateRight(ListNode* head, int k) { + //测试的时候首先是忘记了边界情况,例如空链表,和链表数为1的情况 + //第二是忘记处理如果翻转数很大的时候的情况,应该取模 + if (head == NULL) { + return NULL; + } else if (head != NULL && head->next == NULL) { + return head; + } + int len = 0; + ListNode *p = head; + ListNode *q = p->next; + while (p != NULL) { + p = p->next; + len++; + } + k = k % len; + while (k != 0) { + p = head; + q = p->next; + while (q->next != NULL) { + p = q; + q = q->next; + } + p->next = NULL; + q->next = head; + head = q; + k--; + } + return head; + } +}; +// @lc code=end + diff --git a/Week 01/id_461/66.plus-one.cpp b/Week 01/id_461/66.plus-one.cpp new file mode 100644 index 000000000..6ecbc95d1 --- /dev/null +++ b/Week 01/id_461/66.plus-one.cpp @@ -0,0 +1,67 @@ +/* + * @lc app=leetcode id=66 lang=cpp + * + * [66] Plus One + * + * https://leetcode.com/problems/plus-one/description/ + * + * algorithms + * Easy (41.72%) + * Likes: 1028 + * Dislikes: 1801 + * Total Accepted: 458.4K + * Total Submissions: 1.1M + * Testcase Example: '[1,2,3]' + * + * Given a non-empty array of digits representing a non-negative integer, plus + * one to the integer. + * + * The digits are stored such that the most significant digit is at the head of + * the list, and each element in the array contain a single digit. + * + * You may assume the integer does not contain any leading zero, except the + * number 0 itself. + * + * Example 1: + * + * + * Input: [1,2,3] + * Output: [1,2,4] + * Explanation: The array represents the integer 123. + * + * + * Example 2: + * + * + * Input: [4,3,2,1] + * Output: [4,3,2,2] + * Explanation: The array represents the integer 4321. + * + */ + +// @lc code=start +class Solution { +public: + vector plusOne(vector& digits) { + int len = digits.size(); + if (digits[len - 1] != 9) { + digits[len - 1] += 1; + return digits; + } else { + digits[len - 1] += 1; + for (int i = len - 1; i >= 0; i--) { + if (i != 0 && digits[i] == 10) { + digits[i] = 0; + digits[i - 1] += 1; + } + } + } + if (digits[0] == 10) { + digits[0] = 0; + digits.insert(digits.begin(), 1); + } + return digits; + } +}; +// @lc code=end + diff --git "a/Week 01/id_461/\345\255\246\344\271\240\346\200\273\347\273\223.md" "b/Week 01/id_461/\345\255\246\344\271\240\346\200\273\347\273\223.md" new file mode 100644 index 000000000..0a313d966 --- /dev/null +++ "b/Week 01/id_461/\345\255\246\344\271\240\346\200\273\347\273\223.md" @@ -0,0 +1,2 @@ +## 学习总结 +本周主要是学习简单的链表,数组,队列,栈等比较初级的数据结构,我最大的收获其实应该是获得了一些刷题时候的经验,有些代码的小技巧都是通过老师讲课,或者看别人的更优解法得到的,有时候会感慨有些思想的确自己想不到,非常的巧妙;但是我认为主要原因还是积累得不够多,以后加强积累的深度和熟练度,应该也能达到举一反三的效果。 \ No newline at end of file diff --git a/Week 01/id_466/LeetCode_26_466.java b/Week 01/id_466/LeetCode_26_466.java new file mode 100644 index 000000000..b66fdd5fb --- /dev/null +++ b/Week 01/id_466/LeetCode_26_466.java @@ -0,0 +1,87 @@ +//给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。 +// +// 不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。 +// +// 示例 1: +// +// 给定数组 nums = [1,1,2], +// +//函数应该返回新的长度 2, 并且原数组 nums 的前两个元素被修改为 1, 2。 +// +//你不需要考虑数组中超出新长度后面的元素。 +// +// 示例 2: +// +// 给定 nums = [0,0,1,1,1,2,2,3,3,4], +// +//函数应该返回新的长度 5, 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4。 +// +//你不需要考虑数组中超出新长度后面的元素。 +// +// +// 说明: +// +// 为什么返回数值是整数,但输出的答案是数组呢? +// +// 请注意,输入数组是以“引用”方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。 +// +// 你可以想象内部操作如下: +// +// // nums 是以“引用”方式传递的。也就是说,不对实参做任何拷贝 +//int len = removeDuplicates(nums); +// +//// 在函数里修改输入数组对于调用者是可见的。 +//// 根据你的函数返回的长度, 它会打印出数组中该长度范围内的所有元素。 +//for (int i = 0; i < len; i++) { +//    print(nums[i]); +//} +// +// Related Topics 数组 双指针 +package com.aseara.leetcode.editor.cn.a26; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * desc: 删除排序数组中的重复项
+ * Date: 2019/10/20
+ * + * @author qiujingde + */ +class RemoveDuplicatesFromSortedArray { + private Solution solution = new Solution(); + + @Test + void test1() { + int[] test = new int[0]; + assertEquals(0, solution.removeDuplicates(test)); + + test = new int[] {1,1,2}; + assertEquals(2, solution.removeDuplicates(test)); + assertEquals(1, test[0]); + assertEquals(2, test[1]); + } + +} + + +//leetcode submit region begin(Prohibit modification and deletion) +class Solution { + public int removeDuplicates(int[] nums) { + if (nums.length == 0) { + return 0; + } + int last = 0; + int crt = nums[0]; + for (int i = 1; i < nums.length; i++) { + if (nums[i] != crt) { + crt = nums[i]; + last ++; + nums[last] = crt; + } + } + return last + 1; + } +} +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 01/id_466/LeetCode_66_466.java b/Week 01/id_466/LeetCode_66_466.java new file mode 100644 index 000000000..32f435a62 --- /dev/null +++ b/Week 01/id_466/LeetCode_66_466.java @@ -0,0 +1,74 @@ +//给定一个由整数组成的非空数组所表示的非负整数,在该数的基础上加一。 +// +// 最高位数字存放在数组的首位, 数组中每个元素只存储单个数字。 +// +// 你可以假设除了整数 0 之外,这个整数不会以零开头。 +// +// 示例 1: +// +// 输入: [1,2,3] +//输出: [1,2,4] +//解释: 输入数组表示数字 123。 +// +// +// 示例 2: +// +// 输入: [4,3,2,1] +//输出: [4,3,2,2] +//解释: 输入数组表示数字 4321。 +// +// Related Topics 数组 +package com.aseara.leetcode.editor.cn.a66; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; + +/** + * desc: 加一
+ * Date: 2019/10/20
+ * + * @author qiujingde + */ +class PlusOne { + private Solution solution = new Solution(); + + @Test + void test1() { + int[] test = new int[] {1,2,3}; + int[] result = new int[] {1,2,4}; + assertArrayEquals(result, solution.plusOne(test)); + + test = new int[] {4,3,2,1}; + result = new int[] {4,3,2,2}; + assertArrayEquals(result, solution.plusOne(test)); + + test = new int[] {9}; + result = new int[] {1,0}; + assertArrayEquals(result, solution.plusOne(test)); + + test = new int[] {2,9}; + result = new int[] {3,0}; + assertArrayEquals(result, solution.plusOne(test)); + } + +} + + +//leetcode submit region begin(Prohibit modification and deletion) +class Solution { + public int[] plusOne(int[] digits) { + for (int i = digits.length - 1; i >= 0; i--) { + if (digits[i] != 9) { + int[] result = new int[ digits.length ]; + System.arraycopy(digits, 0, result, 0, i); + result[i] = digits[i] + 1; + return result; + } + } + int[] result = new int[ digits.length + 1 ]; + result[0] = 1; + return result; + } +} +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 01/id_471/LeetCode_189_471.java b/Week 01/id_471/LeetCode_189_471.java new file mode 100644 index 000000000..4172af37a --- /dev/null +++ b/Week 01/id_471/LeetCode_189_471.java @@ -0,0 +1,36 @@ +//经过三次反转操作,第一次是将整个数组从中间节点反转 +//第二步是将前 k 个数字反转 +//第三步是将 k - n 中间的数字反转 +class Solution { + 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); + } + + public void reverse(int[] nums, int start, int end){ + while(start < end){ + int temp = nums[start]; + nums[start++] = nums[end]; + nums[end--] = temp; + } + } +} + +//暴力法,双层循环,每次移动一个位置。移动的过程中,每次都要移动 n-1 个元素,然后需要移动 k 次 +//时间复杂度: O(n*k); +//空间复杂度为: O(1); +class Solution { + public void rotate(int[] nums, int k) { + int temp = 0; + for(int i = 0; i < k; i++){ + temp = nums[nums.length-1]; + for(int j = nums.length-1; j >= 1; j--){ + nums[j] = nums[j-1]; + } + nums[0] = temp; + } + } +} \ No newline at end of file diff --git a/Week 01/id_471/LeetCode_1_471.java b/Week 01/id_471/LeetCode_1_471.java new file mode 100644 index 000000000..09ca2fb99 --- /dev/null +++ b/Week 01/id_471/LeetCode_1_471.java @@ -0,0 +1,17 @@ +//使用map缓存已经遍历过的数字,然后在遍历过程中再看map中有没有满足与当前数字之和为 target 的值 +//时间复杂度为:O(n) +//空间复杂度为:O(n) + +class Solution { + public int[] twoSum(int[] nums, int target) { + Map map = new HashMap(); + for(int i = 0; i < nums.length; i++){ + if(map.containsKey(target-nums[i])){ + return new int[]{map.get(target-nums[i]), i}; + } + map.put(nums[i], i); + } + + return new int[]{0,0}; + } +} \ No newline at end of file diff --git a/Week 01/id_471/LeetCode_21_471.java b/Week 01/id_471/LeetCode_21_471.java new file mode 100644 index 000000000..ecd233261 --- /dev/null +++ b/Week 01/id_471/LeetCode_21_471.java @@ -0,0 +1,29 @@ +//借助两个临时变量结点,newNode为头结点,tail为尾节点,然后遍历两个链表,按照从小到大的顺序通过tail链接。最后得到的newNode即为新的合并链表的头结点 +//时间复杂度O ( l1.length + l2.length ) +//空间复杂度:O(1) + +class Solution { + public ListNode mergeTwoLists(ListNode l1, ListNode l2) { + ListNode newNode = new ListNode(-1); + ListNode tail = newNode; + + while(l1 != null && l2 != null){ + if(l1.val < l2.val){ + tail.next = l1; + l1 = l1.next; + tail = tail.next; + }else{ + tail.next = l2; + l2 = l2.next; + tail = tail.next; + } + } + if(l1 != null){ + tail.next = l1; + } + if(l2 != null){ + tail.next = l2; + } + return newNode.next; + } +} \ No newline at end of file diff --git a/Week 01/id_471/LeetCode_26_471.java b/Week 01/id_471/LeetCode_26_471.java new file mode 100644 index 000000000..ba41ae346 --- /dev/null +++ b/Week 01/id_471/LeetCode_26_471.java @@ -0,0 +1,45 @@ +//使用一个变量checked来表示已经遍历过的元素,以此将数组切成两部分,checked的之前为已经遍历好的,checked之后的为未遍历的,然后在遍历过程中如果发现新元素,就把新元素放入前面半部分,最终 cheched+1 即为没有重复数字数组的长度 +//时间复杂度:O(n) +//空间复杂度:O(1) +class Solution { + public int removeDuplicates(int[] nums) { + int checked = 0; + + for(int i = 1; i < nums.length; i++){ + if(nums[i] != nums[checked]){ + nums[++checked] = nums[i]; + } + } + + return checked+1; + } +} + +//暴力法 +//遍历数组,当发现相邻元素相同的时候,删掉其中一个,然后将后面所有元素往前移一位,如此循环,直到所有多余的重复元素都被移除 +//时间复杂度: O(n^2) +//空间复杂度:O(1) + +class Solution { + public int removeDuplicates(int[] nums) { + int length = nums.length; + for(int i = 0; i < length; i++){ + if(i == 0){ + continue; + } + while(nums[i] == nums[i-1]){ + if(i == length-1){ + length--; + break; + } + + for(int j = i; j < length-1; j++){ + //System.out.println(j); + nums[j] = nums[j+1]; + } + length--; + } + } + return length; + } +} \ No newline at end of file diff --git a/Week 01/id_471/LeetCode_283_471.java b/Week 01/id_471/LeetCode_283_471.java new file mode 100644 index 000000000..56b82e7a4 --- /dev/null +++ b/Week 01/id_471/LeetCode_283_471.java @@ -0,0 +1,58 @@ +//使用临时变量 j 来对应 0 的下标,遍历数组,如果发现不为 0 的元素就跟是 0 的元素交换,类似冒泡的方法,把 0 都冒到数组的后端 +//时间复杂度:O(n) +//空间复杂度:O(1) + +class Solution { + public void moveZeroes(int[] nums) { + int j = 0; + for(int i = 0; i < nums.length; i++){ + if(nums[i] != 0){ + int temp = nums[i]; + nums[i] = nums[j]; + nums[j++] = temp; + } + } + } +} + +//借助额外数组法,空间复杂度为O(n), 时间复杂度为O(n) + +class Solution { + public void moveZeroes(int[] nums) { + int result[] = new int[nums.length]; + int count = 0; + for( int i = 0; i < nums.length; i++ ){ + if(nums[i] != 0){ + result[count++] = nums[i]; + } + } + + for( int i = 0; i < count; i++ ){ + nums[i] = result[i]; + } + + for ( int i = count; i < nums.length; i++){ + nums[i] = 0; + } + + } +} + +//原数组上直接操作,借助一个变量在遍历数组的过程中将非零数字从后往前重新插入数组中,后面的补零,时间复杂度为 O(n), 空间复杂度为 O(1) + +class Solution { + public void moveZeroes(int[] nums) { + + int insertIndex = 0; + for( int i = 0, j = 0 ; i < nums.length; i++ ){ + if(nums[i] != 0){ + nums[insertIndex++] = nums[i]; + } + } + + for(int i = insertIndex; i < nums.length; i++){ + nums[i] = 0; + } + + } +} \ No newline at end of file diff --git a/Week 01/id_471/LeetCode_66_471.java b/Week 01/id_471/LeetCode_66_471.java new file mode 100644 index 000000000..942cdfe15 --- /dev/null +++ b/Week 01/id_471/LeetCode_66_471.java @@ -0,0 +1,22 @@ +//从后往前遍历,如果数字为 9 ,加 1 之后需要进位, 则继续往前遍历,直到数字不为 9 或者遍历全部数字。 +// 如果遍历所有了数字,说明数组中全部都为9,只需要扩充数组,把第一个元素设为 1 +// 如果没有遍历所有数字,则在断点处对那个数字加一 +class Solution { + public int[] plusOne(int[] digits) { + int index = digits.length-1; + + while(index >= 0 && digits[index] == 9){ + digits[index] = 0; + index--; + } + if(index < 0){ + int[] results = new int[digits.length+1]; + results[0] = 1; + return results; + }else{ + digits[index] = digits[index]+1; + } + + return digits; + } +} \ No newline at end of file diff --git a/Week 01/id_471/LeetCode_84_471.java b/Week 01/id_471/LeetCode_84_471.java new file mode 100644 index 000000000..d05265e0f --- /dev/null +++ b/Week 01/id_471/LeetCode_84_471.java @@ -0,0 +1,35 @@ +//使用单调递增栈,即栈中的元素是从小到大递增的,但是此问题入栈的是元素的下标,即按照下标对应的元素是单调递增的 +//该问题主要关注的点是,如果想以第 i 个元素的高度为矩形的高度,那么height[i]应该是跟它一起构成矩形所有矩形条中最小的, +//于是需要找满足这个条件的相对于 i 的左边界和右边界 +//左边界和右边界的距离就是矩形的宽,跟高度的积就是矩形的面积 +//遍历元素,如果在遍历过程中当前元素比栈顶元素大,说明栈顶元素的右边界还没有找到,于是将其入栈 +//如果在遍历过程中当前元素比栈顶元素小,那说明以栈顶元素对应高度做矩阵的高的情况的右边界已经找到 +//然后对应元素的左边界就是栈顶元素的下一个元素,因为栈是单调递增栈,故栈顶元素出出栈后的新的栈顶元素即为左边界 +//在遍历过程中使用临时变量 maxArea 记录最大面积 +//时间复杂度:O(n) +//空间复杂度:O(n) +//参考链接:https://www.cnblogs.com/boring09/p/4231906.html + +public class Solution { + public int largestRectangleArea(int[] height) { + + ArrayDeque stack = new ArrayDeque(); + int[] heights = Arrays.copyOf(height, height.length+1); + heights[height.length] = -1; + int maxArea = 0; + for(int i = 0; i < heights.length; i++){ + while(!stack.isEmpty() && heights[i] < heights[stack.peek()]){ + if(stack.size() == 1){ + maxArea = Math.max(maxArea,heights[stack.pop()]*i); + }else{ + int index = stack.peek(); + maxArea = Math.max(maxArea,heights[stack.peek()]*(i-stack.pop()+index-stack.peek()-1)); + } + } + + stack.push(i); + } + + return maxArea; + } +} \ No newline at end of file diff --git a/Week 01/id_471/LeetCode_88_471.java b/Week 01/id_471/LeetCode_88_471.java new file mode 100644 index 000000000..8098635f4 --- /dev/null +++ b/Week 01/id_471/LeetCode_88_471.java @@ -0,0 +1,66 @@ +//每个数组从尾到头遍历,然后从大到小将数字插入到nums1中 +//时间复杂度为 O(n+m) +//空间复杂度为 O(1) +class Solution { + public void merge(int[] nums1, int m, int[] nums2, int n) { + int i = m-1; + int j = n-1; + int k = m+n-1; + + while(i >= 0 && j >= 0){ + if(nums1[i] > nums2[j]){ + nums1[k--] = nums1[i--]; + }else{ + nums1[k--] = nums2[j--]; + } + } + + while(j >= 0){ + nums1[k--] = nums2[j--]; + } + } +} + +//方法2,使用一个中间数组,将 nums1 和 nums2 中的数组放入中间数组中,然后再把中间数组赋值给nums1 +//时间复杂度为:O(m+n) +//空间复杂度为:O(m+n) +class Solution { + public void merge(int[] nums1, int m, int[] nums2, int n) { + int[] temp = new int[nums1.length]; + int i = 0, j = 0, count = 0; + + while(i < m && j < n){ + if(nums1[i] < nums2[j]){ + temp[count++] = nums1[i++]; + }else{ + temp[count++] = nums2[j++]; + } + } + + while(i < m){ + temp[count++] = nums1[i++]; + } + while(j < n){ + temp[count++] = nums2[j++]; + } + + + for(i = 0; i < temp.length; i++){ + nums1[i] = temp[i]; + } + } +} + +//将nums2中的数据放入nums1,然后排序 +//时间复杂度为: O(nlogn) +//空间复杂度为:O(1) +class Solution { + public void merge(int[] nums1, int m, int[] nums2, int n) { + + for(int i = m; i < m + n; i++){ + nums1[i] = nums2[i-m]; + } + + Arrays.sort(nums1); + } +} \ No newline at end of file diff --git a/Week 01/id_476/LeetCode_21_476.java b/Week 01/id_476/LeetCode_21_476.java new file mode 100644 index 000000000..66ad05cc1 --- /dev/null +++ b/Week 01/id_476/LeetCode_21_476.java @@ -0,0 +1,93 @@ +//将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 +// +// 示例: +// +// 输入:1->2->4, 1->3->4 +//输出:1->1->2->3->4->4 +// +// Related Topics 链表 + +package com.markdown.leetcode.editor.cn; + +public class MergeTwoSortedLists { + public static void main(String[] args) { + Solution solution = new MergeTwoSortedLists().new Solution(); + } + + public class ListNode { + int val; + ListNode next; + ListNode(int x) { val = x; } + } + //leetcode submit region begin(Prohibit modification and deletion) + // class Solution { + // public ListNode mergeTwoLists(ListNode l1, ListNode l2) { + // if (l1 == null) return l2; + // if (l2 == null) return l1; + // ListNode main = l1, minor = l2; + // if (l1.val > l2.val) { + // main = l2; + // minor = l1; + // } + // ListNode head = main; + // while (main != null && main.next != null) { + // if (minor == null) { + // break; + // } + // if (main.next.val > minor.val) { + // ListNode mainNext = main.next; + // ListNode minorNext = minor.next; + // main.next = minor; + // minor.next = mainNext; + // if (minorNext != null && mainNext.val <= minorNext.val) { + // main = mainNext; + // } + // minor = minorNext; + // } else { + // main = main.next; + // } + // } + // if (minor != null) { + // main.next = minor; + // } + // return head; + // } + // } + + // class Solution { + // public ListNode mergeTwoLists(ListNode l1, ListNode l2) { + // // 递归 + // if (l1 == null) return l2; + // if (l2 == null) return l1; + // if (l1.val < l2.val) { + // l1.next = mergeTwoLists(l1.next, l2); + // return l1; + // } else { + // l2.next = mergeTwoLists(l1, l2.next); + // return l2; + // } + // } + // } + + class Solution { + public ListNode mergeTwoLists(ListNode l1, ListNode l2) { + // 迭代 + ListNode prehead = new ListNode(-1); + ListNode prev = prehead; + 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 ? l1 : l2; + return prehead.next; + } + } + //leetcode submit region end(Prohibit modification and deletion) + +} \ No newline at end of file diff --git a/Week 01/id_476/LeetCode_26_476.java b/Week 01/id_476/LeetCode_26_476.java new file mode 100644 index 000000000..d26cae121 --- /dev/null +++ b/Week 01/id_476/LeetCode_26_476.java @@ -0,0 +1,62 @@ +//给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。 +// +// 不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。 +// +// 示例 1: +// +// 给定数组 nums = [1,1,2], +// +//函数应该返回新的长度 2, 并且原数组 nums 的前两个元素被修改为 1, 2。 +// +//你不需要考虑数组中超出新长度后面的元素。 +// +// 示例 2: +// +// 给定 nums = [0,0,1,1,1,2,2,3,3,4], +// +//函数应该返回新的长度 5, 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4。 +// +//你不需要考虑数组中超出新长度后面的元素。 +// +// +// 说明: +// +// 为什么返回数值是整数,但输出的答案是数组呢? +// +// 请注意,输入数组是以“引用”方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。 +// +// 你可以想象内部操作如下: +// +// // nums 是以“引用”方式传递的。也就是说,不对实参做任何拷贝 +//int len = removeDuplicates(nums); +// +//// 在函数里修改输入数组对于调用者是可见的。 +//// 根据你的函数返回的长度, 它会打印出数组中该长度范围内的所有元素。 +//for (int i = 0; i < len; i++) { +//    print(nums[i]); +//} +// +// Related Topics 数组 双指针 + +public class RemoveDuplicatesFromSortedArray { + public static void main(String[] args) { + Solution solution = new RemoveDuplicatesFromSortedArray().new Solution(); + } + + + //leetcode submit region begin(Prohibit modification and deletion) + class Solution { + public int removeDuplicates(int[] nums) { + if (nums == null) return 0; + int index = 0; + for (int i = 1; i < nums.length; i++) { + if (nums[i] != nums[index]) { + nums[++index] = nums[i]; + } + } + return index + 1; + } + } + //leetcode submit region end(Prohibit modification and deletion) + +} \ No newline at end of file diff --git a/Week 01/id_476/LeetCode_42_476.java b/Week 01/id_476/LeetCode_42_476.java new file mode 100644 index 000000000..4da1548c0 --- /dev/null +++ b/Week 01/id_476/LeetCode_42_476.java @@ -0,0 +1,65 @@ +//给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。 +// +// +// +// 上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。 感谢 Marcos 贡献此图。 +// +// 示例: +// +// 输入: [0,1,0,2,1,0,1,3,2,1,2,1] +//输出: 6 +// Related Topics 栈 数组 双指针 + +package com.markdown.leetcode.editor.cn; + +import java.util.Stack; + +public class TrappingRainWater { + public static void main(String[] args) { + Solution solution = new TrappingRainWater().new Solution(); + } + + + //leetcode submit region begin(Prohibit modification and deletion) + // class Solution { + // public int trap(int[] height) { + // + // int total = 0; + // for (int i = 1; i < height.length - 1; i++) { + // int maxLeft = 0, maxRight = 0; + // for (int j = 0; j <= i; j++) { + // maxLeft = Math.max(maxLeft, height[j]); + // } + // for (int k = i; k < height.length; k++) { + // maxRight = Math.max(maxRight, height[k]); + // } + // total += Math.min(maxLeft, maxRight) - height[i]; + // } + // return total; + // } + // } + + class Solution { + public int trap(int[] height) { + + int total = 0; + Stack stack = new Stack<>(); + for (int i = 0; i < height.length; i++) { + while (!stack.isEmpty() && height[stack.peek()] < height[i]) { + Integer pop = stack.pop(); + if (stack.isEmpty()) { + break; + } + int h = height[pop]; + int dist = i - stack.peek() - 1; + int min = Math.min(height[stack.peek()], height[i]); + total += (min - h) * dist; + } + stack.push(i); + } + return total; + } + } + //leetcode submit region end(Prohibit modification and deletion) + +} \ No newline at end of file diff --git a/Week 01/id_476/LeetCode_641_476.java b/Week 01/id_476/LeetCode_641_476.java new file mode 100644 index 000000000..2de0dab41 --- /dev/null +++ b/Week 01/id_476/LeetCode_641_476.java @@ -0,0 +1,157 @@ +//设计实现双端队列。 +//你的实现需要支持以下操作: +// +// +// MyCircularDeque(k):构造函数,双端队列的大小为k。 +// insertFront():将一个元素添加到双端队列头部。 如果操作成功返回 true。 +// insertLast():将一个元素添加到双端队列尾部。如果操作成功返回 true。 +// deleteFront():从双端队列头部删除一个元素。 如果操作成功返回 true。 +// deleteLast():从双端队列尾部删除一个元素。如果操作成功返回 true。 +// getFront():从双端队列头部获得一个元素。如果双端队列为空,返回 -1。 +// getRear():获得双端队列的最后一个元素。 如果双端队列为空,返回 -1。 +// isEmpty():检查双端队列是否为空。 +// isFull():检查双端队列是否满了。 +// +// +// 示例: +// +// MyCircularDeque circularDeque = new MycircularDeque(3); // 设置容量大小为3 +//circularDeque.insertLast(1); // 返回 true +//circularDeque.insertLast(2); // 返回 true +//circularDeque.insertFront(3); // 返回 true +//circularDeque.insertFront(4); // 已经满了,返回 false +//circularDeque.getRear(); // 返回 2 +//circularDeque.isFull(); // 返回 true +//circularDeque.deleteLast(); // 返回 true +//circularDeque.insertFront(4); // 返回 true +//circularDeque.getFront(); // 返回 4 +//  +// +// +// +// 提示: +// +// +// 所有值的范围为 [1, 1000] +// 操作次数的范围为 [1, 1000] +// 请不要使用内置的双端队列库。 +// +// Related Topics 设计 队列 + +import java.util.LinkedList; +import java.util.List; + +public class DesignCircularDeque { + public static void main(String[] args) { + // Solution solution = new DesignCircularDeque().new Solution(); + } + + + //leetcode submit region begin(Prohibit modification and deletion) + class MyCircularDeque { + + List forward = new LinkedList<>(); + List backward = new LinkedList<>(); + int length; + + /** + * Initialize your data structure here. Set the size of the deque to be k. + */ + public MyCircularDeque(int k) { + this.length = k; + } + + /** + * Adds an item at the front of Deque. Return true if the operation is successful. + */ + public boolean insertFront(int value) { + if (isFull()) { + return false; + } + forward.add(0, value); + backward.add(value); + return true; + } + + /** + * Adds an item at the rear of Deque. Return true if the operation is successful. + */ + public boolean insertLast(int value) { + if (isFull()) { + return false; + } + forward.add(value); + backward.add(0, value); + return true; + } + + /** + * Deletes an item from the front of Deque. Return true if the operation is successful. + */ + public boolean deleteFront() { + if (isEmpty()) { + return false; + } + forward.remove(0); + backward.remove(backward.size() - 1); + return true; + } + + /** + * Deletes an item from the rear of Deque. Return true if the operation is successful. + */ + public boolean deleteLast() { + if (isEmpty()) { + return false; + } + forward.remove(forward.size() - 1); + backward.remove(0); + return true; + } + + /** + * Get the front item from the deque. + */ + public int getFront() { + if (isEmpty()) return -1; + return forward.get(0); + } + + /** + * Get the last item from the deque. + */ + public int getRear() { + if (isEmpty()) return -1; + return backward.get(0); + } + + /** + * Checks whether the circular deque is empty or not. + */ + public boolean isEmpty() { + return forward.size() == 0; + } + + /** + * Checks whether the circular deque is full or not. + */ + public boolean isFull() { + return forward.size() == length; + } + } + + /** + * 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(); + */ + //leetcode submit region end(Prohibit modification and deletion) + +} \ No newline at end of file diff --git a/Week 01/id_481/LeetCode_1_481.java b/Week 01/id_481/LeetCode_1_481.java new file mode 100644 index 000000000..529e822b2 --- /dev/null +++ b/Week 01/id_481/LeetCode_1_481.java @@ -0,0 +1,48 @@ +//给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。 +// +// 你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。 +// +// 示例: +// +// 给定 nums = [2, 7, 11, 15], target = 9 +// +//因为 nums[0] + nums[1] = 2 + 7 = 9 +//所以返回 [0, 1] +// +// Related Topics 数组 哈希表 + +package leetcode.editor.cn; + +//Java:两数之和 +public class P1TwoSum { + public static void main(String[] args) { + Solution solution = new P1TwoSum().new Solution(); + } + + + //leetcode submit region begin(Prohibit modification and deletion) + class Solution { + + /** + * 暴力求解 + * @param nums + * @param target + * @return + */ + public int[] twoSum(int[] nums, int target) { + int result[] = new int[2]; + for (int i = 0; i < nums.length - 1; i++) { + for (int j = i + 1; j < nums.length; j++) { + if (target == (nums[i] + nums[j])) { + result[0] = i; + result[1] = j; + return result; + } + } + } + return result; + } + } +//leetcode submit region end(Prohibit modification and deletion) + +} diff --git a/Week 01/id_481/LeetCode_283_481.java b/Week 01/id_481/LeetCode_283_481.java new file mode 100644 index 000000000..adfc218ad --- /dev/null +++ b/Week 01/id_481/LeetCode_283_481.java @@ -0,0 +1,90 @@ +//给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。 +// +// 示例: +// +// 输入: [0,1,0,3,12] +//输出: [1,3,12,0,0] +// +// 说明: +// +// +// 必须在原数组上操作,不能拷贝额外的数组。 +// 尽量减少操作次数。 +// +// Related Topics 数组 双指针 + +package leetcode.editor.cn; + +import java.util.Arrays; + +//Java:移动零 +public class P283MoveZeroes { + public static void main(String[] args) { + int[] arr = {0,1,0,0,3,12}; + //利用冒泡的思想实现了一个二的方法 时间复杂度为 n^2 + Solution01 solution = new P283MoveZeroes().new Solution01(); + solution.moveZeroes(arr); + System.out.println(Arrays.toString(arr)); + + int[] test = {1,2,0,0,1,0,0,3,12}; + Solution02 solution1 = new P283MoveZeroes().new Solution02(); + solution1.moveZeroes(test); + System.out.println(Arrays.toString(test)); + + int[] test3 = {1,2,0,0,1,0,0,3,12}; + Solution03 solution03 = new P283MoveZeroes().new Solution03(); + solution03.moveZeroes(test3); + System.out.println(Arrays.toString(test3)); + + } + + class Solution03 { + //思考: 这个理解起来是比较顺的, 先把非0找好位置,剩下的补0 + public void moveZeroes(int[] nums) { + int j = 0; + for (int i = 0; i <= nums.length - 1; i++) { + if (nums[i] != 0) { + nums[j++] = nums[i]; + } + } + for (int i = j; i <= nums.length - 1; i++) { + nums[i] = 0; + } + } + } + + + class Solution02 { + //思考:要注意 i != j 在设置i的值 + public void moveZeroes(int[] nums) { + int j = 0; + for (int i = 0; i <= nums.length - 1; i++) { + if (nums[i] != 0) { + nums[j] = nums[i]; + if (i != j) { + nums[i] = 0; + } + j++; + } + } + } + } + + //leetcode submit region begin(Prohibit modification and deletion) + class Solution01 { + //基于冒泡的思想 + public void moveZeroes(int[] nums) { + for (int i = 0; i < nums.length - 1; i++) { + for (int j = 0; j < nums.length - 1; j++) { + if (nums[j] == 0) { + int temp = nums[j]; + nums[j] = nums[j + 1]; + nums[j + 1] = temp; + } + } + } + } + } +//leetcode submit region end(Prohibit modification and deletion) + +} diff --git a/Week 01/id_481/LeetCode_89_481.java b/Week 01/id_481/LeetCode_89_481.java new file mode 100644 index 000000000..93ad0db32 --- /dev/null +++ b/Week 01/id_481/LeetCode_89_481.java @@ -0,0 +1,60 @@ +//给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数。 +// +// 示例 1: +// +// 输入: [1,2,3,4,5,6,7] 和 k = 3 +//输出: [5,6,7,1,2,3,4] +//解释: +//向右旋转 1 步: [7,1,2,3,4,5,6] +//向右旋转 2 步: [6,7,1,2,3,4,5] +//向右旋转 3 步: [5,6,7,1,2,3,4] +// +// +// 示例 2: +// +// 输入: [-1,-100,3,99] 和 k = 2 +//输出: [3,99,-1,-100] +//解释: +//向右旋转 1 步: [99,-1,-100,3] +//向右旋转 2 步: [3,99,-1,-100] +// +// 说明: +// +// +// 尽可能想出更多的解决方案,至少有三种不同的方法可以解决这个问题。 +// 要求使用空间复杂度为 O(1) 的 原地 算法。 +// +// Related Topics 数组 + +package leetcode.editor.cn; + +import java.util.Arrays; + +//Java:旋转数组 +public class P189RotateArray { + public static void main(String[] args) { + Solution solution = new P189RotateArray().new Solution(); + // TO TEST + int[] arr = {1, 2, 3, 4, 5, 6, 7}; + solution.rotate(arr, 3); + } + + // lenght - 1 lenght - 2 lenght - 3 + // + + //leetcode submit region begin(Prohibit modification and deletion) + class Solution { + public void rotate(int[] nums, int k) { + for (int i = 0; i < k; i++) { + int temp = nums[nums.length - 1]; + for (int j = nums.length - 1; j > 0; j--) { + nums[j] = nums[j-1]; + } + nums[0] = temp; + } + } + } +//leetcode submit region end(Prohibit modification and deletion) + +} + diff --git a/Week 01/id_481/NOTE.md b/Week 01/id_481/NOTE.md index a6321d6e2..c515b2d3d 100644 --- a/Week 01/id_481/NOTE.md +++ b/Week 01/id_481/NOTE.md @@ -1,4 +1,17 @@ # NOTE - +#### +知识点比较多,一周的时间不一定能够吃透。 +做题的思路:如果没有精妙的思路,那就先暴力做出来。 + +#### LeetCode 89 +最开始没有审清题 +解体思路: +1 外层控制旋转次数,内层负责把数往后移动, +2 用一个temp记录每次移出来的值,每次转出来的值都是最后一个,然后都是要放在第一个位置。 + +#### LeetCode 283 +写了3种方法,总体感觉solution03是更适合自己理解与记忆的。 +思路: +先把非0数找好位置,按顺序排列好(j就是在做这个事情)。剩下的补0即可 diff --git a/Week 01/id_491/LeetCode_1_491.java b/Week 01/id_491/LeetCode_1_491.java new file mode 100644 index 000000000..a99437126 --- /dev/null +++ b/Week 01/id_491/LeetCode_1_491.java @@ -0,0 +1,16 @@ +twoSum Solution { + public int[] twoSum(int[] nums, int target) { + Map sortedList = new HashMap<>(nums.length); + int[] result = new int[2]; + for(int i = 0 ; i < nums.length; i++){ + if(sortedList.containsKey(target - nums[i])){ + result[0] = i; + result[1] = sortedList.get(target - nums[i]); + } else { + sortedList.put(nums[i], i); + } + } + + return result; + } +} diff --git a/Week 01/id_491/LeetCode_26_491.java b/Week 01/id_491/LeetCode_26_491.java new file mode 100644 index 000000000..d94489431 --- /dev/null +++ b/Week 01/id_491/LeetCode_26_491.java @@ -0,0 +1,16 @@ +class removeDuplicatesFromSortedArray { + public int removeDuplicates(int[] nums) { + int notDuplicate = 0; + for (int i = 1; i < nums.length; i++) { + if (nums[i] == nums[i - 1]) { + continue; + } else { + notDuplicate++; + if (notDuplicate != i) { + nums[notDuplicate] = nums[i]; + } + } + } + return notDuplicate + 1; + } +} diff --git a/Week 01/id_491/LeetCode_283_491.java b/Week 01/id_491/LeetCode_283_491.java new file mode 100644 index 000000000..48829da6a --- /dev/null +++ b/Week 01/id_491/LeetCode_283_491.java @@ -0,0 +1,16 @@ +class moveZeroes { + public void moveZeroes(int[] nums) { + int notZero = 0; + for (int i = 0; i < nums.length; i++) { + if (nums[i] == 0) { + continue; + } else { + if (notZero != i) { + nums[notZero] = nums[i]; + nums[i] = 0; + } + notZero++; + } + } + } +} diff --git a/Week 01/id_491/LeetCode_42_491.java b/Week 01/id_491/LeetCode_42_491.java new file mode 100644 index 000000000..ffe8d89c8 --- /dev/null +++ b/Week 01/id_491/LeetCode_42_491.java @@ -0,0 +1,49 @@ +class trappingRainWater { + public int trap(int[] height) { + int sum = 0; + Stack stack = new Stack<>(); + if (height == null || height.length <= 2) { + return 0; + } else { + for (int i = 0; i < height.length; i++) { + if (i == 0) { + stack.push(i); + } else { + if (height[stack.peek()] <= height[i]) { + stack.push(i); + } + } + } + + int first = stack.pop(); + while (!stack.empty()) { + int second = stack.pop(); + for (int i = second + 1; i <= first - 1; i++) { + sum += height[second] - height[i]; + } + first = second; + } + + for (int i = height.length - 1; i >= 0; i--) { + if (i == height.length - 1) { + stack.push(i); + } else { + if (height[stack.peek()] < height[i]) { + stack.push(i); + } + } + } + + first = stack.pop(); + while (!stack.empty()) { + int second = stack.pop(); + for (int i = first + 1; i <= second - 1; i++) { + sum += height[second] - height[i]; + } + first = second; + } + } + + return sum; + } +} diff --git a/Week 01/id_491/LeetCode_66_491.java b/Week 01/id_491/LeetCode_66_491.java new file mode 100644 index 000000000..1c1b8ad77 --- /dev/null +++ b/Week 01/id_491/LeetCode_66_491.java @@ -0,0 +1,28 @@ +class plusOne { + public int[] plusOne(int[] digits) { + boolean hasNotNine = false; + for (int i = digits.length - 1;i >= 0; i--) { + if(digits[i] != 9){ + digits[i] = digits[i] + 1; + hasNotNine = true; + break; + } else { + digits[i] = 0; + } + } + + if(!hasNotNine){ + int[] result = new int[digits.length + 1]; + for(int i = 0; i < result.length; i++){ + if(i == 0){ + result[i] = 1; + } else { + result[i] = 0; + } + } + return result; + } else { + return digits; + } + } +} diff --git a/Week 01/id_491/LeetCode_88_491.java b/Week 01/id_491/LeetCode_88_491.java new file mode 100644 index 000000000..785d96ae2 --- /dev/null +++ b/Week 01/id_491/LeetCode_88_491.java @@ -0,0 +1,18 @@ +class mergeSortedArray { + public void merge(int[] nums1, int m, int[] nums2, int n) { + int totalSize = m + n - 1; + m = m - 1; + n = n - 1; + while (totalSize >= 0) { + if (m < 0) { + nums1[totalSize--] = nums2[n--]; + } else if(n < 0){ + break; + } else if (nums1[m] > nums2[n]) { + nums1[totalSize--] = nums1[m--]; + } else { + nums1[totalSize--] = nums2[n--]; + } + } + } +} diff --git a/Week 01/id_501/homework/week01/MergeSortedArray.java b/Week 01/id_501/homework/week01/MergeSortedArray.java new file mode 100644 index 000000000..f8cf3b003 --- /dev/null +++ b/Week 01/id_501/homework/week01/MergeSortedArray.java @@ -0,0 +1,67 @@ +package homework.week01; + +import java.util.Arrays; + +/** + * 88. 合并两个有序数组 + * https://leetcode-cn.com/problems/merge-sorted-array/ + */ +public class MergeSortedArray{ + + /** + * 暴力法: + * 合并后,排序 + * @param nums1 + * @param m + * @param nums2 + * @param n + */ + public static void merge(int[] nums1, int m, int[] nums2, int n) { + System.arraycopy(nums2, 0, nums1, m, n); + Arrays.sort(nums1); + } + + /** + * 思路: + * 双指针法 + * 获取到nums1元素最大索引p1,nums2最大索引p2,获取合并后元素最大索引p + * nums1[p1] < nums2[p2] 把nums2[p2] 的值放到nums1[p] 上,然后进行下一轮循环 + * 最后结果[1,2,2,3,5,6] + * @param nums1 + * @param m + * @param nums2 + * @param n + */ + public static void merge2(int[] nums1, int m, int[] nums2, int n){ + // nums1最后面元素索引 + int p1 = m - 1; + // nums1最后面元素索引 + int p2 = n - 1; + + // 合并后最后面元素索引 + int p = m + n - 1; + + while(p1 >= 0 && p2 >= 0){ + if(nums1[p1] < nums2[p2] ){ + nums1[p] = nums2[p2]; + p2--; + + }else{ + nums1[p] = nums1[p1]; + p1--; + } + p--; + } + // 当前 + System.arraycopy(nums2, 0, nums1, 0, p2 + 1); + } + + public static void main(String[] args) { + int[] nums1 = new int[]{1,2,3,0,0,0}; + int[] nums2 = new int[]{2,5,6}; + // merge(nums1, 3, nums2, 3); + merge2(nums1, 3, nums2, 3); + System.out.println(Arrays.toString(nums1)); + } + +} \ No newline at end of file diff --git a/Week 01/id_501/homework/week01/MoveZeros.java b/Week 01/id_501/homework/week01/MoveZeros.java new file mode 100644 index 000000000..bfd6d4f23 --- /dev/null +++ b/Week 01/id_501/homework/week01/MoveZeros.java @@ -0,0 +1,58 @@ +package homework.week01; + +import java.util.Arrays; + +/** + * 283. 移动零 + * https://leetcode-cn.com/problems/move-zeroes/ + */ +public class MoveZeros{ + /** + * 方法一: + * 两层for循环,第一个和第二个数判断,第一个数为0,则与第二个数换位置 + * 互换后还是0,再与第三个互换,直到非零为止。 + * @param nums + */ + public static void moveZero1(int[] nums) { + int temp; + for(int i = 0; i < nums.length-1; i ++){ + for(int j = i + 1;j < nums.length ; j++){ + if(nums[i] == 0 ){ + temp = nums[i]; + nums[i] = nums[j]; + nums[j] = temp; + } + } + } + } + + /** + * 方法二: + * for循环把所有非零的数移动到前面,然后数组剩余位置补0 + * 使用指针i,指向需要插入的下标,使用指针j指向遍历的下标。遍历一遍,如果j指向的位置为0, + * 则i不变,j++后移;如果j指向的位置不为0,则将j位置的元素值赋值到i位置,然后i++。 + * 参考链接: + * https://leetcode-cn.com/problems/move-zeroes/solution/javashi-yong-2ge-xia-biao-zhi-zhen-fu-zhi-zui-shao/ + * @param nums + */ + public static void moveZero2(int[] nums){ + // 定义填充非零数据下标 + int i = 0; + for(int j = 0;j < nums.length;j++){ + if(nums[j] != 0){ + nums[i] = nums[j]; + i++; + } + } + // 补0 + for(int k = i;k < nums.length;k++){ + nums[k] = 0; + } + } + + public static void main(String[] args) { + int[] nums = new int[]{0,1,0,3,12}; + moveZero1(nums); + System.out.println(Arrays.toString(nums)); + } +} \ No newline at end of file diff --git a/Week 01/id_501/homework/week01/PlusOne.java b/Week 01/id_501/homework/week01/PlusOne.java new file mode 100644 index 000000000..8612a92d1 --- /dev/null +++ b/Week 01/id_501/homework/week01/PlusOne.java @@ -0,0 +1,71 @@ +package homework.week01; + +import java.util.Arrays; + +/** + * 66. 加一 + * https://leetcode-cn.com/problems/plus-one/ + */ +public class PlusOne{ + + /** + * 暴力法 + * 思路: + * 先判断最后一位+1,是不是大于9,如果小于,直接最后一位+1,返回数组 + * 如果最后一位+1,大于9,则需要向前一位进1,从后向前遍历, + * 如果当前数值 小于10,则直接返回 + * 如果当前数值 大于9,则当前位置为0 + * 当i = 0时,表示最后一位 +1 还是大于9,则要扩容数组 + * @param digits + * @return + */ + public static int[] plusOne(int[] digits) { + int end = digits[digits.length - 1]; + if(end + 1 <= 9){ + digits[digits.length - 1] = end + 1; + return digits; + } + for(int i = digits.length - 1;i >= 0; i --){ + if(digits[i] + 1 <= 9){ + digits[i] = digits[i] + 1; + break; + }else{ + digits[i] = 0; + if(i == 0){ + int[] result = new int[digits.length + 1]; + result[0] = 1; + System.arraycopy(digits, 0, result, 1, digits.length); + return result; + } + } + } + return digits; + } + + /** + * 思路: + * 关键在于 %= 10, 与10取余,如果=0,表示+1为10,如果不为0,表示+1,小于10 + * @param digits + * @return + */ + public static int[] plusOne2(int[] digits) { + for(int i = digits.length - 1; i >= 0; i --){ + digits[i] ++ ; + digits[i] %= 10; + if(digits[i] != 0){ + return digits; + } + } + digits = new int[digits.length + 1]; + digits[0] = 1; + return digits; + } + + public static void main(String[] args) { + int[] digits = new int[]{8,9,9}; + // int[] digits = new int[]{1,2,3}; + plusOne(digits); + System.out.println(Arrays.toString(digits)); + } + +} \ No newline at end of file diff --git a/Week 01/id_501/homework/week01/RemoveDuplicatesFromArray.java b/Week 01/id_501/homework/week01/RemoveDuplicatesFromArray.java new file mode 100644 index 000000000..11ce5b7a7 --- /dev/null +++ b/Week 01/id_501/homework/week01/RemoveDuplicatesFromArray.java @@ -0,0 +1,36 @@ +package homework.week01; + +import java.util.Arrays; + +/** + * 26. 删除排序数组中的重复项 + * https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array + */ +public class RemoveDuplicatesFromArray{ + /** + * 思路: + * i 和 j 比较,j 比 1索引大1,判断是否相等,如果相等,就比较i和j+1,依次类推,直到i和j + n不相等, + * 就把 i + 1,换成 j + n的值。本次替换结束,下一次,i + 1,继续和j+n+1的值比较。直到j = nums.length -1 + * @param nums + * @return + */ + public static int removeDuplicates(int[] nums) { + int i = 0; + int j = 1; + while(j < nums.length){ + if(nums[i] != nums[j]){ + nums[i + 1] = nums[j]; + i ++ ; + } + j ++ ; + System.out.println("i,j = " + i + "," + j +" " + Arrays.toString(nums)); + } + return i + 1 ; + } + public static void main(String[] args) { + int[] nums = new int[]{0,0,1,1,1,2,2,3,3,4}; + int count = removeDuplicates(nums); + System.out.println(Arrays.toString(nums)); + System.out.println(count); + } +} \ No newline at end of file diff --git a/Week 01/id_501/homework/week01/RotateArray.java b/Week 01/id_501/homework/week01/RotateArray.java new file mode 100644 index 000000000..793ac4b7c --- /dev/null +++ b/Week 01/id_501/homework/week01/RotateArray.java @@ -0,0 +1,67 @@ +package homework.week01; + +import java.util.Arrays; + +/** + * 189. 旋转数组 + * https://leetcode-cn.com/problems/rotate-array/ + */ +public class RotateArray{ + + /** + * 暴力法 + * 思路:先写出来每次移动一位的方法,首尾互换,然后再根据k遍历,然后移动k次即可。 + * @param nums + * @param k + */ + public static void rotate(int[] nums, int k) { + for (int j = 0;j < k;j++){ + int temp; + int end = nums[nums.length - 1]; + for(int i = 0;i < nums.length;i++){ + temp = end; + end = nums[i]; + nums[i] = temp; + } + } + } + + /** + * 反转法 + * 参考链接:https://leetcode-cn.com/problems/rotate-array/solution/xuan-zhuan-shu-zu-by-leetcode/ + * 旋转数组k次,k%n个尾部元素会被移动到头部,剩余的元素会向后移动 + * 首先把所有元素反转,然后反转前k个,然后再反转后面n-k个,则得到结果 + * @param nums + * @param k + */ + public static void rotate2(int[] nums, int k) { + k %= nums.length; + reverse(nums, 0, nums.length - 1); + reverse(nums, 0, k -1); + reverse(nums, k, nums.length - 1); + } + + /** + * 反转 + * @param nums + * @param start + * @param end + */ + public static void reverse(int[] nums, int start, int end){ + while(start < end){ + int temp = nums[start]; + nums[start] = nums[end]; + nums[end] = temp; + start ++; + end -- ; + } + } + + + public static void main(String[] args) { + int[] nums = new int[]{1,2,3,4,5,6,7}; + // rotate(nums,3); + rotate2(nums,3); + System.out.println(Arrays.toString(nums)); + } +} \ No newline at end of file diff --git a/Week 01/id_501/homework/week01/TwoSum.java b/Week 01/id_501/homework/week01/TwoSum.java new file mode 100644 index 000000000..8996204eb --- /dev/null +++ b/Week 01/id_501/homework/week01/TwoSum.java @@ -0,0 +1,65 @@ +package homework.week01; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +/** + * 1. 两数之和 + * https://leetcode-cn.com/problems/two-sum/ + */ +public class TwoSum{ + + /** + * 暴力法 + * 思路:双层for循环,第一个和第二个相加,第一个和第三个相加,... 复杂度O(n*n) + * @param nums + * @param target + * @return + */ + public static int[] twoSum(int[] nums, int target) { + int[] result = new int[2]; + for(int i = 0;i < nums.length - 1; i ++) { + for(int j = i + 1; j < nums.length; j ++){ + if(nums[i] + nums [j] == target){ + result[0] = i; + result[1] = j; + } + } + } + return result; + } + + /** + * 思路: + * target - nums[i] = hashMap.get(j)说明匹配整取 + * map 存储的key为nums的数值,value为nums的索引 + * @param nums + * @param target + * @return + */ + public static int[] twoSum2(int[] nums, int target) { + int[] result = new int[2]; + Map sumMap = new HashMap<>(); + int dstNum; + Integer index; + for(int i = 0; i < nums.length; i++) { + dstNum = target - nums[i]; + index = sumMap.get(dstNum); + if(index != null){ + result[0] = i; + result[1] = index; + return result; + } + sumMap.put(nums[i], i); + } + return result; + } + + public static void main(String[] args) { + int[] nums = new int []{2, 7, 11, 15}; + // int[] result = twoSum(nums, 9); + int[] result = twoSum2(nums, 9); + System.out.println(Arrays.toString(result)); + } +} \ No newline at end of file diff --git a/Week 01/id_506/LeetCode_ 26_506.java b/Week 01/id_506/LeetCode_ 26_506.java new file mode 100644 index 000000000..dadfab014 --- /dev/null +++ b/Week 01/id_506/LeetCode_ 26_506.java @@ -0,0 +1,23 @@ +class Solution { + public int removeDuplicates(int[] nums) { + + int p1 = 0; + int p2 = 1; + + while(p2 < nums.length){ + + if (nums[p1] != nums[p2]){ + + p1++; + nums[p1] = nums[p2]; + + } + p2++; + + } + return ++p1; + + } + + +} \ No newline at end of file diff --git a/Week 01/id_506/LeetCode_21_506.java b/Week 01/id_506/LeetCode_21_506.java new file mode 100644 index 000000000..ca43e2286 --- /dev/null +++ b/Week 01/id_506/LeetCode_21_506.java @@ -0,0 +1,40 @@ +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode(int x) { val = x; } + * } + */ +class Solution { + public ListNode mergeTwoLists(ListNode l1, ListNode l2) { + + ListNode head = new ListNode(-1); + + ListNode prev = head; + + + while (l1 != null && l2 != null) { + if (l1.val > l2.val) { + prev.next = l2; + l2 = l2.next; + + + }else { + prev.next = l1; + l1 = l1.next; + } + prev = prev.next; + } + + if (l2 != null){ + prev.next = l2; + } + + if (l1 != null){ + prev.next = l1; + } + + return head.next; + } +} \ No newline at end of file diff --git a/Week 01/id_506/LeetCode_66_506.java b/Week 01/id_506/LeetCode_66_506.java new file mode 100644 index 000000000..309cb3bd5 --- /dev/null +++ b/Week 01/id_506/LeetCode_66_506.java @@ -0,0 +1,49 @@ +class Solution { + public int[] plusOne(int[] digits) { + int index = -1; + + for (int i = digits.length -1 ;i > -1; i--){ + + if (digits[i] != 9){ + index = i; + break; + } + + } + + if (index == -1){ + int[] result = new int[digits.length + 1]; + result[0] = 1; + for (int i = 1; i < digits.length + 1; i++){ + result[i] = 0; + } + return result; + + } + + digits[index]++; + for (int i = index+1; i < digits.length; i++){ + digits[i] = 0; + } + + return digits; + } + + + public int[] plusOne1(int[] digits) { + for (int i = digits.length - 1; i >=0; i--) { + if (digits[i] != 9) { + digits[i]++; + break; + } else { + digits[i] = 0; + } + } + if (digits[0] == 0) { + int[] res = new int[digits.length+1]; + res[0] = 1; + return res; + } + return digits; + } +} \ No newline at end of file diff --git a/Week 01/id_506/LeetCode_88_506.java b/Week 01/id_506/LeetCode_88_506.java new file mode 100644 index 000000000..93e430987 --- /dev/null +++ b/Week 01/id_506/LeetCode_88_506.java @@ -0,0 +1,23 @@ +class Solution { + public void merge(int[] nums1, int m, int[] nums2, int n) { + int i = m + n -1; + + int a = m -1; + int b = n -1; + + while(a >= 0 && b >= 0){ + + + if (nums1[a] <= nums2[b]){ + nums1[i] = nums2[b]; + b--; + + }else{ + nums1[i] = nums1[a]; + a--; + } + i --; + } + System.arraycopy(nums2, 0, nums1, 0, b + 1); + } +} \ No newline at end of file diff --git a/Week 01/id_511/LeetCode_01_511.java b/Week 01/id_511/LeetCode_01_511.java new file mode 100644 index 000000000..440b45119 --- /dev/null +++ b/Week 01/id_511/LeetCode_01_511.java @@ -0,0 +1,68 @@ +package id_511; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +/** + * @version 1.0 + * @Description: 两数之和 + * @author: hxw + * @date: 2019/4/8 21:56 + */ +public class LeetCode_01_511 { + + //方法一:暴力法,一个一个进行比对,时间复杂度O(n^2) + public int[] twoSum1(int[] nums, int target) { + int arr[] = new int[2]; + int b; + for(int i=0;i<=nums.length;i++){ + for(int a=0,j=i+1;a<=(b=(nums.length-i-1));a++){ + if(j<=nums.length-1 && (nums[i]+nums[j])==target){ + arr[0] = i; + arr[1] = j; + return arr; + } + j++; + } + } + return null; + } + + //方法二:两遍哈希表 时间复杂度O(n) 遍历了两次,即2n + public int[] twoSum2(int[] nums, int target){ + Map map = new HashMap<>(); + for (int i = 0; i < nums.length; i++) { //第一次遍历将数组元素和索引一一对应存到hash表中 + map.put(nums[i], i); + } + for (int i = 0; i < nums.length; i++) { + int complement = target - nums[i]; //检查每个元素所对应的目标元素(target - nums[i])是否存在于hash表中 + if (map.containsKey(complement) && map.get(complement) != i) { //如果存在并且不是自身则说明是满足条件的 + return new int[] { i, map.get(complement) }; + } + } + throw new IllegalArgumentException("No two sum solution"); + } + + //方法三: 一遍哈希表 使用hashMap,数组内容为key,索引为value,循环查找,在put当前数之前进行一次containsKey查询 + public int[] twoSum3(int[] nums, int target){ + Map map = new HashMap<>(); + for (int i = 0; i < nums.length; i++) { + int complement = target - nums[i]; + if (map.containsKey(complement)) { + return new int[] { map.get(complement), i }; + } + map.put(nums[i], i); + } + throw new IllegalArgumentException("No two sum solution"); + } + + public static void main(String[] args){ + int nums[] = {5, 7, 11, 15}; + //int nums[] = {3,2,4}; + int target = 10; + LeetCode_01_511 leetCode01511 = new LeetCode_01_511(); + int[] ints = leetCode01511.twoSum3(nums, target); + System.out.println(Arrays.toString(ints)); + } +} diff --git a/Week 01/id_511/LeetCode_11_511.java b/Week 01/id_511/LeetCode_11_511.java new file mode 100644 index 000000000..fe9da28c4 --- /dev/null +++ b/Week 01/id_511/LeetCode_11_511.java @@ -0,0 +1,81 @@ +package id_511; + +/** + * @version 1.0 + * @Description: 盛水最多的容器 + * @author: bingyu + * @date: 2019/10/19 19:03 + */ +public class LeetCode_11_511 { + + //方法一:自己的解决思路:其实就是求得长和宽的面积哪个最大,我们遍历每个数字,并让这个数字其它每个数字组和成一个面积,然后取最大的那一个 + //嵌套循环,时间复杂度是O(n^2) + public static int getMaxArea(int[] arr){ + int maxArea = 0; + for (int i = 0;i < arr.length - 1;++i) { //i控制左数字遍历(注意这里需要控制好边界) + for (int j = i + 1;j < arr.length;++j) { //j是控制右数字遍历 + int area = (j - i) * getMinHeigh(arr,i,j); //这里j是始终大于i的 + maxArea = getMax(maxArea,area); + } + } + return maxArea; + } + + public static int getMax(int maxArea, int area) { + if (maxArea < area) { + maxArea = area; + } + return maxArea; + } + + //选择其中最小的一个高 + public static int getMinHeigh(int[] arr, int i, int j) { + return (arr[i] > arr[j]) ? arr[j] : arr[i]; + } + + //思路:左右边界,向中间逼近,即用最左边和最右边的柱子,然后向中间移动,当遇到比现在的柱子还要高的柱子时计算面积比较大小,直到两根柱子碰到一起 + //时间复杂度O(n) + public static int maxArea(int[] arr){ + int height = getMinHeigh(arr,0,arr.length-1); //两边界的高度 + int maxArea = height * (arr.length - 1); //两边界形成的面积 + for (int i = 0,j = arr.length - 1;i < j;) { //i代表最左边的柱子,j代表最右边的柱子 + int minHeight = getMinHeigh(arr,i,j); //这里第一次计算就是两边界容器的高度 + int length = j - i; //当前容器的长 + if (height < minHeight && maxArea < minHeight * length) { //如果当前高度大于两边界容器的高度,并且计算的面积也要比之前的面积大,赋值给maxArea + height = minHeight; //注意这里height始终用边界容器的高度比较 + maxArea = minHeight * length; + } + if (arr[i] > arr[j]) { //当等到左边界向中间移动至大于右边界时,右边界再开始向中间移动(该题的重点) + j--; + }else { + i++; + } + } + return maxArea; + } + + //覃超老师的解法 + public static int maxArea2(int[] arr) { + int max = 0; + for (int i = 0, j = arr.length - 1; i < j; ) { + int minHeight = arr[i] < arr[j] ? arr[i++] : arr[j--]; + //这里有一个重要的细节就是,当等到左边界向中间移动至大于右边界时,右边界才开始向中间移动,为什么要这样做? + // 因为容器的大小取决于小的那一个数字,如果开始左边界小于右边界,右边界就开始移动,就算下一个比右边界大,但是容器的大小仍取决于小的左边界没有任何意义, + // 所以只有等到左边界的高度大于右边界的高度时,右边界再向中间移动才会有意义 + int area = (j - i + 1) * minHeight; //计算area = [ j - i + 1] * minheight时,这里之所以要加1,是因为上一步操作将i++或者j--了 + max = Math.max(max,area); + } + return max; + } + + public static void main(String[] args) { + //int[] arr = {1,8,6,2,5,4,8,3,7}; + int[] arr = {2,3,4,5,18,17,6}; + int maxArea = maxArea(arr); + System.out.println(maxArea); + } + + + + +} diff --git a/Week 01/id_511/LeetCode_15_511.java b/Week 01/id_511/LeetCode_15_511.java new file mode 100644 index 000000000..4a08e0932 --- /dev/null +++ b/Week 01/id_511/LeetCode_15_511.java @@ -0,0 +1,68 @@ +package id_511; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * @version 1.0 + * @Description: 三数之和 + * @author: bingyu + * @date: 2019/10/20 19:53 + */ +public class LeetCode_15_511 { + + //方法1:暴力求解,首先求三数之和就是a + b + c = 0 可以看出求两数之和即 a + b = -c + //先求出两数之和的方法 + public static int[] twoSum(int target,int[] arr){ + int tsum[] = new int[3]; + for (int i = 0;i < arr.length - 1;++i) { + for (int j = i + 1;j < arr.length;++j) { + if (arr[i] + arr[j] == target) { + tsum[0] = arr[i]; + tsum[1] = arr[j]; + break; + } + } + } + return tsum; + } + + //TODO : 待去重 + // 接下来三数之和就是相当于在二数之和的基础上target是不断变化的 + public static List> threeSum(int [] arr){ + List> outList = new ArrayList<>(); + for (int k = 0;k < arr.length - 2;++k) { + Integer[] tsum = new Integer[3]; + for (int i = k + 1;i < arr.length - 1;++i) { + for (int j = i + 1;j < arr.length;++j) { + if (arr[i] + arr[j] == -arr[k]) { //现在问题是如何去重 + tsum[0] = arr[k]; + tsum[1] = arr[i]; + tsum[2] = arr[j]; + List list = Arrays.asList(tsum); + outList.add(list); + } + } + } + } + return outList; + } + + + //方法二:使用hash表 + + + //方法三:双指针收敛 + public static List> threeSum3(int [] arr){ + + return null; + } + + public static void main(String[] args) { + int[] arr = {-1, 0, 1, 2, -1, -4}; + //int[] ints = twoSum(9, arr); + List> lists = threeSum(arr); + System.out.println(lists); + } +} diff --git a/Week 01/id_511/LeetCode_283_511.java b/Week 01/id_511/LeetCode_283_511.java new file mode 100644 index 000000000..f174a88a9 --- /dev/null +++ b/Week 01/id_511/LeetCode_283_511.java @@ -0,0 +1,70 @@ +package id_511; + +import java.util.Arrays; +import java.util.PriorityQueue; + +/** + * @version 1.0 + * @Description: 移动零(考点是一维数组的坐标变换) + * @author: bingyu + * @date: 2019/10/16 20:54 + */ +public class LeetCode_283_511 { + + //解法1:快慢指针 + public static void moveZeroes(int[] nums) { + int j = 0; + for (int i = 0;i 0) { //如果遇到的是非零元素,且雪球大小不为0(说明之前没有遇到过零) + int t = nums[i]; + nums[i] = 0; + nums[i - snowBallSize] = t; //当前非零元素的位置减去雪球的大小就是与雪球要交换的位置 + } + } + } + + + + + + public static void main(String[] args) { + int [] arr = {5,0,4,0,3,12}; + moveZeroes3(arr); + System.out.println(Arrays.toString(arr)); + } + + + + +} diff --git a/Week 01/id_511/LeetCode_70_511.java b/Week 01/id_511/LeetCode_70_511.java new file mode 100644 index 000000000..f466acc3d --- /dev/null +++ b/Week 01/id_511/LeetCode_70_511.java @@ -0,0 +1,34 @@ +package id_511; + +/** + * @version 1.0 + * @Description: 爬楼梯 + * @author: bingyu + * @date: 2019/10/20 18:19 + */ +public class LeetCode_70_511 { + + + //思路,第n个台阶先简化思路,第n级台阶有两种爬法,一个从n-1跨一步,一个是从n-2跨2步 + //可以得到一个递推公式:f(n) = f(n-1) + f(n-2),事实上就是求"斐波那契数列" + //方法1:递归暴力法 + public static int climbStairs(int n){ + if (n < 2) { //n小于2说明是第一个台阶了,只有一种爬法 + return 1; + } + return climbStairs(n - 1) + climbStairs(n - 2); + } + + //公式法: + public static int climbStairs2(int n){ + double sqrt_5 = Math.sqrt(5); + double fib_n = Math.pow((1 + sqrt_5) / 2, n + 1) - Math.pow((1 - sqrt_5) / 2,n + 1); + return (int)(fib_n / sqrt_5); + } + + + public static void main(String[] args) { + int i = climbStairs(3); + System.out.println(i); + } +} diff --git a/Week 01/id_511/NOTE.md b/Week 01/id_511/NOTE.md index a6321d6e2..9ba1af10f 100644 --- a/Week 01/id_511/NOTE.md +++ b/Week 01/id_511/NOTE.md @@ -1,4 +1,19 @@ -# NOTE - - - +##第一周遇到的问题: +很明显感觉到时间不够,学习量还是挺大的,花在时间最多的是在做题上面,在做题以及理解题目的解法,然后自己再写一遍 +往往就花掉了大半的时间,之前栈和队列自己有学习过,在这周我总结一下学到的新东西。 +##跳表的原理: +跳表实际上是为了解决链表访问效率低而进行的优化,对一维链表进行升维,增加索引从而加速元素访问;但因此带来了另一个问题, +在增加和删除元素后,索引需要重新进行维护,所以其维护成本相对变高。 +跳表的时间复杂度:O(logn)。 + +总结:这一周另一个就是对数组的操作变的更加熟练了,for循环中的左右边界的处理等。所以这周我除了学到了跳表这个新知识,重点还是在 +解题上,以及老师解题的思维过程。关于队列, +我之前写过两篇博文,有兴趣可以点进去看一下。 + +优先队列介绍:优先级队列的元素按照其自然顺序进行排序,或者根据构造队列时提供的 Comparator 进行排序,具体取决于所使用的构造方法。优先级队列不允许使用 null 元素。依靠自然顺序的优先级队列还不允许插入不可比较的对象(这样做可能导致 ClassCastException)。 +此队列的头 是按指定排序方式确定的最小 元素。如果多个元素都是最小值,则头是其中一个元素——选择方法是任意的。队列获取操作 poll、remove、peek 和 element 访问处于队列头的元素。 +优先级队列是无界的,但是有一个内部容量,控制着用于存储队列元素的数组大小。它通常至少等于队列的大小。随着不断向优先级队列添加元素,其容量会自动增加。无需指定容量增加策略的细节。 +对于优先队列的源码分析,由于时间关系,我这里附上一个我之前看过的博文链接:优先队列,有兴趣的小伙伴可以仔细看看 + + + diff --git a/Week 01/id_516/DequeTest.java b/Week 01/id_516/DequeTest.java new file mode 100644 index 000000000..3eab29b24 --- /dev/null +++ b/Week 01/id_516/DequeTest.java @@ -0,0 +1,73 @@ +package com.hjj.test; + +import java.util.Deque; +import java.util.LinkedList; + +public class DequeTest { + public static void main(String[] args) { + oldAPI(); + newAPI(); + } + + public static void oldAPI() { + Deque deque = new LinkedList<>(); + deque.push("a"); + deque.push("b"); + deque.push("c"); + System.out.println(deque); + + String peek = deque.peek(); + System.out.println(peek); + System.out.println(deque); + + + while (deque.size() > 0 ) { + System.out.println(deque.pop()); + } + System.out.println(deque); + } + + + public static void newAPI() { + Deque deque = new LinkedList<>(); + deque.addFirst("a"); + deque.addFirst("b"); + deque.addFirst("c"); + System.out.println(deque); + + String peek = deque.getFirst(); + System.out.println(peek); + String peekFirst = deque.peekFirst(); + System.out.println(peekFirst); + + String last = deque.getLast(); + System.out.println(last); + + String peekLast = deque.peekLast(); + System.out.println(peekLast); + System.out.println(deque); + + + while (deque.size() > 0 ) { + System.out.println(deque.pollFirst()); + } + // 可能为空 + System.out.println(deque.pollFirst()); + try { + // 报错 + System.out.println(deque.pop()); + } catch (Exception e) { + e.printStackTrace(); + } + System.out.println(deque); + + + deque.addLast("a"); + deque.addLast("b"); + deque.addLast("c"); + + System.out.println(deque); + + System.out.println(deque.element() == deque.getFirst()); + } +} diff --git a/Week 01/id_516/LeetCode_189_516.java b/Week 01/id_516/LeetCode_189_516.java new file mode 100644 index 000000000..b4c129333 --- /dev/null +++ b/Week 01/id_516/LeetCode_189_516.java @@ -0,0 +1,144 @@ +//给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数。 +// +// 示例 1: +// +// 输入: [1,2,3,4,5,6,7] 和 k = 3 +//输出: [5,6,7,1,2,3,4] +//解释: +//向右旋转 1 步: [7,1,2,3,4,5,6] +//向右旋转 2 步: [6,7,1,2,3,4,5] +//向右旋转 3 步: [5,6,7,1,2,3,4] +// +// +// 示例 2: +// +// 输入: [-1,-100,3,99] 和 k = 2 +//输出: [3,99,-1,-100] +//解释: +//向右旋转 1 步: [99,-1,-100,3] +//向右旋转 2 步: [3,99,-1,-100] +// +// 说明: +// +// +// 尽可能想出更多的解决方案,至少有三种不同的方法可以解决这个问题。 +// 要求使用空间复杂度为 O(1) 的 原地 算法。 +// +// Related Topics 数组 + + +//leetcode submit region begin(Prohibit modification and deletion) + +/** + * 思路 + * 1. 开个新数组 + * 2. 环状替换 + * 3. 反转 + *

+ * 三个时间复杂度都是O(n) + * 但第一个由于开了新的数组会相对占用更多空间 额外空间O(n) + */ +class Solution { + + /** + * 思路1 开辟新数组 + * + * 1. calculate min movement + * 2. new same length array + * 3. copy the content to new array where exactly it should be + * 4. copy all new array content back to nums + * @param nums + * @param k + */ + public void rotate1(int[] nums, int k) { + // min movement + k = k % nums.length; + // store new array + int[] tmpArr = new int[nums.length]; + for (int i = 0; i < nums.length; i++) { + // i + k may exceed nums.length + tmpArr[(i + k) % nums.length] = nums[i]; + } + // copy back to nums + for (int i = 0; i < nums.length; i++) { + nums[i] = tmpArr[i]; + } + } + + /** + * 思路2 环状替换 + * + * 1. 计算最小移动量 k + * 2. 环装替换内容到对应的位置(暂存被替代的内容) + * 2.1 循环位置如 + * 0, 0 + k, 0 + 2k ... + * 1, 1 + k, 1 + 2k ... + * 2, 2 + k, 2 + 2k ... + * ... + * n, n + k, n + 2k ... + * + * 2.2 环状替换 (计数器在这里做增加) + * nums[0 + k] -> formerValue; + * nums[0] -> [0 + k]; + * ... + * @param nums + * @param k + */ + public void rotate2(int[] nums, int k) { + // min movement + k = k % nums.length; + int count = 0; + for (int n = 0; count < nums.length; n++) { + int curr = n; + // 用以记录前一个的值 + int formerValue = nums[curr]; + do { + int next = (curr + k) % nums.length; + // 交换 formerValue , num[next] + int tmp = nums[next]; + nums[next] = formerValue; + formerValue = tmp; + curr = next; + count++; + }while (n != curr); + } + } + + + /** + * 思路3 反转 + * + * 基于事实情况进行的算法 + * 1,2,3,4,5,6 2 + * 6,5,4,3,2,1 + * 5,6,4,3,2,1 + * 5,6,1,2,3,4 + * + * @param nums + * @param k + */ + public void rotate3(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); + } + + /** + * 交换功能 + * @param nums 数组 + * @param startIndex 传入想要交换的前索引 + * @param endIndex 传入想要交换的后索引 + */ + public static void reverse(int[] nums, int startIndex, int endIndex) { + while (startIndex < endIndex) { + // exchange + int temp = nums[startIndex]; + nums[startIndex] = nums[endIndex]; + nums[endIndex] = temp; + startIndex++; + endIndex--; + } + } +} +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 01/id_516/LeetCode_21_516.java b/Week 01/id_516/LeetCode_21_516.java new file mode 100644 index 000000000..4141ee106 --- /dev/null +++ b/Week 01/id_516/LeetCode_21_516.java @@ -0,0 +1,40 @@ +//将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 +// +// 示例: +// +// 输入:1->2->4, 1->3->4 +//输出:1->1->2->3->4->4 +// +// Related Topics 链表 + + + +//leetcode submit region begin(Prohibit modification and deletion) +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode(int x) { val = x; } + * } + */ +class Solution { + public ListNode mergeTwoLists(ListNode l1, ListNode l2) { + ListNode res = new ListNode(-1); + ListNode prev = res; + 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 res.next; + } +} +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 01/id_516/LeetCode_26_516.java b/Week 01/id_516/LeetCode_26_516.java new file mode 100644 index 000000000..916f994b9 --- /dev/null +++ b/Week 01/id_516/LeetCode_26_516.java @@ -0,0 +1,66 @@ +//给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。 +// +// 不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。 +// +// 示例 1: +// +// 给定数组 nums = [1,1,2], +// +//函数应该返回新的长度 2, 并且原数组 nums 的前两个元素被修改为 1, 2。 +// +//你不需要考虑数组中超出新长度后面的元素。 +// +// 示例 2: +// +// 给定 nums = [0,0,1,1,1,2,2,3,3,4], +// +//函数应该返回新的长度 5, 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4。 +// +//你不需要考虑数组中超出新长度后面的元素。 +// +// +// 说明: +// +// 为什么返回数值是整数,但输出的答案是数组呢? +// +// 请注意,输入数组是以“引用”方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。 +// +// 你可以想象内部操作如下: +// +// // nums 是以“引用”方式传递的。也就是说,不对实参做任何拷贝 +//int len = removeDuplicates(nums); +// +//// 在函数里修改输入数组对于调用者是可见的。 +//// 根据你的函数返回的长度, 它会打印出数组中该长度范围内的所有元素。 +//for (int i = 0; i < len; i++) { +//    print(nums[i]); +//} +// +// Related Topics 数组 双指针 + + + +//leetcode submit region begin(Prohibit modification and deletion) + +import java.util.HashSet; +import java.util.Set; + +/** + * 思路: + * 1、 双指针 + */ +class Solution { + + // 双指针 思路1 + public int removeDuplicates2(int[] nums) { + int i = 0; + for (int j = 1; j < nums.length; j++) { + if (nums[i] != nums[j]) { + // 注意 ++i : 把不同的值追加到索引i的后一位 + nums[++i] = nums[j]; + } + } + return i + 1; + } +} +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 01/id_516/LeetCode_88_516.java b/Week 01/id_516/LeetCode_88_516.java new file mode 100644 index 000000000..497e0e605 --- /dev/null +++ b/Week 01/id_516/LeetCode_88_516.java @@ -0,0 +1,42 @@ +//给定两个有序整数数组 nums1 和 nums2,将 nums2 合并到 nums1 中,使得 num1 成为一个有序数组。 +// +// 说明: +// +// +// 初始化 nums1 和 nums2 的元素数量分别为 m 和 n。 +// 你可以假设 nums1 有足够的空间(空间大小大于或等于 m + n)来保存 nums2 中的元素。 +// +// +// 示例: +// +// 输入: +//nums1 = [1,2,3,0,0,0], m = 3 +//nums2 = [2,5,6], n = 3 +// +//输出: [1,2,2,3,5,6] +// Related Topics 数组 双指针 + + + +//leetcode submit region begin(Prohibit modification and deletion) +class Solution { + public void merge(int[] nums1, int m, int[] nums2, int n) { + int p1 = m - 1; + int p2 = n - 1; + int p = m + n - 1; + + while (p1 >= 0 && p2 >= 0) { + if (nums1[p1] > nums2[p2]) { + nums1[p] = nums1[p1]; + p1 --; + } else { + nums1[p] = nums2[p2]; + p2 --; + } + p--; + } + // 最后如果nums2的指针没有到底,p2 + 1个元素需拷贝 + System.arraycopy(nums2, 0, nums1, 0, p2 + 1); + } +} +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 01/id_516/NOTE.md b/Week 01/id_516/NOTE.md index a6321d6e2..49c227b89 100644 --- a/Week 01/id_516/NOTE.md +++ b/Week 01/id_516/NOTE.md @@ -1,4 +1,213 @@ -# NOTE +# 第一周学习总结 - + +## 总体 + +### 获得 + +- 如何自主学习算法 +- 五毒神掌的运用实践 +- 牢记空间换时间,升维 +- 算法都是找最近重复性 + + + + + +### 缺失 + +- 没有做预习 +- 许多解题都没有自己的思路 +- 做题经常缺少最后一步 去国外网站查看discuss +- 没有把写代码前的思路先写出来 -> clean code -> 新闻稿 + + + + + +## 具体 + +1. 如何自主学习算法 + - 搜索引擎的运用 + - Queue java source ${version} + - Queue java ${version} + - java source code + - 分析源码 + - 由于java鲁棒性强,所以可以查看java代码 + - 先看注释了解大致思路 + - 找到核心逻辑点 + - 看代码 + - 反复debug(不会的)逻辑点 + + + + + +2. 五毒神掌的使用 + - https://leetcode-cn.com/submissions/#/1 查看这个网址 去看 1天前做的什么题目 5天前做的什么题目 + + + +3. 空间换时间 +4. 最近重复性 + 1. 栈 :结合现实-> 洋葱 了解其结构 最近相关性 使用栈 + 2. 队列: 结合现实 -> 排队 了解其结构 先来后到 使用队列 + + + + + + + +5. 没有做预习 + 1. 这周开始做预习 +6. 做题没有思路 + 1. 花多一些时间 原本 5 -> 8分钟 + 2. 把基础巩固扎实 +7. 经常忘记查看discuss + 1. feedback的感觉不是很强烈 除了有一次看到比较逗比的算法除外 + + + + + + + + + + + + + + + + + +## 其他 + +1. 奇妙算法 + + - 旋转数组 为什么可以通过 通过三次反转来将最后的结果获得? + +2. 现实中运用栈这个数据结构,使用Deque。 + +3. 双指针 + + 1. 快慢指针 + 1. 环状问题 + 2. 重复值问题 + 2. 夹壁定律? + +4. review + + 1. LeetCode_1_386 + + 1. 暴力法时间复杂度是O(n^2) + + 2. 解法也是错误的其会反复利用同一个值 + + 3. 题目 + + 1. 他的解法 + + ```java + class SumOfTwoNumbers { + public int[] twoSum(int[] nums, int target) { + int[] n = new int[2]; + for (int i = 0; i < nums.length; i++) { + for (int j = 0; j < nums.length; j++) { + if (i != j && (nums[i] + nums[j] == target)) { + // System.out.println(i + ", " + j); + if (i < j) { + n[0] = i; + n[1] = j; + } else { + n[0] = j; + n[1] = i; + } + return n; + } + } + } + return new int[0]; + } + } + ``` + + 2.  我修改后的解法 + + ```java + class Solution { + public int[] twoSum(int[] nums, int target) { + int[] n = new int[2]; + for (int i = 0; i < nums.length - 1; i++) { + for (int j =i + 1; j < nums.length; j++) { + if (i != j && (nums[i] + nums[j] == target)) { + n[0] = i; + n[1] = j; + return n; + } + } + } + return new int[0]; + } + } + ``` + + + + 3. 但时间复杂度过高 应该考虑 升维 通过使用 map来存储 每次遍历将元素存入,如果遇到以前存过的值和当前遍历值之和为目标直接返回有如下代码: + + ```java + public int[] twoSum(int[] nums, int target) { + Map map = new HashMap<>(nums.length); + for (int i = 0; i < nums.length; i++) { + Integer oldIndex = map.get(target - nums[i]); + if (oldIndex == null) { + map.put(nums[i],i); + }else { + return new int[] {oldIndex,i}; + } + } + throw new RuntimeException("error not found"); + } + ``` + + + + 2. [LeetCode_ 26_506](https://github.com/algorithm004-01/algorithm004-01/pull/140/files#diff-c35b3c96cd8bf526be962faaeb3931fd) + + 1. 说明: 这个方法和官方题解思维逻辑上没有太大的区别。但存在边界值的问题. 然后发现自己写得代码传入空数组也是一样返回1,应加入前置判断 + + ```java + if (nums.length == 0) return 0; + ``` + + 3. https://github.com/algorithm004-01/algorithm004-01/pull/163/files 这个自己有写测试类,移出重复值仍然跟上面一样存在问题。 + + 4. mark https://github.com/algorithm004-01/algorithm004-01/issues/160 别人的解题方式。比我的高级多了,可以学习一下 + + > 每道题的第一次完解控制在1h + > \1. 审题,理解题意 + > \2. 先问自己,这个问题属于哪类算法问题? + > \1. 列出所有可能得算法,每种方法的时间复杂度 + > \2. 要将不熟悉的题转换成熟悉的题(比如:三数求和—>2数求和—>双指针) + > \3. 再思考并写下所给条件中有哪些性质是可以利用的? + > \1. 比如题中有序数组的有序就是一个可以利用的条件) + > \2. 比如题中是否存在,就联想到哈希表的数据结构 + > \4. 这类算法问题通常的解题思路? + > \1. “解决链表问题最好的办法是在脑中或者纸上把链表画出来” + > \2. 数组—>双指针 + > \5. 以上4点需要在15min 内完成 + > \6. 先用伪代码写出逻辑,再补全小段代码 + > \7. 找重复性(重复单元) + > \8. notion记录自己的解题过程(这一点很重要,可以发现自己的缺陷,方便日后对景对情),和最优解做对比 + > \9. 将**不同的解法**,制成anki 卡片记录 + > \1. 搜索优质解题方法和思路(博客,leetcode 国际站) + > \2. 制作 gif 图片 + > \10. 五遍刷题法,重写所有的解法 + + 最后可以将所有的题目类似的 进行归类 反向归类 + + 5. https://github.com/algorithm004-01/algorithm004-01/issues/109 我也可以将自己梳理的发到自己的博客上。 \ No newline at end of file diff --git "a/Week 01/id_516/PriorityQueue\346\272\220\347\240\201\345\210\206\346\236\220.md" "b/Week 01/id_516/PriorityQueue\346\272\220\347\240\201\345\210\206\346\236\220.md" new file mode 100644 index 000000000..050573ecb --- /dev/null +++ "b/Week 01/id_516/PriorityQueue\346\272\220\347\240\201\345\210\206\346\236\220.md" @@ -0,0 +1,261 @@ +## PriorityQueue + +> 基于**优先级堆**的无限优先级队列。队列中的元素是基于自然排序(Comparable)或是基于构造参数传来的(Comparator),优先级队列不允许有空元素,优先级队列不允许插入不可比较(non-comparable)对象,如果传入会导致ClassCastException。 +> +> 关于其具体的排序,队列的头是最小的元素。如果最小值有多个,堆会放这些元素之一,(ties are broken arbitrarily) 关系会任意破坏。队列的数据检索操作是poll ,remove,peek,element (取元素头)。 +> +> 优先级队列是无限的,但有个内部容量管理数组的大小用作于存储元素到队列。容量至少为队列的大小。当元素加到优先级队列中。容量他会自动增加。每次增加细节不是指定的。 +> +> ... +> +> 此实现并非线程安全的,如果想要使用线程安全的请使用{@link java.util.concurrent.PriorityBlockingQueue} +> +> +> +> 此实现:提供了O(log(n))的排队(offer,add)和出队(poll,remove)方法 +> +> O(n) remove(Object) 和 contains(Object) +> +> O(1)的数据操作方法 peek,element,size + + + +### 使用 + +```java +public class PriorityQueueTest { + + public static void main(String[] args) { + PriorityQueue pq = new PriorityQueue<>(); + pq.add(new Person(170,"x170")); + pq.add(new Person(180,"x180")); + pq.offer(new Person(190,"x190")); + pq.offer(new Person(200,"x200")); + + pq.forEach(i-> System.out.println(i)); + + System.out.println("peek = " + pq.peek()); + System.out.println("element = " + pq.element()); + System.out.println("size = " + pq.size()); + System.out.println("poll = " + pq.poll()); + System.out.println("remove = " + pq.remove()); + + pq.forEach(i-> System.out.println(i)); + + System.out.println("========================="); + // 如果传入Comparator 则Person类不需要实现Comparable接口 + PriorityQueue pq2 = new PriorityQueue<>(Comparator.comparing(a -> a.name)); + pq2.add(new Person(170,"d170")); + pq2.add(new Person(180,"c180")); + pq2.offer(new Person(190,"b190")); + pq2.offer(new Person(200,"a200")); + + pq2.forEach(i-> System.out.println(i)); + } + @Data + @AllArgsConstructor + static class Person implements Comparable{ + private Integer height; + private String name; + + @Override + public int compareTo(Person o) { + if(this.height == o.height) + return 0; + else if(this.height > o.height) + return 1; + else + return -1; + } + } + +} +``` + +### 如何实现? + +> 优先级队列意味着 **平衡二叉堆**,queue[n]的俩个子节点是 queue[2n + 1]和queue[2n + 2]。优先级队列使用compator来排序,或是使用元素的自然排序,如果compartor是空: 对于每一个在堆中的节点 n 他的每个子孙 d 都满足 n <= d 即最小堆。 如果队列不为空,元素最小值在queue[0]. + + + +#### add offer 核心 + +```java + /** + * 大致思路就是将元素插入最后一位,不断比较他和父亲节点,如果他小那么就往上不断做siftUp + */ + public boolean offer(E e) { + if (e == null) + throw new NullPointerException(); + modCount++; + int i = size; + if (i >= queue.length) + grow(i + 1); + size = i + 1; + if (i == 0) + queue[0] = e; + else + siftUp(i, e); + return true; + } + + // k > 0 + private void siftUp(int k, E x) { + if (comparator != null) + siftUpUsingComparator(k, x); + else + siftUpComparable(k, x); + } + + @SuppressWarnings("unchecked") + private void siftUpUsingComparator(int k, E x) { + while (k > 0) { + int parent = (k - 1) >>> 1; + Object e = queue[parent]; + if (comparator.compare(x, (E) e) >= 0) + break; + queue[k] = e; + k = parent; + } + queue[k] = x; + } + + private void siftUpComparable(int k, E x) { + // same code + } +``` + + + +#### poll,remove 核心 + +```java + /** + * 大致思路就是将第一个元素移出后,最后一个元素补到第一个元素位,如果不符合最小堆比对做siftDown + * 一直比较的是左子节点 + */ + public E poll() { + if (size == 0) + return null; + int s = --size; + modCount++; + E result = (E) queue[0]; + E x = (E) queue[s]; + queue[s] = null; + if (s != 0) + siftDown(0, x); + return result; + } + + private void siftDown(int k, E x) { + if (comparator != null) + siftDownUsingComparator(k, x); + else + siftDownComparable(k, x); + } + + @SuppressWarnings("unchecked") + private void siftDownComparable(int k, E x) { + Comparable key = (Comparable)x; + int half = size >>> 1; // loop while a non-leaf + // size / 2 < ele then ele is non-leaf + while (k < half) { + int child = (k << 1) + 1; // **assume left child is least** + Object c = queue[child]; + int right = child + 1; + // 这行的意义是什么? 右节点存在 并且 左节点大于右节点,那么左节点应该为右节点值 + // 因为这个循环只是一直比较左边的孩子节点与父亲节点的大小,所以如果不进行此操作会导致堆不成立 + if (right < size && + ((Comparable) c).compareTo((E) queue[right]) > 0) + c = queue[child = right]; + // 与左子节点比较 如果已经小了那么就不需要再进行变动了 + if (key.compareTo((E) c) <= 0) + break; + queue[k] = c; + k = child; + } + queue[k] = key; + } + + + private E removeAt(int i) { + // assert i >= 0 && i < size; + modCount++; + int s = --size; + if (s == i) // removed last element + queue[i] = null; + else { + E moved = (E) queue[s]; + queue[s] = null; + siftDown(i, moved); + if (queue[i] == moved) { + siftUp(i, moved); + if (queue[i] != moved) + return moved; + } + } + return null; + } +``` + + + + + +#### 查询方法 + +```java + public E peek() { + return (size == 0) ? null : (E) queue[0]; + } + + private int indexOf(Object o) { + if (o != null) { + for (int i = 0; i < size; i++) + if (o.equals(queue[i])) + return i; + } + return -1; + } +``` + +#### 其他方法 + + + +```java + // 找到所有非叶子节点 从后往前全部左排序 最后能够形成一个最小堆 + private void heapify() { + for (int i = (size >>> 1) - 1; i >= 0; i--) + siftDown(i, (E) queue[i]); + } + + + /** + * The maximum size of array to allocate. + * Some VMs reserve some header words in an array. + * Attempts to allocate larger arrays may result in + * OutOfMemoryError: Requested array size exceeds VM limit + */ + private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; + + private void grow(int minCapacity) { + int oldCapacity = queue.length; + // Double size if small; else grow by 50% + int newCapacity = oldCapacity + ((oldCapacity < 64) ? + (oldCapacity + 2) : + (oldCapacity >> 1)); + // overflow-conscious code + if (newCapacity - MAX_ARRAY_SIZE > 0) + newCapacity = hugeCapacity(minCapacity); + queue = Arrays.copyOf(queue, newCapacity); + } + + private static int hugeCapacity(int minCapacity) { + if (minCapacity < 0) // overflow + throw new OutOfMemoryError(); + return (minCapacity > MAX_ARRAY_SIZE) ? + Integer.MAX_VALUE : + MAX_ARRAY_SIZE; + } +``` \ No newline at end of file diff --git a/Week 01/id_516/Queue.md b/Week 01/id_516/Queue.md new file mode 100644 index 000000000..5f316364d --- /dev/null +++ b/Week 01/id_516/Queue.md @@ -0,0 +1,102 @@ +# Queue源码分析 + +> ```java +> * A collection designed for holding elements prior to processing. +> * Besides basic {@link java.util.Collection Collection} operations, +> * queues provide additional insertion, extraction, and inspection +> * operations. Each of these methods exists in two forms: one throws +> * an exception if the operation fails, the other returns a special +> * value (either {@code null} or {@code false}, depending on the +> * operation). The latter form of the insert operation is designed +> * specifically for use with capacity-restricted {@code Queue} +> * implementations; in most implementations, insert operations cannot +> * fail. +> +> 一个设计为先保有元素后加工的集合。除了基础的Collection的操作,队列提供了额外的插入、提取和检查操作。这些方法每一个都保有两种形式,一种抛出异常,另一种返回特殊的值。后者的插入操作是为了给那些容量右限制的队列实现类。在大多数实现中,插入操作都不会失败。 +> * +> * +> * +> * +> * +> * +> * +> * +> * +> * +> * +> * +> * +> * +> * +> * +> * +> * +> * +> * +> * +> * +> *
Summary of Queue methods
Throws exceptionReturns special value
Insert{@link Queue#add add(e)}{@link Queue#offer offer(e)}
Remove{@link Queue#remove remove()}{@link Queue#poll poll()}
Examine{@link Queue#element element()}{@link Queue#peek peek()}
+> +> queues 一般来说(但不是必须的)是以一种FIFO先进先出的模式。例外中有如下:优先级队列(Priority Queues 他的顺序是通过比较器,或是元素的自然顺序),LIFO (Last in fisrt out)队列如Stack,但不管你是如何排列,remove,poll方法都是移出头节点。若是FIFO队列,所有元素都是插入到最后一个元素,其他的队列可能会有不同的规则。每个实现必须指定他的顺序属性。 +> 方法offer在能插入元素时插入元素,否则将返回false。这个方法与集合的add方法有不同之处。add方法如果插入不进元素会抛出异常。offer方法被设计当错误是正常的。 +> remove和poll方法都会返回头元素。这俩方法唯一的区别是在于当队列位空的情况下,remove会抛出异常,而poll方法返回空 +> element和peek都会返回头元素,但不会移出。 +> Queue不回定义并发编程的方法 +> Queue一般不允许插入null元素。而LinkedList可以插入空。poll方法的相关性 +> +> ``` + +## add + +> ```java +> boolean add(E e); +> ``` +> +> 向队列中插入具体的元素,如果没有违反容量的限制那么立马返回true如果没有空间则抛出IllegalStateException + + + + + +## offer + +> ```java +> boolean offer(E e); +> ``` +> +> 向队列中插入具体的元素,如果没有违反容量的限制。当你想要使用容量限制的队列时,建议你使用add方法。 + + + +## remove + +>```java +>E remove(); +>``` +> +>检索并且移出队列头元素,这个方法不同于poll,这个当队列为空时会抛出异常NoSuchElementException + +## poll + +> ```java +> E poll(); +> ``` +> +> 检索并且移出队列头元素,如果队列为空,则返回Null + +## element + +> ```java +> E element(); +> ``` +> +> 检索但不移出队列的头。这个方法不同于peek,当队列为空时会抛出异常。 + +## peek + +> ```java +> E peek(); +> ``` +> +> 检索但不移出队列的头。如果队列为空则返回null。 + diff --git a/Week 01/id_518/LeetCode_001_518.c b/Week 01/id_518/LeetCode_001_518.c new file mode 100644 index 000000000..1ddf3efc4 --- /dev/null +++ b/Week 01/id_518/LeetCode_001_518.c @@ -0,0 +1,35 @@ +#include +#include + +void printArray(int *nums, int numSize) { + for (int i = 0; i < numSize; i++) { + printf("%d ", nums[i]); + } + printf("\n"); +} + +int *twoSum(int* nums, int numsSize, int target, int *returnSize) { + int *arr = malloc(sizeof(int) * 2); + *returnSize = 0; + for (int i = 0; i < numsSize - 1; i++) { + for (int j = i + 1; j < numsSize; j++) { + if (target == nums[i] + nums[j]) { + arr[0] = i; + arr[1] = j; + *returnSize += 2; + return arr; + } + } + } + return NULL; +} + +int main(void) { + int nums[] = { 3, 7, 11, 15 }; + int numsSize = sizeof(nums) / sizeof(nums[0]); + int target = 9; + int returnSize; + int *arr = twoSum(nums, numsSize, target, &returnSize); + printArray(nums, numsSize); + printArray(arr, returnSize); +} \ No newline at end of file diff --git a/Week 01/id_518/LeetCode_283_518.c b/Week 01/id_518/LeetCode_283_518.c new file mode 100644 index 000000000..4c1d7711c --- /dev/null +++ b/Week 01/id_518/LeetCode_283_518.c @@ -0,0 +1,36 @@ +#include + +void printArray(int *nums, int numSize) { + for (int i = 0; i < numSize; i++) { + printf("%d ", nums[i]); + } + printf("\n"); +} + + +void moveZeroes(int *nums, int numsSize) { + int j = 0; + for (int i = 0; i < numsSize; i++) { + if (nums[i] != 0) { + nums[j] = nums[i]; + if (i != j) { // i must be larger or equal to j + nums[i] = 0; + } + j++; + } + } + printArray(nums, numsSize); +} + +/** + * input [0,1,0,3,12] + * output [1,3,12,0,0] + **/ + +int main(void) { + int input[] = { 0, 1, 0, 3, 12 }; + int length = sizeof(input)/sizeof(input[0]); + printArray(input, length); + moveZeroes(input, length); +} + diff --git a/Week 01/id_518/NOTE.md b/Week 01/id_518/NOTE.md new file mode 100644 index 000000000..e69de29bb diff --git a/Week 01/id_526/LeetCode_01_526.java b/Week 01/id_526/LeetCode_01_526.java new file mode 100644 index 000000000..560b46ff2 --- /dev/null +++ b/Week 01/id_526/LeetCode_01_526.java @@ -0,0 +1,20 @@ +class Solution { + public int[] twoSum(int[] nums, int target) { + if (nums == null) { + return null; + } + int[] result = new int[2]; + HashMap map = new HashMap(); + int numsLength = nums.length; + for (int i = 0 ; i < numsLength ; i++ ) { + Integer num = nums[i]; + if (map.containsKey(num)){ + result[0] = i; + result[1] = map.get(num); + return result; + } + map.put(target - num,i); + } + return result; + } +} \ No newline at end of file diff --git a/Week 01/id_526/LeetCode_189_526.java b/Week 01/id_526/LeetCode_189_526.java new file mode 100644 index 000000000..f975b058c --- /dev/null +++ b/Week 01/id_526/LeetCode_189_526.java @@ -0,0 +1,44 @@ +class Solution { + //暴力求解 + public void rotate(int[] nums, int k) { + if (nums == null) { + return; + } + int n = nums.length; + k = k % n; + for (int i = 0; i < k ; i++) { + int temp = nums[n-1]; + for (int j = n -1 ; j > 0 ; j--) { + nums[j] = nums[j-1]; + } + nums[0] = temp; + } + } + /** + * 分3步翻转 + * 1. 反转全部元素 + * 2. 反转0-k个元素 + * 3. 反转剩余的0-n-k个元素 + * @param nums + * @param k + */ + public void rotate(int[] nums, int k) { + if (nums == null){ + return; + } + int n = nums.length; + k %= n; + reverse(nums, 0, n - 1); + reverse(nums, 0, k - 1); + reverse(nums, k, n - 1); + } + public void reverse(int[] nums, int start, int end) { + while (start < end) { + int temp = nums[start]; + nums[start] = nums[end]; + nums[end] = temp; + start++; + end--; + } + } +} \ No newline at end of file diff --git a/Week 01/id_526/LeetCode_21_526.java b/Week 01/id_526/LeetCode_21_526.java new file mode 100644 index 000000000..e6831d010 --- /dev/null +++ b/Week 01/id_526/LeetCode_21_526.java @@ -0,0 +1,19 @@ +class Solution { + public ListNode mergeTwoLists(ListNode l1, ListNode l2) { + ListNode prehead = new ListNode(-1); + ListNode prev = prehead; + 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; + } + //如果l1为空直接指向l2 + prev.next = l1 == null ? l2 : l1; + return prehead.next; + } +} \ No newline at end of file diff --git a/Week 01/id_526/LeetCode_26_526.java b/Week 01/id_526/LeetCode_26_526.java new file mode 100644 index 000000000..d5fcdd0f8 --- /dev/null +++ b/Week 01/id_526/LeetCode_26_526.java @@ -0,0 +1,22 @@ +class Solution { + public int removeDuplicates(int[] nums) { + if (nums == null) { + return 0; + } + int length = nums.length; + if (length < 2) { + return length; + } + int minNum = nums[0]; + int replace = 1; + for (int i = 1;i < length; i++){ + if (nums[i] == minNum) { + continue; + } + nums[replace] = nums[i]; + minNum = nums[i]; + replace++; + } + return replace; + } +} \ No newline at end of file diff --git a/Week 01/id_526/LeetCode_283_526.java b/Week 01/id_526/LeetCode_283_526.java new file mode 100644 index 000000000..dce5545b4 --- /dev/null +++ b/Week 01/id_526/LeetCode_283_526.java @@ -0,0 +1,20 @@ +class Solution { + public void moveZeroes(int[] nums) { + if (nums == null || nums.length == 1) { + return; + } + int zeroNums = 0; + int length = nums.length; + for (int i = 0; i < length; i++) { + int value = nums[i]; + if (value == 0) { + zeroNums++; + continue; + } + if (zeroNums > 0) { + nums[i] = 0; + nums[i-zeroNums] = value; + } + } + } +} \ No newline at end of file diff --git a/Week 01/id_526/LeetCode_66_526.java b/Week 01/id_526/LeetCode_66_526.java new file mode 100644 index 000000000..16b329bfc --- /dev/null +++ b/Week 01/id_526/LeetCode_66_526.java @@ -0,0 +1,22 @@ +class Solution { + public int[] plusOne(int[] digits) { + if (digits == null || digits.length == 0) { + return null; + } + int length = digits.length; + for (int i = length-1; i >= 0; i--) { + int value = digits[i]; + if (value < 9) { + digits[i] = value + 1; + break; + }else { + digits[i] = 0; + } + if (i == 0) { + digits = new int[length+1]; + digits[0] = 1; + } + } + return digits; + } +} \ No newline at end of file diff --git a/Week 01/id_526/LeetCode_88_526.java b/Week 01/id_526/LeetCode_88_526.java new file mode 100644 index 000000000..bf4a6fbe4 --- /dev/null +++ b/Week 01/id_526/LeetCode_88_526.java @@ -0,0 +1,39 @@ +class Solution { + //按照顺序合并 + public void merge(int[] nums1, int m, int[] nums2, int n) { + if (n == 0) { + return; + } + int i=m-1; + int j=n-1; + int k = m+n-1; + while (i >= 0 && j >= 0) { + int v1 = nums1[i]; + int v2 = nums2[j]; + if (v1 >= v2) { + nums1[k] = v1; + i--; + }else { + nums1[k] = v2; + j--; + } + k--; + } + while(j>=0) { + nums1[k] = nums2[j]; + k--; + j--; + } + } + + //暴力 + public void merge(int[] nums1, int m, int[] nums2, int n) { + if (n == 0) { + return; + } + for (int i = 0; i < n ; i++) { + nums1[m+i] = nums2[i]; + } + Arrays.sort(nums1); + } +} \ No newline at end of file diff --git a/Week 01/id_531/LeetCode_189_531.go b/Week 01/id_531/LeetCode_189_531.go new file mode 100644 index 000000000..fa26a8069 --- /dev/null +++ b/Week 01/id_531/LeetCode_189_531.go @@ -0,0 +1,26 @@ +package id531 + +func rotate(nums []int, k int) { + var pre int + for i:=0;i 0 { + nums[i-zeroCount] = nums[i] + nums[i] = 0 + } + } + } +} + +// MoveZeros2 双指针 +func MoveZeros2(nums []int) { + j := 0 + for i := 0; i < len(nums); i++ { + if nums[i] != 0 { + nums[j] = nums[i] + j++ + } + } + + for i := j; i < len(nums); i++ { + nums[i] = 0 + } +} diff --git a/Week 01/id_531/LeetCode_283_531_test.go b/Week 01/id_531/LeetCode_283_531_test.go new file mode 100644 index 000000000..beed4541d --- /dev/null +++ b/Week 01/id_531/LeetCode_283_531_test.go @@ -0,0 +1,67 @@ +package id531 + +import ( + "reflect" + "testing" +) + +func Test_moveZeros(t *testing.T) { + type args struct { + nums []int + } + tests := []struct { + name string + args args + want []int + }{ + { + name: "move_zero_1", + args: args{ + nums: []int{0, 1, 0, 3, 12}, + }, + want: []int{1, 3, 12, 0, 0}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + MoveZeros1(tt.args.nums) + if !reflect.DeepEqual(tt.args.nums, tt.want) { + t.Errorf("MoveZeros1() = %v, want %v", tt.args.nums, tt.want) + } + }) + } +} + +func TestMoveZeros2(t *testing.T) { + type args struct { + nums []int + } + tests := []struct { + name string + args args + want []int + }{ + { + name: "move_zero_2", + args: args{ + nums: []int{0, 1, 0, 3, 12}, + }, + want: []int{1, 3, 12, 0, 0}, + }, + { + name: "move_zero_2", + args: args{ + nums: []int{0, 0, 0, 0, 12}, + }, + want: []int{12, 0, 0, 0, 0}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + MoveZeros2(tt.args.nums) + if !reflect.DeepEqual(tt.args.nums, tt.want) { + t.Errorf("MoveZeros2() = %v, want %v", tt.args.nums, tt.want) + } + }) + } +} \ No newline at end of file diff --git a/Week 01/id_531/leetCode_21_531.go b/Week 01/id_531/leetCode_21_531.go new file mode 100644 index 000000000..12fc33416 --- /dev/null +++ b/Week 01/id_531/leetCode_21_531.go @@ -0,0 +1,25 @@ + +package id531 + + + +type ListNode struct { + Val int + Next *ListNode + } + +func mergeTwoLists(l1 *ListNode, l2 *ListNode) *ListNode { + if l1==nil { + return l2 + } + if l2 ==nil { + return l1 + } + if l1.Val x 从p向下移动一格 + + 如果当前位置在最底层的链中(S0),且还要往下移动的话,则输出查询失败。 + + 2、插入 + + 在跳跃表中插入一个元素x,按照以下步骤进行: + + 插入的位置和插入对应元素。 + + 当我们往跳表中插入数据的时候,我们可以通过一个随机函数,来决定这个结点插入到哪几级索引层中, + + 随机函数的选择是非常有讲究的,从概率上讲,能够保证跳表的索引大小和数据大小平衡性,不至于性能的过度退化。 + + 至于随机函数的选择,见下面的C++代码实现: + /***** 随机函数起始********/ + private int randomLevel() + { + int level = 1; + for(int i = 1; i < MAX_LEVEL; ++i)//MAX_LEVEL为链条数 + { + if(random.nextInt() % 2 == 1){ + level++; + } + } + return level; + } + /******随机函数结束********/ + 3、删除 + + 从跳跃表中删除一个元素x,按照以下步骤进行: + + 1)在跳跃表中查找到这个元素的位置,如果未找到,则退出 + + 2)将该元素所在整列从表中删除 + + 3)将多余的“空链”删除 + +###### 第三部分:跳表的应用 + 使用跳跃表的产品: + + 1、Lucene, elasticSearch + + 2、Redis: + + Redis sorted set的内部使用HashMap和跳跃表(SkipList)来保证数据的存储和有序, + + HashMap里放的是成员到score的映射,而跳跃表里存放的 是所有的成员,排序依据是HashMap里存的score, + + 使用跳跃表的结构可以获得比较高的查找效率,并且在实现上比较简单。 + +###### 写在最后 + + 1、要深刻理解跳表,需要自己动手用代码实现一遍,这个暂且搁置后续实现; + + 2、leetcode涉及跳表题目:1206 设计跳表; + +## 1.2其他感想 + +#### 算法学习习惯的探索 + +覃超老师说过算法学习需要刻意练习,印象最深的就是“五毒神掌”,相同的题目要不断的刷。道理很简单,但真正做到有难度,因为工作较忙,结合实际情况,只能减少遍数,我的算法学习步骤大致计划如下: + +1、覃超老师的在线课程先听一遍,在听的过程中,涉及算法例题讲解的部分,自己同步在纸上写思路,和手写源码; + + 注:第一遍主要是完成课程,了解知识点。 + +2、听完在线课程后,针对例题和练习题,学习leetcode上经典题解,每题在IDE里至少两种解法编写,提交leetcode; + + 注:第二遍主要是刻意练习,巩固知识点。 + +3、对于做过的题目,跳出自己认为难理解、容易忘的题目再次IDE里编写,提交leetcode; + + 注:第三遍主要是查漏补缺,掌握知识点。 + + +--- + +# 2.改写代码和分析源码 +主要用C/C++,不熟悉Java + +--- + +# 3.Review和点评 + + diff --git a/Week 01/id_536/leetcode_1_536.cpp b/Week 01/id_536/leetcode_1_536.cpp new file mode 100644 index 000000000..95338aca6 --- /dev/null +++ b/Week 01/id_536/leetcode_1_536.cpp @@ -0,0 +1,92 @@ +#include +#include +#include + +using namespace std; + +class Solution { +public: + /********* + ⷨ1 + ********/ + vector twoSum1(vector& nums, int target) { + int i,j; + vector res; + for(i=0;i twoSum2(vector& nums, int target) { + map iMap; + vector res; + int i,temp; + for(i=0;i twoSum3(vector& nums, int target) { + map iMap; + vector res; + int i,temp; + for(i=0;i nums,res; + /******* + ²֤ + *****/ + nums.push_back(2); + nums.push_back(7); + nums.push_back(11); + nums.push_back(15); + res=s.twoSum3(nums,9); + for(int i=0;i +#include + +using namespace std; + +class Solution { +public: + /********* + ⷨ1˫ָ뷨 + ********/ + void moveZeroes1(vector& nums) { + int i,j,k; + j=0; + for(i=0;i& nums) { + int i,j,k; + vector numsAns; + j=0; + for(i=0;i nums; + /******* + ²֤ + *****/ + nums.push_back(0); + nums.push_back(1); + nums.push_back(0); + nums.push_back(3); + nums.push_back(12); + s.moveZeroes2(nums); + for(int i=0;i +#include + +using namespace std; + +class Solution { +public: + /******* + ⷨ1תΪ1ת + ýⷨᵼԽ磬Ҫ + ******/ + vector plusOne1(vector& digits) { + int i,temp,ten; + temp = 0; + ten = 1; + vector res; + for(i = digits.size()-1; i >= 0; --i) + { + temp += digits[i] * ten;//תΪ + ten *= 10; + } + temp += 1;//ĿҪ1 + + if(temp / ten) //жλǷλ1 + { + res.push_back(1); + temp %= ten; + } + ten /= 10; + while(ten) + { + res.push_back(temp/ten); + temp %= ten; + ten /= 10; + } + return res; + } + + /****** + ⷨ2ÿλӡ + 1ȫ91299->1300 + 2ȫ99999->10000 + ******/ + vector plusOne2(vector& digits) { + int i; + for(i=digits.size()-1;i>=0;--i) + { + if(digits[i] == 9) + { + digits[i] = 0; + } + else + { + digits[i] += 1; + break; + } + } + if(i == -1 && digits[0] == 0)//ȫ9 + { + digits.push_back(0); + digits[0] = 1; + } + return digits; + } +}; + +/***** + ²Դ +****/ +int main() +{ + vector nums,res; + Solution s; + nums.push_back(9); + nums.push_back(3); + nums.push_back(9); + res = s.plusOne1(nums); + for(int i=0;i + /// LeetCode:189,输入: [1,2,3,4,5,6,7] 和 k = 3,输出: [5,6,7,1,2,3,4] + /// + public class RotateArray + { + ///

+ /// 方法一(原创):使用单个循环,先将起始元素A存储起来,然后找目标元素B,将B的值写入到A的位置,然后再找B元素的目标元素C,依次类推:A->B,B->C,C->D,D=A + /// + /// + /// + public static void Rotate(int[] nums, int k) + { + int len = nums.Length; + k = k > len ? k % len : k; + int current = 0; //当前需要计算的元素的索引 + int t = 0; + int temp = nums[t]; //保存第一个元素的值 + + int count = 0; //循环计数器 + + while (count < len) + { + if (-k + current == t) + { + nums[current] = temp; + t++; + current = t; + if (t < len) + { + temp = nums[t]; + } + } + else + { + //判断目标元素是否在当前元素的左边 + if (-k + current > 0) + { + nums[current] = nums[-k + current]; + current = -k + current; + } + else + { + //计算当前元素的值的来源 + nums[current] = nums[len - k + current]; + //将目标元素设置为当前需要计算的元素,下一次循环的时候,找设置后的元素的来源,依次内推 + current = len - k + current; + } + } + + count++; + } + } + + /// + /// 方法二:双重循环 + /// + /// + /// + public static void Rotate2(int[] nums, int k) + { + int temp, end; + for (int i = 0; i < k; i++) + { + end = nums[nums.Length - 1]; //获取最后一个元素 + for (int j = 0; j < nums.Length; j++) + { + temp = nums[j]; + nums[j] = end; + end = temp; + } + } + } + + public static void Run() + { + //int[] nums = { 1, 2, 3, 4, 5, 6, 7, 8 }; + int[] nums = { -1, -100, 3, 99 }; + + Rotate(nums, 2); + foreach (var n in nums) + { + Console.WriteLine(n); + } + } + } +} \ No newline at end of file diff --git a/Week 01/id_546/LeetCode_26_546.csharp b/Week 01/id_546/LeetCode_26_546.csharp new file mode 100644 index 000000000..b87dcd020 --- /dev/null +++ b/Week 01/id_546/LeetCode_26_546.csharp @@ -0,0 +1,74 @@ +using System; + +namespace Easy +{ + /// + /// LeetCode:26. 删除排序数组中的重复项 + /// + public class RemoveDuplicatesFromSortedArray + { + /// + /// 双指针法 + /// + /// + /// + public static int RemoveDuplicates2(int[] nums) + { + //1,2,3,3,2,2,4=>1,2,3,2,4 + if (nums.Length == 0) return 0; + + int i = 0; + for (int j = 1; j < nums.Length; j++) + { + if (nums[j] != nums[i]) + { + i++; + nums[i] = nums[j]; + } + } + return i + 1; + } + + /// + /// 扩展题目: 1,2,3,3,2,2,4=>1,2,3,4 + /// + /// + /// + public static int RemoveDuplicates(int[] nums) + { + //nums ={ 1, 1, 2 }; + if (nums.Length == 0) + return 0; + int a = 1; + bool skip = false; + for (int i = 1; i < nums.Length; i++) + { + skip = false; + for (int j = 0; j < a; j++) + { + if (nums[i] == nums[j]) + { + skip = true; + break; + } + } + if (!skip) + { + nums[a] = nums[i]; + a++; + } + } + return a; + } + + public static void Run() + { + int[] nums = { 1, 2, 2, 1, 4 }; + RemoveDuplicates2(nums); + foreach (var n in nums) + { + Console.WriteLine(n); + } + } + } +} \ No newline at end of file diff --git a/Week 01/id_546/LeetCode_283_546.csharp b/Week 01/id_546/LeetCode_283_546.csharp new file mode 100644 index 000000000..6b7a7583e --- /dev/null +++ b/Week 01/id_546/LeetCode_283_546.csharp @@ -0,0 +1,46 @@ +using System; + +namespace Easy +{ + /// + /// LeetCode:283. 移动零 + /// + public class MoveZeroes + { + /// + /// 单层循环遍历原创 + /// + /// + public static void MoveZeroes1(int[] nums) + { + //输入: [0, 1, 0, 3, 12] + //输出: [1, 3, 12, 0, 0] + + int j = 0; + + for (int i = 0; i < nums.Length; i++) + { + if (nums[i] != 0) + { + nums[j] = nums[i]; + if (i > j) + { + nums[i] = 0; + } + j++; + } + } + } + + public static void Run() + { + int[] nums = new[] { 1, 0 }; + + MoveZeroes1(nums); + foreach (var n in nums) + { + Console.WriteLine(n); + } + } + } +} \ No newline at end of file diff --git a/Week 01/id_546/LeetCode_66_546.csharp b/Week 01/id_546/LeetCode_66_546.csharp new file mode 100644 index 000000000..06e16a59b --- /dev/null +++ b/Week 01/id_546/LeetCode_66_546.csharp @@ -0,0 +1,44 @@ +using System; + +namespace Easy +{ + public class PlusOne + { + /// + /// 66. 加一 + /// + /// + /// + public static int[] PlusOne1(int[] digits) + { + // 输入: [1, 9, 9] + //输出: [2, 0, 0] + //if (digits[0] == 0) return new [] { 1 }; + + for (int i = digits.Length - 1; i >= 0; i--) + { + if (++digits[i] >= 10) + { + digits[i] = 0; + } + if (digits[i] != 0) return digits; + } + + digits = new int[digits.Length + 1]; + digits[0] = 1; + return digits; + } + + public static void Run() + { + //int[] nums = { 1, 2, 3, 4, 5, 6, 7, 8 }; + int[] nums = { 1, 9, 9 }; + + int[] n2 = PlusOne1(nums); + foreach (var n in n2) + { + Console.WriteLine(n); + } + } + } +} \ No newline at end of file diff --git a/Week 01/id_546/LeetCode_88_546.csharp b/Week 01/id_546/LeetCode_88_546.csharp new file mode 100644 index 000000000..ca6978229 --- /dev/null +++ b/Week 01/id_546/LeetCode_88_546.csharp @@ -0,0 +1,35 @@ +using System; + +namespace Easy +{ + /// + /// LeetCode:88. 合并两个有序数组 + /// + public class MergeSortedArray + { + /// + /// 方法一:暴力求解法 + /// + /// + /// + /// + /// + public static void Merge(int[] nums1, int m, int[] nums2, int n) + { + nums2.CopyTo(nums1, m); + Array.Sort(nums1); + } + + public static void Run() + { + int[] nums1 = new[] { 1, 2, 3, 4, 0, 0, 0 }; + int[] nums2 = new[] { 2, 3 }; + + Merge(nums1, 3, nums2, 3); + foreach (var n in nums1) + { + Console.WriteLine(n); + } + } + } +} \ No newline at end of file diff --git a/Week 01/id_551/LeetCode_21_551.swift b/Week 01/id_551/LeetCode_21_551.swift new file mode 100644 index 000000000..621aff663 --- /dev/null +++ b/Week 01/id_551/LeetCode_21_551.swift @@ -0,0 +1,35 @@ +/* + 21. 合并两个有序链表 + + 思路:递归,找到重复子过程。 +*/ +/** + * Definition for singly-linked list. + * public class ListNode { + * public var val: Int + * public var next: ListNode? + * public init(_ val: Int) { + * self.val = val + * self.next = nil + * } + * } + */ +class Solution { + func mergeTwoLists(_ l1: ListNode?, _ l2: ListNode?) -> ListNode? { + guard let l1 = l1 else { + return l2 + } + + guard let l2 = l2 else { + return l1 + } + + if l1.val < l2.val { + l1.next = mergeTwoLists(l1.next, l2) + return l1 + } else { + l2.next = mergeTwoLists(l2.next, l1) + return l2 + } + } +} diff --git a/Week 01/id_551/LeetCode_26_551.swift b/Week 01/id_551/LeetCode_26_551.swift new file mode 100644 index 000000000..c76ac8d76 --- /dev/null +++ b/Week 01/id_551/LeetCode_26_551.swift @@ -0,0 +1,22 @@ +/* + 26. 删除排序数组中的重复项 + + 1、注意判空。 + 2、快慢指针法,当快慢指针指向的值不同的时候,慢指针指向的值存储快指针指向的值。 +*/ +class Solution { + func removeDuplicates(_ nums: inout [Int]) -> Int { + if nums.count == 0 { + return 0 + } + + var i = 0 + for j in 1.. stack = new Stack(); + for (int i = 0; i < s.length(); ++i) { + if (s.charAt(i) == '(') { + stack.push(')'); + } else if (s.charAt(i) == '{') { + stack.push('}'); + } else if (s.charAt(i) == '[') { + stack.push(']'); + } else if (stack.isEmpty() || stack.pop() != s.charAt(i)) { + return false; + } + } + return stack.isEmpty(); + } + + } +} +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 01/id_556/LeetCode_283_556.java b/Week 01/id_556/LeetCode_283_556.java new file mode 100644 index 000000000..c18d0e8dc --- /dev/null +++ b/Week 01/id_556/LeetCode_283_556.java @@ -0,0 +1,21 @@ +public class MoveZeroes { + public static void main(String[] args) { + int[] nums = new int[]{1}; + moveZeroes(nums); + } + + public static 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; + } + } + for (int i = 0; i < nums.length; ++i) { + System.out.println(nums[i]); + } + } +} diff --git a/Week 01/id_556/LeetCode_42_556.java b/Week 01/id_556/LeetCode_42_556.java new file mode 100644 index 000000000..293a52c2a --- /dev/null +++ b/Week 01/id_556/LeetCode_42_556.java @@ -0,0 +1,42 @@ +import java.util.Stack; + +public class TrappingRainWater { + public static void main(String[] args) { + int[] h = new int[]{0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1}; + int[] h2 = new int[]{4, 2, 3}; + System.out.println(trap(h2)); + System.out.println(trap2(h2)); + } + + public static int trap(int[] height) { + int result = 0; + for (int i = 1; i <= height.length - 2; ++i) { + int max_left = 0, max_right = 0; + for (int j = i; j >= 0; --j) { + max_left = Math.max(max_left, height[j]); + } + for (int j = i; j <= height.length - 1; ++j) { + max_right = Math.max(max_right, height[j]); + } + result += Math.min(max_left, max_right) - height[i]; + } + return result; + } + + public static int trap2(int[] height) { + int result = 0, current = 0; + Stack stack = new Stack<>(); + while (current < height.length) { + while (!stack.isEmpty() && height[current] > height[stack.peek()]) { + int top = stack.pop(); + if (stack.isEmpty()) + break; + int distance = current - stack.peek() - 1; + int minHeight = Math.min(height[current], height[stack.peek()]) - height[top]; + result += distance * minHeight; + } + stack.push(current++); + } + return result; + } +} diff --git a/Week 01/id_556/LeetCode_641_556.java b/Week 01/id_556/LeetCode_641_556.java new file mode 100644 index 000000000..e1596b523 --- /dev/null +++ b/Week 01/id_556/LeetCode_641_556.java @@ -0,0 +1,127 @@ +public class MyCircularDeque { + + int[] queue; + int front; + int rear; + int size; + int capacity; + + /** + * Initialize your data structure here. Set the size of the deque to be k. + */ + public MyCircularDeque(int k) { + this.queue = new int[k]; + this.front = 0; + this.rear = 0; + this.size = 0; + this.capacity = k; + } + + public static void main(String[] args) { + MyCircularDeque obj = new MyCircularDeque(3); + System.out.println(obj.insertLast(1)); + System.out.println(obj.insertLast(2)); + System.out.println(obj.deleteFront()); + System.out.println(obj.deleteLast()); + System.out.println(obj.getFront()); + System.out.println(obj.getRear()); + System.out.println(obj.isEmpty()); + System.out.println(obj.isFull()); + } + + /** + * Adds an item at the front of Deque. Return true if the operation is successful. + */ + public boolean insertFront(int value) { + if (isFull()) { + // the queue is full + return false; + } else { + // compute the index + front = (front + capacity - 1) % capacity; + queue[front] = value; + return true; + } + } + + /** + * Adds an item at the rear of Deque. Return true if the operation is successful. + */ + public boolean insertLast(int value) { + if (isFull()) { + // the queue is full + return false; + } else { + queue[rear] = value; + rear = (rear + 1 + capacity) % capacity; + size++; + return true; + } + } + + /** + * Deletes an item from the front of Deque. Return true if the operation is successful. + */ + public boolean deleteFront() { + if (isEmpty()) { + // empty + return false; + } else { + front = (front + 1) % capacity; + size--; + return true; + } + } + + /** + * Deletes an item from the rear of Deque. Return true if the operation is successful. + */ + public boolean deleteLast() { + if (isEmpty()) { + // empty + return false; + } else { + rear = (rear - 1 + capacity) % capacity; + size--; + return true; + } + } + + /** + * Get the front item from the deque. + */ + public int getFront() { + if (isEmpty()) { + // empty + return -1; + } else { + return queue[front]; + } + } + + /** + * Get the last item from the deque. + */ + public int getRear() { + if (isEmpty()) { + // empty + return -1; + } else { + return queue[(rear - 1 + capacity) % capacity]; + } + } + + /** + * Checks whether the circular deque is empty or not. + */ + public boolean isEmpty() { + return ((rear == front) && size == 0); + } + + /** + * Checks whether the circular deque is full or not. + */ + public boolean isFull() { + return (rear == front && size == capacity); + } +} diff --git a/Week 01/id_556/NOTE.md b/Week 01/id_556/NOTE.md index a6321d6e2..829f38e82 100644 --- a/Week 01/id_556/NOTE.md +++ b/Week 01/id_556/NOTE.md @@ -1,4 +1,149 @@ -# NOTE +## Week1-学习总结 - +### 1. 用 add first 或 add last 这套新的 API 改写 Deque 的代码 +```java +Deque deque = new LinkedList(); +deque.addFirst("a"); +// deque.offerFirst("a"); +deque.addFirst("b"); +deque.addFirst("c"); +System.out.println(deque); + +String str = deque.peekFirst(); +System.out.println(str); +System.out.println(deque); + +while (deque.size() > 0) { + System.out.println(deque.removeFirst()); + // System.out.println(deque.pollFirst()); +} +System.out.println(deque); +``` + +### 2. 分析 Queue 和 Priority Queue 的源码 (JDK8) + +```java +package java.util; +// 队列是一个FIFO的数据结构, Java中的实现继承了Collection +/* BlockingQueue接口:不是立即从队列中添加或者删除元素,线程执行操作阻塞,直到有空间或者元素可用,实现了阻塞接口的类如下: + * ArrayBlockingQueue :一个由数组支持的有界队列。 + * LinkedBlockingQueue :一个由链接节点支持的可选有界队列。 + * PriorityBlockingQueue :一个由优先级堆支持的无界优先级队列。 + */  +// LinkedList实现了java.util.Queue接口和java.util.AbstractQueue接口, 没有实现阻塞接口,PriorityQueue 和 ConcurrentLinkedQueue也不阻塞 +/*

This interface is a member of the + * + * Java Collections Framework. + * + * @see java.util.Collection + * @see LinkedList + * @see PriorityQueue + * @see java.util.concurrent.LinkedBlockingQueue + * @see java.util.concurrent.BlockingQueue + * @see java.util.concurrent.ArrayBlockingQueue + * @see java.util.concurrent.LinkedBlockingQueue + * @see java.util.concurrent.PriorityBlockingQueue + * @since 1.5 + * @author Doug Lea + * @param the type of elements held in this collection + */ +public interface Queue extends Collection { + // 增加一个元索。如果队列已满,则抛出一个IllegalStateException异常 + boolean add(E e); + // 添加一个元素并返回true。如果队列已满,则返回false + boolean offer(E e); + // 移除并返回队列头部的元素。如果队列为空,则抛出一个NoSuchElementException异常 + E remove(); + // 移除并返问队列头部的元素。如果队列为空,则返回null + E poll(); + // 返回队列头部的元素。如果队列为空,则抛出一个NoSuchElementException异常 + E element(); + // 返回队列头部的元素。如果队列为空,则返回null + E peek(); +} +``` + +```java +package java.util; +// 继承AbstractQueue,而AbstractQueue继承AbstractCollection,实现Queue接口 +public class PriorityQueue extends AbstractQueue { + // 内部使用堆实现,每次取堆顶元素 + transient Object[] queue; // non-private to simplify nested class access + + private static final int DEFAULT_INITIAL_CAPACITY = 11; + // 主要构造函数:initialCapacity 为初始堆大小,一般来说,为了避免扩容,或者空间浪费,要选择合适的值,默认值为 DEFAULT_INITIAL_CAPACITY = 11 + public PriorityQueue(int initialCapacity, Comparator comparator){ + ... + } + // 添加元素 + public boolean add(E e) { + return offer(e); + } + // 调用的是offer + public boolean offer(E e) { + if (e == null) + throw new NullPointerException(); + // 主要是记录修改次数,实际上是为了防止在遍历的时候更改数据造成不一致,会抛出ConcurrentModificationException 异常 + modCount++; + int i = size; + // 检查是否需要扩容,queue就是真实数据 + if (i >= queue.length) + grow(i + 1); + size = i + 1; + if (i == 0) + queue[0] = e; + else + // 使用经典的siftUp上移最后添加的元素,保证堆还是有序的 + siftUp(i, e); + return true; + } + // 删除元素 + public E poll() { + if (size == 0) + return null; + int s = --size; + modCount++; + E result = (E) queue[0]; + E x = (E) queue[s]; + queue[s] = null; + if (s != 0) + // 使用 siftDown,首先将最后一个元素移到堆顶,再调整堆 + siftDown(0, x); + return result; + } + // 获取元素 + // 也可以使用父类AbstractQueue的element()方法 + public E peek() { + // 直接返回数组的第一个值 + return (size == 0) ? null : (E) queue[0]; + } +} +``` + +### 3. 学习笔记 + +#### Week1-4-数组,链表,跳表 + +- 数组:插入/删除平均复杂度 O(n),查找O(1) (随机存取)。对Java ArrayList进行插入操作,涉及arraycopy,效率偏低 +- 单链表:`node --> next`,prepend/append复杂度O(1),插入/删除复杂度 O(1) (指针修改的2次操作),查找O(n)。 +- 双向链表 (Java中默认的)(应用于实现LRU cache):`prev <-- node --> next`,插入/删除复杂度O(1),查找复杂度O(n) +- 循环链表:`tail-->head` +- 跳表(skip list,应用于Redis):为克服链表访问的复杂度O(n),采用升维+空间换时间策略进行加速:加索引:一维-->二维 + - 一级索引:指向next+1,跨越2个元素 + - 二级索引:跨越4个元素 + - 多级索引:log2(n)级索引 + - 最终达到增加/删除log(n)的时间复杂度,但维护成本较高,因为要更新索引,空间复杂度为O(n),但比同为O(n)的简单链表要大 + +> 很多算法靠自己想出来是不可能的,需要去学习前人的总结,所以没有什么不好意思的。 + +#### Week1-5-栈,队列 + +- Stack: FILO,增加删除O(1),查询(需要遍历)O(n) +- Queue: FIFO,增加删除O(1),查询O(n) +- Deque: Double-end queue, 增加删除O(1),查询O(n) +- Priority Queue:插入O(1),取出O(logn),按优先级取出,为了保持有序性,可以用heap/bst/treap实现 + +> 每种数据结构在不同编程语言都可能由不同底层来实现,甚至由多个其他数据结构实现,比如用两个栈实现队列 + +> 一维数组的坐标变换,i/j嵌套遍历,双指针夹逼,枚举中间找左右边界等套路代码,需要非常熟练 \ No newline at end of file diff --git a/Week 01/id_576/LeetCode_1_576.java b/Week 01/id_576/LeetCode_1_576.java new file mode 100644 index 000000000..533a0ec46 --- /dev/null +++ b/Week 01/id_576/LeetCode_1_576.java @@ -0,0 +1,39 @@ +import java.util.HashMap; +import java.util.Map; + +/** + * _1TwoSum + */ +public class LeetCode_1_576 { + //1. 暴力法,on2,两层for 循环遍历匹配 + public int[] twoSum1(int[] nums, int target) { + //肌肉记忆的两层遍历数组的模版,三层遍历也要会,for (int k = 0; i < nums.length - 2; i++) + int[] res = new int[2]; + for (int i = 0; i < nums.length - 1; i++) { + for (int j = i + 1; j < nums.length; j++) { + if (nums[i] + nums[j] == target) { + res[0] = i; + res[1] = j; + return res; + } + } + } + return new int[0]; + } + + //1. 哈希表,O(n),把数组元素的值和位置用hashmap存储,遍历条件target-nums[i],看是否有key存在,则取位置值为输出结果。 + //记住这种用hash表存储值来判断的思路 + public int[] twoSum2(int[] nums, int target) { + int[] result = new int[2]; + Map map = new HashMap<>(); + for (int i = 0; i < nums.length; i++) { + if (map.containsKey(target - nums[i])) { + result[1] = i; + result[0] = map.get(target - nums[i]); + return result; + } + map.put(nums[i], i); + } + return result; + } +} \ No newline at end of file diff --git a/Week 01/id_576/LeetCode_283_576.java b/Week 01/id_576/LeetCode_283_576.java new file mode 100644 index 000000000..5fdf64b76 --- /dev/null +++ b/Week 01/id_576/LeetCode_283_576.java @@ -0,0 +1,38 @@ +/** + * LeetCode_283_576 + */ +public class LeetCode_283_576 { + //1. 用j记录下一个非零位置,遇到非零元素就替换到将j位置上,再将i位置置为0,O(n) + public void moveZeroes1(int[] nums) { + //用j记录新加入元素位置的小操作,一定要熟记! + int j = 0;//永远记录下一个非零位置 + for (int i = 0; i < nums.length; i++) { + if (nums[i] != 0) { + nums[j] = nums[i]; + if (i != j) { + nums[i] = 0; + } + j++; + } + } + + } + + //2. 先把非零元素都移动到前面,在后面补0,O(n),参考国际站讨论区解法 + public void moveZeroes2(int[] nums) { + if (nums == null || nums.length == 0) { + return; + }//注意合理非法条件的判断,增加逻辑严谨性 + int j = 0; + for (int i = 0; i < nums.length; i++) { + if (nums[i] != 0) { + nums[j++] = nums[i]; + } + } + while (j < nums.length) { + nums[j++] = 0; + } + } + + +} \ No newline at end of file diff --git a/Week 01/id_576/_141LinkedListCycle.java b/Week 01/id_576/_141LinkedListCycle.java new file mode 100644 index 000000000..e69de29bb diff --git a/Week 01/id_576/_15ThreeSums.java b/Week 01/id_576/_15ThreeSums.java new file mode 100644 index 000000000..fded3b77e --- /dev/null +++ b/Week 01/id_576/_15ThreeSums.java @@ -0,0 +1,51 @@ +import java.util.ArrayList; +import java.util.Arrays; +import java.util.LinkedList; + +import com.sun.tools.javac.code.Type.ForAll; +import com.sun.tools.javac.util.List; + +/** + * _15ThreeSums + */ +public class _15ThreeSums { + //1. 暴力法,O(n^3) + public List> threeSum1(int[] nums) { + List> res = new ArrayList<>(); + for (int i = 0; i < nums.length - 2; i++) { + for (int j = i + 1; j < nums.length - 1; j++) { + for (int k = j + 1; k < nums.length; k++) { + if (nums[i] + nums[j] == -nums[k]) { + res.add(new ArrayList(Arrays.asList(nums[i],nums[j],nums[k]))); + } + } + } + } + return res; + } + + //2. hash table + //3. 双指针逼近 + public List> threeSum3(int[] nums) { + Arrays.sort(nums); + List> res = new LinkedList<>(); + for (int i = 0; i < nums.length - 2; i++) {//遍历target + if (i == 0 || (i > 0 && nums[i] != nums[i - 1])) { + //确定双指针左右边界和target值 + int lo = i + 1, hi = nums.length - 1, sum = 0 - nums[i]; + while (lo < hi) { + if (nums[lo] + nums[hi] == sum) { + res.add(Arrays.asList(nums[i], nums[lo], nums[hi])); + //跳过重复解 + while (lo < hi && nums[lo] == nums[lo + 1]) lo++; + while (lo < hi && nums[hi] == nums[hi - 1]) hi--; + lo++; hi--; + } else if (nums[lo] + nums[hi] < sum) lo++;//说明lo值小了 + else hi--; + } + } + } + return res; + } +} + diff --git a/Week 01/id_576/_70ClimbStairs.java b/Week 01/id_576/_70ClimbStairs.java new file mode 100644 index 000000000..3a29cf08e --- /dev/null +++ b/Week 01/id_576/_70ClimbStairs.java @@ -0,0 +1,73 @@ +/* +1.升维的思想,时间换空间 +2.最大误区:刷题只刷一遍 +3. 形成肌肉记忆 + + */ + + +class _70ClimbStaira { + + //暴力法:斐波那契额数列 + //f(n) = f(n-1) + f(n-2) + public int climbStairs1(int n) { + if (n <= 2) { + return n; + } + + return climbStairs1(n - 1) + climbStairs1(n - 2); + } + + /** + * 方法二:dynamic programming + * 第 ii 阶可以由以下两种方法得到: + +在第 (i-1)(i−1) 阶后向上爬一阶。 + +在第 (i-2)(i−2) 阶后向上爬 22 阶。 + +所以到达第 ii 阶的方法总数就是到第 (i-1)(i−1) 阶和第 (i-2)(i−2) 阶的方法数之和。 + +令 dp[i]dp[i] 表示能到达第 ii 阶的方法总数: + +dp[i]=dp[i-1]+dp[i-2] +dp[i]=dp[i−1]+dp[i−2] + + */ + public int climbStairs2 (int n) { + if (n == 1) { + return 1; + } + int[] dp = new int[n + 1]; + dp[1] = 1; + dp[2] = 2; + for (int i = 3; i <= n; i++) { + dp[i] = dp[i - 1] + dp[i - 2]; + } + return dp[n]; + } + + /** + * Basically it's a fibonacci + * r if we look at it closer, it is clear that this is basically a fibonacci number, + * with the starting numbers as 1 and 2, instead of 1 and 1. + */ + public int climbStairs(int n) { + //base cases + if (n <= 0) return 0; + if (n == 1) return 1; + if (n == 2) return 2; + + int one_step_before = 2; + int two_step_before = 1; + int all_ways = 0; + + for (int i = 2; i < n; i++) { + all_ways = one_step_before + two_step_before; + two_step_before = one_step_before; + one_step_before = all_ways;// keep updating two/one step ways + } + return all_ways; + } + +} \ No newline at end of file diff --git a/Week 01/id_586/11-container-with-most-water.c b/Week 01/id_586/11-container-with-most-water.c new file mode 100644 index 000000000..4531cdb79 --- /dev/null +++ b/Week 01/id_586/11-container-with-most-water.c @@ -0,0 +1,45 @@ +int maxArea(int* height, int heightSize){ +#if 0 + /* 1. 暴力求解 */ + int i = 0; + int j = 0; + int max = 0; + int area = 0; + int h = 0; + + for (; i < heightSize; i++) { + for (j = i + 1; j < heightSize; j++) { + h = (height[i] < height[j] ? height[i] : height[j]); + area = (j - i) * h; + if (max < area) + max = area; + } + } + + return max; +#else + /* 双指针法 */ + /* 重点在于理解双指针的移动,每次都移动较短的指针 */ + + int i = 0; + int j = heightSize - 1; + + int max = 0; + int area = 0; + int h = 0; + + while (i < j) { + h = (height[i] < height[j] ? height[i] : height[j]); + area = (j - i) * h; + if (max < area) max = area; + //if (height[i] < height[j]) + // i++; + // else + // j--; + while ((height[i] <= h) && i < j) i++; + while ((height[j] <= h) && i < j) j--; + } + + return max; +#endif +} diff --git a/Week 01/id_586/141-linked-list-cycle.c b/Week 01/id_586/141-linked-list-cycle.c new file mode 100644 index 000000000..4ae6043fd --- /dev/null +++ b/Week 01/id_586/141-linked-list-cycle.c @@ -0,0 +1,32 @@ +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * struct ListNode *next; + * }; + */ + +/* + * 使用的是快慢指针的方法 + * */ +bool hasCycle(struct ListNode *head) { + struct ListNode *slow = head; + struct ListNode *fast = head; + + if (!head || !head->next) return 0; + + while (slow && fast) { + slow = slow->next; + fast = fast->next; + + if (!fast) + return 0; + + fast = fast->next; + + if (slow == fast) + return 1; + } + + return 0; +} diff --git a/Week 01/id_586/142-linked-list-cycle-ii.c b/Week 01/id_586/142-linked-list-cycle-ii.c new file mode 100644 index 000000000..d7078a7a7 --- /dev/null +++ b/Week 01/id_586/142-linked-list-cycle-ii.c @@ -0,0 +1,44 @@ +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * struct ListNode *next; + * }; + */ +struct ListNode *detectCycle(struct ListNode *head) { + if (head == NULL || head->next == NULL) + return NULL; + + struct ListNode *fast = head; + struct ListNode *slow = head; + struct ListNode *meet = NULL; + + while (fast) { + slow = slow->next; + fast = fast->next; + + if (!fast) { + return false; + } + + fast = fast->next; + + if (fast == slow) { + meet = fast; + break; + } + } + + if (meet == NULL) + return NULL; + + while (head && meet) { + if (head == meet) { + return head; + } + head = head->next; + meet = meet->next; + } + + return NULL; +} diff --git a/Week 01/id_586/206-reverse-linked-list.c b/Week 01/id_586/206-reverse-linked-list.c new file mode 100644 index 000000000..6aaad0bcc --- /dev/null +++ b/Week 01/id_586/206-reverse-linked-list.c @@ -0,0 +1,24 @@ +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * struct ListNode *next; + * }; + */ + +/* 1. 使用一个 new_head 作为翻转链表的头指针的,遍历给定的链表, + * 2. 把遍历的元素使用头插的方法,插入链表, + * 3. 返回 new_head */ +struct ListNode* reverseList(struct ListNode* head){ + struct ListNode *new_head = NULL; + + while (head) { + struct ListNode *tmp = head; + head = head->next; + tmp->next = new_head; + new_head = tmp; + } + + return new_head; +} + diff --git a/Week 01/id_586/21-merge-two-sorted-lists.c b/Week 01/id_586/21-merge-two-sorted-lists.c new file mode 100644 index 000000000..48e8ef7d9 --- /dev/null +++ b/Week 01/id_586/21-merge-two-sorted-lists.c @@ -0,0 +1,35 @@ +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * struct ListNode *next; + * }; + */ + + +struct ListNode* mergeTwoLists(struct ListNode* l1, struct ListNode* l2){ + if (!l1) return l2; + if (!l2) return l1; + + struct ListNode dummy; + struct ListNode *prev = &dummy; + + while (l1 && l2) { + if (l1->val < l2->val) { + prev->next = l1; + l1 = l1->next; + } else { + prev->next = l2; + l2 = l2->next; + } + + prev = prev->next; + } + + if (l1) + prev->next = l1; + if (l2) + prev->next = l2; + + return dummy.next; +} diff --git a/Week 01/id_586/24-swap-nodes-in-pairs.c b/Week 01/id_586/24-swap-nodes-in-pairs.c new file mode 100644 index 000000000..a55130c2b --- /dev/null +++ b/Week 01/id_586/24-swap-nodes-in-pairs.c @@ -0,0 +1,39 @@ +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * struct ListNode *next; + * }; + */ + +/* + * 1. 先保存需要替换的指向的内容 + * 2. 依次修改指针个指向 + * 3. 调整新的头节点 + * */ +struct ListNode* swapPairs(struct ListNode* head){ + struct ListNode dummy; + struct ListNode *prev; + struct ListNode* n1 = NULL; + struct ListNode* n2 = NULL; + struct ListNode* last = NULL; + + dummy.next = head; + prev = &dummy; + + while (head && head->next) { + n1 = head; + n2 = head->next; + last = head->next->next; + + prev->next = n2; + n2->next = n1; + n1->next = last; + + prev = n1; + head = last; + } + + return dummy.next; +} + diff --git a/Week 01/id_586/26-remove-duplicates-from-sorted-array.c b/Week 01/id_586/26-remove-duplicates-from-sorted-array.c new file mode 100644 index 000000000..7d2fcf9c3 --- /dev/null +++ b/Week 01/id_586/26-remove-duplicates-from-sorted-array.c @@ -0,0 +1,18 @@ +/* 双指针法: + * 两个指针 ii 和 jj,其中 ii 是慢指针,而 jj 是快指针。只要 nums[i] = nums[j]nums[i]=nums[j],我们就增加 jj 以跳过重复项 + */ +int removeDuplicates(int* nums, int numsSize){ + if (numsSize <= 0) return 0; + + int i = 0; + int j = 0; + + for (j = 1; j < numsSize; j++) { + if (nums[i] != nums[j]) { + i++; + nums[i] = nums[j]; + } + } + + return i + 1; +} diff --git a/Week 01/id_586/42-trapping-rain-water.cc b/Week 01/id_586/42-trapping-rain-water.cc new file mode 100644 index 000000000..57128d0a1 --- /dev/null +++ b/Week 01/id_586/42-trapping-rain-water.cc @@ -0,0 +1,39 @@ +class Solution { +public: +/* +我们可以不用像方法 2 那样存储最大高度,而是用栈来跟踪可能储水的最长的条形块。使用栈就可以在一次遍历内完成计算。 + +我们在遍历数组时维护一个栈。如果当前的条形块小于或等于栈顶的条形块,我们将条形块的索引入栈,意思是当前的条形块被栈中的前一个条形块界定。如果我们发现一个条形块长于栈顶,我们可以确定栈顶的条形块被当前条形块和栈的前一个条形块界定,因此我们可以弹出栈顶元素并且累加答案到 \text{ans}ans 。 + +算法 + +使用栈来存储条形块的索引下标。 +遍历数组: +当栈非空且 height[current]>height[st.top()] +意味着栈中元素可以被弹出。弹出栈顶元素 top。 +计算当前元素和栈顶元素的距离,准备进行填充操作 +distance=current−st.top()−1 +找出界定高度 +bounded_height=min(height[current],height[st.top()])−height[top] +往答案中累加积水量 ans+=distance×bounded_height +将当前索引下标入栈 +将 current 移动到下个位置 +*/ + int trap(vector& height) { + int ans = 0, current = 0; + stack st; + while (current < height.size()) { + while (!st.empty() && height[current] > height[st.top()]) { + int top = st.top(); + st.pop(); + if (st.empty()) + break; + int distance = current - st.top() - 1; + int bounded_height = min(height[current], height[st.top()]) - height[top]; + ans += distance * bounded_height; + } + st.push(current++); + } + return ans; + } +}; diff --git a/Week 01/id_586/641-design-circular-deque.cc b/Week 01/id_586/641-design-circular-deque.cc new file mode 100644 index 000000000..809069da4 --- /dev/null +++ b/Week 01/id_586/641-design-circular-deque.cc @@ -0,0 +1,91 @@ +class MyCircularDeque { +private: + vector buffer; + int cnt; + int k; + int front; + int rear; +public: + /** Initialize your data structure here. Set the size of the deque to be k. */ + MyCircularDeque(int k) : buffer(k, 0), cnt(0), k(k), front(k - 1), rear(0) { + } + + /** Adds an item at the front of Deque. Return true if the operation is successful. */ + bool insertFront(int value) { + if (cnt == k) return false; + + buffer[front] = value; + front = (front - 1 + k) % k; + ++cnt; + + return true; + } + + /** Adds an item at the rear of Deque. Return true if the operation is successful. */ + bool insertLast(int value) { + if (cnt == k) return false; + + buffer[rear] = value; + rear = (rear + 1) % k; + ++cnt; + + return true; + } + + /** Deletes an item from the front of Deque. Return true if the operation is successful. */ + bool deleteFront() { + if (cnt == 0) return false; + + front = (front + 1) % k; + --cnt; + + return true; + } + + /** Deletes an item from the rear of Deque. Return true if the operation is successful. */ + bool deleteLast() { + if (cnt == 0) return false; + + rear = (rear - 1 + k) % k; + --cnt; + + return true; + } + + /** Get the front item from the deque. */ + int getFront() { + if (cnt == 0) return -1; + + return buffer[(front + 1) % k]; + } + + /** Get the last item from the deque. */ + int getRear() { + if (cnt == 0) return -1; + + return buffer[(rear - 1 + k) % k]; + } + + /** Checks whether the circular deque is empty or not. */ + bool isEmpty() { + return cnt == 0; + } + + /** Checks whether the circular deque is full or not. */ + bool isFull() { + return cnt == k; + } +}; + +/** + * Your MyCircularDeque object will be instantiated and called as such: + * MyCircularDeque* obj = new MyCircularDeque(k); + * bool param_1 = obj->insertFront(value); + * bool param_2 = obj->insertLast(value); + * bool param_3 = obj->deleteFront(); + * bool param_4 = obj->deleteLast(); + * int param_5 = obj->getFront(); + * int param_6 = obj->getRear(); + * bool param_7 = obj->isEmpty(); + * bool param_8 = obj->isFull(); + */ diff --git a/Week 01/id_586/NOTE.md b/Week 01/id_586/NOTE.md index a6321d6e2..d8598696b 100644 --- a/Week 01/id_586/NOTE.md +++ b/Week 01/id_586/NOTE.md @@ -1,4 +1,51 @@ # NOTE - +## Class 3 +两数之和题目: https://leetcode-cn.com/problems/two-sum/ + +Array 实战题目 + +https://leetcode-cn.com/problems/container-with-most-water/ +https://leetcode-cn.com/problems/move-zeroes/ +https://leetcode.com/problems/climbing-stairs/ +https://leetcode-cn.com/problems/3sum/ (高频老题) + +Linked List 实战题目 + +https://leetcode.com/problems/reverse-linked-list/ +https://leetcode.com/problems/swap-nodes-in-pairs +https://leetcode.com/problems/linked-list-cycle +https://leetcode.com/problems/linked-list-cycle-ii +https://leetcode.com/problems/reverse-nodes-in-k-group/ + +课后作业 + +https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array/ +https://leetcode-cn.com/problems/rotate-array/ +https://leetcode-cn.com/problems/merge-two-sorted-lists/ +https://leetcode-cn.com/problems/merge-sorted-array/ +https://leetcode-cn.com/problems/two-sum/ +https://leetcode-cn.com/problems/move-zeroes/ +https://leetcode-cn.com/problems/plus-one/ + +## Class 4 + +预习题目 + +https://leetcode-cn.com/problems/valid-parentheses/ +https://leetcode-cn.com/problems/min-stack/ + +实战题目 + +https://leetcode-cn.com/problems/largest-rectangle-in-histogram +https://leetcode-cn.com/problems/sliding-window-maximum + +课后作业 + +用 add first 或 add last 这套新的 API 改写 Deque 的代码 +分析 Queue 和 Priority Queue 的源码 +https://leetcode.com/problems/design-circular-deque +https://leetcode.com/problems/trapping-rain-water/ + +说明:改写代码和分析源码这两项作业,同学们需要在第 1 周的个人总结中完成。 diff --git a/Week 01/id_591/design-circular-deque.js b/Week 01/id_591/design-circular-deque.js new file mode 100644 index 000000000..e69de29bb diff --git a/Week 01/id_591/remove-duplicates-from-sorted-array.js b/Week 01/id_591/remove-duplicates-from-sorted-array.js new file mode 100644 index 000000000..776cb019f --- /dev/null +++ b/Week 01/id_591/remove-duplicates-from-sorted-array.js @@ -0,0 +1,15 @@ +/** + * @param {number[]} nums + * @return {number} + */ +var removeDuplicates = function(nums) { + let i=0,j=0; + for(i=0; i 0) { + System.arraycopy(array, 0, array, 1, size); + } + array[0] = value; + size ++; + return true; + } + + /** Adds an item at the rear of Deque. Return true if the operation is successful. */ + public boolean insertLast(int value) { + if (size == capacity) { + return false; + } + + array[size] = value; + size ++; + return true; + } + + /** Deletes an item from the front of Deque. Return true if the operation is successful. */ + public boolean deleteFront() { + if (size == 0) { + return false; + } + + // 使用后面的元素覆盖头部 + System.arraycopy(array, 1, array, 0, --size); + return true; + } + + /** Deletes an item from the rear of Deque. Return true if the operation is successful. */ + public boolean deleteLast() { + if (size == 0) { + return false; + } + + size --; + return true; + } + + /** Get the front item from the deque. */ + public int getFront() { + if (size == 0) { + return -1; + } + + return array[0]; + } + + /** Get the last item from the deque. */ + public int getRear() { + if (size == 0) { + return -1; + } + + return array[size - 1]; + } + + /** Checks whether the circular deque is empty or not. */ + public boolean isEmpty() { + return size == 0; + } + + /** Checks whether the circular deque is full or not. */ + public boolean isFull() { + return size == capacity; + } +} + +/** + * 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(); + */ \ No newline at end of file diff --git a/Week 01/id_596/NOTE.md b/Week 01/id_596/NOTE.md index a6321d6e2..51ef0b3df 100644 --- a/Week 01/id_596/NOTE.md +++ b/Week 01/id_596/NOTE.md @@ -1,4 +1,84 @@ # NOTE - +## 用新API改写Deque代码 +``` java +Deque deque = new LinkedList(); + + deque.addFirst("a"); + deque.addFirst("b"); + deque.addLast("c"); + + System.out.println(deque); + + String str = deque.peekFirst(); + System.out.println(str); + System.out.println(deque); + + while(deque.size() > 0) { + System.out.println(deque.removeFirst()); + } + System.out.println(deque); +``` + +## Queue 的源码分析 +底层使用链表实现,成员变量为头指针first,尾指针last和一个用来记录队列长度的 int 值 n。 +### 主要方法实现 +* isEmpty() - 头指针是否为null +* size() - 队列长度即 n 的值 +* peek() - 不为空的话返回head对应的元素,为空的话抛出异常 +* enqueue(item) - 在尾部插入item操作,增加队列长度 n++ +* dequeue() - 在头部进行删除item操作,减少队列长度 n-- + +## Priority Queue 的源码分析 +底层使用平衡二叉堆来实现,二叉堆是一颗完全二叉树或者近似二叉树。当父节点的键值总是大于或等于任何一个子节点的键值时为“最大堆”。当父节点的键值总是小于或等于任何一个子节点的键值时为“最小堆”。 +Priority Queue使用的正是最小堆,堆的底层实现是数组。数组第n个元素的的两个子节点分别为第2*n+1和2*(n+1)个元素。 +加入的元素都需要实现Comparator,优先级的比较正是使用compareTo方法实现的。 + +### 主要方法实现 +* add()/offer() - 在数组尾部插入新元素,执行siftUp操作:如果其值小于堆父节点的话,与父节点交换。重复该操作,直至其值大于等于父节点或者到了根节点。size ++。 +* peek() - 返回第0个元素,如果数组为空返回null +* poll() - 返回第0个元素,执行siftDown操作:将最后一个元素填在堆顶即第0个元素,然后不然和子节点比较调整位置。size --。 +* size() - 返回内部成员变量size的值。size随着add()和poll()的操作增加或减少 + +## 学习总结 +### 数组、链表和跳表 +数组和链表都是最基本的数据结构,很多复杂数据结构就是基于他们实现的。 +数组的底层实际上使用的是计算机内存空间中开辟的一段连续的地址,而链表是一组连在一起的节点Node,每个Node都有一个value值和一个next指针,next指针指向下一个元素。由于底层实现的不同他们在随机访问,插入和删除操作上面有很大的不同,我们在使用的时候要根据各自的特性来挑选最适合的。他们进行基本操作的时间复杂度分别为: +数组: +* 随机访问:O(1),直接访问内存地址 +* 插入:O(n),需要将插入位置之后的元素向后移动 +* 删除:O(n),需要将删除位置之后的元素向前移动 + +链表: +* 随机访问:O(n),需要遍历节点来搜索值 +* 插入:O(1),直接操作next指针 +* 删除:O(1),直接操作next指针 + +链表插入操作代码示例: +``` +newNode->next = node->next +node->next = newNode +``` +链表删除操作代码示例: +``` +preNode->next = delNode->next +delNode->next = null +``` + +跳表可以认为是优化了随机访问速度的链表,在算法中优化时间复杂度的核心思想有两个: +1. 升维 +2. 空间换时间 + +跳表在链表的基础上额外增加了一系列索引来优化访问速度。添加索引的规律是第n级索引的每两个索引的跨度是2的n次方,即第一级索引每隔2个节点一个索引,第二级每隔4个节点一个索引,......。因此有n个元素就有logn级索引,第k级索引的节点数为 n / (2^k)。 +跳表查询的时间复杂度与索引的高度相关为O(logn),在实际使用中插入和删除操作会导致重新编排索引,因此它的复杂度也为O(logn)。 +由于使用的额外的索引,跳表的空间复杂度为O(n)。 + +### 栈、队列、优先队列和双端队列 +栈和队列最大的区别就在于元素的进出方式,栈是先入后出即FILO,队列为先入先出即FIFO。他们的添加和删除复杂度都为O(1)。 +将队列优化一下,使得两端都可以进行添加删除操作的话就变成了双端队列(Deque: Double-End Queue),由于两端可以进行操作,双端队列可以用来代替栈。 +如果对队列的元素取出做一个限制,按照优先级来操作,那么就是优先级队列了。由于取出操作需要对元素优先级进行比较,所以其取出的时间复杂度为O(logN),插入依然是O(1)。优先队列的底层实现的数据结构比较多样和复杂,常见的有heap, bst, treap。Java中使用的是heap。 + +在算法题中,栈和队列可以用来解决特定的问题: +* 栈 - 最近相关性问题 +* 队列 - 先来后到问题 \ No newline at end of file diff --git a/Week 01/id_601/LeetCode_189_601.java b/Week 01/id_601/LeetCode_189_601.java new file mode 100644 index 000000000..3c9f7d762 --- /dev/null +++ b/Week 01/id_601/LeetCode_189_601.java @@ -0,0 +1,17 @@ +class Solution { + public static void rotate(int[] nums, int k) { + reverse(nums, 0, nums.length - 1); + reverse(nums, 0, k - 1); + reverse(nums, k, nums.length - 1); + } + + public static void reverse(int[] nums, int start, int end) { + while (start < end) { + int temp = nums[start]; + nums[start] = nums[end]; + nums[end] = temp; + start++; + end--; + } + } +} diff --git a/Week 01/id_601/LeetCode_283_601.java b/Week 01/id_601/LeetCode_283_601.java new file mode 100644 index 000000000..80d3c0786 --- /dev/null +++ b/Week 01/id_601/LeetCode_283_601.java @@ -0,0 +1,18 @@ +class Solution { + public void moveZeroes(int[] nums) { + int j = 0; + for (int i = 0; i 0){ + while(j < nums.length){ + nums[j]=0; + j++; + } + } + } +} diff --git a/Week 01/id_601/LeetCode_88_601.java b/Week 01/id_601/LeetCode_88_601.java new file mode 100644 index 000000000..8fb7785df --- /dev/null +++ b/Week 01/id_601/LeetCode_88_601.java @@ -0,0 +1,34 @@ +class Solution { + public void merge(int[] nums1, int m, int[] nums2, int n) { + /** + * 没有考虑 nums1[0] 的值是 0 时候 + * 在 leetcode 执行代码没有问题,但是在提交报数组下标越界,没有排查出来,但是在 intellijdea 里可以运行 + */ + int j = 0; + int temp = 0; + for (int i = 0; i nums2[j+1]){} 作用: + * 当 nums2[0] 元素比 nums2[1] 大时候,做相应处理 + */ + if (j < nums2.length-1 && nums2[j] > nums2[j+1]) { + temp = nums2[j]; + nums2[j] = nums2[j+1]; + nums2[j+1] = temp; + } + nums1[i] = nums2[j]; + j++; + } + } + } +} diff --git a/Week 01/id_606/.DS_Store b/Week 01/id_606/.DS_Store new file mode 100644 index 000000000..5008ddfcf Binary files /dev/null and b/Week 01/id_606/.DS_Store differ diff --git "a/Week 01/id_606/1.\344\270\244\346\225\260\344\271\213\345\222\214.java" "b/Week 01/id_606/1.\344\270\244\346\225\260\344\271\213\345\222\214.java" new file mode 100644 index 000000000..ca31d0335 --- /dev/null +++ "b/Week 01/id_606/1.\344\270\244\346\225\260\344\271\213\345\222\214.java" @@ -0,0 +1,48 @@ +/* + * @lc app=leetcode.cn id=1 lang=java + * + * [1] 两数之和 + * + * https://leetcode-cn.com/problems/two-sum/description/ + * + * algorithms + * Easy (46.73%) + * Likes: 6612 + * Dislikes: 0 + * Total Accepted: 624.4K + * Total Submissions: 1.3M + * Testcase Example: '[2,7,11,15]\n9' + * + * 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。 + * + * 你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。 + * + * 示例: + * + * 给定 nums = [2, 7, 11, 15], target = 9 + * + * 因为 nums[0] + nums[1] = 2 + 7 = 9 + * 所以返回 [0, 1] + * + * + */ + +// @lc code=start +class Solution { + public int[] twoSum(int[] nums, int target) { + Map map = new HashMap<>(); + for (int i = 0; i < nums.length; i++) { + map.put(nums[i], i); + } + for (int i = 0; i < nums.length; i++) { + int complement = target - nums[i]; + if (map.containsKey(complement) && map.get(complement) != i) { + return new int[] { i, map.get(complement) }; + } + } + + return null; + + } +} +// @lc code=end diff --git "a/Week 01/id_606/11.\347\233\233\346\234\200\345\244\232\346\260\264\347\232\204\345\256\271\345\231\250.java" "b/Week 01/id_606/11.\347\233\233\346\234\200\345\244\232\346\260\264\347\232\204\345\256\271\345\231\250.java" new file mode 100644 index 000000000..607ac376b --- /dev/null +++ "b/Week 01/id_606/11.\347\233\233\346\234\200\345\244\232\346\260\264\347\232\204\345\256\271\345\231\250.java" @@ -0,0 +1,27 @@ +/* + * @lc app=leetcode.cn id=11 lang=java + * + * [11] 盛最多水的容器 + */ + +// @lc code=start +class Solution { + public int maxArea(int[] height) { + int area = 0; + int f = 0; + int l = height.length - 1; + while (l > f) { + int thisHeight = Math.min(height[f], height[l]); + int thisArea = thisHeight * (l - f); + area = Math.max(area, thisArea); + if (height[f] < height[l]) { + f++; + } else { + l--; + } + } + return area; + } + +} +// @lc code=end diff --git "a/Week 01/id_606/26.\345\210\240\351\231\244\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\351\207\215\345\244\215\351\241\271.java" "b/Week 01/id_606/26.\345\210\240\351\231\244\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\351\207\215\345\244\215\351\241\271.java" new file mode 100644 index 000000000..2b8003d8f --- /dev/null +++ "b/Week 01/id_606/26.\345\210\240\351\231\244\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\351\207\215\345\244\215\351\241\271.java" @@ -0,0 +1,73 @@ +/* + * @lc app=leetcode.cn id=26 lang=java + * + * [26] 删除排序数组中的重复项 + * + * https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array/description/ + * + * algorithms + * Easy (46.63%) + * Likes: 1131 + * Dislikes: 0 + * Total Accepted: 182.4K + * Total Submissions: 389.4K + * Testcase Example: '[1,1,2]' + * + * 给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。 + * + * 不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。 + * + * 示例 1: + * + * 给定数组 nums = [1,1,2], + * + * 函数应该返回新的长度 2, 并且原数组 nums 的前两个元素被修改为 1, 2。 + * + * 你不需要考虑数组中超出新长度后面的元素。 + * + * 示例 2: + * + * 给定 nums = [0,0,1,1,1,2,2,3,3,4], + * + * 函数应该返回新的长度 5, 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4。 + * + * 你不需要考虑数组中超出新长度后面的元素。 + * + * + * 说明: + * + * 为什么返回数值是整数,但输出的答案是数组呢? + * + * 请注意,输入数组是以“引用”方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。 + * + * 你可以想象内部操作如下: + * + * // nums 是以“引用”方式传递的。也就是说,不对实参做任何拷贝 + * int len = removeDuplicates(nums); + * + * // 在函数里修改输入数组对于调用者是可见的。 + * // 根据你的函数返回的长度, 它会打印出数组中该长度范围内的所有元素。 + * for (int i = 0; i < len; i++) { + * print(nums[i]); + * } + * + * + */ + +// @lc code=start +class Solution { + public int removeDuplicates(int[] nums) { + if (nums.length == 0) + return 0; + int i = 0; + for (int j = 1; j < nums.length; j++) { + if (nums[j] != nums[i]) { + i++; + nums[i] = nums[j]; + } + } + return i + 1; + + } +} +// @lc code=end diff --git "a/Week 01/id_606/283.\347\247\273\345\212\250\351\233\266.java" "b/Week 01/id_606/283.\347\247\273\345\212\250\351\233\266.java" new file mode 100644 index 000000000..efdca4cf4 --- /dev/null +++ "b/Week 01/id_606/283.\347\247\273\345\212\250\351\233\266.java" @@ -0,0 +1,48 @@ +/* + * @lc app=leetcode.cn id=283 lang=java + * + * [283] 移动零 + * + * https://leetcode-cn.com/problems/move-zeroes/description/ + * + * algorithms + * Easy (56.98%) + * Likes: 414 + * Dislikes: 0 + * Total Accepted: 76K + * Total Submissions: 132.8K + * Testcase Example: '[0,1,0,3,12]' + * + * 给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。 + * + * 示例: + * + * 输入: [0,1,0,3,12] + * 输出: [1,3,12,0,0] + * + * 说明: + * + * + * 必须在原数组上操作,不能拷贝额外的数组。 + * 尽量减少操作次数。 + * + * + */ + +// @lc code=start +class Solution { + public void moveZeroes(int[] nums) { + int nonzeroIndex = 0;//0的位置 + for (int i = 0; i < nums.length; i++) { + if (nums[i] != 0) { + if (i > nonzeroIndex) { + nums[nonzeroIndex] = nums[i];//0的位置,设置i + nums[i] = 0;//不是0的位置设置为0 + } + nonzeroIndex++; + } + } + + } +} +// @lc code=end diff --git a/Week 01/id_611/LeetCode_189_611.java b/Week 01/id_611/LeetCode_189_611.java new file mode 100644 index 000000000..f0e76b38c --- /dev/null +++ b/Week 01/id_611/LeetCode_189_611.java @@ -0,0 +1,45 @@ +class Solution { + //环形替换法 + public void rotate(int[] nums, int k) { + //提取k位置 + k = k % nums.length; + //位移次数 + int count = 0; + for(int start = 0; count < nums.length; start++){ + //前置变量 + int prev = nums[start]; + //当前值下标 + int current = start; + do{ + int next = (current + k)% nums.length; + //值替换操作 + int tmp = nums[next]; + + nums[next] = prev; + prev =tmp; + current = next; + count ++; + + }while(start != current); + } + } + + //反转法 + public void rotate2(int[] nums, int k) { + int n = nums.length; + k %= n; + reverse(nums,0,n-1); + reverse(nums,0,k-1); + reverse(nums,k,n-1); + } + + public void reverse(int[] nums,int start,int end){ + while(start < end){ + int tmp = nums[start]; + nums[start] = nums[end]; + nums[end] = tmp; + start++; + end--; + } + } +} \ No newline at end of file diff --git a/Week 01/id_611/LeetCode_26_611.java b/Week 01/id_611/LeetCode_26_611.java new file mode 100644 index 000000000..fed6bbaf8 --- /dev/null +++ b/Week 01/id_611/LeetCode_26_611.java @@ -0,0 +1,18 @@ +class Solution { + //双指针解法 + public int removeDuplicates(int[] nums) { + if(nums.length == 0){ + return 0; + } + int j = 0; + for(int i = 0; i < nums.length; i++){ + //判断是否为重复,往前移动 + if(nums[i] != nums[j]){ + j++; + nums[j] = nums[i]; + } + } + //从零开始+1 + return j+1; + } +} \ No newline at end of file diff --git a/Week 01/id_616/LeetCode_189_616.cpp b/Week 01/id_616/LeetCode_189_616.cpp new file mode 100644 index 000000000..3ddcb61cf --- /dev/null +++ b/Week 01/id_616/LeetCode_189_616.cpp @@ -0,0 +1,13 @@ +class Solution { +public: + void rotate(vector& nums, int k) { + if(k == 0) return; + k %= nums.size(); + + std::reverse(std::begin(nums), std::end(nums)); + std::reverse(std::begin(nums), std::begin(nums)+k); + std::reverse(std::begin(nums)+k, std::end(nums)); + + return; + } +}; \ No newline at end of file diff --git a/Week 01/id_616/LeetCode_1_616.cpp b/Week 01/id_616/LeetCode_1_616.cpp new file mode 100644 index 000000000..3f54d01eb --- /dev/null +++ b/Week 01/id_616/LeetCode_1_616.cpp @@ -0,0 +1,18 @@ +class Solution { +public: + vector twoSum(vector& nums, int target) { + std::map m; + vector res; + for(int i=0;isecond); + res.push_back(i); + return res; + }else{ + m.emplace(target - nums[i],i); + } + } + return res; + } +}; \ No newline at end of file diff --git a/Week 01/id_616/LeetCode_21_616.cpp b/Week 01/id_616/LeetCode_21_616.cpp new file mode 100644 index 000000000..45a8be45e --- /dev/null +++ b/Week 01/id_616/LeetCode_21_616.cpp @@ -0,0 +1,33 @@ +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode(int x) : val(x), next(NULL) {} + * }; + */ +class Solution { +public: + ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) { + if(l1 == nullptr) return l2; + if(l2 == nullptr) return l1; + + ListNode pre_head = ListNode(-1); + + ListNode* cur = &pre_head; + while(l1 != nullptr && l2 != nullptr){ + if(l1->val <= l2->val){ + cur->next = l1; + l1 = l1->next; + }else{ + cur->next = l2; + l2 = l2->next; + } + cur = cur->next; + } + + cur->next = l1 == nullptr ? l2 : l1; + + return pre_head.next; + } +}; \ No newline at end of file diff --git a/Week 01/id_616/LeetCode_22_616.cpp b/Week 01/id_616/LeetCode_22_616.cpp new file mode 100644 index 000000000..5ded5f071 --- /dev/null +++ b/Week 01/id_616/LeetCode_22_616.cpp @@ -0,0 +1,22 @@ +class Solution { +public: + void merge(vector& nums1, int m, vector& nums2, int n) { + int cur = m + n - 1; + m--; + n--; + while(m >= 0 && n >= 0){ + if(nums1[m] >= nums2[n]){ + nums1[cur] = nums1[m--]; + }else{ + nums1[cur] = nums2[n--]; + } + cur--; + } + + if(m < 0){ + while(cur >= 0){ + nums1[cur--] = nums2[n--]; + } + } + } +}; \ No newline at end of file diff --git a/Week 01/id_616/LeetCode_26_616.cpp b/Week 01/id_616/LeetCode_26_616.cpp new file mode 100644 index 000000000..be5874892 --- /dev/null +++ b/Week 01/id_616/LeetCode_26_616.cpp @@ -0,0 +1,17 @@ +class Solution { +public: + int removeDuplicates(vector& nums) { + if(nums.size() < 2) return nums.size(); + + int len = 0; + int j = 0; + for(int i = 1; i < nums.size(); ++i){ + if(nums[j] != nums[i]){ + nums[++j] = nums[i]; + } + } + len = j+1; + nums.resize(len); + return len; + } +}; \ No newline at end of file diff --git a/Week 01/id_616/LeetCode_283_616.cpp b/Week 01/id_616/LeetCode_283_616.cpp new file mode 100644 index 000000000..3d338181e --- /dev/null +++ b/Week 01/id_616/LeetCode_283_616.cpp @@ -0,0 +1,14 @@ +class Solution { +public: + void moveZeroes(vector& nums) { + int j = 0; + for(int i = 0; i < nums.size(); ++i){ + if(nums[i] != 0){ + nums[j++] = nums[i]; + } + } + for(;j plusOne(vector& digits) { + int flag = 0; + for(int i = 0; i < digits.size(); ++i){ + if(digits[i] != 9) { + flag = 1; + break; + } + } + if(flag){ + for(int i = digits.size() -1; i >= 0; --i){ + digits[i] += 1; + if(digits[i] == 10){ + digits[i] = 0; + } else { + break; + } + } + }else{ + digits[0] = 1; + for(int i = 1; i < digits.size(); ++i){ + digits[i] = 0; + } + digits.push_back(0); + } + return digits; + } +}; \ No newline at end of file diff --git a/Week 01/id_616/NOTE.md b/Week 01/id_616/NOTE.md index a6321d6e2..f15a06252 100644 --- a/Week 01/id_616/NOTE.md +++ b/Week 01/id_616/NOTE.md @@ -1,4 +1,61 @@ -# NOTE +# 学习总结 - +## 数组、链表、跳表、栈 +### 数组 Array + +在内存中开辟了连续的地址存储数据 +时间复杂度 prepend O(1) append O(1) lookup O(1) insert O(n) delete O(n) + +### 链表 Linked list + +链表不需要连续的内存空间,通过指针将零散的内存块串联起来使用​ +时间复杂度 prepend O(1) append O(1) lookup O(n) insert O(1) delete O(1) + +常见的链表结构 +单链表 +双向链表 +循环链表 +常见的缓存策略 +先进先出 FIFO(First In, First out) +最少使用 LFU(Least Frequently Used) +最近最少使用 LRU(Least Recently Used) + +### 跳表 Skip list + +升维思想,空间换时间 +把链表变成二维空间,使用了更多的索引节点 +跳表的时间复杂度与红黑树一致,但是实现起来更简单 +在并发环境下跳表有另一个优势,红黑树在插入和删除的时候可能需要做 rebalance 操作,可能会涉及到整个树的其他部分,而跳表的操作更局部一些,锁住的节点更少,这样性能会更好一些 + +## 队列、双端队列、优先队列 + +### 栈 Stack + +从栈的操作特性上来看,栈是一种“操作受限”的线性表,只允许再一端插入和删除数据。栈主要包含连个操作,入栈和出站,也就是在栈顶插入一个数据和从栈顶删除一个数据 +先进后出,后进先出 +栈的实现 +用链表实现的栈,叫链式栈 +用数组实现的栈,叫顺序栈 +时间复杂度 access O(n) search O(n) insert O(1) delete O(1) + +### 队列 Queue + +先进先出,后进后出 +时间复杂度 search O(n) access O(n) insertion O(1) deletion O(1) + +### 双端队列 Deque: Double-End Queue + +双端队列可以在队首添加/删除元素,也可以在队尾添加/删除元素在实际应用中,一般使用双端队列替代普通队列​ +Queue 和 Stack 的结合体 +时间复杂度 access O(n) search O(n) insertion O(1) deletion O(1) + +### 优先队列 PriorityQueue + +时间复杂度 insert O(1) pop O(logN) + +## 心得 + +1. 在做题之前仔细读题非常重要,先搞清楚题目的意思,免得写了半天代码才发现起点就错了。 +2. 先在草稿纸上画下最简单情况的图解,很有助于找出重复部分。 +3. 添加辅助指针真的是个非常有用的方法。 diff --git a/Week 01/id_636/LeetCode_1_636.go b/Week 01/id_636/LeetCode_1_636.go new file mode 100644 index 000000000..56cf6ac51 --- /dev/null +++ b/Week 01/id_636/LeetCode_1_636.go @@ -0,0 +1,35 @@ +package id_636 + +/* + 从列表中筛选出两个数字,使得相加等于 Target, + 如果能找到则返回数字的下标 ,找不到则返回空。 + 两种办法: + 1:暴力破解,时间复杂度 O(n^2) + 2:使用 map 方法,可以记录已经遍历的数字,一次遍历即可 +*/ + +// 省略暴力方法的代码,直接用第二种 +func twoSum(nums []int, target int) []int { + // 略过判断数组长度的部分, 呃,还是写上吧 + if len(nums) < 2 { + return []int{} + } + + // 记录已经存在 + exist := make(map[int]int) + + // 循环遍历数组 + for i := 0; i < len(nums); i++ { + // index & value + value := nums[i] + index := i + + // check + possibleNum := target - value + if key, ok := exist[possibleNum]; ok { + return []int{key, index} + } + exist[value] = index + } + return []int{} +} \ No newline at end of file diff --git a/Week 01/id_636/LeetCode_1_636.py b/Week 01/id_636/LeetCode_1_636.py new file mode 100644 index 000000000..34beb985d --- /dev/null +++ b/Week 01/id_636/LeetCode_1_636.py @@ -0,0 +1,29 @@ +class Solution: + def twoSum(self, nums: list, target: int) -> list: + # check exist + exist = dict() + res = [] + # for one loops + for index in range(len(nums)): + # store current value + value = nums[index] + # check two numbers whether exist + if (target - value) in exist: + if index == exist.get(target-value): + continue + return [exist.get(target-value), index] + exist.update({ + value: index + }) + # not exist + return [] + +if __name__ == '__main__': + ''' + For test. + 仅返回头一个遇到的结果。 + ''' + s = Solution() + nums = [0, 1, 2, 3, 5, 8] + target = 6 + print("res: ", s.twoSum(nums, target)) diff --git a/Week 01/id_636/LeetCode_26_636.py b/Week 01/id_636/LeetCode_26_636.py new file mode 100644 index 000000000..03111f869 --- /dev/null +++ b/Week 01/id_636/LeetCode_26_636.py @@ -0,0 +1,31 @@ +class Solution: + def removeDuplicates(self, nums: list) -> (int, list): + # check length + if len(nums) <= 1: + return len(nums), nums + + # init len + arrayLen = 0 + # cur, next = 0, 0 + cur = 0 + # for loop + while True: + # get value + value = nums[cur] + + if cur + 1 < len(nums) and value == nums[cur + 1]: + del nums[cur + 1] + continue + + cur += 1 + if cur == len(nums): + break + + return len(nums), nums + +if __name__ == '__main__': + s = Solution() + nums = [0,0,1,1,1,2,2,3,3,4,4,5,6,7,8,8,9,9,9,9,9,9,9,9,9] + arrayLen, nums = s.removeDuplicates(nums) + print("After: ", nums) + print("Len: ", arrayLen) \ No newline at end of file diff --git a/Week 01/id_636/NOTE.md b/Week 01/id_636/NOTE.md index a6321d6e2..67505e401 100644 --- a/Week 01/id_636/NOTE.md +++ b/Week 01/id_636/NOTE.md @@ -1,4 +1,105 @@ + + # NOTE - +## 数组 + +* 支持 O(1) 的随机访问 +* 连续的一段内存空间 +* 平均为 O(n) 的插入、删除 +* 警惕越界错误,防止 Panic + +--- + +##链表 + +#### 单链表 + +* 不支持随机访问,需要遍历去访问节点 + +* 插入删除:移动指针,O(1) + +* 每个节点需要单独存储指针,比数组消耗大 + +#### 双链表 + +* 单节点基础上,增加前驱节点的内存地址 + +#### 循环链表 + +* 尾节点指向头节点 + +#### 静态链表 + +* 依托数组,伴随指向后继节点的指针 + +### 链表的优缺点 + +* 灵活地分配内存空间 +* 单链表 - 能在 O(1) 时间内添加或删除 element(元素已知) +* 双链表 - 如果后一个元素已知,也可在 O(1) 时间内添加或删除 +* 不能在 O(1) 时间内读取一个元素,从头开始 +* 读取第 K 个元素,需要 O(k) 的时间 + +--- + +## 栈 + +* 顺序和链式都可以实现,先进后出 + +#### 实际应用 + +* 浏览器的前进、后退 +* 括号匹配 +* 表达式计算 + +--- + +## 队列 + +#### 普通队列 + +* 顺序、链式都可实现:先进先出 + +* 实现:双链表 + +* 在O(1)时间内对头完成查看、删除,队尾实现查看、添加 + +#### 双边队列 + +* 入口、出口都可实现:进队、出队 + +* 实现:双链表 + +* 可以在O(1) 的时间内完成查看、添加、删除首尾两端数据 + +#### 优先级队列 +* 根据优先级出队 +* 实际应用 +* LRU Cache + +--- + +## 源码阅读 + +### Deque + +```go +type Deque struct { + maxLen int + blocks list.List + frontIdx, backIdx int + len int +} + +maxLen:最大长度 +blocks:链表数据 +frontIdx:头部 +backIdx:尾部 +len:长度 +``` + + + +#待更新 :) diff --git a/Week 01/id_641/Leetcode26.java b/Week 01/id_641/Leetcode26.java new file mode 100644 index 000000000..1b4f079bc --- /dev/null +++ b/Week 01/id_641/Leetcode26.java @@ -0,0 +1,90 @@ +package vip.ruoyun; + +import java.util.ArrayList; +import java.util.List; + +//26 +public class Leetcode26 { + + public static void main(String[] args) { + List integerList = new ArrayList<>(); + integerList.add(1); + integerList.add(1); + integerList.add(2); + Solution solution = new Solution(); +// solution.removeDuplicates(integerList); + + int[] nums = {0, 0, 1, 1, 1, 2, 2, 3, 3, 4}; + int length = solution.removeDuplicates(nums); + + for (int i = 0; i < length; i++) { + System.out.println(nums[i]); + } + + } +} + + +class Solution { + public int removeDuplicates(List nums) { + //返回值为长度 + //额外空间 O(1) + //1.遍历数组 + int num; + for (int i = 0; i < nums.size(); i++) { + //暴力,保存 每一份,然后遍历 删除 + System.out.println(nums.get(i)); + num = nums.get(i); + for (int j = i + 1; j < nums.size(); j++) { + System.out.println(nums.get(j)); + if (num == nums.get(j)) { + //删除多余的元素 + nums.remove(j); + } + } + } + System.out.println(nums.toString()); + return nums.size(); + } + + public int removeDuplicates(int[] nums) { + if (nums.length == 0) return 0; + int i = 0; + for (int j = 1; j < nums.length; j++) { + if (nums[j] != nums[i]) { + if (j - i > 0) {//优化 + i++; + nums[i] = nums[j]; + } + } + } + return i + 1; + } + + public int removeDuplicates2(int[] nums) { + if (nums.length == 0) return 0; + int i = 0; + int j = 1; + while (j < nums.length) { + if (nums[j] != nums[i]) { + if (j - i > 0) {//优化 + i++; + nums[i] = nums[j]; + } + } + j++; + } + return i + 1; + } + + +} + +//遇到问题 +//1.怎么删除 int[] 中的元素,所以使用了 java 中的 list +//2.如果不经过 2 重循环的话,怎么找到重复元素 +//3.题目给出 是排好序的数组,所以在查找重复元素的时候,只要找前一个和后一个数的值 是否相等,就可以判断是否重复 + +// +//java 中的标记清除算法,可以减少删除元素后,数组移动的次数,来达到优化的效果 +//O(n) 复杂度 \ No newline at end of file diff --git a/Week 01/id_641/Leetcode42.java b/Week 01/id_641/Leetcode42.java new file mode 100644 index 000000000..cc127d671 --- /dev/null +++ b/Week 01/id_641/Leetcode42.java @@ -0,0 +1,69 @@ +package vip.ruoyun; + +public class Leetcode42 { + public static int trap(int[] height) { + if (height.length < 2) return 0; + + int area = 0; + int tempArea = 0; + int pos = 0;//位置 高度 + int hei = 0; + + int maxPos = 0; + int temMax = height[0]; + //找到最大值 + for (int i = 1; i < height.length; i++) { + if (height[i] > temMax) { + temMax = height[i]; + maxPos = i; + } + } + + //然后找到面积 + for (int i = 0; i < maxPos; i++) { + //找到第一个值 + if (pos == 0 && height[i] > 0) { + pos = i; + hei = height[i]; + continue; + } + if (height[i] < hei) { + tempArea += hei - height[i]; + } else { + //找到面积 + area += tempArea; + tempArea = 0; + pos = i; + hei = height[i]; + } + } + + pos = 0;//位置 高度 + hei = 0; + for (int i = height.length - 1; i > maxPos; i--) { + //找到第一个值 + if (pos == 0 && height[i] > 0) { + pos = i; + hei = height[i]; + continue; + } + if (height[i] < hei) { + tempArea += hei - height[i]; + } else { + //找到面积 + area += tempArea; + tempArea = 0; + pos = i; + hei = height[i]; + } + } + return area; + } + + //思路不好找 + public static void main(String[] args) { + int[] height = {0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1}; + System.out.println(trap(height)); + } + +} diff --git a/Week 01/id_641/Leetcode641.java b/Week 01/id_641/Leetcode641.java new file mode 100644 index 000000000..95542bfb2 --- /dev/null +++ b/Week 01/id_641/Leetcode641.java @@ -0,0 +1,121 @@ +package vip.ruoyun; + +public class Leetcode641 { + + private int[] deque; + private int head;//指针 + private int tail;//尾指针 + private int maxSize;//最大值 + private int count;//当前的容量 + + public Leetcode641(int k) { + count = 0; + maxSize = k; + deque = new int[k]; + head = 0; + tail = 0; + } + + //将一个元素添加到双端队列头部。 如果操作成功返回 true。 + public boolean insertFront(int value) { + if (count >= maxSize) { + return false; + } + //添加 + deque[head] = value; + head = maxSize - 1 - head; + count++; + return true; + } + + //将一个元素添加到双端队列尾部。如果操作成功返回 true。 + public boolean insertLast(int value) { + if (count >= maxSize) { + return false; + } + //添加 + tail = (tail + 1) % maxSize; + deque[tail] = value; + count++; + return true; + } + + //从双端队列头部删除一个元素。 如果操作成功返回 true + public boolean deleteFront() { + if (count == 0) { + return false; + } + head = (head + 1) % maxSize; + count--; + 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; + } + tail = (tail - 1); + if (tail < 0) { + tail = tail + maxSize; + } + count--; + return true; + } + + public int getFront() { + if (count == 0) { + return -1; + } + return deque[head]; + } + + /** + * Get the last item from the deque. + */ + public int getRear() { + if (count == 0) { + return -1; + } + return deque[tail]; + } + + /** + * Checks whether the circular deque is empty or not. + */ + public boolean isEmpty() { + if (count == 0) { + return true; + } + return false; + } + + /** + * Checks whether the circular deque is full or not. + */ + public boolean isFull() { + if (count == maxSize) { + return true; + } + return false; + } + + public static void main(String[] args) { + Leetcode641 circularDeque = new Leetcode641(3); // 设置容量大小为3 + circularDeque.insertLast(1); // 返回 true + circularDeque.insertLast(2); // 返回 true + circularDeque.insertLast(2); // 返回 true + circularDeque.insertLast(2); // 返回 true +// circularDeque.insertFront(3); // 返回 true +// circularDeque.insertFront(4); // 已经满了,返回 false +// circularDeque.getRear(); // 返回 2 +// circularDeque.isFull(); // 返回 true +// circularDeque.deleteLast(); // 返回 true +// circularDeque.insertFront(4); // 返回 true +// circularDeque.getFront(); + } +} + +//卡在一个问题中: \ No newline at end of file diff --git a/Week 01/id_641/leetcode189.java b/Week 01/id_641/leetcode189.java new file mode 100644 index 000000000..5f2e77e40 --- /dev/null +++ b/Week 01/id_641/leetcode189.java @@ -0,0 +1,57 @@ +package vip.ruoyun; + +import java.util.Arrays; + +public class leetcode189 { + + //空间复杂度 O(k) k nums.length) { + k = k - nums.length;// + } else if (k == nums.length) { + return; + } + //[ length-2 ,length] ,[0, length-3] + int[] temp = new int[k]; + System.arraycopy(nums, nums.length - k, temp, 0, k);//把后面的拷贝到 临时的内存空间中 + System.arraycopy(nums, 0, nums, k, nums.length - k);//把数组中的 前面的元素,拷贝到 移动后的位置中 + System.arraycopy(temp, 0, nums, 0, temp.length);//把临时数组中的内容拷贝到 前面的位置 + System.out.println(Arrays.toString(nums)); + } + + + //使用环状替换,空间复杂度 O(n) + public static void rotate2(int[] nums, int k) { + if (nums.length == 0 || k == nums.length) { + return; + } + int[] newNums = new int[nums.length]; + for (int i = 0; i < nums.length; i++) { + newNums[(k + i) % nums.length] = nums[i]; + } + System.out.println(Arrays.toString(newNums)); + } + + //使用环状替换,空间复杂度 O(1),写法暂时没有思考出来 + public static void rotate3(int[] nums, int k) { + if (nums.length == 0 || k == nums.length) { + return; + } + k = k % nums.length; + int temp; + for (int i = 0; i < k; i++) { +// for (int j = 0;i a - b); + for (let i = 0, j = nums.length - 1; i < nums.length - 1;) { + if (i >= j) break; + if (nums[i] + nums[j] > target) { + --j; + } else if (nums[i] + nums[j] < target) { + ++i; + } else { + newNums.forEach((value, index) => { + if ([nums[i], nums[j]].includes(value)) { + indexArr = indexArr.concat([index]); + } + }); + break; + } + } + return indexArr; +}; +``` + +### hash数据结构方法: +```javascript +var twoSum = function (nums, target) { + let map = new Map(); + for (let i = 0; i < nums.length ; i++) { + if (map.has(target - nums[i])) { + return [map.get(target - nums[i]), i] + } else { + map.set(nums[i], i); + } + } +}; +``` \ No newline at end of file diff --git "a/Week 01/id_646/\347\256\227\346\263\225\351\242\230--\345\212\240\344\270\200.md" "b/Week 01/id_646/\347\256\227\346\263\225\351\242\230--\345\212\240\344\270\200.md" new file mode 100644 index 000000000..c9daaf2c2 --- /dev/null +++ "b/Week 01/id_646/\347\256\227\346\263\225\351\242\230--\345\212\240\344\270\200.md" @@ -0,0 +1,50 @@ +[加1](https://leetcode-cn.com/problems/plus-one/) + + +/** + * @param {number[]} digits + * @return {number[]} + */ +- 不可行的第一印象的方法:首先数组[1,2,3]join为string'123'然后转换为number123,加一之后,再转为string,再通过splite转为数组,此方法因为js数字边界的问题无法使用 +```javascript +var plusOne = function (digits) { + let stringDigits = digits.join(''); + let numberDigits = +stringDigits; + let stringPlusOneNumberDigits = '' + (numberDigits + 1); + let newDigits = stringPlusOneNumberDigits.split(''); + return newDigits; +}; +``` +- 2,方法:从后往前遍历真个数组,最后一位加1,如果=10,下一位加一,以此类推,直到不等于十直接break, 方法中的边界问题:最左边的数字是9的情况没有考虑到导致提交的两次才成功 +#### 第一次提交的解法: +```javascript +var plusOne = function (digits) { + for (let i = digits.length - 1; i >= 0; --i) { + const plusOneItem = digits[i] + 1; + if (plusOneItem === 10) { + digits[i] = 0; + if (i === 0) { + digits.unshift(1); + } + continue; + } else { + digits[i] = plusOneItem; + break; + } + } + return digits; +}; +``` +- 看了别人的代码后:1,取余操作,2,如果未到零,数字加一没到十就不用进一位直接返回,否则就需要需要在数组顶部加一位1 +#### 优化后的解法: +```javascript +var plusOne = function (digits) { + for (let i = digits.length - 1; i >= 0; --i) { + digits[i]++; + digits[i] = digits[i] % 10; + if (digits[i] !== 0) return digits; + } + digits.unshift(1); + return digits; +}; +``` \ No newline at end of file diff --git a/Week 01/id_651/LeetCode_42_651.cpp b/Week 01/id_651/LeetCode_42_651.cpp new file mode 100644 index 000000000..c31296ddc --- /dev/null +++ b/Week 01/id_651/LeetCode_42_651.cpp @@ -0,0 +1,63 @@ +/* + 思路 + 1. 暴力求解1:按列计算盛水量, 定住一个柱体,然后用遍历左右两边的柱体,找到左右的最高高度。 + 再获取这个最高高度与当前柱体的高度差,依次遍历完所有柱体即可获得所有的水量. + (第一个以及最后一个不需要,因为只有一个右/左柱体) + 2. 头尾双指针移动逼近, 计算当前柱体的高度与头指针,尾指针所在位置高度的大小关系。 移动指针,最后计算出水量 + +*/ +# include +# include +# include +using namespace std; + +int trap(vector & height){ + int ans = 0; + int size = height.size(); + for (int i = 1; i < size - 1;i++){ + int max_left = 0, max_right = 0; + for (int j = i; j >= 0; j--) + max_left = max(max_left, height[j]); + for (int j = i; j < size; j++) + max_right = max(max_right, height[j]); + ans += min(max_left, max_right) - height[i]; + } + return ans; +}; + +int trap_pointer(vector & height){ + int water = 0; + int left = 0, right = 0; + int first = 0, last = height.size() - 1; + while(first < last){ + if (height[first] < height[last]){ + height[first] >= left ? (left = height[first]) : water += (left - height[first]); + ++first; + } + else{ + height[last] >= right ? (right = height[last]) : water += (right - height[last]); + --last; + } + cout << water << endl; + } + return water; +}; + +int main(){ + vector height; + height.push_back(0); + height.push_back(1); + height.push_back(0); + height.push_back(2); + height.push_back(1); + height.push_back(0); + height.push_back(1); + height.push_back(3); + height.push_back(2); + height.push_back(1); + height.push_back(2); + height.push_back(1); + cout << trap_pointer(height) << endl; + Sleep(10000); + return 0; +} \ No newline at end of file diff --git a/Week 01/id_651/LeetCode_641_651.cpp b/Week 01/id_651/LeetCode_641_651.cpp new file mode 100644 index 000000000..64ec32ad4 --- /dev/null +++ b/Week 01/id_651/LeetCode_641_651.cpp @@ -0,0 +1,83 @@ +/* + 思路 + 1. 循环数组。 通过移动索引的方式处理。 + 新增头,则赋值给头索引位置的值,索引相应的减1并跑多一圈,对结果求余,得到新头索引 + 新增尾,则复制给尾索引位置的值,索引相应的加1,对结果求余,得到新尾索引 + 删除头,(将头指针指向下一个)头索引相应的加1,对结果求余,得到新头索引 + 删除尾,(将尾指针指向上一个)尾索引相应的减1,并跑多一圈,对结果求余,得到新为尾索引。 + 结论: + 相对于思路1, 思路2的代码更简单清晰, 可以少很多的判断条件。 + 1. 指针的初始值也很重要 + 2. 与环形链表的题类似, 在那个基础上加了增删查的操作 +*/ +# include +# include +# include +using namespace std; + +class MyCircularDeque { + private: + vector buffer; + int count; + int msize; + int first; + int last; +public: + MyCircularDeque(int k) { + // 初始化值 + buffer.assign(k, 0); + msize = k, count = 0, last = 0, first = msize - 1; + } + + bool insertFront(int value) { + if (count == msize) return false; + buffer[first] = value; + first = (first - 1 + msize) % msize; + ++count; + return true; + } + + bool insertLast(int value) { + if (count == msize) return false; + buffer[last] = value; + last = (last + 1) % msize; + ++count; + return true; + } + + bool deleteFront() { + if (isEmpty()) return false; + first = (first + 1) % msize; + --count; + return true; + } + + bool deleteLast() { + if (isEmpty()) return false; + last = (last - 1 + msize) % msize; + --count; + return true; + } + + int getFront() { + return isEmpty() ? -1 : buffer[(first + 1) % msize]; + } + + int getRear() { + return isEmpty() ? -1 : buffer[(last - 1 + msize) % msize]; + } + + bool isEmpty() { + return count == 0; + } + + bool isFull() { + return count == msize; + } +}; + + +int main(){ + MyCircularDeque mq(3); + return 0; +} \ No newline at end of file diff --git a/Week 01/id_651/NOTE.md b/Week 01/id_651/NOTE.md index a6321d6e2..86d7e89b6 100644 --- a/Week 01/id_651/NOTE.md +++ b/Week 01/id_651/NOTE.md @@ -1,4 +1,74 @@ # NOTE +第一周总结: - +1. 顺序表 : 查, 不利于增删改(因为需要遍历之后, 再进行crud操作,还需要对后续的数据进行位移) + 链表 : 增删改,不利于查找(只能遍历链表,一个一个的找,O(n)) + 例题总结: + 1.1 移动零 + -> 新建数组,将非0元素插入既可/可以通过辅助索引来交换非0值的位置,最后补0。 + + 1.2 盛水最多的容器 + -> 两层遍历,最后获取最大值/双指针, 两两夹逼, 求最大面积 + + 1.3 爬楼梯 + -> 需要找出重复性的点, 通过规律看,可用递归或者循环的方式 + + 1.4 三数之和 + -> 固定一个位置, 然后在后续的空间中使用双指针, 两两夹逼. + ( 需要注意值相等的情况要跳过即可 ) + + 1.5 环形链表 + -> 双指针/快慢指针。 如果是循环的链表, 则一定会有出现重复的地方。 + (判断是否环形 / 判断环形的起点) + + +2. 队列: 先进先出(FIFO) + 栈 : 先进后出(FILO) + + 例题总结: + 2.1 有小括号 + -> 利用栈的FILO的特性, 遍历字符组, 每次将字符的对称字符压栈, + 直到出现对称字符的时候,和栈顶元素作对比 + 2.2 最小栈 + -> 利用辅助栈, 辅助栈用来存储最小值(保持最小值在栈顶) + 如果主栈pop的值为最小值, 则辅助栈要弹出栈顶元素 + 2.3 滑动窗口最大值 + -> 暴力解法,2层遍历获取最大值 + -> 双端队列 *** 暂时没理解的解法 + 个人理解: 主要是在比较相邻的两个数的大小,然后通过索引的移动,继续进行比较。 + 如果当前索引超过长度k的大小范围,则弹出前面的元素。 + 如果当前元素大于队列的最后一个元素,则弹出最后一个元素。 + 在每次判断完之后,判断当前索引是否大于长度k-1,是则插入结果列表。 + -> 集合,利用集合排序的特性, 每次遍历n个值,就弹出最后一个最大的值,并找到当前n+1减去k的位置的元素并删除 + + + 2.4 柱状图中最大的矩形 + -> 暴力解法1,两层遍历, 固定一点,遍历剩余的部分,找出最小高度, 获取面积最大值。 + -> 利用栈, 遍历柱体 (存储索引值) + 使 -1 作为栈的初始栈顶, 便于计算面积, 即使是相等, 也不会出现距离为0的情况 + 2.4.1 判断待入栈的柱体的高度, 是否大于栈顶的高度。 + 2.4.2 如果大于, 则入栈。 反之,则处理该元素,算出面积,继续判断栈顶元素的大小。 + 直到栈顶元素为-1或者栈顶元素小于待入栈元素 + 2.4.3 最后还需要清空栈, 继续计算最大的面积。直到栈顶为-1 + +3. 课后作业: + 3.1 循环数组的设计 + -> 毫无思路, 直接看题解, 看到仍然是双指针,又类似双端队列。 + -> 头尾指针的移动, 前移则仅需加1再求余, 后移除了减1还需要加上数组长度再求余(才可以真正的回到下一个位置) + -> 还需要考虑一下边界的问题, 头指针的位置指向以及尾指针的位置指向。 + (在图例上来看, 头尾指针的位置一直是对称,不重和的) + + 3.2 求盛水量 + -> 暴力解法也是用的类似双指针的解法, 只是用的for循环 + -> 双指针解法, 通过头尾指针, 向中间靠拢, 同时比较左右的最大高度, + 求出指针与最大高度的最小值,使之和指针指向的柱体高度做减法获取到盛水量。 + +4. 总结: + 虽然大多数的题都是略微思考下, 就看题解, 然后手写, 默写, 靠记忆盲敲, 第二天再敲一遍,还是能发现一些小缺漏 + 接触了一些之前没看过没了解过的知识点,有一些则是知道特性, 却没有实际应用。 + 看到题解之后,确实有一种很微妙的感觉, 解法很巧妙。 + 第一周的课程收获就蛮多的 + 一是移动指针, 双指针等。 个人认为是索引/下标的一种高级用法。 + 二是栈和队列的运用,虽然做的题还不是很熟练, 但是觉得解题的过程开始变得有趣起来. + 三是会开始注意到边界条件, 一些空的或者越区的经常会漏掉。 \ No newline at end of file diff --git a/Week 01/id_666/LeetCode_26_666.java b/Week 01/id_666/LeetCode_26_666.java new file mode 100644 index 000000000..93dbef907 --- /dev/null +++ b/Week 01/id_666/LeetCode_26_666.java @@ -0,0 +1,33 @@ +/** + * 给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。 + * + * 不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。 + * + * 来源:力扣(LeetCode) + * 链接:https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array + * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + */ +class Solution { + public int removeDuplicates(int[] nums) { + + int p = 0; + int q = 1; + + while(q < nums.length) { + if(nums.length == 2) { + if (nums[p] != nums[q]) { + return q+1; + } else { + return p+1; + } + } + if(nums[p] != nums[q]) { + nums[p+1] = nums[q]; + p++; + } + q++; + } + + return p + 1; + } +} \ No newline at end of file diff --git a/Week 01/id_666/LeetCode_88_666.java b/Week 01/id_666/LeetCode_88_666.java new file mode 100644 index 000000000..556bdbbdf --- /dev/null +++ b/Week 01/id_666/LeetCode_88_666.java @@ -0,0 +1,22 @@ +/** + 给定两个有序整数数组 nums1 和 nums2,将 nums2 合并到 nums1 中,使得 num1 成为一个有序数组。 + + 说明: + + 初始化 nums1 和 nums2 的元素数量分别为 m 和 n。 + 你可以假设 nums1 有足够的空间(空间大小大于或等于 m + n)来保存 nums2 中的元素。 + **/ +class Solution { + public void merge(int[] nums1, int m, int[] nums2, int n) { + + int len1 = m - 1; + int len2 = n - 1; + + int len = m + n - 1; + + while(len1 >= 0 && len2 >= 0) { + nums1[len--] = nums1[len1] > nums2[len2] ? nums1[len1--] : nums2[len2--]; + } + System.arraycopy(nums2, 0, nums1, 0, len2 + 1); + } +} diff --git a/Week 01/id_681/.gitignore b/Week 01/id_681/.gitignore new file mode 100644 index 000000000..723ef36f4 --- /dev/null +++ b/Week 01/id_681/.gitignore @@ -0,0 +1 @@ +.idea \ No newline at end of file diff --git a/Week 01/id_681/LeetCode_189_681.java b/Week 01/id_681/LeetCode_189_681.java new file mode 100644 index 000000000..4b4687e81 --- /dev/null +++ b/Week 01/id_681/LeetCode_189_681.java @@ -0,0 +1,13 @@ +class Solution { + public void rotate(int[] nums, int k) { + int temp, previous; + for (int i = 0; i < k; i++) { + previous = nums[nums.length - 1]; + for (int j = 0; j < nums.length; j++) { + temp = nums[j]; + nums[j] = previous; + previous = temp; + } + } + } +} diff --git a/Week 01/id_681/LeetCode_1_681.java b/Week 01/id_681/LeetCode_1_681.java new file mode 100644 index 000000000..3ca710531 --- /dev/null +++ b/Week 01/id_681/LeetCode_1_681.java @@ -0,0 +1,12 @@ +class Solution { + public int[] twoSum(int[] nums, int target) { + for (int i = 0; i < nums.length; i++) { + for (int j = i + 1; j < nums.length; j++) { + if (nums[j] == target - nums[i]) { + return new int[]{i, j}; + } + } + } + return null; + } +} \ No newline at end of file diff --git a/Week 01/id_681/LeetCode_21_681.java b/Week 01/id_681/LeetCode_21_681.java new file mode 100644 index 000000000..7edfccc97 --- /dev/null +++ b/Week 01/id_681/LeetCode_21_681.java @@ -0,0 +1,15 @@ +class Solution { + public ListNode mergeTwoLists(ListNode l1, ListNode l2) { + if (l1 == null) { + return l2; + } else if (l2 == null) { + return l1; + } else if (l1.val < l2.val) { + l1.next = mergeTwoLists(l1.next, l2); + return l1; + } else { + l2.next = mergeTwoLists(l1, l2.next); + return l2; + } + } +} diff --git a/Week 01/id_681/LeetCode_26_681.java b/Week 01/id_681/LeetCode_26_681.java new file mode 100644 index 000000000..d0f791c41 --- /dev/null +++ b/Week 01/id_681/LeetCode_26_681.java @@ -0,0 +1,15 @@ +class Solution { + public int removeDuplicates(int[] nums) { + if (nums.length == 0) { + return 0; + } + int i = 0; + for (int j = 1; j < nums.length; j++) { + if (nums[j] != nums[i]) { + i++; + nums[i] = nums[j]; + } + } + return i + 1; + } +} \ No newline at end of file diff --git a/Week 01/id_681/LeetCode_283_681.java b/Week 01/id_681/LeetCode_283_681.java new file mode 100644 index 000000000..2455260eb --- /dev/null +++ b/Week 01/id_681/LeetCode_283_681.java @@ -0,0 +1,15 @@ +class Solution { + public void moveZeroes(int[] nums) { + int count = 0; + for (int i = 0; i < nums.length; i++) { + if (nums[i] == 0) { + count++; + } else { + nums[i - count] = nums[i]; + } + } + for (int i = nums.length - count; i < nums.length; i++) { + nums[i] = 0; + } + } +} \ No newline at end of file diff --git a/Week 01/id_681/LeetCode_66_681.java b/Week 01/id_681/LeetCode_66_681.java new file mode 100644 index 000000000..6df75e1ce --- /dev/null +++ b/Week 01/id_681/LeetCode_66_681.java @@ -0,0 +1,14 @@ +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; + } + } + digits = new int[digits.length + 1]; + digits[0] = 1; + return digits; + } +} diff --git a/Week 01/id_681/LeetCode_88_681.java b/Week 01/id_681/LeetCode_88_681.java new file mode 100644 index 000000000..598394d80 --- /dev/null +++ b/Week 01/id_681/LeetCode_88_681.java @@ -0,0 +1,6 @@ +class Solution { + public void merge(int[] nums1, int m, int[] nums2, int n) { + System.arraycopy(nums2, 0, nums1, m, n); + Arrays.sort(nums1); + } +} diff --git a/Week 01/id_686/LeetCode_1_686.java b/Week 01/id_686/LeetCode_1_686.java new file mode 100644 index 000000000..39a947d73 --- /dev/null +++ b/Week 01/id_686/LeetCode_1_686.java @@ -0,0 +1,30 @@ +//给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。 +// +// 你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。 +// +// 示例: +// +// 给定 nums = [2, 7, 11, 15], target = 9 +// +//因为 nums[0] + nums[1] = 2 + 7 = 9 +//所以返回 [0, 1] +// +// Related Topics 数组 哈希表 + + + +//leetcode submit region begin(Prohibit modification and deletion) +class Solution { + public int[] twoSum(int[] nums, int target) { + Map map = new HashMap<>(); + for (int i = 0; i List[int]: + dict_1 = {} + for i,m in enumerate(nums): + n = target - m + if n in dict_1: + return [dict_1[n],i] + else: + dict_1[m] = i +# @lc code=end + diff --git a/Week 01/id_686/LeetCode_26_686.py b/Week 01/id_686/LeetCode_26_686.py new file mode 100644 index 000000000..a99af3c1f --- /dev/null +++ b/Week 01/id_686/LeetCode_26_686.py @@ -0,0 +1,20 @@ +# +# @lc app=leetcode.cn id=26 lang=python3 +# +# [26] 删除排序数组中的重复项 +# + +# @lc code=start +class Solution: + def removeDuplicates(self, nums: List[int]) -> int: + if not nums: + return 0 + i = 0 + for j in range(len(nums)): + if nums[j] != nums[i]: + i += 1 + nums[i] = nums[j] + return i+1 + +# @lc code=end + diff --git a/Week 01/id_686/LeetCode_641_686.java b/Week 01/id_686/LeetCode_641_686.java new file mode 100644 index 000000000..21ae272ab --- /dev/null +++ b/Week 01/id_686/LeetCode_641_686.java @@ -0,0 +1,130 @@ +//设计实现双端队列。 +//你的实现需要支持以下操作: +// +// +// MyCircularDeque(k):构造函数,双端队列的大小为k。 +// insertFront():将一个元素添加到双端队列头部。 如果操作成功返回 true。 +// insertLast():将一个元素添加到双端队列尾部。如果操作成功返回 true。 +// deleteFront():从双端队列头部删除一个元素。 如果操作成功返回 true。 +// deleteLast():从双端队列尾部删除一个元素。如果操作成功返回 true。 +// getFront():从双端队列头部获得一个元素。如果双端队列为空,返回 -1。 +// getRear():获得双端队列的最后一个元素。 如果双端队列为空,返回 -1。 +// isEmpty():检查双端队列是否为空。 +// isFull():检查双端队列是否满了。 +// +// +// 示例: +// +// MyCircularDeque circularDeque = new MycircularDeque(3); // 设置容量大小为3 +//circularDeque.insertLast(1); // 返回 true +//circularDeque.insertLast(2); // 返回 true +//circularDeque.insertFront(3); // 返回 true +//circularDeque.insertFront(4); // 已经满了,返回 false +//circularDeque.getRear(); // 返回 2 +//circularDeque.isFull(); // 返回 true +//circularDeque.deleteLast(); // 返回 true +//circularDeque.insertFront(4); // 返回 true +//circularDeque.getFront(); // 返回 4 +//  +// +// +// +// 提示: +// +// +// 所有值的范围为 [1, 1000] +// 操作次数的范围为 [1, 1000] +// 请不要使用内置的双端队列库。 +// +// Related Topics 设计 队列 + + + +//leetcode submit region begin(Prohibit modification and deletion) +class MyCircularDeque { + private int[] data; + private int head; + private int tail; + private int capacity; + + /** Initialize your data structure here. Set the size of the deque to be k. */ + public MyCircularDeque(int k) { + data = new int[k+1]; + capacity = k + 1; + } + + /** Adds an item at the front of Deque. Return true if the operation is successful. */ + public boolean insertFront(int value) { + if (isFull()) { + return false; + } + + data[head = ((head - 1 + capacity) % capacity)] = value; + return true; + } + + /** Adds an item at the rear of Deque. Return true if the operation is successful. */ + public boolean insertLast(int value) { + if (isFull()) { + return false; + } + + data[tail] = value; + tail = (tail + 1) % capacity; + return true; + } + + /** Deletes an item from the front of Deque. Return true if the operation is successful. */ + public boolean deleteFront() { + if (isEmpty()) { + return false; + } + + head = (head + 1) % capacity; + return true; + } + + /** Deletes an item from the rear of Deque. Return true if the operation is successful. */ + public boolean deleteLast() { + if (isEmpty()) { + return false; + } + + tail = (tail - 1 + capacity) % capacity; + return true; + } + + /** Get the front item from the deque. */ + public int getFront() { + return isEmpty() ? -1 : data[head]; + } + + /** Get the last item from the deque. */ + public int getRear() { + return isEmpty() ? -1 : data[(tail - 1 + capacity) % capacity]; + } + + /** Checks whether the circular deque is empty or not. */ + public boolean isEmpty() { + return head == tail; + } + + /** Checks whether the circular deque is full or not. */ + public boolean isFull() { + return (tail + 1) % capacity == head; + } +} + +/** + * 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(); + */ +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 01/id_701/NOTE.md b/Week 01/id_701/NOTE.md index a6321d6e2..613164fc1 100644 --- a/Week 01/id_701/NOTE.md +++ b/Week 01/id_701/NOTE.md @@ -1,4 +1,124 @@ -# NOTE +# 【701-week1】第一周学习总结 + +## 数组 + +特点: + +- 是一种线性数据结构,用连续的存储空间存储相同类型数据; +- 下标从 `0` 开始; +- 支持 `随机访问`,根据下标随机访问的时间复杂度为 O(1); +- 低效的 `插入` 和 `删除`; +- 警惕 `越界` 访问问题; +- 基于数组类型的 `容器类型` 支持动态扩容; + +复杂度分析: +- 时间复杂度:平均的时间复杂度为 O(n) + - prepend/append:O(1) + - lookup: 按下标访问是 O(1) + - insert:最好是 O(1),最坏是 O(n),平均是 O(n) + - delete:最好是 O(1),最坏是 O(n),平均是 O(n) +- 空间复杂度:O(1) + +## 链表 + +特点: + +- 常用于插入/删除操作较频繁的场景(空间换时间) +- 元素数量未知 +- 缓存机制 + +复杂度分析: + +- 时间复杂度 + - prpend:O(1) + - append:O(1) + - lookup:O(n) + - insert:O(1) + - delete:O(1) +- 空间复杂度:O(1) + +实现思路: + +- 理解指针或引用的含义 +- 警惕指针丢失和内存泄漏 +- 利用 `哨兵` 简化实现难度 +- 重点留意边界条件 +- 举例画图,辅助思考 +- 多写多练 + +常见操作: + +- 单链表反转 +- 链表中环的检测 +- 两个有序链表的合并 +- 删除链表倒数第 n 个结点 +- 求链表的中间结点 + +工程应用: + +- LRU Cache - Linked List +- Redis - Skip List + +### 单链表 + +### 双链表 + +### 循环链表 + +### 跳表 + +通过为链表添加 `有序索引` 的方式解决传统链表的 `低效查找问题`,以 `空间换时间` + +- 在跳表中查询任意数据的时间复杂度是 O(logn) +- 空间复杂度是 O(n) + + +## 总结 + +数组是一种简单的 `线性` 数据结构,在内存中是一段只能存储 `同种数据类型` 的 `连续的内存空间`。其原理和实现思路是通过提前开辟好一段合适大小的内存空间,方便数据 `按下标方式` 能够进行快速查找。为了解决数组低效的插入和删除操作,链表应运而生,其在内存中是 `非连续` 的,通过 `指针` 方式来进行 `动态扩容`,这样一来,和数组相比,对应的插入和删除操作就非常高效,只需要移动对应结点的指针指向即可。基于此种数据结构衍生的数据结构类型还有 `循环链表`、`双链表`、`调表`。其中跳表是为了解决传统链表结构中低效的查询操作,所以其对应的实现思路是通过在原始链表的基础上建立 `n 级有序索引` 的方式来进行快速查找,是一种 `以空间换时间` 的解决方法。 + +数组、链表、跳表的复杂度如下表所示: + +| | 时间复杂度 | 空间复杂度 | +| :----:| :----: | :----: | +| 数组 | 插入&删除 O(n); 查找 O(1) | O(1) | +| 链表 | 插入&删除 O(1); 查找 O(n) | O(1) | +| 跳表 | 查找 O(logn) | O(n) | + +## 栈 & 队列 + +- stack:FILO,add&del:O(1),find:O(n) +- queue:FIFO,add&del:O(1),find:O(n) + +## 双端队列 + +- 两端都可以进出的 Queue +- add&del: O(1) + +## 优先队列 + +- 插入操作:O(1) +- 取出操作:O(logN) - 按照元素的优先级取出 +- 底层具体实现的数据结构较为多样和复杂:heap,bst,treap + +## 总结 + +`栈(FILO)` 和 `队列(FIFO)` 依然是 `线性` 的数据结构,这两种数据结构只允许同时在一端进行插入/删除操作,时间复杂度是 O(1),实际工程中基于前两种数据结构又衍生出了 双端队列,该种类型的队列允许在两端进行插入/删除操作,时间复杂度为 O(1);此外,基于此有产生了 优先队列,这种数据结构通过为对应结点设置优先级的方式来进行级别控制,在实际工程应用中较为广泛,例如会员系统的设计。 + +## 源码解析 - C# 版 + +[Stack](https://source.dot.net/#System.Collections.NonGeneric/System/Collections/Stack.cs,6acda10c5f8b128e) + +> 通过查看源码得知,`Stack` 是采用 `array` 这种数据类型来进行相关操作,初始大小为 `10` 个单位长度。入栈操作为 `push`,函数内部直接对目标数组进行增加元素操作,期间会对数组长度进行安全检查;出栈操作为 `Pop`,函数内部直接对目标数组进行最后下标访问,返回该元素,并将数组中对应元素置空;查找操作为 `Peek`,该操作只会返回数组末尾元素对应的值,并不会对该数字进行任何修改。上述三种操作对应的时间复杂度均为 `O(1)`;`Contains` 方法为查找目标元素是否存在,其内部采用 while 循环的方式进行查找,时间复杂度为 `O(n)`。此外,Stack 本身是 `非线程安全的`, 所以 .NET 也提供了线程安全类型的版本 `SyncStack`。 + +[Deque](https://source.dot.net/#System.Threading.Channels/System/Collections/Generic/Deque.cs,8efc3f793e2f3a69) + +> 通过查看源码得知,`Deque` 是采用 `array` 这种数据类型来进行相关操作,初始状态为 `0` 个单位长度,入队操作为 `EnqueueTail`,函数内部直接对目标数组进行增加元素操作,期间也会对数组进行动态扩容;出队操作为 `DequeueHead` 和 `DequeueTail`;这几种操作方式都相对简单,对应的时间复杂度均为 `O(1)`。此外,由于官方并未提供查找接口,所以我们只能通过 `GetEnumerator` 方式来进行查找,其内部采用 while 循环方式转为为 `list` 并返回,其对应的时间复杂度为 `O(n)`。 + +[PriorityQueue](https://source.dot.net/#WindowsBase/MS/Internal/PriorityQueue.cs,8017d5f6bed3a97e) + +> 通过查看源码得知,`PriorityQueue` 内部采用了一个有序列表 `SortedList>` 和一个缓存栈 `Stack>` 来进行组合管理,有序列表是存着当前的所有数据,考虑到优先队列中数据优先级的修改频繁,将每次入队出队的数据都缓存到缓存栈中一份,避免对象的频繁创建,其中缓存栈的初始大小为 `10` 个单位长度;入队操作为 `Enqueue`,函数内部会往有序列表中添加元素(移动指针方式),同时会在缓存栈中进行出栈操作;出队操作为 `Peek`,该操作会将有序列表中的最后一个元素移除并返回;删除操作为 `RemoveItem`,函数内部会首先对有序列表中的对应元素执行删除操作,同时会将缓存栈执行入栈操作,将删除的目标数据加入到缓存栈中。 + + - diff --git a/Week 01/id_701/leetcode_21_701.cs b/Week 01/id_701/leetcode_21_701.cs new file mode 100644 index 000000000..6811ea0d1 --- /dev/null +++ b/Week 01/id_701/leetcode_21_701.cs @@ -0,0 +1,31 @@ +/** + * Definition for singly-linked list. + * public class ListNode { + * public int val; + * public ListNode next; + * public ListNode(int x) { val = x; } + * } + */ +public class Solution +{ + public ListNode MergeTwoLists(ListNode l1, ListNode l2) + { + if (l1 is null || l2 is null) + { + return l1 is null ? l2 : l1; + } + else + { + if (l1.val < l2.val) + { + l1.next = MergeTwoLists(l1.next, l2); + return l1; + } + else + { + l2.next = MergeTwoLists(l1, l2.next); + return l2; + } + } + } +} \ No newline at end of file diff --git a/Week 01/id_701/leetcode_21_701.py b/Week 01/id_701/leetcode_21_701.py new file mode 100644 index 000000000..0a78944d1 --- /dev/null +++ b/Week 01/id_701/leetcode_21_701.py @@ -0,0 +1,17 @@ +# Definition for singly-linked list. +class ListNode: + def __init__(self, x): + self.val = x + self.next = None + + +class Solution: + def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode: + if l1 is None or l2 is None: + return l1 or l2 + elif l1.val < l2.val: + l1.next = self.mergeTwoLists(l1.next, l2) + return l1 + else: + l2.next = self.mergeTwoLists(l1, l2.next) + return l2 diff --git a/Week 01/id_701/leetcode_26_701.cs b/Week 01/id_701/leetcode_26_701.cs new file mode 100644 index 000000000..c5d70e6b8 --- /dev/null +++ b/Week 01/id_701/leetcode_26_701.cs @@ -0,0 +1,23 @@ +public class Solution +{ + public int RemoveDuplicates(int[] nums) + { + if (nums is null || nums.Length == 0) + { + return 0; + } + else + { + int id = 0; + for (int i = 1; i < nums.Length; i++) + { + if (nums[i] != nums[id]) + { + nums[id + 1] = nums[i]; + id += 1; + } + } + return id + 1; + } + } +} \ No newline at end of file diff --git a/Week 01/id_701/leetcode_26_701.py b/Week 01/id_701/leetcode_26_701.py new file mode 100644 index 000000000..7964c921a --- /dev/null +++ b/Week 01/id_701/leetcode_26_701.py @@ -0,0 +1,20 @@ +class Solution: + # 逆序遍历 + def removeDuplicates(self, nums: list) -> int: + if nums is None: + return 0 + for i in range(len(nums) - 1, 0, -1): + if nums[i] == nums[i-1]: + nums.pop(i) + return len(nums) + + # 下标法 + def removeDuplicates2(self, nums: list) -> int: + if nums is None: + return 0 + id = 0 + for i in range(1, len(nums)): + if nums[i] == nums[id]: + nums[id+1] = nums[i] + id += 1 + return id+1 diff --git a/Week 01/id_701/leetcode_283_701.cs b/Week 01/id_701/leetcode_283_701.cs new file mode 100644 index 000000000..2e20ae819 --- /dev/null +++ b/Week 01/id_701/leetcode_283_701.cs @@ -0,0 +1,17 @@ +public class Solution +{ + public void MoveZeroes(int[] nums) + { + int id = 0; + for (int i = 0; i < nums.Length; i++) + { + if (nums[i] != 0) + { + int temp = nums[id]; + nums[id] = nums[i]; + nums[i] = temp; + id += 1; + } + } + } +} \ No newline at end of file diff --git a/Week 01/id_701/leetcode_283_701.py b/Week 01/id_701/leetcode_283_701.py new file mode 100644 index 000000000..065e24f95 --- /dev/null +++ b/Week 01/id_701/leetcode_283_701.py @@ -0,0 +1,13 @@ +class Solution: + def moveZeroes(self, nums: list) -> None: + for i in range(len(nums)): + if nums[i] == 0: + nums.remove(0) + nums.append(0) + + def moveZeroes(self, nums: list) -> None: + id = 0 + for i in range(len(nums)): + if nums[i] != 0: + nums[id], nums[i] = nums[i], nums[id] + id += 1 diff --git a/Week 01/id_701/leetcode_641_701.cs b/Week 01/id_701/leetcode_641_701.cs new file mode 100644 index 000000000..b97c18ad2 --- /dev/null +++ b/Week 01/id_701/leetcode_641_701.cs @@ -0,0 +1,101 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace ConsoleApp +{ + public class MyCircularDeque + { + private readonly List _queue; + private readonly int _length; + + /** Initialize your data structure here. Set the size of the deque to be k. */ + public MyCircularDeque(int k) + { + _length = k; + _queue = new List(_length); + } + + /** Adds an item at the front of Deque. Return true if the operation is successful. */ + public bool InsertFront(int value) + { + if (IsFull()) + { + return false; + } + else + { + _queue.Insert(0, value); + return true; + } + } + + /** Adds an item at the rear of Deque. Return true if the operation is successful. */ + public bool InsertLast(int value) + { + if (IsFull()) + { + return false; + } + else + { + _queue.Add(value); + return true; + } + } + + /** Deletes an item from the front of Deque. Return true if the operation is successful. */ + public bool DeleteFront() + { + if (IsEmpty()) + { + return false; + } + else + { + _queue.RemoveAt(0); + return true; + } + } + + /** Deletes an item from the rear of Deque. Return true if the operation is successful. */ + public bool DeleteLast() + { + if (IsEmpty()) + { + return false; + } + else + { + _queue.RemoveAt(_queue.Count - 1); + return true; + } + } + + /** Get the front item from the deque. */ + public int GetFront() => IsEmpty() ? -1 : _queue.First(); + + /** Get the last item from the deque. */ + public int GetRear() => IsEmpty() ? -1 : _queue.Last(); + + /** Checks whether the circular deque is empty or not. */ + public bool IsEmpty() => _queue == null || _queue.Count == 0; + + /** Checks whether the circular deque is full or not. */ + public bool IsFull() => _queue != null && _queue.Count == _length; + } + + /** + * Your MyCircularDeque object will be instantiated and called as such: + * MyCircularDeque obj = new MyCircularDeque(k); + * bool param_1 = obj.InsertFront(value); + * bool param_2 = obj.InsertLast(value); + * bool param_3 = obj.DeleteFront(); + * bool param_4 = obj.DeleteLast(); + * int param_5 = obj.GetFront(); + * int param_6 = obj.GetRear(); + * bool param_7 = obj.IsEmpty(); + * bool param_8 = obj.IsFull(); + */ +} diff --git a/Week 01/id_701/leetcode_641_701.py b/Week 01/id_701/leetcode_641_701.py new file mode 100644 index 000000000..10be36db0 --- /dev/null +++ b/Week 01/id_701/leetcode_641_701.py @@ -0,0 +1,84 @@ +class MyCircularDeque: + + def __init__(self, k: int): + """ + Initialize your data structure here. Set the size of the deque to be k. + """ + self.q = [] + self.length = k + + def insertFront(self, value: int) -> bool: + """ + Adds an item at the front of Deque. Return true if the operation is successful. + """ + if self.isFull(): + return False + else: + self.q.insert(0, value) + return True + + def insertLast(self, value: int) -> bool: + """ + Adds an item at the rear of Deque. Return true if the operation is successful. + """ + if self.isFull(): + return False + else: + self.q.append(value) + return True + + def deleteFront(self) -> bool: + """ + Deletes an item from the front of Deque. Return true if the operation is successful. + """ + if self.isEmpty(): + return False + else: + self.q.pop(0) + return True + + def deleteLast(self) -> bool: + """ + Deletes an item from the rear of Deque. Return true if the operation is successful. + """ + if self.isEmpty(): + return False + else: + self.q.pop() + return True + + def getFront(self) -> int: + """ + Get the front item from the deque. + """ + return -1 if self.isEmpty() else self.q[0] + + def getRear(self) -> int: + """ + Get the last item from the deque. + """ + return -1 if self.isEmpty() else self.q[-1] + + def isEmpty(self) -> bool: + """ + Checks whether the circular deque is empty or not. + """ + return len(self.q) == 0 + + def isFull(self) -> bool: + """ + Checks whether the circular deque is full or not. + """ + return len(self.q) == self.length + + +# Your MyCircularDeque object will be instantiated and called as such: +# obj = MyCircularDeque(k) +# param_1 = obj.insertFront(value) +# param_2 = obj.insertLast(value) +# param_3 = obj.deleteFront() +# param_4 = obj.deleteLast() +# param_5 = obj.getFront() +# param_6 = obj.getRear() +# param_7 = obj.isEmpty() +# param_8 = obj.isFull() diff --git a/Week 01/id_711/Leetcode_189_711.java b/Week 01/id_711/Leetcode_189_711.java new file mode 100644 index 000000000..1f2e88c33 --- /dev/null +++ b/Week 01/id_711/Leetcode_189_711.java @@ -0,0 +1,91 @@ +package Week1; + +public class Lettcode_189 { + public static void main(String[] args) { + int[] nums = {1,2,3,4,5,6,7}; + int k = 3; + rotate3(nums,k); + for (int i = 0; i < nums.length; i++) { + System.out.println(nums[i]) ; + } + } + + + + /** + * 暴力解法,O(n*k) + * 执行用时 : 126 ms , 在所有 java 提交中击败了22.49%的用户 + * 内存消耗 : 36.7 MB , 在所有 java 提交中击败了95.45%的用户 + * @param nums + * @param k + */ + private static void rotate1(int[] nums, int k) { + int len = nums.length; + k = k % len; + for (int i = 0; i < k; i++) { + int x = nums[len - 1]; + for (int j = len - 1; j > 0; j--) { + nums[j] = nums[j - 1]; + } + nums[0] = x; + } + } + + /** + * 开新的数组转存 + * 执行用时 :1 ms, 在所有 java 提交中击败了95.05%的用户 + * 内存消耗 :36.7 MB, 在所有 java 提交中击败了95.45%的用户 + */ + private static void rotate(int[] nums, int k) { + int[] help = new int[nums.length]; + for (int i = 0; i < nums.length; i++) { + help[(i + k) % nums.length] = nums[i]; + } + for (int i = 0; i < nums.length; i++) { + nums[i] = help[i]; + } + } + + /** + * 反转数组 + * 执行用时 :1 ms, 在所有 java 提交中击败了94.76%的用户 + * 内存消耗 :37.7 MB, 在所有 java 提交中击败了94.46%的用户 + */ + private static void rotate2(int[] nums, int k) { + k %= nums.length; + reverse(nums,0,nums.length - 1); + reverse(nums,0,k - 1); + reverse(nums, k, nums.length - 1); + } + + private static void reverse(int[] nums, int l, int r) { + while (l < r){ + int t = nums[r]; + nums[r--] = nums[l]; + nums[l++] = t; + } + } + + /** + * 环状替换 + * 执行用时 :1 ms, 在所有 java 提交中击败了94.76%的用户 + * 内存消耗 :37 MB, 在所有 java 提交中击败了95.45%的用户 + */ + private static void rotate3(int[] nums, int k) { + k %= nums.length; + int count = 0; + for (int i = 0; count < nums.length; i++) { + int current = i; + int prev = nums[i]; + do { + int next = (current + k) % nums.length; + int temp = nums[next]; + nums[next] = prev; + prev = temp; + current = next; + count++; + } + while (i != current); + } + } +} diff --git a/Week 01/id_711/Leetcode_1_711.java b/Week 01/id_711/Leetcode_1_711.java new file mode 100644 index 000000000..7f4ae4535 --- /dev/null +++ b/Week 01/id_711/Leetcode_1_711.java @@ -0,0 +1,36 @@ +package Week1; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; + +public class Lettcode_001 { + public static void main(String[] args) { + int[] nums = {2,7,11,15}; + int target = 13; + int[] array = twoSum(nums,target); + System.out.println(Arrays.toString(array)); + } + + /** + * 思路:用map存储当前值与target的差值,遍历到这个差值即为答案 + * 执行用时 :3 ms, 在所有 java 提交中击败了98.88%的用户 + * 内存消耗 :37.3 MB, 在所有 java 提交中击败了89.88%的用户 + * @param nums + * @param target + * @return + */ + private static int[] twoSum(int[] nums, int target) { + HashMap map = new HashMap<>(); + for (int i = 0; i < nums.length; i++) { + if (map.containsKey(nums[i])) { + int[] ans = {map.get(nums[i]),i}; + return ans; + } + else { + map.put(target - nums[i],i); + } + } + return null; + } +} diff --git a/Week 01/id_711/Leetcode_21_711.java b/Week 01/id_711/Leetcode_21_711.java new file mode 100644 index 000000000..521f45f65 --- /dev/null +++ b/Week 01/id_711/Leetcode_21_711.java @@ -0,0 +1,51 @@ +package Week1; + +public class Lettcode_021 { + public static void main(String[] args) { + ListNode l1 = new ListNode(1); + ListNode l2 = new ListNode(2); + ListNode l3 = new ListNode(3); + l1.next = l2; + l2.next = l3; + ListNode r1 = new ListNode(1); + ListNode r2 = new ListNode(2); + ListNode r3 = new ListNode(3); + r1.next = r2; + r2.next = r3; + + ListNode list = mergeTwoLists(l1,r1); + while (list != null){ + System.out.print(list.val + " "); + list = list.next; + } + } + + /** + * 模拟即可 + * 执行用时 :1 ms, 在所有 java 提交中击败了94.36%的用户 + * 内存消耗 :39.8 MB, 在所有 java 提交中击败了66.20%的用户 + * @param l1 + * @param l2 + * @return + */ + private static ListNode mergeTwoLists(ListNode l1, ListNode l2) { + ListNode head = new ListNode(-1); + ListNode pre = head; + while (l1 != null && l2 != null){ + if (l1.val < l2.val){ + pre.next = l1; + l1 = l1.next; + pre = pre.next; + } + else{ + pre.next = l2; + l2 = l2.next; + pre = pre.next; + } + } + pre.next = l1 == null ? l2 : l1; + return head.next; + } + + +} diff --git a/Week 01/id_711/Leetcode_26_711.java b/Week 01/id_711/Leetcode_26_711.java new file mode 100644 index 000000000..b5a851d5f --- /dev/null +++ b/Week 01/id_711/Leetcode_26_711.java @@ -0,0 +1,45 @@ +package Week1; + +public class Lettcode_026 { + public static void main(String[] args) { + int[] nums = {}; + System.out.println(removeDuplicates(nums)); + } + + /** + * 执行用时 :1 ms, 在所有 java 提交中击败了100.00%的用户 + * 内存消耗 :39.6 MB, 在所有 java 提交中击败了95.94%的用户 + * @param nums + * @return + */ + private static int removeDuplicates(int[] nums) { + if (nums.length < 1) + return 0; + int length = 1; + int x = nums[0]; + int index = 1; + while (index < nums.length){ + if (nums[index] != x) { + nums[length++] = nums[index]; + x = nums[index]; + } + index++; + } + return length; + } + + /** + * 最优版 + */ + private static int solution(int[] nums) { + if (nums.length < 1) + return 0; + int index = 1; + for (int i = 1; i < nums.length; i++) { + if (nums[i] != nums[i - 1]) { + nums[index++] = nums[i]; + } + } + return index; + } +} diff --git a/Week 01/id_711/Leetcode_283_711.java b/Week 01/id_711/Leetcode_283_711.java new file mode 100644 index 000000000..da052d99a --- /dev/null +++ b/Week 01/id_711/Leetcode_283_711.java @@ -0,0 +1,29 @@ +package Week1; + +import java.util.Arrays; + +public class Lettcode_283 { + public static void main(String[] args) { + int[] nums = {0,1,0,3,12}; + moveZeros(nums); + System.out.println(Arrays.toString(nums)); + } + + /** + * 简单模拟 + * 执行用时 :0 ms, 在所有 java 提交中击败了100.00%的用户 + * 内存消耗 :37.6 MB, 在所有 java 提交中击败了95.46%的用户 + * @param nums + */ + private static void moveZeros(int[] nums) { + int index = 0; + for (int i = 0; i < nums.length; i++) { + if (nums[i] != 0){ + nums[index++] = nums[i]; + } + } + for (int i = index; i < nums.length ; i++) { + nums[i] = 0; + } + } +} diff --git a/Week 01/id_711/Leetcode_42_711.java b/Week 01/id_711/Leetcode_42_711.java new file mode 100644 index 000000000..c1e61ef67 --- /dev/null +++ b/Week 01/id_711/Leetcode_42_711.java @@ -0,0 +1,93 @@ +package Week1; + +import java.util.Stack; + +public class Leetcode_042 { + public static void main(String[] args) { + int[] height = {0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1}; + System.out.println(trap(height)); + } + + + + + /** + * 两遍扫描方法,找到index位置左边的最大高度和右边的最大高度 + * 执行用时 :1 ms, 在所有 java 提交中击败了100.00%的用户 + * 内存消耗 :37.2 MB, 在所有 java 提交中击败了84.69%的用户 + * @param height + * @return + */ + private static int trap(int[] height) { + int len = height.length; + int[] left = new int[len]; + int[] right = new int[len]; + left[0] = height[0]; + for (int i = 1; i < len; i++) { + left[i] = Math.max(left[i - 1], height[i]); + } + right[len - 1] = height[len - 1]; + for (int i = len - 2; i >= 0; i--) { + right[i] = Math.max(right[i + 1], height[i]); + } + int ans = 0; + for (int i = 1; i < len - 1; i++) { + ans += Math.min(left[i], right[i]) - height[i]; + } + return ans; + } + + /** + * 双指针解法 + * 巧妙。。。想不出来 + * 执行用时 :1 ms, 在所有 java 提交中击败了100.00%的用户 + * 内存消耗 :37.7 MB, 在所有 java 提交中击败了82.55%的用户 + */ + private static int trap1(int[] height) { + int left = 0, right = height.length - 1; + int ans = 0; + int leftMax = 0, rightMax = 0; + while (left < right){ + if (height[left] < height[right]) { + if (height[left] >= leftMax) { + leftMax = height[left]; + } + else { + ans += leftMax - height[left]; + } + left++; + } + else { + if (height[right] >= rightMax) { + rightMax = height[right]; + } + else { + ans += rightMax - height[right]; + } + right--; + } + } + return ans; + } + +// /** +// * 栈解法,暂时错误 +// */ +// private static int trap2(int[] height) { +// Stack stack = new Stack<>(); +// int ans = 0, current = 0; +// while (current < height.length){ +// while (!stack.isEmpty() && height[current] > stack.peek()) { +// int top = stack.pop(); +// if (stack.isEmpty()) +// break; +// int distance = current - stack.pop() - 1; +// int boundHeight = Math.min(height[current], height[stack.pop()] - height[top]); +// ans += distance * boundHeight; +// } +// stack.push(current++); +// } +// return ans; +// } + +} diff --git a/Week 01/id_711/Leetcode_66_711.java b/Week 01/id_711/Leetcode_66_711.java new file mode 100644 index 000000000..b9d5e3c2b --- /dev/null +++ b/Week 01/id_711/Leetcode_66_711.java @@ -0,0 +1,44 @@ +package Week1; + +import java.util.Arrays; + +public class Lettcode_66 { + public static void main(String[] args) { + int[] nums = {9}; + int[] ans = plusOne(nums); + System.out.println(Arrays.toString(ans)); + } + + /** + * SB 的模拟做法。。。。 + * 执行用时 :0 ms, 在所有 java 提交中击败了100.00%的用户 + * 内存消耗 :35.2 MB, 在所有 java 提交中击败了37.71%的用户 + * @param nums + * @return + */ + private static int[] plusOne(int[] nums) { + nums[nums.length - 1] += 1; + int index = nums.length - 1; + boolean flag = false; + while (index >= 0 && nums[index] > 9){ + if (index == 0){ + nums[index] %= 10; + flag = true; + } + else{ + nums[index] %= 10; + nums[index - 1] += 1; + } + index--; + } + if (flag){ + int[] help = new int[nums.length + 1]; + help[0] = 1; + for (int i = 0; i < nums.length ; i++) { + help[i + 1] = nums[i]; + } + return help; + } + else return nums; + } +} diff --git a/Week 01/id_711/Leetcode_88_711.java b/Week 01/id_711/Leetcode_88_711.java new file mode 100644 index 000000000..cd793bfd3 --- /dev/null +++ b/Week 01/id_711/Leetcode_88_711.java @@ -0,0 +1,47 @@ +package Week1; + +import java.util.Arrays; + +public class Lettcode_088 { + public static void main(String[] args) { + int[] nums1 = {1,2,3,0,0,0}; + int m = 3; + int[] nums2 = {2,5,6}; + int n = 3; + merge(nums1,m,nums2,n); + System.out.println(Arrays.toString(nums1)); + } + + /** + * 用新的数组辅助 + * 看了题解后发现从后往前不需要辅助数组! + * 执行用时 :0 ms, 在所有 java 提交中击败了100.00%的用户 + * 内存消耗 :36.1 MB, 在所有 java 提交中击败了85.44%的用户 + * @param nums1 + * @param m + * @param nums2 + * @param n + */ + private static void merge(int[] nums1, int m, int[] nums2, int n) { + int[] help = new int[m + n]; + int index = 0; + int l1 = 0, l2 = 0; + while (l1 < m && l2 < n) { + if (nums1[l1] < nums2[l2]){ + help[index++] = nums1[l1++]; + } + else { + help[index++] = nums2[l2++]; + } + } + while (l1 < m) { + help[index++] = nums1[l1++]; + } + while (l2 < n) { + help[index++] = nums2[l2++]; + } + for (int i = 0; i < m + n; i++) { + nums1[i] = help[i]; + } + } +} diff --git a/Week 01/id_711/NOTE.md b/Week 01/id_711/NOTE.md index a6321d6e2..050c9fcbd 100644 --- a/Week 01/id_711/NOTE.md +++ b/Week 01/id_711/NOTE.md @@ -2,3 +2,7 @@ +极客大学算法训练营第一周算法作业题 + +Leetcode 01 21 26 66 88 189 283 + diff --git a/Week 01/id_716/LeetCode_189_716.go b/Week 01/id_716/LeetCode_189_716.go new file mode 100644 index 000000000..30760afb6 --- /dev/null +++ b/Week 01/id_716/LeetCode_189_716.go @@ -0,0 +1,101 @@ +package id_716 + +// 旋转数组: https://leetcode-cn.com/problems/rotate-array/ + +// 1. 笨方法,一个一个移动, 每次只移动一个,时间复杂度 O(n*k) +func rotate1(nums []int, k int) { + length := len(nums) + k = k % length + if k == 0 { return } + + for i := 0; i < k; i++ { + tmp := nums[length - 1] + for j := length - 2; j >= 0; j-- { + nums[j + 1] = nums[j] + } + nums[0] = tmp + } +} + +// 2. 使用新数组 Copy,当k确定后,进行旋转后的位置是确定的 (i + k) % length +// 时间复杂度 O(n) 空间复杂度 O(n) +func rotate2(nums []int, k int) { + // 申请一个新切片 + tmpNums := make([]int, len(nums)) + + // 将旋转后的数组放在临时切片中 + for i := range nums { + pos := (i + k) % len(nums) + tmpNums[pos] = nums[i] + } + + // copy to nums + copy(nums, tmpNums) +} + +// 3. 反转 +// 反转整个字符串,然后反转前k个,再反转后n-k个 +func rotate3(nums []int, k int) { + length := len(nums) + k = k % length + + reverse(nums, 0, length - 1) + reverse(nums, 0, k - 1) + reverse(nums, k, length - 1) +} + +// 反转的思路是根据中间为轴,对称交换 +func reverse(nums []int, start, end int) { + for i, j := start, end; i < j; i, j = i + 1, j - 1 { + nums[i], nums[j] = nums[j], nums[i] + } +} + +// 4. 交换法,这个思路是最开始想起来的,但是在落地代码时出现了问题,有一部分逻辑不知道代码如何写 +// 思路是:旋转后每个位置是确定的,所以走一遍,把所有元素放在他应有的位置上,代码实现稍微有些复杂 +// 时间复杂度 O(n), 空间复杂度 O(1) +func rotate4(nums []int, k int) { + length := len(nums) + if k = k % length; k == 0 { + return + } + + // 移动次数 + moveCnt := 0 + startPos := 0 + currentValTmp := -1 + nextValTmp := -1 + + for moveCnt < length { + currentPos := startPos + currentValTmp = nums[startPos] + + // 当形成环时,进入到下一轮替换 + nextPos := (currentPos + k) % length + for nextPos != startPos { + // 计算当前元素移动到的位置 + nextPos = (currentPos + k) % length + + // 移动过去 + nextValTmp = nums[nextPos] + nums[nextPos] = currentValTmp + + // 切换指针,准备进入下一轮移动 + currentPos = nextPos + currentValTmp = nextValTmp + + moveCnt++ + } + + startPos++ + } +} + +// 5. golang 中比较 tricky 的写法 +func rotate5(nums []int, k int) { + length := len(nums) + k %= length + // if k == 0 { return } + temp := append(nums[length - k:], nums[:length - k]...) + copy(nums, temp) +} diff --git a/Week 01/id_716/LeetCode_1_716.go b/Week 01/id_716/LeetCode_1_716.go new file mode 100644 index 000000000..96fa35c03 --- /dev/null +++ b/Week 01/id_716/LeetCode_1_716.go @@ -0,0 +1,43 @@ +package id_716 + +// https://leetcode-cn.com/problems/two-sum/ + +// 1. 暴力法,O(n^2)复杂度的遍历查找 +func twoSum1(nums []int, target int) []int { + length := len(nums) + if length <= 1 { + return []int{} + } + + for i := 0; i < length - 1; i++ { + diff := target - nums[i] + for j := i + 1; j < length; j++ { + if diff == nums[j] { + return []int{i, j} + } + } + } + + return []int{} +} + +// 2. hash 表法,使用临时的映射表空间记录已经遍历过的数字 +func twoSum2(nums []int, target int) []int { + length := len(nums) + if length <= 1 { + return []int{} + } + + // 记录访问过的数字 + tracker := make(map[int]int) + for i := 0; i < length; i++ { + delta := target - nums[i] + v, ok := tracker[delta] + if ok { + return []int{v, i} + } + tracker[nums[i]] = i + } + + return []int{} +} diff --git a/Week 01/id_716/LeetCode_21_716.go b/Week 01/id_716/LeetCode_21_716.go new file mode 100644 index 000000000..82174338b --- /dev/null +++ b/Week 01/id_716/LeetCode_21_716.go @@ -0,0 +1,79 @@ +package id_716 + +/** + * Definition for singly-linked list. + * type ListNode struct { + * Val int + * Next *ListNode + * } + */ +type ListNode struct { + Val int + Next *ListNode +} + +// 1 +func mergeTwoLists1(l1 *ListNode, l2 *ListNode) *ListNode { + // check range + if l1 == nil && l2 == nil { return nil } + if l1 == nil && l2 != nil { return l2 } + if l1 != nil && l2 == nil { return l1 } + + head := l1 + if l1.Val > l2.Val { + head = l2 + } + + for l1 != nil && l2 != nil { + if l1.Val <= l2.Val { + // 在 l1 中找到一个合适的位置插入 l2 的元素 + for l1.Next != nil && l1.Next.Val < l2.Val { + l1 = l1.Next + } + + // move ptr + tmp1 := l1.Next + l1.Next = l2 + l2 = l2.Next + l1.Next.Next = tmp1 + } else { + // 在 l2 中找到一个合适的位置插入 l1 的元素 + for l2.Next != nil && l2.Next.Val < l1.Val { + l2 = l2.Next + } + + // move ptr + tmp2 := l2.Next + l2.Next = l1 + l1 = l1.Next + l2.Next.Next = tmp2 + } + } + + return head +} + +// 2 另外一种代码实现 +func mergeTwoLists2(l1 *ListNode, l2 *ListNode) *ListNode { + // 前置节点,用来指向新链表 + head := &ListNode{Next: nil} + // 记录已经排好序列表的最后位置 + prev := head + + for l1 != nil && l2 != nil { + if l1.Val <= l2.Val { + prev.Next = l1 + l1 = l1.Next + } else { + prev.Next = l2 + l2 = l2.Next + } + + prev = prev.Next + } + + if l1 != nil { prev.Next = l1 } + if l2 != nil { prev.Next = l2 } + + return head.Next +} diff --git a/Week 01/id_716/LeetCode_42_716.go b/Week 01/id_716/LeetCode_42_716.go new file mode 100644 index 000000000..ea6fb6647 --- /dev/null +++ b/Week 01/id_716/LeetCode_42_716.go @@ -0,0 +1,71 @@ +package id_716 + +// https://leetcode-cn.com/problems/trapping-rain-water + +// 1. 暴力法,遍历找左右边界 +func trap1(height []int) int { + + length := len(height) + res := 0 + + for i := 1; i < length; i++ { + maxLeft, maxRight := 0, 0 + // 找左边最大高度 + for j := i; j >= 0; j-- { + maxLeft = max(maxLeft, height[j]) + } + // 找右边最大最大高度 + for j := i; j < length; j++ { + maxRight = max(maxRight, height[j]) + } + // 计算每个柱子能贡献的雨水 + res += min(maxLeft, maxRight) - height[i] + } + + return res +} + +func min(m, n int) int { + if m <= n { + return m + } + return n +} + +func max(m, n int) int { + if m >= n { + return m + } + return n +} + +// 2. 双指针,向中间缩进 +func trap(height []int) int { + length := len(height) + res := 0 + left, right := 0, length - 1 + leftMax, rightMax := 0, 0 + + for left < right { + if height[left] <= height[right] { + // 找左边是否有比他大的,有的话,就可以贡献雨水,因为右边已经比它高了 + if leftMax > height[left] { + res += (leftMax - height[left]) + } else { + // 更新左边的最大值 + leftMax = height[left] + } + left++ + } else { + // 找右边是否有比他大的,有的话,就可以贡献雨水,因为左边已经比它高了 + if rightMax > height[right] { + res += (rightMax - height[right]) + } else { + rightMax = height[right] + } + right-- + } + } + + return res +} \ No newline at end of file diff --git a/Week 01/id_716/LeetCode_66_716.go b/Week 01/id_716/LeetCode_66_716.go new file mode 100644 index 000000000..00559c6f8 --- /dev/null +++ b/Week 01/id_716/LeetCode_66_716.go @@ -0,0 +1,19 @@ +package id_716 + +// https://leetcode-cn.com/problems/plus-one/ + +// 1. 模拟进位 +func plusOne(digits []int) []int { + length := len(digits) + + // 从后向前 + for i := length - 1; i >= 0; i-- { + digits[i]++ + digits[i] = digits[i] % 10 + + if digits[i] != 0 { + return digits + } + } + return append([]int{1}, digits...) +} diff --git a/Week 01/id_716/LeetCode_88_716.go b/Week 01/id_716/LeetCode_88_716.go new file mode 100644 index 000000000..f5ff6d0f7 --- /dev/null +++ b/Week 01/id_716/LeetCode_88_716.go @@ -0,0 +1,49 @@ +package id_716 + +// https://leetcode-cn.com/problems/merge-sorted-array/ + +// 1. 新数组copy +func merge1(nums1 []int, m int, nums2 []int, n int) { + tmpRes := make([]int, m + n) + + i, j := 0, 0 + for i < m && j < n { + if nums1[i] <= nums2[j] { + tmpRes[i+j] = nums1[i] + i++ + } else { + tmpRes[i+j] = nums2[j] + j++ + } + } + + for i < m { + tmpRes[i+n] = nums1[i] + i++ + } + for j < n { + tmpRes[j+m] = nums2[j] + j++ + } + + copy(nums1, tmpRes) +} + +// 2. 原地移动,从后向前移动 +func merge2(nums1 []int, m int, nums2 []int, n int) { + i, j := m - 1, n - 1 + for j >= 0 { + if i >= 0 && nums1[i] >= nums2[j] { + nums1[i+j+1] = nums1[i] + i-- + } else { + nums1[i+j+1] = nums2[j] + j-- + } + } +} + +// 3. 排序法,这个就不做实现了,这个方式有点绕远了 +// 伪代码: +// nums2 append to nums1 +// sort nums1 (quick sort or merge sort) diff --git a/Week 01/id_716/NOTE.md b/Week 01/id_716/NOTE.md index 190a9405c..27214813b 100644 --- a/Week 01/id_716/NOTE.md +++ b/Week 01/id_716/NOTE.md @@ -2,6 +2,8 @@ ## 【716-Week 01】学习总结 +本周总结标题:【716-Week 01】学会渐进式的优化思路 + 总结可以从两部分来做:关于算法本身新的认识和算法所涉及到的更加底层的知识(如OS层面的,编译原理层面的,或者Linux的代码实现中也会用到的东西等) 列一下这周可以做总结的地方 @@ -13,3 +15,286 @@ blabla... +--- + +## 总结正文 + +#### 【716-Week 01】关于复杂度分析和渐进式优化 + +这是训练营第一周,很想总结一下有关算法复杂度分析和解决问题时的渐进式优化思路。一直都认为思路和方法是很重要的,所以要更好的掌握复杂度分析和渐进式优化。 + +我们需要知道为什么要复杂度分析,因为在程序未写出来之前是没有办法运行的,如果都到了程序写出来之后才能验证快不快,着实浪费时间和精力,所以在编程之前就粗略估计时空开销,这个过程就是复杂度分析。 + +复杂度分析的一些关键点: + +- 复杂度分析的一般规则,也是一些简单的规则 + +1. 一般有限次操作的时间复杂度是 O(1), 有限次操作是指随着数据量的增加,操作次数不增加 +2. 一般单次 for 循环的时间复杂度是 O(n), 表示和数据量的线性关系 +3. 一般嵌套 m 次 for 循环的时间复杂度是 O(n^m) +4. 一般树的高度的时间复杂度是 O(logn) +5. 一般对于二叉查找树的二分查找时间复杂度是 O(logn) +6. 一般对于一个堆,弹出堆顶元素后,重新堆化的时间复杂度是 O(logn) + +- 复杂度分析的组合方式 + +1. 嵌套的多层循环,时间复杂度和嵌套层数m有关系,一般是 O(n^m), 如冒泡排序O(n^2) +2. 有时算法是分多步完成的,例如 Topk 问题可以分解为:新建k个元素的堆;然后遍历 n - k 个元素插入堆中;调整堆;时间复杂度的组合就是:O(k) + O(n-k) * O(logk) = O(n*logk)。需要根据具体算法分清楚是加还是乘 + +``` +// 表示成公式 +如果 T1(N) = O(f(n)), T2(N) = O(g(n)), 那么 +a. T1(N) + T2(N) = max(O(f(n)), O(g(n))) +b. T1(N) * T2(N) = O(f(n)*g(n)) + +如果 T(N) 是一个k次多项式,则 T(N) = O(N^k) +``` + +- 复杂度分析的递归求解 + +递归的分析方法相对来讲要复杂一些,需要先找出终止条件、子问题和递归式,然后可以使用一些数学分析方法来求解。 + +``` +// 二分查找的例子 +int binarySearch(int[] arr, int low, int hight, int target) { + if (low > hight) return -1; + int mid = low + (hight - low) >> 1; + if (arr[mid] == target) return mid; + if (arr[mid] > target) { + return binarySearch(arr, low, mid - 1, target); + } else { + return binarySearch(arr, mid + 1, hight, target); + } +} + +// 下面是分析 +T(n) = O(f(n)), f(n) 用来表示数据量是 n 时的复杂度公式(或者叫操作次数等),那么 f(1) = 1 (可以理解为 1 是常量级的); +从代码可知,每次递归查找会将数据量减半,所以有 f(n) = f(n/2) + 1, 依次递推则有: +f(n) = f(n/2) + 1 +f(n/2) = f(n/4) + 1 +... +f(n/2^(m-1)) = f(n/2^m) + 1 +左右分别相加得到,f(n) = f(n/2^m) + m (总共有m次递归调用) +当 n/2^m = 1 时,f(n/2^m) = 1, 达到常量级,可求出解;所以 m = logn +f(n) = 1 + logn, 所以 T(n) = O(logn),二分查找的时间复杂度是 O(logn) +``` + +递归求解需要根据算法进行一步步的分析,得出递推式,进行详细推导。此外,还可以使用主定理来分析递归。 + +- 均摊分析 + +摊还分析,又叫平摊分析,是一种特殊情况下的复杂度分析方法。暂时请参考[这里](https://time.geekbang.org/column/article/40447) + +- 例子:归并排序的复杂度分析 + +``` +// 归并排序复杂度分析 +int mergeSort(int[] arr, int low, int high) { + if (low >= high) return; + int mid = low + (hight - low) >> 1; + + mergeSort(arr, low, mid) + mergeSort(arr, mid + 1, high) + merge(arr, low, mid, high) +} +// 合并函数, 将两个有序数组合并为一个有序数组 +void merge(int[] arr, int low, int mid, int high) { + +} +``` + + +--- + +#### 改写代码 + +使用add first或add last这套新的API改写Deque的代码 + +```java +import java.util.Deque; +import java.util.LinkedList; + +public class DequeDemo { + public static void main(String[] args) { + Deque deque = new LinkedList<>(); + + // add element to stack + deque.addFirst("a"); + deque.addFirst("b"); + deque.addFirst("c"); + System.out.println(deque); + + // check the first element + String peekFirst = deque.peekFirst(); + System.out.println(peekFirst); + assert peekFirst.equals("c"); + System.out.println(deque); + + // pop + while (deque.size() > 0) { + System.out.println(deque.removeFirst()); + } + System.out.println(deque); + } +} +``` + +#### Queue 和 Priority Queue 源码分析 + +##### Queue 源码分析 + +`Queue` 的实现比较多 + + + +##### Priority Queue 源码分析 + +`java.util.PriorityQueue` 是优先级队列的实现,底层依赖的核心数据结构是二叉堆,支持插入元素、删除元素、peek、poll、查找等核心功能;现从以下几点进行分析: + +1. 使用的数据结构介绍 +2. 容量增长策略 +3. 核心API及分析(插入,删除,修改,查找/检查) + +###### 1. 使用的数据结构介绍 + +`PriorityQueue` 使用了二叉堆,堆是一个完全二叉树,且每个节点大于(或者小于)他的左右子节点。完全二叉树这种数据结构非常适合使用数组来存储,从 `PriorityQueue` 源码中也得到证实,使用了 `transient Object[] queue;` 作为存储元素的容器;所有对 `PriorityQueue` 的操作其实都是对这个二叉堆的操作,下面我们会分析各种操作的具体方法和复杂度。 + +使用数组存储时,位置在n的节点,他的两个自己点的位置分别为:`2*n+1`和`2*(n+1)` + +###### 2. 容量增长策略 + +``` +public PriorityQueue(); +public PriorityQueue(int initialCapacity); +public PriorityQueue(int initialCapacity, Comparator comparator); +... +``` +`PriorityQueue` 提供了数个构造方法,可以指定初始容量,如果不指定,默认是11;同时还可以指定 Comparator 接口,这个我们先忽略,这个只是用于比较两个对象的大小。 + +`PriorityQueue` 是使用数组存储的,那么容量是一个很关键的问题,分析可知,`PriorityQueue` 通过 `grow` 函数进行扩容,策略是:当前容量小于64时,每次翻倍;当前容量大于64时,每次增长50%;扩容的过程是:计算新的容量 -> 申请新的数组 -> copy到新数组。 + +###### 3. 核心API及分析(插入,删除,修改,查找/检查) + +- 插入操作 add/offer + +```java +public boolean offer(E e) { + // null 检查,直接抛出运行时异常 + if (e == null) + throw new NullPointerException(); + modCount++; + int i = size; + // 判断数组容量,否则就扩容 + if (i >= queue.length) + grow(i + 1); + // 底层数组容量+1 + size = i + 1; + // 如果是第一个元素,放在第一个即可 + if (i == 0) + queue[0] = e; + // 不是第一个元素,进行堆化过程,以满足堆的特性 + else + siftUp(i, e); + return true; +} + +// 堆化的插入过程, 这个过程是一个从下往上找的过程,直到堆顶或者中途结束 +private void siftUpComparable(int k, E x) { + Comparable key = (Comparable) x; + while (k > 0) { + // 找到位置k的父节点的位置, (k - 1) >>> 1 是无符号右移操作,相当于 (k - 1) / 2 + int parent = (k - 1) >>> 1; + // 暂存父节点位置的元素 + Object e = queue[parent]; + // 和父节点位置的元素比较一下,如果要插入的元素小于父节点,就退出 + if (key.compareTo((E) e) >= 0) + break; + // 否则,把父节点下移 + queue[k] = e; + // 继续往上找 + k = parent; + } + // 找到了合适的插入位置,就把要插入的元素放进去 + queue[k] = key; +} +``` + +时间复杂度分析,核心操作是插入堆化,每次查找就除2,可以简单评估出 2 ^ k = n, 最大查找次数 k = logn, 所以时间复杂度是 O(logn); 由于整个过程中并没有占用额外空间,空间复杂度是 O(1) + +- 删除操作 remove/removeEq + +```java +// 定位指定元素,找到位置并返回 +private int indexOf(Object o) { + if (o != null) { + for (int i = 0; i < size; i++) + if (o.equals(queue[i])) + return i; + } + return -1; +} + +// 这个删除的核心方法,删除指定位置的元素,删除后需要堆化,这个过程会有些复杂 +private E removeAt(int i) { + // assert i >= 0 && i < size; + modCount++; + int s = --size; + // 如果是删除最后一个元素,直接删掉 + if (s == i) // removed last element + queue[i] = null; + else { + // 取最后一个元素暂存,并删除最后一个元素 + E moved = (E) queue[s]; + queue[s] = null; + // 进行删除的堆化过程,以满足堆的特性,主要是将最后一个元素插入到合适位置 + siftDown(i, moved); + // 这里的意思是,如果删除的是叶子节点,就走插入堆化的流程,可参考上面的分析 + if (queue[i] == moved) { + siftUp(i, moved); + if (queue[i] != moved) + return moved; + } + } + return null; +} +// 这个是从上到下的堆化过程,其中 k 是要删除的位置,x 是要插入的元素 +private void siftDownComparable(int k, E x) { + Comparable key = (Comparable)x; + // 为什么取一半? 主要是因为n个节点的堆,他的叶子节点的个数是 n/2, 如果是叶子节点的删除,只需要做 + // 从下到上的堆化过程即可,走插入流程;非叶子节点先进行从上到下的堆化 + int half = size >>> 1; // loop while a non-leaf + while (k < half) { + int child = (k << 1) + 1; // assume left child is least + Object c = queue[child]; + int right = child + 1; + // 左右节点比较,如果右节点大就使用右节点 + if (right < size && + ((Comparable) c).compareTo((E) queue[right]) > 0) + c = queue[child = right]; + // 如果要移动的左右节点小于要插入的数据就终止 + if (key.compareTo((E) c) <= 0) + break; + // 把较大的子节点移动到父节点的位置 + queue[k] = c; + // 继续向下移动 + k = child; + } + // 插入到合适的位置 + queue[k] = key; +} +``` + +梳理下删除的流程就是: +1. 先找到删除元素的位置,不存在,就退出了 +2. 取最后一个元素当作初始需要移动的数据,将这个元素插入到合适的位置(为什么是最后一个元素,我想是这样操作起来是最方便的把,不然,要保证是完全二叉树还是挺麻烦的) +3. 如果删除的元素是非叶子节点,就从他的子节点里找合适的节点往上移动,同时还要和取出来的最后一个元素比较,谁大谁就留在那个位置,就这样一直比较下去,直到叶子节点或者中途退出 +4. 如果删除的是叶子节点,或者取出的最后一个元素比删除的元素的子节点都大(还需要看是不是比删除元素的父节点也大,所以需要向上做堆化),就需要做一个从下向上的插入堆化过程 + +- poll peek contains + +这些操作都比较简单: +poll: 取堆顶元素,然后做一个从上到下的堆化过程,可以参考 remove 的 `siftDownComparable` 流程,时间复杂度O(logn) +peek: 取数组第一个元素返回即可,时间复杂度O(1) +contains: 遍历数组一遍,找是否有相等的元素,时间复杂度O(n) + +到此 `PriorityQueue` 的核心功能基本分析完成。 diff --git a/Week 01/id_721/LeetCode_1_721.java b/Week 01/id_721/LeetCode_1_721.java new file mode 100644 index 000000000..7c4622996 --- /dev/null +++ b/Week 01/id_721/LeetCode_1_721.java @@ -0,0 +1,26 @@ +package array; + +/** + * @author alis + * @date 2019/10/20 3:58 PM + * @description + */ +public class LC_01_TwoSum { + + /** + * 暴力循环 + * O(n^2) + * 中文网上使用哈希表的方式辅助判断有没有存在目标值的方式,说明时间复杂度是O(n), + * 但是没考虑到哈希表对数据结构对处理,包括了扩容,排序,哈希计算等开销,如果从源码角度分析,这种算法恐怕比O(n^2)的时间复杂度更大 + */ + public int[] twoSumLoop(int[] nums, int target) { + for (int i = 0; i < nums.length - 1; i++) { + for (int j = i + 1; j < nums.length; j++) { + if (nums[i] + nums[j] == target) { + return new int[]{i, j}; + } + } + } + return new int[0]; + } +} diff --git a/Week 01/id_721/LeetCode_26_721.java b/Week 01/id_721/LeetCode_26_721.java new file mode 100644 index 000000000..b95cff5fa --- /dev/null +++ b/Week 01/id_721/LeetCode_26_721.java @@ -0,0 +1,34 @@ +package array; + +/** + * 给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。 + *

+ * 不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。 + *

+ * 来源:力扣(LeetCode) + * 链接:https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array + * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + *

+ * 思路: + * 1. 遍历有序数组,用一个指针标记k标记k前面的数字都已去重;当遍历标记i遍历的时候,与前一位比较是否相等,如果相等,则k移动到当前 + *

+ * + * @author alis + * @date 2019/10/20 3:03 PM + * @description + */ +public class LC_26_RemoveDuplicatesFromSortedArray { + + public int removeDuplicates(int[] sortNums) { + int k = 0; + for (int i = 1; i < sortNums.length; i++) { + if (sortNums[i] != sortNums[i - 1]) { + sortNums[++k] = sortNums[i]; + } + + } + return k + 1; + + + } +} diff --git a/Week 01/id_721/LeetCode_283_721.java b/Week 01/id_721/LeetCode_283_721.java new file mode 100644 index 000000000..68fd25aec --- /dev/null +++ b/Week 01/id_721/LeetCode_283_721.java @@ -0,0 +1,99 @@ +package array; + +/** + * 思路 + * 1. ~~从前往后遍历数组,如果元素为0,~~~~则交换位置~~~~,将0位与最后一个非0位交换位置,直到将数据遍历到0的下标为止~~ + * 2. 遍历数组,0位提出来,后续元素向前移动位置,移动完了,把0元素位放在最后一位(14ms) + * 3. 用一个常量保存其实位置的0元素下标,遍历数组的时候,将非0元素与这个0下标的元素交换位置(1ms) + * + * @date 2019/10/16 12:21 AM + */ +public class LC_283_MoveZeroes { + + public static void main(String[] args) { + new LC_283_MoveZeroes().moveZeroes_twice_1016(new int[]{0, 0, 1}); + new LC_283_MoveZeroes().moveZeroes_twice_1016(new int[]{1, 0, 3, 12}); + } + + public void moveZeroes(int[] nums) { + int j = nums.length; + for (int i = 0; i < j; ) { + if (nums[i] == 0) { + int temp = nums[i]; + for (int i1 = i; i1 < j - 1; i1++) { + nums[i1] = nums[i1 + 1]; + } + nums[j - 1] = temp; + j--; + } else { + i++; + } + + } + for (int num : nums) { + System.out.println(num); + } + } + + public void moveZeroes1(int[] nums) { + int j = 0;//保存0元素下标 + for (int i = 0; i < nums.length; i++) { + if (nums[i] != 0) { + int temp = nums[i]; + nums[i] = nums[j]; + nums[j] = temp; + j++; + } + } + + for (int num : nums) { + System.out.println(num); + } + } + + public void moveZeroes3(int[] nums) { + int zeroIndex = 0; + for (int i = 0; i < nums.length; i++) { + if (nums[zeroIndex] != 0) { + zeroIndex++; + continue; + } + if (nums[i] != 0 && nums[zeroIndex] == 0) { + nums[zeroIndex++] = nums[i]; // 利用javap运算,减少代码量 + nums[i] = 0; + } + } + + for (int num : nums) { + System.out.println(num); + } + } + + /** + * @param nums 数组 + * @return void + * @author Rico + * @description 做第二遍; 卡壳了一阵,做题的时候只记得用i和j分别表示0位和非0位元素, + * 发现test case跑失败,愣了一下,不知所措,后来静下来分析l一下, + * j位也需要移动找到0位,因为有可能起始位不是0 + * @date 2019/10/17 1:39 AM + */ + public void moveZeroes_twice_1016(int[] nums) { + int j = 0; + for (int i = 1; i < nums.length; i++) { + if (nums[i] != 0 && nums[j] == 0) { + nums[j++] = nums[i]; + nums[i] = 0; + } + if (nums[j] != 0) { + j++; + } + } + System.out.println(); + for (int num : nums) { + System.out.print(num + ", "); + } + + } + +} diff --git a/Week 01/id_721/NOTE.md b/Week 01/id_721/NOTE.md index a6321d6e2..703fccb23 100644 --- a/Week 01/id_721/NOTE.md +++ b/Week 01/id_721/NOTE.md @@ -1,4 +1,37 @@ -# NOTE +# 第一周作业总结 +#### 练习过的题目 +1. LC_01_TwoSum + + 在思考思路的时候,因为之前老师讲解过,可以使用双指针的方式去将双循环将为单循环, + 但是最后考虑到,如果需要排序的话,那么返回的数组下标将不准确, 所以如果用这种双指针法去降低时间复杂度, + 还需要使用数组或者哈希辅助记录原来元素的数组,在确定目标数据之后,再取出元素的旧下标,返回; + 这样就是牺牲空间复杂度,来换取时间(也有可能会带来源码层面更大的时间复杂度消耗),故此路不通 + + 另外,在leetcode的国内站点或者国际站都出现用辅助哈希来降低时间复杂度为O(n), 但是这种解法的时间复杂度 + 并不为O(n), 在计算时间复杂度的时候,直接忽略了jdk源码处理哈希所带来的消耗 +2. LC_11_ContainWithMostWater + + 解法除了暴力枚举,还用到了双指针法,从边界遍历夹逼,寻找目标元素输出;并且双边指针也是根据计算结果来动态移动, + 这种方式比较巧妙 +3. LC_15_ThreeSum + + 3sum的暴力枚举写出来的代码超出来leetcode的时间限制 + + 双指针法将O(n^3)的复杂度将为O(n^2); 我觉得其中巧妙的地方处理使用双指针的方式去寻找元素之外, + 还有就是在双边指针移动的时候,很巧妙的利用了java运算的方式去避免相同值的元素重复计算`while (i < j && nums[i] == nums[++i]);` +4. LC_26_RemoveDuplicatesFromSortedArray + + 使用指针标记确认了非重复元素的位置,并在符合条件的时候,往后移动这个指针,数据只变更标记后面的元素信息; + 题目要求直接返回非重复元素的个数,所以直接将这个指针+1返回即可 +5. LC_70_ClimbingStairs + + 爬楼梯是一个涉及到动态规划的问题,这个题目对动态规划对感受不是很深, + 所以对斐波那契数列的规则计算的方式比较容易理解;而动态规划的算法,后面需要更加深刻的理解并练习 +6. LC_283_MoveZeroes + + 移动0位置这道题,当初自己写的时候,使用了swap来对调两个元素的位置,但是其实看了discuss之后,发现主要关注非0元素位置即可,而0元素位不需要处理 + +#### 个人总结 ++ 在预习周学习了刷题技巧之后,本周跟着老师的课程,实战进入了leetcode的刷题状态,避免了像以前一样, + 一道题看了题目之后,就埋头思考解法,结果耗费了很多时间,产生了自己一定要解出来,不然就是能力的问题, + 就这样陷入了死胡同,一直以来的挫败感压抑着,心中产生了对刷题特别是算法题的畏惧;而这两周的刷题技巧实战, + 让我纠正了这种心理 ++ 另外针对解题技巧,也积累了万能的暴力循环法、双指针法、还有遇到没头绪的题目可以用列举进行归纳找规律等思路,很受用 ++ 不过,反思了一下这周的算法学习以及刷题时间,这周自己都是在晚上十点以后,或者周末这种能够有大片时间的时段来学习及刷题 + 这样的话,既然自己无法利用碎片时间让自己学习,那就合理安排这种一大段时间来系统学习算法,只有这样静下来连续学习, + 才能系统的建立自己的知识架构;希望这个可能让我养成这个习惯,以后运用到别的专业知识的学习上 diff --git a/Week 01/id_731/LeetCode_1_731.py b/Week 01/id_731/LeetCode_1_731.py new file mode 100644 index 000000000..3e8af2d0b --- /dev/null +++ b/Week 01/id_731/LeetCode_1_731.py @@ -0,0 +1,6 @@ +class Solution(object): + def twoSum(self, nums, target): + lens = len(nums) + for i in range(lens): + if target - nums[i] in nums[i+1:]: + return [i, nums.index(target - nums[i], i+1)] \ No newline at end of file diff --git a/Week 01/id_731/LeetCode_283_731.py b/Week 01/id_731/LeetCode_283_731.py new file mode 100644 index 000000000..7bddc3029 --- /dev/null +++ b/Week 01/id_731/LeetCode_283_731.py @@ -0,0 +1,11 @@ +class Solution(object): + def moveZeroes(self, nums): + """ + :type nums: List[int] + :rtype: None Do not return anything, modify nums in-place instead. + """ + j = 0 + for i in range(len(nums)): + if nums[i] != 0: + nums[j], nums[i] = nums[i], nums[j] + j += 1 \ No newline at end of file diff --git a/Week 01/id_731/LeetCode_42_731.py b/Week 01/id_731/LeetCode_42_731.py new file mode 100644 index 000000000..ca1d087a4 --- /dev/null +++ b/Week 01/id_731/LeetCode_42_731.py @@ -0,0 +1,15 @@ +class Solution(object): + def trap(self, height): + """ + :type height: List[int] + :rtype: int + """ + total = 0 + for i in range(1,len(height)-1): + m1 = max(height[0:i]) + m2 = max(height[i+1:]) + mi = min(m1,m2) + if mi > height[i]: + total += mi - height[i] + + return total \ No newline at end of file diff --git a/Week 01/id_731/LeetCode_641_731.py b/Week 01/id_731/LeetCode_641_731.py new file mode 100644 index 000000000..30abce6b7 --- /dev/null +++ b/Week 01/id_731/LeetCode_641_731.py @@ -0,0 +1,89 @@ +class MyCircularDeque(object): + + def __init__(self, k): + """ + Initialize your data structure here. Set the size of the deque to be k. + :type k: int + """ + self.k = k + self.q = [] + + + def insertFront(self, value): + """ + Adds an item at the front of Deque. Return true if the operation is successful. + :type value: int + :rtype: bool + """ + if len(self.q) < self.k: + self.q.insert(0, value) + return True + return False + + + def insertLast(self, value): + """ + Adds an item at the rear of Deque. Return true if the operation is successful. + :type value: int + :rtype: bool + """ + if len(self.q) < self.k: + self.q.append(value) + return True + return False + + + def deleteFront(self): + """ + Deletes an item from the front of Deque. Return true if the operation is successful. + :rtype: bool + """ + return self.q.pop(0) <= float('inf') if self.q else False + + + def deleteLast(self): + """ + Deletes an item from the rear of Deque. Return true if the operation is successful. + :rtype: bool + """ + return self.q.pop() <= float('inf') if self.q else False + + def getFront(self): + """ + Get the front item from the deque. + :rtype: int + """ + return self.q[0] if self.q else -1 + + def getRear(self): + """ + Get the last item from the deque. + :rtype: int + """ + return self.q[-1] if self.q else -1 + + def isEmpty(self): + """ + Checks whether the circular deque is empty or not. + :rtype: bool + """ + return len(self.q) == 0 + + def isFull(self): + """ + Checks whether the circular deque is full or not. + :rtype: bool + """ + return len(self.q) == self.k + + +# Your MyCircularDeque object will be instantiated and called as such: +# obj = MyCircularDeque(k) +# param_1 = obj.insertFront(value) +# param_2 = obj.insertLast(value) +# param_3 = obj.deleteFront() +# param_4 = obj.deleteLast() +# param_5 = obj.getFront() +# param_6 = obj.getRear() +# param_7 = obj.isEmpty() +# param_8 = obj.isFull() \ No newline at end of file diff --git a/Week 01/id_736/LeetCode_11_736.go b/Week 01/id_736/LeetCode_11_736.go new file mode 100644 index 000000000..01124b0c8 --- /dev/null +++ b/Week 01/id_736/LeetCode_11_736.go @@ -0,0 +1,43 @@ +package id_736 + +func Min(a, b int) int { + if a < b { + return a + } + return b +} + +func Max(a, b int) int { + if a < b { + return b + } + return a +} +func maxArea(height []int) int { + //brute force O(n^2) + //right := len(height) + //maxValue := -1 + //for i := 1; i <= right-1; i++ { + // for j := i + 1; j <= right; j ++ { + // sum := ( j - i ) * Min(height[i-1], height[j-1]) + // if maxValue < sum { + // maxValue = sum + // } + // } + //} + //return maxValue + + arrayLen := len(height) + result := -1 + left := 0 + right := arrayLen-1 + for left < right { + result = Max(result, ( right - left ) * Min(height[right], height[left])) + if height[right] < height[left] { + right = right - 1 + } else { + left = left + 1 + } + } + return result +} \ No newline at end of file diff --git a/Week 01/id_736/LeetCode_189_736.go b/Week 01/id_736/LeetCode_189_736.go new file mode 100644 index 000000000..18e998597 --- /dev/null +++ b/Week 01/id_736/LeetCode_189_736.go @@ -0,0 +1,35 @@ +package id_736 + + +func rotateArrayBruteForce(nums []int, k int) { + for i := 0; i < k; i++ { + move(nums, len(nums)-1) + } +} + +func reverseThreeTimes(nums []int, k, numsLen int) { + k %= numsLen; + reverse(nums, 0, numsLen-1) + reverse(nums, 0, k-1) + reverse(nums, k, numsLen-1) +} + +func rotate(nums []int, k int) { + // rotateArrayBruteForce(nums, k) + reverseThreeTimes(nums, k, len(nums)) +} + +func move(nums []int, numsLen int) []int { + temp := nums[numsLen] + for j := numsLen; j > 0; j-- { + nums[j] = nums[j-1] + } + nums[0] = temp + return nums +} + +func reverse(s []int, start, end int) { + for i, j := start, end; i < j; i, j = i+1, j-1 { + s[i], s[j] = s[j], s[i] + } +} \ No newline at end of file diff --git a/Week 01/id_736/LeetCode_21_736.go b/Week 01/id_736/LeetCode_21_736.go new file mode 100644 index 000000000..62a045e50 --- /dev/null +++ b/Week 01/id_736/LeetCode_21_736.go @@ -0,0 +1,29 @@ +package id_736 + +/** + * Definition for singly-linked list. + * type ListNode struct { + * Val int + * Next *ListNode + * } + */ + +func mergeTwoLists(l1 *ListNode, l2 *ListNode) *ListNode { + if l1 == nil { + return l2 + } + if l2 == nil { + return l1 + } + + if l1.Val < l2.Val { + l1.Next = mergeTwoLists(l1.Next, l2) + return l1 + } else { + l2.Next = mergeTwoLists(l1, l2.Next) + return l2 + } +} + + + diff --git a/Week 01/id_751/LeetCode_189_751.java b/Week 01/id_751/LeetCode_189_751.java new file mode 100644 index 000000000..484b6e7e8 --- /dev/null +++ b/Week 01/id_751/LeetCode_189_751.java @@ -0,0 +1,40 @@ +/** + * 旋转数组 + * + * 给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数。 + * + * 示例 1: + * + * 输入: [1,2,3,4,5,6,7] 和 k = 3 + * 输出: [5,6,7,1,2,3,4] + * 解释: + * 向右旋转 1 步: [7,1,2,3,4,5,6] + * 向右旋转 2 步: [6,7,1,2,3,4,5] + * 向右旋转 3 步: [5,6,7,1,2,3,4] + * 示例 2: + * + * 输入: [-1,-100,3,99] 和 k = 2 + * 输出: [3,99,-1,-100] + * 解释: + * 向右旋转 1 步: [99,-1,-100,3] + * 向右旋转 2 步: [3,99,-1,-100] + * 说明: + * + * 尽可能想出更多的解决方案,至少有三种不同的方法可以解决这个问题。 + * 要求使用空间复杂度为 O(1) 的 原地 算法。 + * + */ +class Solution { + public void rotate(int[] nums, int k) { + int n = nums.length; + k = k % n; + for(int j = 0; j < k; j++) { + int prev = nums[n-1]; + for (int i = 0; i < n; i++) { + int tmp = nums[i]; + nums[i] = prev; + prev = tmp; + } + } + } +} \ No newline at end of file diff --git a/Week 01/id_751/LeetCode_1_751.java b/Week 01/id_751/LeetCode_1_751.java new file mode 100644 index 000000000..8a4a79ee4 --- /dev/null +++ b/Week 01/id_751/LeetCode_1_751.java @@ -0,0 +1,28 @@ +/** + * 两数之和 + * + * 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。 + * + * 你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。 + * + * 示例: + * + * 给定 nums = [2, 7, 11, 15], target = 9 + * + * 因为 nums[0] + nums[1] = 2 + 7 = 9 + * 所以返回 [0, 1] + * + */ + +class Solution { + public int[] twoSum(int[] nums, int target) { + int i,j = 0; + for(i=0; i2->4, 1->3->4 + * 输出:1->1->2->3->4->4 + * + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode(int x) { val = x; } + * } + */ +class Solution { + public ListNode mergeTwoLists(ListNode l1, ListNode l2) { + if (l1 == null) { + return l2; + } + if (l2 == null) { + return l1; + } + if (l1.val < l2.val) { + l1.next = mergeTwoLists(l1.next, l2); + return l1; + } else { + l2.next = mergeTwoLists(l2.next, l1); + return l2; + } + + } +} \ No newline at end of file diff --git a/Week 01/id_751/LeetCode_26_751.java b/Week 01/id_751/LeetCode_26_751.java new file mode 100644 index 000000000..20904ef63 --- /dev/null +++ b/Week 01/id_751/LeetCode_26_751.java @@ -0,0 +1,46 @@ +package com.hao; +import java.util.Arrays; + +/** + * 删除排序数组中的重复项 + * + * 给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。 + * + * 不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。 + * + * 示例 1: + * + * 给定数组 nums = [1,1,2], + * + * 函数应该返回新的长度 2, 并且原数组 nums 的前两个元素被修改为 1, 2。 + * + * 你不需要考虑数组中超出新长度后面的元素。 + * 示例 2: + * + * 给定 nums = [0,0,1,1,1,2,2,3,3,4], + * + * 函数应该返回新的长度 5, 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4。 + * + * 你不需要考虑数组中超出新长度后面的元素。 + * + */ +public class LeetCode_26_751 { + + public int removeDuplicates(int[] nums) { + int i = 0; + for (int j = 1; j < nums.length; j++) { + if (nums[i] != nums[j]) + nums[++i] = nums[j]; + } + return i + 1; + } + + public static void main(String[] args) { + // write your code here + LeetCode_26_751 rd = new LeetCode_26_751(); + int[] nums = new int[]{0, 0, 1, 1, 1, 2, 2, 3, 3, 4}; + System.out.println(Arrays.toString(nums)); + System.out.println(rd.removeDuplicates(nums)); + System.out.println(Arrays.toString(nums)); + } +} diff --git a/Week 01/id_751/LeetCode_283_751.java b/Week 01/id_751/LeetCode_283_751.java new file mode 100644 index 000000000..414185958 --- /dev/null +++ b/Week 01/id_751/LeetCode_283_751.java @@ -0,0 +1,27 @@ +/** + * 移动零 + * 给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。 + * + * 示例: + * + * 输入: [0,1,0,3,12] + * 输出: [1,3,12,0,0] + * 说明: + * + * 必须在原数组上操作,不能拷贝额外的数组。 + * 尽量减少操作次数。 + */ + +class Solution { + public void moveZeroes(int[] nums) { + int i = 0; + for (int j = 0; j < nums.length; j++) { + if (nums[j] != 0) { + nums[i++] = nums[j]; + } + } + for (int k = i; k < nums.length; k++) { + nums[k] = 0; + } + } +} \ No newline at end of file diff --git a/Week 01/id_751/LeetCode_42_751.java b/Week 01/id_751/LeetCode_42_751.java new file mode 100644 index 000000000..0a5d63aaa --- /dev/null +++ b/Week 01/id_751/LeetCode_42_751.java @@ -0,0 +1,48 @@ +/** + * 接雨水 + * 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。 + * + * 上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水) + * + * 示例: + * + * 输入: [0,1,0,2,1,0,1,3,2,1,2,1] + * 输出: 6 + * + */ + +class Solution { + public int trap(int[] height) { + int result = 0; + + //find the highest value/position + int maxHigh = 0; + int maxIdx = 0; + for (int i = 0; i < height.length; i++) { + if (height[i] > maxHigh){ + maxHigh = height[i]; + maxIdx = i; + } + } + + //from the left to the highest postion + int prevHigh = 0; + for (int i = 0; i < maxIdx; i++) { + if(height[i] > prevHigh){ + prevHigh = height[i]; + } + result += (prevHigh - height[i]); + } + + //from the right to the highest postion + prevHigh=0; + for (int i = height.length-1; i > maxIdx; i--) { + if(height[i] > prevHigh) { + prevHigh = height[i]; + } + result += (prevHigh - height[i]); + } + + return result; + } +} \ No newline at end of file diff --git a/Week 01/id_751/LeetCode_641_751.java b/Week 01/id_751/LeetCode_641_751.java new file mode 100644 index 000000000..b901711f2 --- /dev/null +++ b/Week 01/id_751/LeetCode_641_751.java @@ -0,0 +1,118 @@ +/** + * 设计实现双端队列。 + * 你的实现需要支持以下操作: + * + * MyCircularDeque(k):构造函数,双端队列的大小为k。 + * insertFront():将一个元素添加到双端队列头部。 如果操作成功返回 true。 + * insertLast():将一个元素添加到双端队列尾部。如果操作成功返回 true。 + * deleteFront():从双端队列头部删除一个元素。 如果操作成功返回 true。 + * deleteLast():从双端队列尾部删除一个元素。如果操作成功返回 true。 + * getFront():从双端队列头部获得一个元素。如果双端队列为空,返回 -1。 + * getRear():获得双端队列的最后一个元素。 如果双端队列为空,返回 -1。 + * isEmpty():检查双端队列是否为空。 + * isFull():检查双端队列是否满了。 + * 示例: + * + * MyCircularDeque circularDeque = new MycircularDeque(3); // 设置容量大小为3 + * circularDeque.insertLast(1); // 返回 true + * circularDeque.insertLast(2); // 返回 true + * circularDeque.insertFront(3); // 返回 true + * circularDeque.insertFront(4); // 已经满了,返回 false + * circularDeque.getRear(); // 返回 2 + * circularDeque.isFull(); // 返回 true + * circularDeque.deleteLast(); // 返回 true + * circularDeque.insertFront(4); // 返回 true + * circularDeque.getFront(); // 返回 4 + *   + *   + * + * 提示: + * + * 所有值的范围为 [1, 1000] + * 操作次数的范围为 [1, 1000] + * 请不要使用内置的双端队列库。 + * + */ +class MyCircularDeque { + int[] deque; + int front, rear, capacity; + /** Initialize your data structure here. Set the size of the deque to be k. */ + public MyCircularDeque(int k) { + this.deque = new int[k+1]; + this.front = 0; + this.rear = 0; + this.capacity = k + 1; + } + + /** Adds an item at the front of Deque. Return true if the operation is successful. */ + public boolean insertFront(int value) { + if (isFull()) { + return false; + } + deque[front] = value; + front = (front + 1) % capacity; + + return true; + } + + /** Adds an item at the rear of Deque. Return true if the operation is successful. */ + public boolean insertLast(int value) { + if (isFull()) { + return false; + } + rear = (rear - 1 + capacity) % capacity; + deque[rear] = value; + return true; + } + + /** Deletes an item from the front of Deque. Return true if the operation is successful. */ + public boolean deleteFront() { + if (isEmpty()) { + return false; + } + front = (front - 1 + capacity) % capacity; + return true; + } + + /** Deletes an item from the rear of Deque. Return true if the operation is successful. */ + public boolean deleteLast() { + if (isEmpty()) { + return false; + } + rear = (rear + 1) % capacity; + return true; + } + + /** Get the front item from the deque. */ + public int getFront() { + return isEmpty() ? -1 : deque[(front - 1 + capacity) % capacity]; + } + + /** Get the last item from the deque. */ + public int getRear() { + return isEmpty() ? -1 : deque[rear]; + } + + /** Checks whether the circular deque is empty or not. */ + public boolean isEmpty() { + return front == rear; + } + + /** Checks whether the circular deque is full or not. */ + public boolean isFull() { + return (front + 1) % capacity == rear; + } +} + +/** + * 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(); + */ \ No newline at end of file diff --git a/Week 01/id_751/LeetCode_66_751.java b/Week 01/id_751/LeetCode_66_751.java new file mode 100644 index 000000000..f148e5733 --- /dev/null +++ b/Week 01/id_751/LeetCode_66_751.java @@ -0,0 +1,34 @@ +/** + * plus one + * 给定一个由整数组成的非空数组所表示的非负整数,在该数的基础上加一。 + * + * 最高位数字存放在数组的首位, 数组中每个元素只存储单个数字。 + * + * 你可以假设除了整数 0 之外,这个整数不会以零开头。 + * + * 示例 1: + * + * 输入: [1,2,3] + * 输出: [1,2,4] + * 解释: 输入数组表示数字 123。 + * + */ + +class Solution { + public int[] plusOne(int[] digits) { + int len = digits.length; + + for(int i = len-1; i>=0 ;i--) { + digits[i] += 1; + if( digits[i] % 10 != 0 ) { + return digits; + } else { + digits[i] = 0; + } + + } + int[] luckyDigits = new int[len + 1]; + luckyDigits[0] = 1; + return luckyDigits; + } +} diff --git a/Week 01/id_751/LeetCode_88_751.java b/Week 01/id_751/LeetCode_88_751.java new file mode 100644 index 000000000..93df1b364 --- /dev/null +++ b/Week 01/id_751/LeetCode_88_751.java @@ -0,0 +1,26 @@ +/** + * 合并两个有序数组 + * + * 给定两个有序整数数组 nums1 和 nums2,将 nums2 合并到 nums1 中,使得 num1 成为一个有序数组。 + * + * 说明: + * + * 初始化 nums1 和 nums2 的元素数量分别为 m 和 n。 + * 你可以假设 nums1 有足够的空间(空间大小大于或等于 m + n)来保存 nums2 中的元素。 + * 示例: + * + * 输入: + * nums1 = [1,2,3,0,0,0], m = 3 + * nums2 = [2,5,6], n = 3 + * + * 输出: [1,2,2,3,5,6] + * + */ + +class Solution { + public void merge(int[] nums1, int m, int[] nums2, int n) { + System.arraycopy(nums2, 0, nums1, m, n); + Arrays.sort(nums1); + } +} +// public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length) diff --git "a/Week 01/id_756/1.\345\210\240\351\231\244\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\351\207\215\345\244\215\351\241\271.java" "b/Week 01/id_756/1.\345\210\240\351\231\244\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\351\207\215\345\244\215\351\241\271.java" new file mode 100644 index 000000000..be03c9414 --- /dev/null +++ "b/Week 01/id_756/1.\345\210\240\351\231\244\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\351\207\215\345\244\215\351\241\271.java" @@ -0,0 +1,56 @@ +//给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。 +// +// 不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。 +// +// 示例 1: +// +// 给定数组 nums = [1,1,2], +// +//函数应该返回新的长度 2, 并且原数组 nums 的前两个元素被修改为 1, 2。 +// +//你不需要考虑数组中超出新长度后面的元素。 +// +// 示例 2: +// +// 给定 nums = [0,0,1,1,1,2,2,3,3,4], +// +//函数应该返回新的长度 5, 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4。 +// +//你不需要考虑数组中超出新长度后面的元素。 +// +// +// 说明: +// +// 为什么返回数值是整数,但输出的答案是数组呢? +// +// 请注意,输入数组是以“引用”方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。 +// +// 你可以想象内部操作如下: +// +// // nums 是以“引用”方式传递的。也就是说,不对实参做任何拷贝 +//int len = removeDuplicates(nums); +// +//// 在函数里修改输入数组对于调用者是可见的。 +//// 根据你的函数返回的长度, 它会打印出数组中该长度范围内的所有元素。 +//for (int i = 0; i < len; i++) { +//    print(nums[i]); +//} +// +// Related Topics 数组 双指针 + + +//leetcode submit region begin(Prohibit modification and deletion) +class Solution { + public int removeDuplicates(int[] nums) { + int i = 0; + for (int j = 1; j < nums.length; j++) { + if (nums[j] != nums[i]) { + nums[i + 1] = nums[j]; + i++; + } + + } + return i + 1; + } +} +//leetcode submit region end(Prohibit modification and deletion) diff --git "a/Week 01/id_756/2.\346\227\213\350\275\254\346\225\260\347\273\204.java" "b/Week 01/id_756/2.\346\227\213\350\275\254\346\225\260\347\273\204.java" new file mode 100644 index 000000000..68020006e --- /dev/null +++ "b/Week 01/id_756/2.\346\227\213\350\275\254\346\225\260\347\273\204.java" @@ -0,0 +1,53 @@ +//给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数。 +// +// 示例 1: +// +// 输入: [1,2,3,4,5,6,7] 和 k = 3 +//输出: [5,6,7,1,2,3,4] +//解释: +//向右旋转 1 步: [7,1,2,3,4,5,6] +//向右旋转 2 步: [6,7,1,2,3,4,5] +//向右旋转 3 步: [5,6,7,1,2,3,4] +// +// +// 示例 2: +// +// 输入: [-1,-100,3,99] 和 k = 2 +//输出: [3,99,-1,-100] +//解释: +//向右旋转 1 步: [99,-1,-100,3] +//向右旋转 2 步: [3,99,-1,-100] +// +// 说明: +// +// +// 尽可能想出更多的解决方案,至少有三种不同的方法可以解决这个问题。 +// 要求使用空间复杂度为 O(1) 的 原地 算法。 +// +// Related Topics 数组 + + + +//leetcode submit region begin(Prohibit modification and deletion) +class Solution { + public void rotate(int[] nums, int k) { + //k不能大于数组长度 + k = k % nums.length ; + //翻转0到length-1 + reverse(nums,0,nums.length-1); + //翻转0到k-1 + reverse(nums,0,k-1); + //翻转k到length-1 + reverse(nums,k,nums.length-1); + } + public void reverse(int[] nums,int start,int end){ + while (start < end) { + int stemp = nums[end]; + nums[end] = nums[start]; + nums[start] = stemp; + start++; + end--; + } + } +} +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week 03/id_561/LeetCode_189_561.cpp b/Week 03/id_561/LeetCode_189_561.cpp new file mode 100644 index 000000000..64a0fd531 --- /dev/null +++ b/Week 03/id_561/LeetCode_189_561.cpp @@ -0,0 +1,91 @@ +// 旋转数组 +// +// 给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数。 +// +// 示例 1: +// +// 输入: [1,2,3,4,5,6,7] 和 k = 3 +// 输出: [5,6,7,1,2,3,4] +// 解释: +// 向右旋转 1 步: [7,1,2,3,4,5,6] +// 向右旋转 2 步: [6,7,1,2,3,4,5] +// 向右旋转 3 步: [5,6,7,1,2,3,4] +// 示例 2: +// +// 输入: [-1,-100,3,99] 和 k = 2 +// 输出: [3,99,-1,-100] +// 解释: +// 向右旋转 1 步: [99,-1,-100,3] +// 向右旋转 2 步: [3,99,-1,-100] +// 说明: +// +// 尽可能想出更多的解决方案,至少有三种不同的方法可以解决这个问题。 +// 要求使用空间复杂度为 O(1) 的 原地 算法。 +// +// 来源:力扣(LeetCode) +// 链接:https://leetcode-cn.com/problems/rotate-array +// 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + +// 这道题用了两种方法求解, 第一种解法用了 24ms, 第二种解法用了 32ms + +// 解法 1: 循环交换 +class Solution { +public: + void rotate(vector& nums, int k) { + // 计算等价的 k 值 + k = k % nums.size(); + int count = 0; + if (nums.size() == 0 || k == 0) return; + int j = 0; + + // 有时候环状交换会形成 loop, 无法遍历整个数组, 此时将起点递增迭代即可, 直到全部元素被替换成功 + while (count < nums.size()) { + loop_rotate(nums, j, k, count); + j++; + } + } + + void loop_rotate(vector &nums, int start_index, int k, int &count) { + int i = start_index; + int mem = nums[i]; + while (true) { + // 计算最终的位置 + int final_index = (i + k) % nums.size(); + + // 交换 mem 和 nums[final_index] + int mem_temp = nums[final_index]; + nums[final_index] = mem; + mem = mem_temp; + + count++; + i = final_index; + if (i == start_index) break; + } + } +}; + +// 解法 2: 交换法 +class SolutionV2 { +public: + void rotate(vector& nums, int k) { + // 计算等价的 k 值 + k = k % nums.size(); + if (nums.size() == 0 || k == 0) return; + + reverse(nums, 0, nums.size()-1); + reverse(nums, 0, k-1); + reverse(nums, k, nums.size()-1); + } + + void reverse(vector &nums, int start_index, int end_index) { + if (start_index == end_index) return; + + for (int i = start_index, j = end_index; i < j; ) { + int temp = nums[i]; + nums[i] = nums[j]; + nums[j] = temp; + i++, j--; + } + } +}; + diff --git a/Week 03/id_561/LeetCode_1_561.cpp b/Week 03/id_561/LeetCode_1_561.cpp new file mode 100644 index 000000000..78b8c7265 --- /dev/null +++ b/Week 03/id_561/LeetCode_1_561.cpp @@ -0,0 +1,82 @@ +// 两数之和 +// +// 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。 +// +// 你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。 +// +// 示例: +// +// 给定 nums = [2, 7, 11, 15], target = 9 +// +// 因为 nums[0] + nums[1] = 2 + 7 = 9 +// 所以返回 [0, 1] +// +// 来源:力扣(LeetCode) +// 链接:https://leetcode-cn.com/problems/two-sum +// 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + +// 这道题我用了两种方法来做, 一种是排序 + 双指针, 另一种是用哈希表 +// 算法的时间复杂度, 前者是 O(N*logN), 后者是 O(N), +// 但是实际提交后, 前者只用了 4ms, 后者是 8ms, 可能跟哈希表的创建耗时有关系 + +// 第一种方法: +// 因为想通过双指针来做, 需要先对数组做排序, 所以创建一个类来保存数组元素的 value 和 index +struct Number { + int value; + int index; + + Number(int value, int index) { + this->value = value; + this->index = index; + } +}; + +class Solution { +public: + vector twoSum(vector& nums, int target) { + vector input; + int i = 0; + for (auto &a : nums) { + input.push_back(Number(a, i++)); + } + + // 排序 + sort(input.begin(), input.end(), [](Number x, Number y) { return x.value < y.value; }); + + int left = 0; + int right = input.size() - 1; + vector result = {}; + + while (left < right) { + int sum = input[left].value + input[right].value; + if (sum == target) { + result.push_back(input[left].index); + result.push_back(input[right].index); + return result; + } else if (sum < target) { + left++; + } else { + right--; + } + } + + return result; + } +}; + +// 第二种方法: +// 用哈希表来保存 table[target - nums[i]] -> i +class SolutionV2 { +public: + vector twoSum(vector& nums, int target) { + unordered_map mem; + + for (int i = 0; i < nums.size(); i++) { + if (mem.find(target - nums[i]) != mem.end()) + return vector ({mem[target - nums[i]], i}); + mem[nums[i]] = i; + } + + return vector({-1, -1}); + } +}; diff --git a/Week 03/id_561/LeetCode_26_561.cpp b/Week 03/id_561/LeetCode_26_561.cpp new file mode 100644 index 000000000..eef604d81 --- /dev/null +++ b/Week 03/id_561/LeetCode_26_561.cpp @@ -0,0 +1,88 @@ +// 删除排序数组中的重复项 +// +// 给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。 +// +// 不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。 +// +// 示例 1: +// +// 给定数组 nums = [1,1,2], +// +// 函数应该返回新的长度 2, 并且原数组 nums 的前两个元素被修改为 1, 2。 +// +// 你不需要考虑数组中超出新长度后面的元素。 +// 示例 2: +// +// 给定 nums = [0,0,1,1,1,2,2,3,3,4], +// +// 函数应该返回新的长度 5, 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4。 +// +// 你不需要考虑数组中超出新长度后面的元素。 +// 说明: +// +// 为什么返回数值是整数,但输出的答案是数组呢? +// +// 请注意,输入数组是以“引用”方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。 +// +// 你可以想象内部操作如下: +// +// // nums 是以“引用”方式传递的。也就是说,不对实参做任何拷贝 +// int len = removeDuplicates(nums); +// +// // 在函数里修改输入数组对于调用者是可见的。 +// // 根据你的函数返回的长度, 它会打印出数组中该长度范围内的所有元素。 +// for (int i = 0; i < len; i++) { +//     print(nums[i]); +// } +// +// 来源:力扣(LeetCode) +// 链接:https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array +// 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + +// 这道题我用了两种解法, +// 第一种是常规的 O(N) 解法, 耗时 24ms, +// 第二种略作优化, 设置一个 bool 变量, 记录数组中是否存在重复项, 只有存在重复项时才拷贝值, 耗时 20ms + +class Solution { +public: + int removeDuplicates(vector& nums) { + if (nums.size() == 0) return 0; + + int index_final = 0; + + for (int i = 1; i < nums.size(); i++) { + // look back + if (nums[i] == nums[i - 1]) + continue; + index_final++; + nums[index_final] = nums[i]; + } + + return index_final + 1; + } +}; + +// 方法 2: 只有存在重复项才拷贝值, 节省了 4ms +class SolutionV2 { +public: + int removeDuplicates(vector& nums) { + if (nums.size() == 0) return 0; + + bool duplicated_exist = false; + int index_final = 0; + + for (int i = 1; i < nums.size(); i++) { + // look back + if (nums[i] == nums[i - 1]) { + if (!duplicated_exist) + duplicated_exist = true; + continue; + } + index_final++; + if (duplicated_exist) + nums[index_final] = nums[i]; + } + + return index_final + 1; + } +}; diff --git a/Week 03/id_561/LeetCode_283_561.cpp b/Week 03/id_561/LeetCode_283_561.cpp new file mode 100644 index 000000000..76da75918 --- /dev/null +++ b/Week 03/id_561/LeetCode_283_561.cpp @@ -0,0 +1,48 @@ +// 移动零 +// +// 给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。 +// +// 示例: +// +// 输入: [0,1,0,3,12] +// 输出: [1,3,12,0,0] +// +// 来源:力扣(LeetCode) +// 链接:https://leetcode-cn.com/problems/move-zeroes +// 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 +// +// +// 用了两种解法, 解法 1 和 2 原理一样, 都是双指针 (快慢指针), 只是 2 使用元素交换来简化代码, 两者执行时间一致 + +class Solution { +public: + void moveZeroes(vector& nums) { + int left_index = 0; + int right_index = 0; + + for (; right_index < nums.size(); right_index++) { + if (nums[right_index] == 0) + continue; + + if (left_index != right_index) + nums[left_index++] = nums[right_index]; + else + left_index++; + } + + for (int j = left_index; j < nums.size(); j++) { + nums[j] = 0; + } + } +}; + +class SolutionV2 { +public: + void moveZeroes(vector &nums) { + for (int lastNonZeroFoundAt = 0, cur = 0; cur < nums.size(); cur++) { + if (nums[cur] != 0) { + swap(nums[lastNonZeroFoundAt++], nums[cur]); + } + } + } +}; diff --git a/Week 03/id_561/LeetCode_66_561.cpp b/Week 03/id_561/LeetCode_66_561.cpp new file mode 100644 index 000000000..91271863e --- /dev/null +++ b/Week 03/id_561/LeetCode_66_561.cpp @@ -0,0 +1,69 @@ +// 加一 +// +// 给定一个由整数组成的非空数组所表示的非负整数,在该数的基础上加一。 +// +// 最高位数字存放在数组的首位, 数组中每个元素只存储单个数字。 +// +// 你可以假设除了整数 0 之外,这个整数不会以零开头。 +// +// 示例 1: +// +// 输入: [1,2,3] +// 输出: [1,2,4] +// 解释: 输入数组表示数字 123。 +// 示例 2: +// +// 输入: [4,3,2,1] +// 输出: [4,3,2,2] +// 解释: 输入数组表示数字 4321。 +// +// 来源:力扣(LeetCode) +// 链接:https://leetcode-cn.com/problems/plus-one +// 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + +// 这道题用了两种解法, 算法复杂度一致, 但是第二种参考了题解中的代码, 更加简洁高效, 执行时间分别是 4ms 和 0ms. + +class Solution { +public: + vector plusOne(vector& digits) { + int count = 0; + for (int i = 0; i < digits.size(); i++) { + if (digits[i] != 9) break; + count++; + } + + if (count == digits.size()) { + vector result = vector (count + 1, 0); + result[0] = 1; + return result; + } + + digits[digits.size() - 1] += 1; + + for (int i = digits.size() - 1; i > 0; i--) { + int cur_digit = digits[i]; + if (cur_digit > 9) { + digits[i - 1] += digits[i] / 10; + digits[i] = digits[i] % 10; + } + } + + return digits; + } +}; + +class SolutionV2 { +public: + vector plusOne(vector& digits) { + for (int i = digits.size() - 1; i >= 0; i--) { + digits[i]++; + digits[i] = digits[i] % 10; + if (digits[i] != 0) return digits; + } + + vector result = vector(digits.size() + 1, 0); + result[0] = 1; + + return result; + } +}; diff --git "a/Week \351\242\204\344\271\240\345\221\250/id_021/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225\346\200\273\350\247\210.xmind" "b/Week \351\242\204\344\271\240\345\221\250/id_021/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225\346\200\273\350\247\210.xmind" new file mode 100644 index 000000000..c75205542 Binary files /dev/null and "b/Week \351\242\204\344\271\240\345\221\250/id_021/\346\225\260\346\215\256\347\273\223\346\236\204\345\222\214\347\256\227\346\263\225\346\200\273\350\247\210.xmind" differ diff --git "a/Week \351\242\204\344\271\240\345\221\250/id_076/NOTE.md" "b/Week \351\242\204\344\271\240\345\221\250/id_076/NOTE.md" index a6321d6e2..058f717c8 100644 --- "a/Week \351\242\204\344\271\240\345\221\250/id_076/NOTE.md" +++ "b/Week \351\242\204\344\271\240\345\221\250/id_076/NOTE.md" @@ -1,4 +1,14 @@ # NOTE - +windows 下提高效率快捷键 +fn + left[home] 跳转到行首 +fn + right[end] 跳转到行尾 +fn + e 查看最近编辑文件 + +code clean, 自上而下编程 + +最重要的 LeetCode 完成300题,需要学会 + +刻意练习,五毒神掌 +面试算法 4步法 diff --git "a/Week \351\242\204\344\271\240\345\221\250/id_076/\346\225\260\346\215\256\347\273\223\346\236\204.png" "b/Week \351\242\204\344\271\240\345\221\250/id_076/\346\225\260\346\215\256\347\273\223\346\236\204.png" new file mode 100644 index 000000000..98b3b0566 Binary files /dev/null and "b/Week \351\242\204\344\271\240\345\221\250/id_076/\346\225\260\346\215\256\347\273\223\346\236\204.png" differ diff --git "a/Week \351\242\204\344\271\240\345\221\250/id_076/\347\256\227\346\263\225.png" "b/Week \351\242\204\344\271\240\345\221\250/id_076/\347\256\227\346\263\225.png" new file mode 100644 index 000000000..1c8763d73 Binary files /dev/null and "b/Week \351\242\204\344\271\240\345\221\250/id_076/\347\256\227\346\263\225.png" differ diff --git "a/Week \351\242\204\344\271\240\345\221\250/id_091/\351\242\204\344\271\240\345\221\250.png" "b/Week \351\242\204\344\271\240\345\221\250/id_091/\351\242\204\344\271\240\345\221\250.png" new file mode 100644 index 000000000..c23cf05c8 Binary files /dev/null and "b/Week \351\242\204\344\271\240\345\221\250/id_091/\351\242\204\344\271\240\345\221\250.png" differ diff --git "a/Week \351\242\204\344\271\240\345\221\250/id_176/NOTE.md" "b/Week \351\242\204\344\271\240\345\221\250/id_176/NOTE.md" index a6321d6e2..e4b63cfd4 100644 --- "a/Week \351\242\204\344\271\240\345\221\250/id_176/NOTE.md" +++ "b/Week \351\242\204\344\271\240\345\221\250/id_176/NOTE.md" @@ -1,4 +1,32 @@ # NOTE - +## IDE键盘快捷操作技巧(Mac) + +`fn + delete` : 删除光标右侧 + +`command + left / right` : 光标移至行头、行尾 + +`option + left / right` : 光标按单词切分 + +`option + delete` : 向光标左侧删除单词 + +`fn + option + delete` : 向光标右侧删除单词 + +`commond + delete` : 向光标左侧删除至行头 + +`fn + commond + delete` : 向光标右侧删除至行尾 + +`shift + command + left / right` : 选中光标所在行内容至行头、行尾 + +`shift + option + left / right` : 选中光标所在单词至头部、尾部 + + +Top tips for \ + +自顶向下编程方式:先写好主干逻辑,再写细节。 + + + + + diff --git "a/Week \351\242\204\344\271\240\345\221\250/id_196/\346\225\260\346\215\256\347\273\223\346\236\204.url" "b/Week \351\242\204\344\271\240\345\221\250/id_196/\346\225\260\346\215\256\347\273\223\346\236\204.url" new file mode 100644 index 000000000..11b8fb86c --- /dev/null +++ "b/Week \351\242\204\344\271\240\345\221\250/id_196/\346\225\260\346\215\256\347\273\223\346\236\204.url" @@ -0,0 +1,5 @@ +[{000214A0-0000-0000-C000-000000000046}] +Prop3=19,2 +[InternetShortcut] +IDList= +URL=http://naotu.baidu.com/file/85fcf71941d7fc540526942049fc1387?token=d6462e936c7d1d75 diff --git "a/Week \351\242\204\344\271\240\345\221\250/id_196/\347\256\227\346\263\225.url" "b/Week \351\242\204\344\271\240\345\221\250/id_196/\347\256\227\346\263\225.url" new file mode 100644 index 000000000..d22d1eefa --- /dev/null +++ "b/Week \351\242\204\344\271\240\345\221\250/id_196/\347\256\227\346\263\225.url" @@ -0,0 +1,5 @@ +[{000214A0-0000-0000-C000-000000000046}] +Prop3=19,2 +[InternetShortcut] +IDList= +URL=http://naotu.baidu.com/file/f1c6adb0286848fba789a365fbd92774?token=2d6371d673673807 diff --git "a/Week \351\242\204\344\271\240\345\221\250/id_321/NOTE.md" "b/Week \351\242\204\344\271\240\345\221\250/id_321/NOTE.md" index a6321d6e2..960108193 100644 --- "a/Week \351\242\204\344\271\240\345\221\250/id_321/NOTE.md" +++ "b/Week \351\242\204\344\271\240\345\221\250/id_321/NOTE.md" @@ -1,4 +1,4 @@ # NOTE - +嘻嘻嘻 diff --git "a/Week \351\242\204\344\271\240\345\221\250/id_346/TKQ\347\232\204\346\225\260\346\215\256\347\273\223\346\236\204\345\244\247\347\272\262.xmind" "b/Week \351\242\204\344\271\240\345\221\250/id_346/TKQ\347\232\204\346\225\260\346\215\256\347\273\223\346\236\204\345\244\247\347\272\262.xmind" new file mode 100644 index 000000000..bd44f3d75 Binary files /dev/null and "b/Week \351\242\204\344\271\240\345\221\250/id_346/TKQ\347\232\204\346\225\260\346\215\256\347\273\223\346\236\204\345\244\247\347\272\262.xmind" differ diff --git "a/Week \351\242\204\344\271\240\345\221\250/id_346/TKQ\347\232\204\347\256\227\346\263\225\345\244\247\347\272\262.xmind" "b/Week \351\242\204\344\271\240\345\221\250/id_346/TKQ\347\232\204\347\256\227\346\263\225\345\244\247\347\272\262.xmind" new file mode 100644 index 000000000..1a2906813 Binary files /dev/null and "b/Week \351\242\204\344\271\240\345\221\250/id_346/TKQ\347\232\204\347\256\227\346\263\225\345\244\247\347\272\262.xmind" differ diff --git "a/Week \351\242\204\344\271\240\345\221\250/id_386/\346\225\260\346\215\256\347\273\223\346\236\204.png" "b/Week \351\242\204\344\271\240\345\221\250/id_386/\346\225\260\346\215\256\347\273\223\346\236\204.png" new file mode 100644 index 000000000..eab5972eb Binary files /dev/null and "b/Week \351\242\204\344\271\240\345\221\250/id_386/\346\225\260\346\215\256\347\273\223\346\236\204.png" differ diff --git "a/Week \351\242\204\344\271\240\345\221\250/id_386/\347\256\227\346\263\225.png" "b/Week \351\242\204\344\271\240\345\221\250/id_386/\347\256\227\346\263\225.png" new file mode 100644 index 000000000..86f668bfd Binary files /dev/null and "b/Week \351\242\204\344\271\240\345\221\250/id_386/\347\256\227\346\263\225.png" differ diff --git "a/Week \351\242\204\344\271\240\345\221\250/id_451/NOTE.md" "b/Week \351\242\204\344\271\240\345\221\250/id_451/NOTE.md" index a6321d6e2..65c94c4ff 100644 --- "a/Week \351\242\204\344\271\240\345\221\250/id_451/NOTE.md" +++ "b/Week \351\242\204\344\271\240\345\221\250/id_451/NOTE.md" @@ -1,4 +1,11 @@ # NOTE - +# 学习方法 +用脑图整理知识点 +五遍刷题法 +leetcode 上通过国际战查看国际讨论 + +# 时间复杂度分析 +主定理 +根据n的值推断执行次数 diff --git "a/Week \351\242\204\344\271\240\345\221\250/id_451/\347\256\227\346\263\225\345\222\214\346\225\260\346\215\256\347\273\223\346\236\2041.km" "b/Week \351\242\204\344\271\240\345\221\250/id_451/\347\256\227\346\263\225\345\222\214\346\225\260\346\215\256\347\273\223\346\236\2041.km" new file mode 100644 index 000000000..56e661844 --- /dev/null +++ "b/Week \351\242\204\344\271\240\345\221\250/id_451/\347\256\227\346\263\225\345\222\214\346\225\260\346\215\256\347\273\223\346\236\2041.km" @@ -0,0 +1 @@ +{"root":{"data":{"id":"bxo1ako3r8g0","created":1570933059491,"text":"算法和数据结构"},"children":[{"data":{"id":"bxo1b5lr11k0","created":1570933105061,"text":"算法"},"children":[{"data":{"id":"bxo1gijx2fs0","created":1570933525070,"text":"动态规划"},"children":[]},{"data":{"id":"bxo1gmlukoo0","created":1570933533893,"text":"贪心"},"children":[]},{"data":{"id":"bxo1gphn8mw0","created":1570933540170,"text":"图论"},"children":[{"data":{"id":"bxo1h4oru000","created":1570933573252,"text":"最短路"},"children":[]},{"data":{"id":"bxo1h80z4sw0","created":1570933580521,"text":"最小生成树"},"children":[]},{"data":{"id":"bxo1hdsy1xc0","created":1570933593097,"text":"拓扑排序"},"children":[]}]},{"data":{"id":"bxo1huwflv40","created":1570933630312,"text":"遍历"},"children":[{"data":{"id":"bxo1i0epcs00","created":1570933642301,"text":"深度优先"},"children":[]},{"data":{"id":"bxo1i7utco00","created":1570933658512,"text":"广度优先"},"children":[]}]},{"data":{"id":"bxo1idg69ps0","created":1570933670688,"text":"排序"},"children":[{"data":{"id":"bxo1ikaxwr40","created":1570933685609,"text":"快速排序"},"children":[]},{"data":{"id":"bxo1inm3huo0","created":1570933692814,"text":"归并排序"},"children":[]},{"data":{"id":"bxo1it3sebs0","created":1570933704767,"text":"堆排序"},"children":[]}]}]},{"data":{"id":"bxo1b9bwr600","created":1570933113174,"text":"数据结构"},"children":[{"data":{"id":"bxo1bkrnl6w0","created":1570933138070,"text":"数组"},"children":[]},{"data":{"id":"bxo1br4v7l40","created":1570933151930,"text":"哈希表"},"children":[]},{"data":{"id":"bxo1bum0m7k0","created":1570933159497,"text":"链表"},"children":[]},{"data":{"id":"bxo1car68iw0","created":1570933194637,"text":"栈"},"children":[]},{"data":{"id":"bxo1chc8qlc0","created":1570933208972,"text":"二叉树"},"children":[{"data":{"id":"bxo1ctcly000","created":1570933235116,"text":"堆"},"children":[]},{"data":{"id":"bxo1g4n1uq80","created":1570933494785,"text":"avl树"},"children":[]},{"data":{"id":"bxo1g9yslyw0","created":1570933506378,"text":"红黑树"},"children":[]}]},{"data":{"id":"bxo1d4mozg80","created":1570933259670,"text":"图"},"children":[]}]}]},"template":"default","theme":"fresh-blue","version":"1.4.43"} \ No newline at end of file diff --git "a/Week \351\242\204\344\271\240\345\221\250/id_466/\347\256\227\346\263\225\350\256\255\347\273\203\350\220\245.xmind" "b/Week \351\242\204\344\271\240\345\221\250/id_466/\347\256\227\346\263\225\350\256\255\347\273\203\350\220\245.xmind" index e8c72ac4d..7854bc76c 100644 Binary files "a/Week \351\242\204\344\271\240\345\221\250/id_466/\347\256\227\346\263\225\350\256\255\347\273\203\350\220\245.xmind" and "b/Week \351\242\204\344\271\240\345\221\250/id_466/\347\256\227\346\263\225\350\256\255\347\273\203\350\220\245.xmind" differ diff --git "a/Week \351\242\204\344\271\240\345\221\250/id_481/\346\225\260\346\215\256\347\273\223\346\236\204.png" "b/Week \351\242\204\344\271\240\345\221\250/id_481/\346\225\260\346\215\256\347\273\223\346\236\204.png" new file mode 100644 index 000000000..4d0a2ec7a Binary files /dev/null and "b/Week \351\242\204\344\271\240\345\221\250/id_481/\346\225\260\346\215\256\347\273\223\346\236\204.png" differ diff --git "a/Week \351\242\204\344\271\240\345\221\250/id_481/\347\256\227\346\263\225\350\204\221\345\233\276.png" "b/Week \351\242\204\344\271\240\345\221\250/id_481/\347\256\227\346\263\225\350\204\221\345\233\276.png" new file mode 100644 index 000000000..6d28d4dd2 Binary files /dev/null and "b/Week \351\242\204\344\271\240\345\221\250/id_481/\347\256\227\346\263\225\350\204\221\345\233\276.png" differ diff --git "a/Week \351\242\204\344\271\240\345\221\250/id_576/NOTE.md" "b/Week \351\242\204\344\271\240\345\221\250/id_576/NOTE.md" index a6321d6e2..e71f220f2 100644 --- "a/Week \351\242\204\344\271\240\345\221\250/id_576/NOTE.md" +++ "b/Week \351\242\204\344\271\240\345\221\250/id_576/NOTE.md" @@ -2,3 +2,14 @@ +10月13日 + +完成作业脑图的描绘 + +数据结构 + +![数据结构](D:\algorithm004-01-master\algorithm004-01\Week 预习周\id_576\数据结构.png) + +算法 + +![算法](D:\algorithm004-01-master\algorithm004-01\Week 预习周\id_576\算法.png) \ No newline at end of file diff --git "a/Week \351\242\204\344\271\240\345\221\250/id_576/\346\225\260\346\215\256\347\273\223\346\236\204.png" "b/Week \351\242\204\344\271\240\345\221\250/id_576/\346\225\260\346\215\256\347\273\223\346\236\204.png" new file mode 100644 index 000000000..23b79060c Binary files /dev/null and "b/Week \351\242\204\344\271\240\345\221\250/id_576/\346\225\260\346\215\256\347\273\223\346\236\204.png" differ diff --git "a/Week \351\242\204\344\271\240\345\221\250/id_576/\347\256\227\346\263\225.png" "b/Week \351\242\204\344\271\240\345\221\250/id_576/\347\256\227\346\263\225.png" new file mode 100644 index 000000000..a10e10084 Binary files /dev/null and "b/Week \351\242\204\344\271\240\345\221\250/id_576/\347\256\227\346\263\225.png" differ diff --git "a/Week \351\242\204\344\271\240\345\221\250/id_616/\346\225\260\346\215\256\347\273\223\346\236\204.xmind" "b/Week \351\242\204\344\271\240\345\221\250/id_616/\346\225\260\346\215\256\347\273\223\346\236\204.xmind" new file mode 100644 index 000000000..d2d158bef Binary files /dev/null and "b/Week \351\242\204\344\271\240\345\221\250/id_616/\346\225\260\346\215\256\347\273\223\346\236\204.xmind" differ diff --git "a/Week \351\242\204\344\271\240\345\221\250/id_616/\347\256\227\346\263\225.xmind" "b/Week \351\242\204\344\271\240\345\221\250/id_616/\347\256\227\346\263\225.xmind" new file mode 100644 index 000000000..0140383b0 Binary files /dev/null and "b/Week \351\242\204\344\271\240\345\221\250/id_616/\347\256\227\346\263\225.xmind" differ diff --git "a/Week \351\242\204\344\271\240\345\221\250/id_681/\346\225\260\346\215\256\347\273\223\346\236\204.png" "b/Week \351\242\204\344\271\240\345\221\250/id_681/\346\225\260\346\215\256\347\273\223\346\236\204.png" new file mode 100644 index 000000000..f829acad0 Binary files /dev/null and "b/Week \351\242\204\344\271\240\345\221\250/id_681/\346\225\260\346\215\256\347\273\223\346\236\204.png" differ diff --git "a/Week \351\242\204\344\271\240\345\221\250/id_756/\345\270\270\350\247\201\347\256\227\346\263\225.xmind" "b/Week \351\242\204\344\271\240\345\221\250/id_756/\345\270\270\350\247\201\347\256\227\346\263\225.xmind" new file mode 100644 index 000000000..7051975da Binary files /dev/null and "b/Week \351\242\204\344\271\240\345\221\250/id_756/\345\270\270\350\247\201\347\256\227\346\263\225.xmind" differ diff --git "a/Week \351\242\204\344\271\240\345\221\250/id_756/\346\225\260\346\215\256\347\273\223\346\236\204.xmind" "b/Week \351\242\204\344\271\240\345\221\250/id_756/\346\225\260\346\215\256\347\273\223\346\236\204.xmind" new file mode 100644 index 000000000..73a2580f2 Binary files /dev/null and "b/Week \351\242\204\344\271\240\345\221\250/id_756/\346\225\260\346\215\256\347\273\223\346\236\204.xmind" differ diff --git "a/\350\256\262\345\270\210\350\257\276\344\273\266/\346\236\201\345\256\242\345\244\247\345\255\246-\347\256\227\346\263\225\350\256\255\347\273\203\350\220\245-\350\246\203\350\266\205-\347\254\254\344\270\203\350\257\276.pdf" "b/\350\256\262\345\270\210\350\257\276\344\273\266/\346\236\201\345\256\242\345\244\247\345\255\246-\347\256\227\346\263\225\350\256\255\347\273\203\350\220\245-\350\246\203\350\266\205-\347\254\254\344\270\203\350\257\276.pdf" new file mode 100644 index 000000000..128989eb2 Binary files /dev/null and "b/\350\256\262\345\270\210\350\257\276\344\273\266/\346\236\201\345\256\242\345\244\247\345\255\246-\347\256\227\346\263\225\350\256\255\347\273\203\350\220\245-\350\246\203\350\266\205-\347\254\254\344\270\203\350\257\276.pdf" differ diff --git "a/\350\256\262\345\270\210\350\257\276\344\273\266/\346\236\201\345\256\242\345\244\247\345\255\246-\347\256\227\346\263\225\350\256\255\347\273\203\350\220\245-\350\246\203\350\266\205-\347\254\254\344\272\224\350\257\276.pdf" "b/\350\256\262\345\270\210\350\257\276\344\273\266/\346\236\201\345\256\242\345\244\247\345\255\246-\347\256\227\346\263\225\350\256\255\347\273\203\350\220\245-\350\246\203\350\266\205-\347\254\254\344\272\224\350\257\276.pdf" new file mode 100644 index 000000000..0decac6c6 Binary files /dev/null and "b/\350\256\262\345\270\210\350\257\276\344\273\266/\346\236\201\345\256\242\345\244\247\345\255\246-\347\256\227\346\263\225\350\256\255\347\273\203\350\220\245-\350\246\203\350\266\205-\347\254\254\344\272\224\350\257\276.pdf" differ diff --git "a/\350\256\262\345\270\210\350\257\276\344\273\266/\346\236\201\345\256\242\345\244\247\345\255\246-\347\256\227\346\263\225\350\256\255\347\273\203\350\220\245-\350\246\203\350\266\205-\347\254\254\345\205\253\350\257\276.pdf" "b/\350\256\262\345\270\210\350\257\276\344\273\266/\346\236\201\345\256\242\345\244\247\345\255\246-\347\256\227\346\263\225\350\256\255\347\273\203\350\220\245-\350\246\203\350\266\205-\347\254\254\345\205\253\350\257\276.pdf" new file mode 100644 index 000000000..9b6bc0b32 Binary files /dev/null and "b/\350\256\262\345\270\210\350\257\276\344\273\266/\346\236\201\345\256\242\345\244\247\345\255\246-\347\256\227\346\263\225\350\256\255\347\273\203\350\220\245-\350\246\203\350\266\205-\347\254\254\345\205\253\350\257\276.pdf" differ diff --git "a/\350\256\262\345\270\210\350\257\276\344\273\266/\346\236\201\345\256\242\345\244\247\345\255\246-\347\256\227\346\263\225\350\256\255\347\273\203\350\220\245-\350\246\203\350\266\205-\347\254\254\345\205\255\350\257\276.pdf" "b/\350\256\262\345\270\210\350\257\276\344\273\266/\346\236\201\345\256\242\345\244\247\345\255\246-\347\256\227\346\263\225\350\256\255\347\273\203\350\220\245-\350\246\203\350\266\205-\347\254\254\345\205\255\350\257\276.pdf" new file mode 100644 index 000000000..0e6ba1237 Binary files /dev/null and "b/\350\256\262\345\270\210\350\257\276\344\273\266/\346\236\201\345\256\242\345\244\247\345\255\246-\347\256\227\346\263\225\350\256\255\347\273\203\350\220\245-\350\246\203\350\266\205-\347\254\254\345\205\255\350\257\276.pdf" differ