diff --git a/README.md b/README.md index eb56f713..fb1b921f 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ ## 讲师课件下载地址 -请大家通过该链接查看讲师课件并进行下载:链接:https://pan.baidu.com/s/18S8C5ZIXfzbOTr378B4n3A 密码:964l +请大家通过该链接查看讲师课件并进行下载:链接:https://pan.baidu.com/s/14kX8vGP4_0lMyC9FaBu8Tw 密码:31zj ## 仓库目录结构说明 diff --git a/Week_00/G20200343030029/NOTE.md b/Week_00/G20200343030029/NOTE.md index 50de3041..f9dd9615 100644 --- a/Week_00/G20200343030029/NOTE.md +++ b/Week_00/G20200343030029/NOTE.md @@ -1 +1,3 @@ -学习笔记 \ No newline at end of file +#预习周脑图绘制 +*算法脑图* +[算法脑图地址](https://www.processon.com/mindmap/5e47c4cae4b0834dd835b666 "超链接title") \ No newline at end of file diff --git a/Week_00/G20200343030373/NOTE.md b/Week_00/G20200343030373/NOTE.md index 50de3041..cd08da6a 100644 --- a/Week_00/G20200343030373/NOTE.md +++ b/Week_00/G20200343030373/NOTE.md @@ -1 +1,30 @@ -学习笔记 \ No newline at end of file +# 极客大学 算法训练营 第六期 +- `打点`#活动#开始 +- 讲师 + - 覃超 +- 第六期 + - 2.10 - 4.12 + - [课程安排](https://shimo.im/docs/K9pv9HdcJ6KkRDQh/read) +- 任务与作业 + - 上周日00:00-本周日23:59 +- 每周作业 + - 至少2道代码作业提交 + - 一篇学习总结 + - code review 并点评至少5位代码作业或总结 +- [GitHub仓库](https://github.com/algorithm006-class01/algorithm006-class01) + - ReadMe + - Fork, Clone + - PullRequest, e.g. 373-Week 02 + - 作业,e.g. /Week_01/G20200343030373/LeetCode_2_373/LeetCode_2_373_test.go + - 总结,Issues, e.g. 【373-week 03】二叉树的更多理解 +- 毕业 + - 60分(日常作业,期中考试,期末考试) + - 毕业总结 + - 视频观看超80% +- 优秀学员 + - 90分 + - 20分钟以上分享 +- 优秀小组 +- 助教 + - 吴铮 + - 金泽 \ No newline at end of file diff --git a/Week_00/G20200343030391/LeetCode_11_391.java b/Week_00/G20200343030391/LeetCode_11_391.java new file mode 100644 index 00000000..0aa83518 --- /dev/null +++ b/Week_00/G20200343030391/LeetCode_11_391.java @@ -0,0 +1,48 @@ +public class LeetCode_11_391 { + public static void main(String[] args) { + int[] nums = {1, 8, 6, 2, 5, 4, 8, 3, 7}; + int max = maxAreaDoubleCursor(nums); + System.out.println(max); + + } + + /** + * 暴力解法 + * 时间复杂度O(n^2) + * @param height + * @return + */ + public static int maxAreaViolence(int[] height) { + int max = 0; + for (int i = 0; i < height.length; i++) { + for (int j = i + 1; j < height.length; j++) { + max = Math.max(max, Math.min(height[i], height[j]) * (j - i)); + } + } + return max; + } + + /** + * 双指针: + * 两侧夹逼移动最小板 + * 时间复杂度O(n^2) + * @param height + * @return + */ + public static int maxAreaDoubleCursor(int[] height) { + int max = 0; + int i = 0; + int j = height.length - 1; + while (i < j) { + if (height[i] < height[j]) { + max = Math.max(max, height[i] * (j - i)); + i++; + } else { + max = Math.max(max, height[j] * (j - i)); + j--; + } + + } + return max; + } +} diff --git a/Week_00/G20200343030391/LeetCode_141_391.java b/Week_00/G20200343030391/LeetCode_141_391.java new file mode 100644 index 00000000..038b8b6e --- /dev/null +++ b/Week_00/G20200343030391/LeetCode_141_391.java @@ -0,0 +1,46 @@ +package G20200343030391; + +public class LeetCode_141_391 { + public static void main(String[] args) { + //1->2->3->4->5->NULL + ListNode listNode1 = new ListNode(1); + ListNode listNode2 = new ListNode(2); + ListNode listNode3 = new ListNode(3); + ListNode listNode4 = new ListNode(4); + ListNode listNode5 = new ListNode(5); + listNode1.next = listNode2; + listNode2.next = listNode3; + listNode3.next = listNode4; + listNode4.next = listNode5; + listNode5.next = listNode2; + + boolean b = hasCycle(listNode1); + System.out.println(b); + } + + public static boolean hasCycle(ListNode head) { + if (head == null || head.next == null) { + return false; + } + ListNode slow = head; + ListNode fast = head.next; + while (slow != fast) { + if (fast == null || fast.next == null) { + return false; + } + slow = slow.next; + fast = fast.next.next; + } + return true; + } + public static class ListNode { + int val; + ListNode next; + + ListNode(int x) { + val = x; + } + + } + +} diff --git a/Week_00/G20200343030391/LeetCode_15_391.java b/Week_00/G20200343030391/LeetCode_15_391.java new file mode 100644 index 00000000..8d7bb89c --- /dev/null +++ b/Week_00/G20200343030391/LeetCode_15_391.java @@ -0,0 +1,43 @@ +package G20200343030391; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class LeetCode_15_391 { + public static void main(String[] args) { + int[] nums = {-1, 0, 1, 2, -1, -4}; + List> lists = threeSum(nums); + System.out.println(lists); + } + + public static List> threeSum(int[] nums) { + List> ans = new ArrayList<>(); + int len = nums.length; + if (len < 3) { + return ans; + } + Arrays.sort(nums); // 排序 + for (int i = 0; i < len; i++) { + if (nums[i] > 0) break; // 如果当前数字大于0,则三数之和一定大于0,所以结束循环 + if (i > 0 && nums[i] == nums[i - 1]) continue; // 去重 + int L = i + 1; + int R = len - 1; + while (L < R) { + int sum = nums[i] + nums[L] + nums[R]; + if (sum == 0) { + ans.add(Arrays.asList(nums[i], nums[L], nums[R])); + while (L < R && nums[L] == nums[L + 1]) L++; // 去重 + while (L < R && nums[R] == nums[R - 1]) R--; // 去重 + L++; + R--; + } else if (sum < 0) { + L++; + } else { + R--; + } + } + } + return ans; + } +} diff --git a/Week_00/G20200343030391/LeetCode_70_391.java b/Week_00/G20200343030391/LeetCode_70_391.java new file mode 100644 index 00000000..53c9f0d9 --- /dev/null +++ b/Week_00/G20200343030391/LeetCode_70_391.java @@ -0,0 +1,56 @@ +package G20200343030391; + +public class LeetCode_70_391 { + + public static void main(String[] args) { + System.out.println(climbStairs_2(3)); + } + + + /** + * 动态规划 + * @param n + * @return + */ + public static int climbStairs_1(int n) { + int[] dp = new int[n + 1]; + dp[0] = 1; + dp[1] = 1; + for(int i = 2; i <= n; i++) { + dp[i] = dp[i - 1] + dp[i - 2]; + } + return dp[n]; + } + + /** + * 记忆搜索 + * @param n + * @return + */ + public static int climbStairs_2(int n) { + int[] memo = new int[n + 1]; + memo[0] = 1; + return help(memo, n); + } + + private static int help(int[] memo, int n) { + if (n <= 1) { + return 1; + } + if (memo[n] == 0) { + memo[n] = help(memo, n - 1) + help(memo, n - 2); + } + return memo[n]; + } + + /** + * 傻递归 + * @param n + * @return + */ + public static int climbStairs_3(int n) { + return n <= 1 ? 1 : climbStairs_3(n - 1) + climbStairs_3(n - 2); + } + + +} diff --git a/Week_00/G20200343030395/NOTE.md b/Week_00/G20200343030395/NOTE.md index 50de3041..e69de29b 100644 --- a/Week_00/G20200343030395/NOTE.md +++ b/Week_00/G20200343030395/NOTE.md @@ -1 +0,0 @@ -学习笔记 \ No newline at end of file diff --git a/Week_00/G20200343030431/LeetCode_026_431.java b/Week_00/G20200343030431/LeetCode_026_431.java new file mode 100644 index 00000000..153b2ed7 --- /dev/null +++ b/Week_00/G20200343030431/LeetCode_026_431.java @@ -0,0 +1,21 @@ +package FistWork; +// 1 遍历数组,找到重复的元素--java中有现成的函数吧 +// 2 删除重复元素,返回新数组 +// 3 思路尝试不通,估使用(copy)的是leetcode上的解法 +public class Solution01 { + public int removeDuplicates(int[] nums) { + if (nums == null || nums.length == 1) { + return nums.length; + } + int i = 0, j = 1; + while (j < nums.length) { + if (nums[i] == nums[j]) { + j++; + } else { + i++; + nums[i] = nums[j]; + } + } + return i + 1; + } +} diff --git a/Week_00/G20200343030431/LeetCode_088_431.java b/Week_00/G20200343030431/LeetCode_088_431.java new file mode 100644 index 00000000..624c537f --- /dev/null +++ b/Week_00/G20200343030431/LeetCode_088_431.java @@ -0,0 +1,15 @@ +package FistWork; +// 自己思路: 分别遍历数组1 ,数组2 , 合并到一起组成数组3, 在遍历一次,排序,成数组4 +// 最终还是使用(copy代码)leetCode的代码 +public class Solution02 { + 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_00/G20200343030437/readme.txt b/Week_00/G20200343030437/readme.txt new file mode 100644 index 00000000..70bbef18 --- /dev/null +++ b/Week_00/G20200343030437/readme.txt @@ -0,0 +1 @@ +我是第一次 diff --git a/Week_00/G20200343030453/LeetCode_21_453 b/Week_00/G20200343030453/LeetCode_21_453 new file mode 100644 index 00000000..327c89b4 --- /dev/null +++ b/Week_00/G20200343030453/LeetCode_21_453 @@ -0,0 +1,71 @@ +/* + * @lc app=leetcode.cn id=21 lang=c + * + * [21] 合并两个有序链表 + */ + +// @lc code=start +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * struct ListNode *next; + * }; + */ + +// 解法一 迭代 +struct ListNode* mergeTwoLists(struct ListNode* l1, struct ListNode* l2){ + if(!l1 || !l2) { + return l1 == NULL ? l2 : l1; + } + struct ListNode *head = NULL; + if(l1 -> val < l2 -> val) { + head = l1; + l1 = l1 -> next; + } + else { + head = l2; + l2 = l2 -> next; + } + struct ListNode *p = head; + while(l1 || l2) { + if(!l1) { + p -> next = l2; + break; + } + else if(!l2) { + p -> next = l1; + break; + } + else if(l1 -> val < l2 -> val) { + p -> next = l1; + p = p -> next; + l1 = l1 -> next; + } + else { + p -> next = l2; + p = p -> next; + l2 = l2 -> next; + } + } + return head; +} + + +// 解法二 递归 +struct ListNode* mergeTwoLists(struct ListNode* l1, struct ListNode* l2){ + if(!l1) { + return l2; + } + else if(!l2) { + 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; + } +} \ No newline at end of file diff --git a/Week_00/G20200343030453/LeetCode_26_453 b/Week_00/G20200343030453/LeetCode_26_453 new file mode 100644 index 00000000..ad9d7262 --- /dev/null +++ b/Week_00/G20200343030453/LeetCode_26_453 @@ -0,0 +1,16 @@ +//[26] 删除排序数组中的重复项 +int removeDuplicates(int* nums, int numsSize){ + // 1. 暴力法 + // 2. 双指针 O(n) + if(numsSize < 2) { + return numsSize; + } + int i = 0; + int j = 0; + for(i = 1; i < numsSize; i++) { + if(nums[i] != nums[j]) { + nums[++j] = nums[i]; + } + } + return j + 1; +} \ No newline at end of file diff --git a/Week_00/G20200343030453/LeetCode_42_453 b/Week_00/G20200343030453/LeetCode_42_453 new file mode 100644 index 00000000..25d8d5f6 --- /dev/null +++ b/Week_00/G20200343030453/LeetCode_42_453 @@ -0,0 +1,22 @@ +// [42] 接雨水 + +int trap(int* height, int heightSize){ + + // 暴力法 + int i, j; + int size = 0; + for(i = 0; i < heightSize; i++) { + int leftmax = 0, rightmax = 0; + for(j = 0; j < i; j++) { + leftmax = leftmax < height[j] ? height[j] : leftmax; + } + for(j = i + 1; j < heightSize; j++) { + rightmax = rightmax < height[j] ? height[j] : rightmax; + } + int temp = leftmax < rightmax ? leftmax : rightmax; + if(temp > height[i]) { + size += temp - height[i]; + } + } + return size; +} \ No newline at end of file diff --git a/Week_00/G20200343030453/LeetCode_641_453 b/Week_00/G20200343030453/LeetCode_641_453 new file mode 100644 index 00000000..c7720274 --- /dev/null +++ b/Week_00/G20200343030453/LeetCode_641_453 @@ -0,0 +1,123 @@ +// [641] 设计循环双端队列 + +typedef struct { + int *data; + int capacity; + int head; + int tail; +} MyCircularDeque; + +/** Initialize your data structure here. Set the size of the deque to be k. */ + +bool myCircularDequeIsEmpty(MyCircularDeque* obj); +bool myCircularDequeIsFull(MyCircularDeque* obj); + +MyCircularDeque* myCircularDequeCreate(int k) { + MyCircularDeque *Dq = (MyCircularDeque *)calloc(1 , sizeof(MyCircularDeque)); + Dq -> data = (int *)calloc(k + 1, sizeof(int)); + Dq -> capacity = k + 1; + Dq -> head = Dq -> tail = 0; + return Dq; +} + +/** Adds an item at the front of Deque. Return true if the operation is successful. */ +bool myCircularDequeInsertFront(MyCircularDeque* obj, int value) { + if(!myCircularDequeIsFull(obj)) { + obj -> head = (obj -> head - 1 + obj -> capacity) % obj -> capacity; + obj -> data[obj -> head] = value; + return true; + } + return false; +} + +/** Adds an item at the rear of Deque. Return true if the operation is successful. */ +bool myCircularDequeInsertLast(MyCircularDeque* obj, int value) { + + if(!myCircularDequeIsFull(obj)) { + obj -> data[obj -> tail] = value; + obj -> tail = (obj -> tail + 1) % obj -> capacity; + return true; + } + return false; +} + +/** Deletes an item from the front of Deque. Return true if the operation is successful. */ +bool myCircularDequeDeleteFront(MyCircularDeque* obj) { + + if(!myCircularDequeIsEmpty(obj)) { + obj -> head = (obj -> head + 1) % obj -> capacity; // 问题 + return true; + } + return false; +} + +/** Deletes an item from the rear of Deque. Return true if the operation is successful. */ +bool myCircularDequeDeleteLast(MyCircularDeque* obj) { + + if(!myCircularDequeIsEmpty(obj)) { + obj -> tail = (obj -> tail - 1 + obj -> capacity) % obj -> capacity; + return true; + } + return false; +} + +/** Get the front item from the deque. */ +int myCircularDequeGetFront(MyCircularDeque* obj) { + if(myCircularDequeIsEmpty(obj)) { + return -1; + } + + return obj -> data[obj -> head]; +} + +/** Get the last item from the deque. */ +int myCircularDequeGetRear(MyCircularDeque* obj) { + + if(myCircularDequeIsEmpty(obj)) { + return -1; + } + return obj -> data[(obj -> tail - 1 + obj -> capacity) % obj -> capacity]; +} + +/** Checks whether the circular deque is empty or not. */ +bool myCircularDequeIsEmpty(MyCircularDeque* obj) { + + return obj -> head == obj -> tail ? true : false; +} + +/** Checks whether the circular deque is full or not. */ +bool myCircularDequeIsFull(MyCircularDeque* obj) { + + return (obj -> tail + 1) % obj -> capacity == obj -> head ? true : false; +} + +void myCircularDequeFree(MyCircularDeque* obj) { + if(obj != NULL) { + free(obj -> data); + obj -> data = NULL; + free(obj); + obj = NULL; + } +} + +/** + * Your MyCircularDeque struct will be instantiated and called as such: + * MyCircularDeque* obj = myCircularDequeCreate(k); + * bool param_1 = myCircularDequeInsertFront(obj, value); + + * bool param_2 = myCircularDequeInsertLast(obj, value); + + * bool param_3 = myCircularDequeDeleteFront(obj); + + * bool param_4 = myCircularDequeDeleteLast(obj); + + * int param_5 = myCircularDequeGetFront(obj); + + * int param_6 = myCircularDequeGetRear(obj); + + * bool param_7 = myCircularDequeIsEmpty(obj); + + * bool param_8 = myCircularDequeIsFull(obj); + + * myCircularDequeFree(obj); +*/ \ No newline at end of file diff --git a/Week_00/G20200343030453/NOTE.md b/Week_00/G20200343030453/NOTE.md index 50de3041..fdec6200 100644 --- a/Week_00/G20200343030453/NOTE.md +++ b/Week_00/G20200343030453/NOTE.md @@ -1 +1,35 @@ -学习笔记 \ No newline at end of file +学习笔记 + +学号:G20200343030453 姓名: 马辉明 + +日期: 2020.2.16 + +[21] 合并两个有序链表 题目总结 +(1)迭代法: +归并排序的思想,因为两个链表有序,只做一次排序即可,稍作改进,当其中一个有序表结束时,可以将 next 指向另一个链表的剩余节点,不需要遍历完之后作判断,这样节省了比较时间,时间复杂度 O(n + m) +(2)递归法:终止条件:当 l1 或 l2 为空时,返回剩余 l2 或 l1 结束; +返回值为每一层都已排好序的头指针; +递归内容:当 l1 的值 val 较小时,l1 的 next 指向之后排完序的链表头,否则,l2 的 next 指向排好序的链表头; +时间复杂度:O(n + m)空间复杂度也是一样,递归会消耗(n + m)个栈空间 + +[42] 接雨水 题目总结 +(1) 暴力法 遍历每一根柱子,找出该柱子左右两边最高的柱子取较小值,较小值与当前柱子差值为接雨水数 +此题有很多解法,后续抽空总结... + +[641] 设计循环双端队列 题目总结 https://blog.csdn.net/xiaoma_2018/article/details/103997820 +实现该循环队列,需要注意以下几点: + +1.判断队列为空? 当收尾指针相等,队列为空,head == tail +2.判断队列已满? 当尾指针的下一位等于头指针,队列已满,(tail + 1 + capacity) % capacity == head; +3.初始化队列时? 首尾指针从0开始, head = tail = 0 +4.从头部插入数据? head 指针向前移动, head = (head - 1 + capacity) % capacity +5.从尾部插入数据? tail 指针向后移动, tail = (tail + 1) % capacity +6.从头部删除数据? head 指针向后移动, head = (head + 1) % capacity +7.从尾部删除数据? tail 指针向前移动, tail = (tail - 1 + capacity) % capacity +8.从尾部读取数据? 考虑头部插入(head 前移一位)和尾部插入(插入后,tail后移一位),所以读取data[(tail - 1 + capacity) % capacity] + +[26] 删除排序数组中的重复项 题目总结 + +用双指针遍历 + + diff --git a/Week_00/G20200343030491/LeetCode_283_491.py b/Week_00/G20200343030491/LeetCode_283_491.py new file mode 100644 index 00000000..8a582acb --- /dev/null +++ b/Week_00/G20200343030491/LeetCode_283_491.py @@ -0,0 +1,37 @@ +def move_zero_index(nums): + j = 0 + for i in range(len(nums)): + if nums[i] != 0 : + nums[j] = nums[i] + if j != i: + nums[i] = 0 + j += 1 + + return nums + + +def move_zero_swap(nums): + j = 0 + for i in range(len(nums)): + if nums[i] != 0: + nums[j], nums[i] = nums[i], nums[j] + j += 1 + + return nums + +def move_zero(nums): + j = 0 + for i in range(len(nums)): + if nums[i] != 0: + nums[j] = nums[i] + j += 1 + nums[j:] = [0]*(len(nums)-j) + + return nums + +def move_zero_removal(nums): + for i in range(nums.count(0)): + nums.remove(0) + nums.append(0) + + return nums \ No newline at end of file diff --git a/Week_00/G20200343030499/LeetCode_11_499.java b/Week_00/G20200343030499/LeetCode_11_499.java new file mode 100644 index 00000000..2304974f --- /dev/null +++ b/Week_00/G20200343030499/LeetCode_11_499.java @@ -0,0 +1,40 @@ +/* + * @lc app=leetcode id=11 lang=java + * + * [11] Container With Most Water + */ +/** + * an能承载的水量由离an最远的不矮于an的竖线ax决定 + * calculateMaxArea()从左右两个方向寻找ax,并返回最大值。 + * 时间复杂度:O(n^2) 最优O(n),当两端的竖线最长时;最差O(n^2),当最长竖线在中间时 + * 空间复杂度:O(1) + */ +// @lc code=start +class Solution { + public int maxArea(int[] height) { + int result = 0; + for (int i = 0; i < height.length; i++) { + result = Math.max(result, calculateMaxArea(height, i)); + } + return result; + } + + private int calculateMaxArea(int[] height, int selfIndex) { + int left = 0; + int right = height.length - 1; + while (left != selfIndex) { + if (height[selfIndex] <= height[left]) { + break; + } + left++; + } + while (right != selfIndex) { + if (height[selfIndex] <= height[right]) { + break; + } + right--; + } + return Math.max(height[selfIndex] * (selfIndex - left), height[selfIndex] * (right - selfIndex)); + } +} +// @lc code=end diff --git a/Week_00/G20200343030499/LeetCode_141_499.java b/Week_00/G20200343030499/LeetCode_141_499.java new file mode 100644 index 00000000..07c43724 --- /dev/null +++ b/Week_00/G20200343030499/LeetCode_141_499.java @@ -0,0 +1,42 @@ +/* + * @lc app=leetcode id=141 lang=java + * + * [141] Linked List Cycle + */ + +// @lc code=start + +// Definition for singly-linked list. +class ListNode { + int val; + ListNode next; + + ListNode(int x) { + val = x; + next = null; + } +} + +/* + * 使用快慢两个指针:快指针一次走2步,慢指针一次走1步。 如果有环则快慢指针必相遇,否则快指针会首先走到链表尾部(fast == null || + * fast.next == null) + */ +class Solution { + public boolean hasCycle(ListNode head) { + if (head == null || head.next == null) { + return false; + } + + ListNode fast = head.next.next; + ListNode slow = head.next; + while (fast != null && fast.next != null) { + if (fast.val == slow.val) { + return true; + } + fast = fast.next.next; + slow = slow.next; + } + return false; + } +} +// @lc code=end diff --git a/Week_00/G20200343030499/LeetCode_15_499.java b/Week_00/G20200343030499/LeetCode_15_499.java new file mode 100644 index 00000000..272d2d94 --- /dev/null +++ b/Week_00/G20200343030499/LeetCode_15_499.java @@ -0,0 +1,42 @@ +import java.util.*; + +/* + * @lc app=leetcode id=15 lang=java + * + * [15] 3Sum + */ + +// @lc code=start +/*******未通过******* + * 思路: 建立一个Map(key: 加多少等于0, value: nums的下标) + * 遍历nums中所有两个数的组合,利用组合的结果来从map中找到第三个数的下标 + * 未通过,因为虽然下标同,但值可以相同。这个方法不能去除相同的值。例如: + * input: [-1,0,1,2,-1,-4] + * expected: [[-1,-1,2],[-1,0,1]] + * output: [[-1,0,1],[-1,2,-1],[0,1,-1]] + */ +class Solution { + public List> threeSum(int[] nums) { + // key: 加多少等于0, value: nums的下标 + Map map = new HashMap<>(); + for (int i = 0; i < nums.length; i++) { + map.put(-nums[i], i); + } + + List> results = new ArrayList<>(); + for (int i = 0; i < nums.length - 2; i++) { + for (int j = i + 1; j < nums.length - 1; j++) { + Integer thirdNumber = map.get(nums[i] + nums[j]); + if (thirdNumber != null && thirdNumber > j) { + List result = new ArrayList<>(); + result.add(nums[i]); + result.add(nums[j]); + result.add(nums[thirdNumber]); + results.add(result); + } + } + } + return results; + } +} +// @lc code=end diff --git a/Week_00/G20200343030499/LeetCode_283-2_499.java b/Week_00/G20200343030499/LeetCode_283-2_499.java new file mode 100644 index 00000000..e1a1027c --- /dev/null +++ b/Week_00/G20200343030499/LeetCode_283-2_499.java @@ -0,0 +1,27 @@ +/* + * @lc app=leetcode id=283 lang=java + * + * [283] Move Zeroes + */ + +// @lc code=start +class Solution { + public void moveZeroes(int[] nums) { + int insertAt = 0; + for (int i = 0; i < nums.length; i++) { + if (nums[i] != 0) { + if (i != insertAt) { + swap(nums, i, insertAt); + } + insertAt++; + } + } + } + + private void swap(int[] nums, int pos1, int pos2) { + int temp = nums[pos1]; + nums[pos1] = nums[pos2]; + nums[pos2] = temp; + } +} +// @lc code=end diff --git a/Week_00/G20200343030499/LeetCode_70_499.java b/Week_00/G20200343030499/LeetCode_70_499.java new file mode 100644 index 00000000..dcc2c505 --- /dev/null +++ b/Week_00/G20200343030499/LeetCode_70_499.java @@ -0,0 +1,37 @@ +/* + * @lc app=leetcode id=70 lang=java + * + * [70] Climbing Stairs + */ + +// @lc code=start +/* + * 最简单代码可以用递归,直接返回 climbStairs(n - 1) + climbStairs(n - 2)。 + * 但代码会超时,因为大概有一半重复计算。计算climbStairs(n - 1)时其实已经计算了下一个数的climbStairs(n - 2)。 + * 所以用一个数组进行动态规划:dbArray[n] = climbStairs(n)。 + * 时间复杂度:O(2^n) 动态规划树中每一个节点计算一次 + * 空间复杂度:O(n) 只占用了动态规划数组的空间 + */ +class Solution { + public int climbStairs(int n) { + if (n == 0) { + return 0; + } + if (n == 1) { + return 1; + } + if (n == 2) { + return 2; + } + + int[] dbArray = new int[n]; + dbArray[0] = 0; + dbArray[1] = 1; + dbArray[2] = 2; + for (int i = 3; i < n; i++) { + dbArray[i] = dbArray[i - 1] + dbArray[i - 2]; + } + return dbArray[n - 1] + dbArray[n - 2]; + } +} +// @lc code=end diff --git "a/Week_00/G20200343030527/\346\225\260\346\215\256\347\273\223\346\236\204.png" "b/Week_00/G20200343030527/\346\225\260\346\215\256\347\273\223\346\236\204.png" new file mode 100644 index 00000000..f21e4ac4 Binary files /dev/null and "b/Week_00/G20200343030527/\346\225\260\346\215\256\347\273\223\346\236\204.png" differ diff --git "a/Week_00/G20200343030527/\347\256\227\346\263\225.png" "b/Week_00/G20200343030527/\347\256\227\346\263\225.png" new file mode 100644 index 00000000..c6884cd3 Binary files /dev/null and "b/Week_00/G20200343030527/\347\256\227\346\263\225.png" differ diff --git a/Week_00/G20200343030553/LeetCode_21_G20200343030553.java b/Week_00/G20200343030553/LeetCode_21_G20200343030553.java new file mode 100644 index 00000000..3bd1aba6 --- /dev/null +++ b/Week_00/G20200343030553/LeetCode_21_G20200343030553.java @@ -0,0 +1,46 @@ +class Solution { + // public ListNode mergeTwoLists(ListNode l1, ListNode l2) { + // // 复杂度 time O(n) space O(1) + // ListNode dummy = new ListNode(-1); + // ListNode head = dummy; + // ListNode a1 = l1; + // ListNode a2 = l2; + // while(a1!=null && a2!=null){ + // if(a1.val <= a2.val){ + // dummy.next = a1; + // a1 = a1.next; + // }else{ + // dummy.next = a2; + // a2 = a2.next; + // } + // dummy = dummy.next; + // } + + // // while(a1!=null){ + // // dummy.next = a1; + // // a1 = a1.next; + // // dummy = dummy.next; + // // } + // // while(a2!=null){ + // // dummy.next = a2; + // // a2 = a2.next; + // // dummy = dummy.next; + // // } + // // dummy.next = null; + // //优化 + // dummy.next = (a1 !=null) ? a1:a2; + // return head.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; + } + } +} \ No newline at end of file diff --git a/Week_00/G20200343030553/LeetCode_42_G20200343030553.java b/Week_00/G20200343030553/LeetCode_42_G20200343030553.java new file mode 100644 index 00000000..9217feb2 --- /dev/null +++ b/Week_00/G20200343030553/LeetCode_42_G20200343030553.java @@ -0,0 +1,20 @@ +class Solution { + public int trap(int[] height) { + int sum = 0; + + for(int i=1;i=0;j--){ + maxl = Math.max(maxl, height[j]); + } + for(int j=i;jdata->end->NULL +6.2、循环链表是一种特殊的单链表:head->data->data->head +和单链表相比,循环链表的优点是从链尾到链头比较方便。当要处理的数据具有环型结构特点时,就特别适合采用循环链表 +约瑟夫斯问题 +6.3、双向链表:head<->data<->end->NULL +LinkedHashMap +6.4、双向循环链表:head<->data<->data<->head +7、LRU +我的思路是这样的:我们维护一个有序单链表,越靠近链表尾部的结点是越早之前访问的。当有一个新的数据被访问时,我们从链表头开始顺序遍历链表。 +1.如果此数据之前已经被缓存在链表中了,我们遍历得到这个数据对应的结点,并将其从原来的位置删除,然后再插入到链表的头部。 +2如果此数据没有在缓存链表中,又可以分为两种情况: +如果此时缓存未满,则将此结点直接插入到链表的头部; +如果此时缓存已满,则链表尾结点删除,将新的数据结点插入链表的头部。 +现在我们来看下 m 缓存访问的时间复杂度是多少。因为不管缓存有没有满,我们都需要遍历一遍链表,所以这种基于链表的实现思路,缓存访问的时间复杂度为 O(n)。 +实际上,我们可以继续优化这个实现思路,比如引入散列表(Hash table)来记录每个数据的位置,将缓存访问的时间复杂度降到 O(1)。 +因为要涉及我们还没有讲到的数据结构,所以这个优化方案,我现在就不详细说了,等讲到散列表的时候,我会再拿出来讲。除了基于链表的实现思路,实际上还可以用数组来实现 LRU 缓存淘汰策略。 + +## 编写链表技巧: +1、理解指针或引用的含义 +2、警惕指针丢失和内存泄漏 +3、利用哨兵简化实现难度 +利用哨兵简化编程难度(插入排序、归并排序、动态规划等) +把这种有哨兵结点的链表叫带头链表 +4、重点留意边界条件处理 +我经常用来检查链表代码是否正确的边界条件有这样几个: +4.1、如果链表为空时,代码是否能正常工作? +4.2、如果链表只包含一个结点时,代码是否能正常工作? +4.3、如果链表只包含两个结点时,代码是否能正常工作? +4.4、代码逻辑在处理头结点和尾结点的时候,是否能正常工作? +5、举例画图,辅助思考 +6、多写多练,没有捷径 + +## 跳表(Skip list) +Redis 中的有序集合(Sorted Set)就是用跳表来实现的 +那 Redis 为什么会选择用跳表来实现有序集合呢? +为什么不用红黑树呢?红黑树也可以实现快速的插入、删除和查找操作 +1、链表加多级索引的结构,就是跳表 +2、在跳表中查询任意数据的时间复杂度就是 O(logn) +实际上,在软件开发中,我们不必太在意索引占用的额外空间。在讲数据结构和算法时,我们习惯性地把要处理的数据看成整数,但是在实际的软件开发中,原始链表中存储的有可能是很大的对象,而索引结点只需要存储关键值和几个指针,并不需要存储对象,所以当对象比索引结点大很多时,那索引占用的额外空间就可以忽略了。 +3、支持动态的插入、删除操作,而且插入、删除操作的时间复杂度也是 O(logn) +4、跳表是通过随机函数来维护前面提到的“平衡性” +5、Redis 为什么会选择用跳表来实现有序集合 +Redis 中的有序集合是通过跳表来实现的,严格点讲,其实还用到了散列表。不过散列表我们后面才会讲到,所以我们现在暂且忽略这部分。如果你去查看 Redis 的开发手册,就会发现,Redis 中的有序集合支持的核心操作主要有下面这几个: +插入一个数据;删除一个数据;查找一个数据;按照区间查找数据(比如查找值在[100, 356]之间的数据);迭代输出有序序列。 +按照区间来查找数据这个操作,红黑树的效率没有跳表高。 +跳表可以做到 O(logn) 的时间复杂度定位区间的起点 +跳表也不能完全替代红黑树。因为红黑树比跳表的出现要早一些,很多编程语言中的 Map 类型都是通过红黑树来实现的。我们做业务开发的时候,直接拿来用就可以了,不用费劲自己去实现一个红黑树,但是跳表并没有一个现成的实现,所以在开发中,如果你想使用跳表,必须要自己实现。 diff --git "a/Week_00/G20200343030567/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225.png" "b/Week_00/G20200343030567/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225.png" new file mode 100644 index 00000000..e71a97a7 Binary files /dev/null and "b/Week_00/G20200343030567/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225.png" differ diff --git "a/Week_00/G20200343030567/\347\274\226\347\240\201\345\207\206\345\244\207\345\267\245\344\275\234.png" "b/Week_00/G20200343030567/\347\274\226\347\240\201\345\207\206\345\244\207\345\267\245\344\275\234.png" new file mode 100644 index 00000000..5c18055f Binary files /dev/null and "b/Week_00/G20200343030567/\347\274\226\347\240\201\345\207\206\345\244\207\345\267\245\344\275\234.png" differ diff --git "a/Week_00/G20200343030567/\351\241\266\345\260\226\346\260\264\345\271\263.png" "b/Week_00/G20200343030567/\351\241\266\345\260\226\346\260\264\345\271\263.png" new file mode 100644 index 00000000..361230cb Binary files /dev/null and "b/Week_00/G20200343030567/\351\241\266\345\260\226\346\260\264\345\271\263.png" differ diff --git a/Week_00/G20200343030605/NOTE.md b/Week_00/G20200343030605/NOTE.md index 50de3041..c556ff72 100644 --- a/Week_00/G20200343030605/NOTE.md +++ b/Week_00/G20200343030605/NOTE.md @@ -1 +1,2 @@ -学习笔记 \ No newline at end of file +学习笔记 +### Demo diff --git a/Week_00/G20200343030621/NOTE.md b/Week_00/G20200343030621/NOTE.md index 50de3041..4f6b8afb 100644 --- a/Week_00/G20200343030621/NOTE.md +++ b/Week_00/G20200343030621/NOTE.md @@ -1 +1 @@ -学习笔记 \ No newline at end of file +学习笔记 diff --git "a/Week_00/G20200343030631/\347\256\227\346\263\225\350\256\255\347\273\203\350\220\245.xmind" "b/Week_00/G20200343030631/\347\256\227\346\263\225\350\256\255\347\273\203\350\220\245.xmind" new file mode 100644 index 00000000..1b531a0b Binary files /dev/null and "b/Week_00/G20200343030631/\347\256\227\346\263\225\350\256\255\347\273\203\350\220\245.xmind" differ diff --git a/Week_00/G20200343030643/01-two-sum.py b/Week_00/G20200343030643/01-two-sum.py new file mode 100644 index 00000000..1b3c2037 --- /dev/null +++ b/Week_00/G20200343030643/01-two-sum.py @@ -0,0 +1,11 @@ +class Solution(object): + def twoSum(self, nums, target): + """ + :type nums: List[int] + :type target: int + :rtype: List[int] + """ + for i in range(len(nums)) : + for j in range(i+1, len(nums)) : + if (nums[i] + nums[j] == target): + return [i,j] diff --git a/Week_00/G20200343030643/283-move-zeroes.py b/Week_00/G20200343030643/283-move-zeroes.py new file mode 100644 index 00000000..3ce4e17b --- /dev/null +++ b/Week_00/G20200343030643/283-move-zeroes.py @@ -0,0 +1,12 @@ +class Solution(object): + def moveZeroes (self, nums): + if not nums: + return 0 + + j = 0 + for i in xrange(len(nums)): + if nums[i] : + nums[j] = nums[i] + j += 1 + for i in xrange(j,len(nums)): + nums[i] = 0 diff --git a/Week_01/.DS_Store b/Week_01/.DS_Store new file mode 100644 index 00000000..b6908220 Binary files /dev/null and b/Week_01/.DS_Store differ diff --git a/Week_01/G20190282010007/NOTE.md b/Week_01/G20190282010007/NOTE.md index 50de3041..93fc163a 100644 --- a/Week_01/G20190282010007/NOTE.md +++ b/Week_01/G20190282010007/NOTE.md @@ -1 +1,18 @@ -学习笔记 \ No newline at end of file +学习笔记 + +本周(week_01)的学习总结 + +可能因为平时工作中真的接触的太少算法与数据结构的内容, +学的有点吃力啊,主要还是没有什么太明确的概念,也就数组那一块还算ok, +其他的链表,跳表,栈,队列这些,听着有点意思,但是停下来自己思考的时候就 +懵逼了,这些是啥,怎么我平时都没有遇到过 + +通过本周的学习,让我发现我最大的问题就是没有基础,除了数组部分,其他的链表,跳表,栈,队列这些,听着还是有点懵,对于这些基础,我需要自己在课外进行额外的补充学习。 + +关于刷题部分,部分题目在做的时候,直接使用了JavaScript带有的方法,按老师所教的方法看解题之后,发现很多解题都并不涉及对应语言所自带的方便方法,即使不是JavaScript所写的解题代码,也大概还是能看懂的。 + + +最后总结一下,需要按照老师提出的刷题步骤,自我加强训练,额外对自己所欠缺的知识点进行补充。 +后端同学立志不做CURD Boy,前端也同样立志不能当个切图仔 + +尝试一下来自mbp的提交 diff --git a/Week_01/G20190282010007/leetcode_189_007.js b/Week_01/G20190282010007/leetcode_189_007.js new file mode 100644 index 00000000..b29234ed --- /dev/null +++ b/Week_01/G20190282010007/leetcode_189_007.js @@ -0,0 +1,23 @@ +// 题目:旋转数组 +/* + * 题目描述:给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数。 + * +*/ + +// 解题语言: JavaScript + +// 解题 +/** + * @param {number[]} nums + * @param {number} k + * @return {void} Do not return anything, modify nums in-place instead. + */ +var rotate = function(nums, k) { + for (let i = 1; i <= k; i++) { + // 每向右走一步,即将数组最末尾元素移动到数组最前方 + // Array.pop(), 移除数组最后一位元素,将数组长度-1,并返回所移除的元素值 + // Array.unshift(), 向数组的首位插入一个元素 + nums.unshift(nums.pop()) + } + return nums +}; \ No newline at end of file diff --git a/Week_01/G20190282010007/leetcode_1_007.js b/Week_01/G20190282010007/leetcode_1_007.js new file mode 100644 index 00000000..3b0190a5 --- /dev/null +++ b/Week_01/G20190282010007/leetcode_1_007.js @@ -0,0 +1,26 @@ +// 题目: 两数之和 +/** + * 题目描述: + * 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。 + * 你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。 + */ + + // 解题语言: javaScript + + // 解题 + +/** + * @param {number[]} nums + * @param {number} target + * @return {number[]} + */ +var twoSum = function(nums, target) { + // 暴力解题,两重循环 + for(let i = 0; i < nums.length -1 ; i++) { + for(let j = i + 1; j < nums.length; j++) { + if (nums[j] === target - nums[i]) { + return [i, j] + } + } + } +}; \ No newline at end of file diff --git a/Week_01/G20190282010007/leetcode_21_007.js b/Week_01/G20190282010007/leetcode_21_007.js new file mode 100644 index 00000000..4ff095f0 --- /dev/null +++ b/Week_01/G20190282010007/leetcode_21_007.js @@ -0,0 +1,40 @@ +// 题目: 合并两个有序链表 +/** + * 题目描述: + * 将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的 + */ + + // 解题语言: javaScript + + // 解题 + + /** + * Definition for singly-linked list. + * function ListNode(val) { + * this.val = val; + * this.next = null; + * } + */ +/** + * @param {ListNode} l1 + * @param {ListNode} l2 + * @return {ListNode} + */ +var mergeTwoLists = function(l1, l2) { + // 如果链表l1是空的,那么直接返回l2 + if(l1 === null){ + return l2; + } + // 如果链表l2是空的,那么直接返回l1 + 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; + } +}; \ No newline at end of file diff --git a/Week_01/G20190282010007/leetcode_283_007.js b/Week_01/G20190282010007/leetcode_283_007.js new file mode 100644 index 00000000..ab4d8c10 --- /dev/null +++ b/Week_01/G20190282010007/leetcode_283_007.js @@ -0,0 +1,33 @@ +// 题目: 两数之和 +/** + * 题目描述: + * 给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。 + */ + + // 解题语言: javaScript + + // 解题 + +/** + * @param {number[]} nums + * @return {void} Do not return anything, modify nums in-place instead. + */ +var moveZeroes = function(nums) { + // 标记0的下标位置 + let j = 0 + // 循环数组 + for (let i = 0; i < nums.length; i++) { + // 当前元素是否为零,为0则不做任何操作 + if (nums[i] != 0) { + // 当前元素不为零,判断上一个0的下标位置是否与当前元素下标位置相同 + if (i != j) { + // 当0的标记位与当前原始不同时,将两者交换 + // nums[j] = nums[i] + // nums[i] = 0 + // 尝试使用es6的交换方法 + [nums[j], nums[i]] = [nums[i], nums[j]] + } + j++ + } + } +}; \ No newline at end of file diff --git a/Week_01/G20190282010007/leetcode_88_007.js b/Week_01/G20190282010007/leetcode_88_007.js new file mode 100644 index 00000000..55c854df --- /dev/null +++ b/Week_01/G20190282010007/leetcode_88_007.js @@ -0,0 +1,25 @@ +// 题目: 合并两个有序数组 +/** + * 题目描述: + * 给定两个有序整数数组 nums1 和 nums2,将 nums2 合并到 nums1 中,使得 num1 成为一个有序数组。 + */ + + // 解题语言: javaScript + + // 解题 + +/** + * @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) { + // 将nums2中的元素合并到nums1中 + for (var i = 0;i target +則把最右邊的j 往左移 +若兩元素相加< target +則把最左的元素向右移 +直到兩指針相交 (i==j) + +time complexity: O(N) + +leetcode result: +Runtime: 52 ms, faster than 56.49% of Python3 online submissions for Two Sum. +Memory Usage: 14 MB, less than 65.58% of Python3 online submissions for Two Sum. +''' + + +class Solution2: + def twoSum(self, nums, target: int): + orignal_list = nums.copy() + n = len(nums) + nums.sort() + i = 0 + j = n - 1 + while True: + if (nums[i] + nums[j] > target): + j = j - 1 + elif (nums[i] + nums[j] < target): + i = i + 1 + else: + break; + return self._find_index(orignal_list, nums[i], nums[j]) + + def _find_index(self, input_list, a, b): + index_a = input_list.index(a) + index_b = input_list.index(b) + # 去重 + if index_a == index_b: + [index_a, index_b] = [i for i, x in enumerate(input_list) if x == a] + return [index_a, index_b] + + +''' +解法3 空間換時間(字典) +這邊哈希表我還不太熟,待以後來補全解法 +目前先用空間換時間的做法來試試 + +想法為用字典來儲存target - list 中的每一個元素 +如果之後遇到list 中的新元素存在於字典中,表示這個新元素與之前的結果是相匹配的 +=========== +一開始先檢查字典中是否有當前list中的元素 + +若有 則返回字典的key 值與當前list的位址 (表示湊到一對) +若無 則將目前list的位址與減完的結果一併存於字典中,以利後續查找 + +此法只比前面快了一點點(4ms) 、時間複雜度應為 O(N) +多用了0.2mb 的ram +但這取決於array 的大小 +不過代碼是簡潔了很多 + +Runtime: 48 ms, faster than 79.16% of Python3 online submissions for Two Sum. +Memory Usage: 14.2 MB, less than 56.04% of Python3 online submissions for Two Sum. + +''' + + +class Solution3: + def twoSum(self, nums, target: int): + temp_dict = {} + for key, item in enumerate(nums): + check_result = target - item + if item in temp_dict: + return [temp_dict[item], key] + else: + temp_dict[check_result] = key + + + + +if __name__ == "__main__": + # k=[4,5,1,3,2] + # k.sort() + # print(k)3 + s1 = Solution3().twoSum([4, 3, 3], 6) + print(s1) diff --git a/Week_01/G20190343010191/LeetCode_283_191.py b/Week_01/G20190343010191/LeetCode_283_191.py new file mode 100644 index 00000000..599125c7 --- /dev/null +++ b/Week_01/G20190343010191/LeetCode_283_191.py @@ -0,0 +1,118 @@ +''' +Given an array nums, write a function to move all 0's to the end of it while maintaining the relative order of the non-zero elements. + +Example: + +Input: [0,1,0,3,12] +Output: [1,3,12,0,0] +Note: + +* You must do this in-place without making a copy of the array. +* Minimize the total number of operations. +''' + +''' +给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序 + +必须在原数组上操作,不能拷贝额外的数组。 +尽量减少操作次数。 + +''' + +''' +思路1 + +暴力法 + + +遇到0元素即刪除此元刪 + +最後把list末尾填上0 + +Runtime: 44 ms, faster than 91.28% of Python3 online submissions for Move Zeroes. +Memory Usage: 13.9 MB, less than 100.00% of Python3 online submissions for Move Zeroes. + +意外結果還不錯? +''' + + +class Solution1: + def moveZeroes(self, nums): + """ + Do not return anything, modify nums in-place instead. + """ + nums_len = len(nums) + j = 0 + for i in range(nums_len): + if nums[j] == 0: + del nums[j] + j = j - 1 + + j = j + 1 + for i in range(nums_len - len(nums)): + nums.append(0) + + +''' + +思路2 開新數組(題目不允許此操作) + +將非零元素填入新數組,最後按長度補0 + + +Runtime: 44 ms, faster than 91.28% of Python3 online submissions for Move Zeroes. +Memory Usage: 14 MB, less than 100.00% of Python3 online submissions for Move Zeroes. +''' + + +class Solution2: + def moveZeroes(self, nums): + """ + Do not return anything, modify nums in-place instead. + """ + + temp_list = [] + for item in nums: + if item != 0: + temp_list.append(item) + + for i in range(len(nums) - len(temp_list)): + temp_list.append(0) + nums[:] = temp_list[:] + + +''' + +思路3,雙指針操作 + + +用i 遍歷整個數組 +用j 記錄非零元素的位址 +所以遇到0 元素的時候,j 不應該移動。意思就是只有遇上非零元素時,j 才會移動 + +Runtime: 36 ms, faster than 99.49% of Python3 online submissions for Move Zeroes. +Memory Usage: 14 MB, less than 100.00% of Python3 online submissions for Move Zeroes. + +這效果最好 不愧是老師教的 +''' + + +class Solution3: + def moveZeroes(self, nums): + """ + 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] + if i != j: + nums[i] = 0 + j = j + 1 + + +if __name__ == "__main__": + a = [0, 0, 0, 0, 0, 0, 1] + s1 = Solution2() + s1.moveZeroes(a) + print(a) diff --git a/Week_01/G20190343010191/NOTE.md b/Week_01/G20190343010191/NOTE.md index 50de3041..ea9083bd 100644 --- a/Week_01/G20190343010191/NOTE.md +++ b/Week_01/G20190343010191/NOTE.md @@ -1 +1,14 @@ -学习笔记 \ No newline at end of file +学习笔记 +這周比較多考試只趕著做了兩題,很有意思 +下週再慢慢把其他題目補齊 +我這兩題都自已寫了暴力法 +很拙的解法 +還有老師推薦的解法 +看到時間縮短真的很高興 +感覺到算法的樂趣了! +
+這週學習重點: +* 熟悉雙指針操作 +* 熟悉雙邊逼近 + +希望以後越來越好!感謝老師! \ No newline at end of file diff --git a/Week_01/G20190379010083/LeetCode_001_083.swift b/Week_01/G20190379010083/LeetCode_001_083.swift new file mode 100644 index 00000000..4f662a23 --- /dev/null +++ b/Week_01/G20190379010083/LeetCode_001_083.swift @@ -0,0 +1,35 @@ +// +// 0001_2sum.swift +// AlgorithmPractice +// +// https://leetcode-cn.com/problems/two-sum/ +// Created by Ryeagler on 2020/2/14. +// Copyright © 2020 Ryeagle. All rights reserved. +// + +import Foundation + + // 暴力求解 + func twoSumBruteForce(_ nums: [Int], _ target: Int) -> [Int] { + for i in stride(from: 0, to: nums.count, by: 1) { + for j in stride(from: i + 1, to: nums.count, by: 1) { + if nums[i] + nums[j] == target { + return [i, j] + } + } + } + return [] + } + + func twoSum(_ nums: [Int], _ target: Int) -> [Int] { + var map: [Int: Int] = [Int: Int]() + for i in stride(from: 0, to: nums.count, by: 1) { + let current = nums[i] + let another = target - current + if map[another] != nil { + return [i, map[another]!] + } + map.updateValue(i, forKey: nums[i]) + } + return [] + } diff --git a/Week_01/G20190379010083/LeetCode_011_083.swift b/Week_01/G20190379010083/LeetCode_011_083.swift new file mode 100644 index 00000000..6b27d0bb --- /dev/null +++ b/Week_01/G20190379010083/LeetCode_011_083.swift @@ -0,0 +1,46 @@ +// +// 0011_ContainerWithMostWater.swift +// AlgorithmPractice +// +// https://leetcode-cn.com/problems/container-with-most-water/ +// Created by Ryeagler on 2020/2/11. +// Copyright © 2020 Ryeagle. All rights reserved. +// + +import Foundation + + +class ContainerWithMostWater { + // 暴力解法,这个解法在leetcode上超过了时间限制😂 + func maxAreaByBruteForce(_ height: [Int]) -> Int { + var maxArea = 0 + for i in stride(from: 0, to: height.count, by: 1) { + for j in stride(from: i + 1, to: height.count, by: 1) { + let area = (j - i) * min(height[i], height[j]) + maxArea = max(maxArea, area) + } + } + return maxArea + } + + // 双指针解法 + func maxArea(_ height: [Int]) -> Int { + if height.count <= 0 { + return 0 + } + var left = 0 + var right = height.count - 1 + + var maxArea = 0 + while left < right { + let area = (right - left) * (min(height[left], height[right])) + maxArea = max(maxArea, area) + if height[left] < height[right] { + left += 1 + } else { + right -= 1 + } + } + return maxArea + } +} diff --git a/Week_01/G20190379010083/LeetCode_015_083.swift b/Week_01/G20190379010083/LeetCode_015_083.swift new file mode 100644 index 00000000..799dd237 --- /dev/null +++ b/Week_01/G20190379010083/LeetCode_015_083.swift @@ -0,0 +1,100 @@ +// +// 0015_3num.swift +// AlgorithmPractice +// +// https://leetcode-cn.com/problems/3sum/ +// Created by Ryeagler on 2020/2/12. +// Copyright © 2020 Ryeagle. All rights reserved. +// + +import Foundation + +class ThreeSum { + // 暴力方式虽然能解出所有三个数和为0的数组,但是不符合题目中要求的不能包含重复的三元组这个条件 + func threeSumBruteForce(_ nums: [Int]) -> [[Int]] { + var result = [[Int]]() + for i in stride(from: 0, to: nums.count, by: 1) { + for j in stride(from: i + 1, to: nums.count, by: 1) { + for k in stride(from: j + 1, to: nums.count, by: 1) { + if nums[i] + nums[j] + nums[k] == 0 { + var arr = [Int]() + // 错误加下标 + arr.append(nums[i]) + arr.append(nums[j]) + arr.append(nums[k]) + result.append(arr) + break + } + } + } + } + return result + } + + // 这个解法最后还是没有通过leetcode的方法 + func threeSumHashMap(_ nums: [Int]) -> [[Int]] { + var map: [Int: Int] = [Int: Int]() + for i in stride(from: 0, to: nums.count, by: 1) { + map.updateValue(i, forKey: nums[i]) + } + + var result: [[Int]] = [[Int]]() + var resultMap: [[Int]: Bool] = [[Int]: Bool]() + for i in stride(from: 0, to: nums.count, by: 1) { + for j in stride(from: i + 1, to: nums.count, by: 1) { + let another = 0 - (nums[i] + nums[j]) + if map[another] != nil { + // 少了这一步,就会导致3元组中,同一个下标对应的数字出现多次 + if map[another] == i || map [another] == j { + continue + } + let arr = [nums[i], nums[j], another].sorted() + + // 这一步是为了去除重复的 + if resultMap[arr] == true { + continue + } + result.append(arr) + resultMap.updateValue(true, forKey: arr) + } + } + } + + return result + } + + func threeSum(_ nums: [Int]) -> [[Int]] { + if nums.count < 3 { + return [] + } + var result = [[Int]]() + let sortedNums = nums.sorted() + for var i in 0.. 0 { + return [] + } + let last = sortedNums.count - 1 + while i + 1 < last && sortedNums[i] == sortedNums[i+1] { + i += 1 + } + var left = i + 1 + var right = last + while left < right { + let sum = sortedNums[i] + sortedNums[left] + sortedNums[right] + if sum == 0 { + result.append([sortedNums[i], sortedNums[left], sortedNums[right]]) + } + if sum <= 0 { + repeat { + left += 1 + } while left < last && sortedNums[left] == sortedNums[left - 1] + } else { + repeat { + right -= 1 + } while right > 0 && sortedNums[right] == sortedNums[right + 1] + } + } + } + return result + } +} diff --git a/Week_01/G20190379010083/LeetCode_020_083.swift b/Week_01/G20190379010083/LeetCode_020_083.swift new file mode 100644 index 00000000..c665e96c --- /dev/null +++ b/Week_01/G20190379010083/LeetCode_020_083.swift @@ -0,0 +1,31 @@ +// +// 0020_ValidParentheses.swift +// AlgorithmPractice +// +// https://leetcode-cn.com/problems/valid-parentheses/ +// Created by Ryeagler on 2020/2/15. +// Copyright © 2020 Ryeagle. All rights reserved. +// + +import Foundation + +class ValidParentheses { + func isValid(_ s: String) -> Bool { + let map: [Character: Character] = ["[": "]", "(": ")", "{": "}"] + var stack: Stack = Stack() + for character in s { + if map[character] != nil { + stack.push(character) + } else { + if let top = stack.pop() { + if map[top] != character { + return false + } + } else { + return false + } + } + } + return stack.isEmpty + } +} diff --git a/Week_01/G20190379010083/LeetCode_070_083.swift b/Week_01/G20190379010083/LeetCode_070_083.swift new file mode 100644 index 00000000..ff38e8d2 --- /dev/null +++ b/Week_01/G20190379010083/LeetCode_070_083.swift @@ -0,0 +1,33 @@ +// +// 0070_ClimbingStairs.swift +// AlgorithmPractice +// +// https://leetcode-cn.com/problems/climbing-stairs/ +// Created by Ryeagler on 2020/2/12. +// Copyright © 2020 Ryeagle. All rights reserved. +// + +import Foundation + +class ClimbingStairs { + // 递归法,递归的方式超出时间限制 + func climbStairsRecursion(_ n: Int) -> Int { + if n <= 2 { + return n + } + return climbStairsRecursion(n - 1) + climbStairsRecursion(n - 2) + } + + func climbStairs(_ n: Int) -> Int { + if n <= 2 { + return n + } + var first = 1, second = 2, third = 3 + for _ in stride(from: 3, through: n, by: 1) { + third = first + second + first = second + second = third + } + return third + } +} diff --git a/Week_01/G20190379010083/LeetCode_084_083.swift b/Week_01/G20190379010083/LeetCode_084_083.swift new file mode 100644 index 00000000..67b51075 --- /dev/null +++ b/Week_01/G20190379010083/LeetCode_084_083.swift @@ -0,0 +1,29 @@ +// +// 0084-LargestRectangleInHistogram.swift +// AlgorithmPractice +// +// https://leetcode-cn.com/problems/largest-rectangle-in-histogram/ +// Created by Ryeagler on 2020/2/15. +// Copyright © 2020 Ryeagle. All rights reserved. +// + +import Foundation + +class LargestRectangleInHistogram { + /// 暴力解法 + func largestRectangleAreaBruteForce(_ heights: [Int]) -> Int { + var maxArea = 0 + for i in 0.. Int { + return 0 + } +} diff --git a/Week_01/G20190379010083/LeetCode_189_083.swift b/Week_01/G20190379010083/LeetCode_189_083.swift new file mode 100644 index 00000000..90ec8bbd --- /dev/null +++ b/Week_01/G20190379010083/LeetCode_189_083.swift @@ -0,0 +1,62 @@ +// +// 0189_RotateArray.swift +// AlgorithmPractice +// +// Created by Ryeagler on 2020/2/16. +// Copyright © 2020 Ryeagle. All rights reserved. +// + +import Foundation + +class RotateArray { + /// 三次反转法,时间复杂度为O(n),空间复杂度为O(1) + func rotate(_ nums: inout [Int], _ k: Int) { + if k < 0 {return} + // 题目中要求是向右移动k位,最初没有考虑到k大于数组长度的情况 + reverse(&nums, 0, nums.count - 1) + reverse(&nums, 0, k % nums.count - 1) + reverse(&nums, k % nums.count, nums.count - 1) + } + + /// 通过额外的空间反转,时间复杂度为O(n),空间复杂度为O(1) + func rotateAnotherArray(_ nums: inout [Int], _ k: Int) { + var tmpNums = [Int](repeating: 0, count: k) + for i in 0..= nums.count { + return + } + var left = start + var right = end + while left < right { + let tmp = nums[left] + nums[left] = nums[right] + nums[right] = tmp + left += 1 + right -= 1 + } + } +} diff --git a/Week_01/G20190379010083/LeetCode_283_083.swift b/Week_01/G20190379010083/LeetCode_283_083.swift new file mode 100644 index 00000000..65201aef --- /dev/null +++ b/Week_01/G20190379010083/LeetCode_283_083.swift @@ -0,0 +1,63 @@ +// +// 0283_MoveZeros.swift +// AlgorithmPractice +// +// https://leetcode-cn.com/problems/move-zeroes/ +// Created by Ryeagler on 2020/2/11. +// Copyright © 2020 Ryeagle. All rights reserved. +// + +import Foundation + +class MoveZerosSolution { + /// 两遍循环法 + func moveZeroes(_ nums: inout [Int]) { + var countOfNozero = 0 + for i in stride(from: 0, to: nums.count, by: 1) { + if nums[i] != 0 { + nums[countOfNozero] = nums[i] + countOfNozero += 1 + } + } + + for i in stride(from: countOfNozero, to: nums.count, by: 1) { + nums[i] = 0 + } + } + + /// 一次循环:快排思想 + func moveZeroesQs(_ nums: inout [Int]) { + // 第一个指针到那些需要移动前面的数 + // 第二个指针找到将要交换 + var j = 0 + for i in stride(from: 0, to: nums.count, by: 1) { + if (nums[i] != 0) { + let tmp = nums[i] + nums[i] = nums[j] + nums[j] = tmp + j += 1 + } + } + } + + /// 快速分割 + func qsDivide(_ nums: inout [Int]) { + if nums.count <= 0 { + return + } + let right = nums.count - 1 + let pivot = nums[right] + var j = 0 + for i in stride(from: 0, to: nums.count - 1, by: 1) { + if nums[i] <= pivot { + let tmp = nums[i] + nums[i] = nums[j] + nums[j] = tmp + j += 1 + } + } + let tmp = nums[right] + nums[right] = nums[j] + nums[j] = tmp + } +} diff --git a/Week_01/G20200343030001/Leetcode_001_001.java b/Week_01/G20200343030001/Leetcode_001_001.java new file mode 100644 index 00000000..66d146c9 --- /dev/null +++ b/Week_01/G20200343030001/Leetcode_001_001.java @@ -0,0 +1,35 @@ +package Week_01; + +import java.util.HashMap; + +public class Leetcode_001_001 { + // 暴力法 + 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}; + } + } + } + + throw new IllegalArgumentException("No two sum solution"); + } + + // hash表法,一次遍历过程中完成hash表构建和查找元素功能,善用target + public int[] twoSum1(int[] nums, int target) { + HashMap index = new HashMap(); + + for (int i = 0; i < nums.length; i++) { + int idx = nums[i]; + + if (index.containsKey(target - idx)) { + return new int[] {index.get(target - idx), i}; + } + + index.put(idx, i); + } + + throw new IllegalArgumentException("No two sum solution"); + } +} diff --git a/Week_01/G20200343030001/Leetcode_021_001.java b/Week_01/G20200343030001/Leetcode_021_001.java new file mode 100644 index 00000000..4dcb4728 --- /dev/null +++ b/Week_01/G20200343030001/Leetcode_021_001.java @@ -0,0 +1,41 @@ +package Week_01; + +public class Leetcode_021_001 { + public ListNode mergeTwoLists(ListNode l1, ListNode l2) { + if (l1 == null) { + return l2; + } + + if (l2 == null) { + return l1; + } + + ListNode res = new ListNode(0); + ListNode p = l1, q = l2, cur = res; + + while (p != null && q != null) { + int x = p.val; + int y = q.val; + + if (x <= y) { + cur.next = new ListNode(x); + cur = cur.next; + p = p.next; + } else { + cur.next = new ListNode(y); + cur = cur.next; + q = q.next; + } + } + + if (p == null) { + cur.next = q; + } + + if (q == null) { + cur.next = p; + } + + return res.next; + } +} diff --git a/Week_01/G20200343030001/Leetcode_026_001.java b/Week_01/G20200343030001/Leetcode_026_001.java new file mode 100644 index 00000000..29bdff94 --- /dev/null +++ b/Week_01/G20200343030001/Leetcode_026_001.java @@ -0,0 +1,35 @@ +package Week_01; + +import java.util.Arrays; + +public class Leetcode_026_001 { + public int removeDuplicates(int[] nums) { + if (nums == null || nums.length == 0) { + return 0; + } + + int i = 0, j = 1; + + while (j < nums.length) { + if (nums[j] != nums[i]) { + nums[++i] = nums[j]; + } + + j++; + } + + return i + 1; + } + + public static void main(String[] args) { + RamdomArray ramdomArray = new RamdomArray(); + Leetcode_026_001 solution = new Leetcode_026_001(); + + for (int i = 0 ; i < 15; i++) { + int[] array = ramdomArray.generate(i, 10); + Arrays.sort(array); + + System.out.println(Arrays.toString(array) + "\t" +solution.removeDuplicates(array)); + } + } +} diff --git a/Week_01/G20200343030001/Leetcode_189_001.java b/Week_01/G20200343030001/Leetcode_189_001.java new file mode 100644 index 00000000..b4fc8ef7 --- /dev/null +++ b/Week_01/G20200343030001/Leetcode_189_001.java @@ -0,0 +1,42 @@ +package Week_01; + +import java.util.Arrays; + +public class Leetcode_189_001 { + public static void main(String[] args) { + RamdomArray ramdomArray = new RamdomArray(); + Leetcode_189_001 solution = new Leetcode_189_001(); + + for (int i = 0; i < 10; i++) { + int[] arr = ramdomArray.generate(i, 100); + int k = (int)(Math.random() * 10); + + System.out.print(Arrays.toString(arr) + "\t" + k + "\t"); + + solution.rotate(arr, k); + + System.out.println(Arrays.toString(arr)); + } + } + + public void rotate(int[] nums, int k) { + if(nums == null || nums.length == 0){ + return; + } + + int len = nums.length; + k = k % len; + + reverse(nums, 0, len-1); + reverse(nums, k, len-1); + reverse(nums, 0, k-1); + } + + public static void reverse(int[] arr, int i, int j) { + while (i < j) { + int temp = arr[i]; + arr[i++] = arr[j]; + arr[j--] = temp; + } + } +} diff --git a/Week_01/G20200343030001/Leetcode_283_001.java b/Week_01/G20200343030001/Leetcode_283_001.java new file mode 100644 index 00000000..3c0edf37 --- /dev/null +++ b/Week_01/G20200343030001/Leetcode_283_001.java @@ -0,0 +1,31 @@ +package Week_01; + +import java.util.Arrays; + +public class Leetcode_283_001 { + public void moveZeroes(int[] nums) { + 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 main(String[] args) { + int[] arr = { 0, 0, 1, 100, 3, 12}; + + System.out.println(Arrays.toString(arr)); + + new Leetcode_283_001().moveZeroes(arr); + + System.out.println(Arrays.toString(arr)); + } +} diff --git a/Week_01/G20200343030001/ListNode.java b/Week_01/G20200343030001/ListNode.java new file mode 100644 index 00000000..ec557f8d --- /dev/null +++ b/Week_01/G20200343030001/ListNode.java @@ -0,0 +1,10 @@ +package Week_01; + +public class ListNode { + int val; + ListNode next; + + public ListNode(int val) { + this.val = val; + } +} diff --git a/Week_01/G20200343030001/RamdomArray.java b/Week_01/G20200343030001/RamdomArray.java new file mode 100644 index 00000000..345da3c1 --- /dev/null +++ b/Week_01/G20200343030001/RamdomArray.java @@ -0,0 +1,23 @@ +package Week_01; + +/** + * 测试用随机数组生成器 + * + * @author wyj + * @date 2020/2/11 + */ +public class RamdomArray { + public int[] generate(int len, int max) { + if (len <= 0) { + return new int[0]; + } + + int[] arr = new int[len]; + + for (int i = 0; i < len; i++) { + arr[i] = (int)(Math.random() * max); + } + + return arr; + } +} diff --git a/Week_01/G20200343030005/Leetcode_088_001.js b/Week_01/G20200343030005/Leetcode_088_001.js new file mode 100644 index 00000000..da3bedef --- /dev/null +++ b/Week_01/G20200343030005/Leetcode_088_001.js @@ -0,0 +1,40 @@ +// 88. 合并两个有序数组 + +/** + * @param {number[]} arr1 + * @param {number} m + * @param {number[]} arr2 + * @param {number} n + * @return {void} Do not return anything, modify arr1 in-place instead. + */ + +var merge = function(arr1, m, arr2, n) { + // arr1 = arr1.splice(0, m);// arr1 地址已经变了 + // 不改变arr1的地址,需要把m 后面的数据都删除掉 + arr1.splice(m, arr1.length - m); + arr2 = arr2.splice(0, n); + + arr1.splice(arr1.length, 0, ...arr2); + + arr1.sort((n1, n2) => n1 - n2); + + return arr1; +}; + +/** + * @param {number[]} arr1 + * @param {number} m + * @param {number[]} arr2 + * @param {number} n + * @return {void} Do not return anything, modify arr1 in-place instead. + */ + +var merge = function(arr1, m, arr2, n) { + //将nums2中的元素合并到nums1中 + var i = 0; + while (i < n) { + arr1[m++] = arr2[i++]; + } + arr1.sort((n1, n2) => n1 - n2); + return arr1; +}; diff --git a/Week_01/G20200343030005/Leetcode_283_001.js b/Week_01/G20200343030005/Leetcode_283_001.js new file mode 100644 index 00000000..320b4e35 --- /dev/null +++ b/Week_01/G20200343030005/Leetcode_283_001.js @@ -0,0 +1,196 @@ +/** +给定一个数组 arr,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。 + +示例: + +输入: [0,1,0,3,12] +输出: [1,3,12,0,0] +说明: + +必须在原数组上操作,不能拷贝额外的数组。 +尽量减少操作次数。 + + +问题的两个要求是: +将所有 0 移动到数组末尾。 +所有非零元素必须保持其原始顺序。 + */ + +/** + * @param {number[]} arr + * @return {void} Do not return anything, modify nums in-place instead. + */ + +var moveZeroes = function(arr) { + //1、判断0 删除,统计0的个数count + //2、最后一位添加count个0 + let count = 0; + for (var i = 0; i < arr.length; i++) { + if (arr[i] === 0) { + arr.splice(i--, 1); + count++; + } + } + + if (count) { + for (var i = 0; i < count; i++) { + arr.push(0); + } + } + return arr; +}; + +/** + * @param {number[]} arr + * @return {void} Do not return anything, modify nums in-place instead. + */ + +var moveZeroes = function(arr) { + //1、判断0 删除,添加到0的数组中 + //2、追加到原数组 + var zeroArr = []; + for (var i = 0; i < arr.length; i++) { + if (arr[i] === 0) { + arr.splice(i--, 1); + zeroArr.push(0); + } + } + + arr.push(...zeroArr); + return arr; +}; + +/** + * @param {number[]} arr + * @return {void} Do not return anything, modify nums in-place instead. + */ + +var moveZeroes = function(arr) { + //1、判断0 删除 + //2、最后一位添加0 + + var n = arr.length; + + for (var i = 0; i < n; i++) { + if (arr[i] === 0) { + arr.splice(i--, 1); // 删除0 + arr[arr.length] = 0; // 最后一位添加0 + console.log(i, arr); + n--; + } + } + return arr; +}; + +/** + * @param {number[]} arr + * @return {void} Do not return anything, modify nums in-place instead. + */ + +var moveZeroes = function(arr) { + // Count the zeroes + var n = arr.length; + var numZeroes = 0; + for (var i = 0; i < n; i++) { + //true: 1 布尔值为1 + numZeroes += arr[i] == 0; + } + + console.log("numZeroes:", numZeroes); + + var tmp = []; + for (var i = 0; i < n; i++) { + if (arr[i] != 0) { + tmp.push(arr[i]); + } + } + console.log("tmp:", tmp); + + // Move all zeroes to the end + while (numZeroes--) { + tmp.push(0); + } + console.log("tmp:", tmp); + + // Combine the result + for (var i = 0; i < n; i++) { + arr[i] = tmp[i]; + } + return arr; +}; +/** + +方法二:空间最优,操作局部优化(双指针) +这种方法与上面的工作方式相同,即先满足一个需求,然后满足另一个需求。它以一种巧妙的方式做到了这一点。上述问题也可以用另一种方式描述,“将所有非 0 元素置于数组前面,保持它们的相对顺序相同”。 +这是双指针的方法。由变量 “cur” 表示的快速指针负责处理新元素。如果新找到的元素不是 0,我们就在最后找到的非 0 元素之后记录它。最后找到的非 0 元素的位置由慢指针 “lastnonzerofoundat” 变量表示。当我们不断发现新的非 0 元素时,我们只是在 “lastnonzerofoundat+1” 第个索引处覆盖它们。此覆盖不会导致任何数据丢失,因为我们已经处理了其中的内容(如果它是非 0 的,则它现在已经写入了相应的索引,或者如果它是 0,则稍后将进行处理)。 +在 “cur” 索引到达数组的末尾之后,我们现在知道所有非 0 元素都已按原始顺序移动到数组的开头。现在是时候满足其他要求了,“将所有 0 移动到末尾”。我们现在只需要在 “lastnonzerofoundat” 索引之后用 0 填充所有索引。 +C++ + + +作者:LeetCode +链接:https://leetcode-cn.com/problems/move-zeroes/solution/yi-dong-ling-by-leetcode/ + + */ + +/** + * @param {number[]} arr + * @return {void} Do not return anything, modify nums in-place instead. + */ + +var moveZeroes = function(arr) { + console.log("1arr:", arr); + // 将所有非 0 元素置于数组前面,保持它们的相对顺序相同 + var lastNonZeroFoundAt = 0; + for (var i = 0; i < arr.length; i++) { + if (arr[i] != 0) { + arr[lastNonZeroFoundAt++] = arr[i]; + } + } + + console.log("2arr:", arr, lastNonZeroFoundAt); + + // for (var i = lastNonZeroFoundAt; i < arr.length; i++) { + // arr[i] = 0; + // } + + arr.fill(0, lastNonZeroFoundAt, arr.length); + + return arr; +}; + +/** +方法三:最优解 +前一种方法的操作是局部优化的。例如,所有(除最后一个)前导零的数组:[0,0,0,…,0,1]。对数组执行多少写操作?对于前面的方法,它写 0 n-1n−1 次,这是不必要的。我们本可以只写一次。怎么用?… 只需固定非 0 元素。 + +最优方法也是上述解决方案的一个细微扩展。一个简单的实现是,如果当前元素是非 0 的,那么它的正确位置最多可以是当前位置或者更早的位置。如果是后者,则当前位置最终将被非 0 或 0 占据,该非 0 或 0 位于大于 “cur” 索引的索引处。我们马上用 0 填充当前位置,这样不像以前的解决方案,我们不需要在下一个迭代中回到这里。 + +换句话说,代码将保持以下不变: + +慢指针(lastnonzerofoundat)之前的所有元素都是非零的。 +当前指针和慢速指针之间的所有元素都是零。 +因此,当我们遇到一个非零元素时,我们需要交换当前指针和慢速指针指向的元素,然后前进两个指针。如果它是零元素,我们只前进当前指针。 + +作者:LeetCode +链接:https://leetcode-cn.com/problems/move-zeroes/solution/yi-dong-ling-by-leetcode/ + +*/ + +function swap(arr, m, n) { + var tmp = arr[m]; + arr[m] = arr[n]; + arr[n] = tmp; +} +/** + * @param {number[]} arr + * @return {void} Do not return anything, modify nums in-place instead. + */ + +var moveZeroes = function(arr) { + for (var lastNonZeroFoundAt = 0, cur = 0; cur < arr.length; cur++) { + // 当前元素!=0,就把其交换到左边,等于0的交换到右边 + if (arr[cur] != 0) { + swap(arr, lastNonZeroFoundAt++, cur); + } + } + return arr; +}; \ No newline at end of file diff --git a/Week_01/G20200343030005/NOTE.md b/Week_01/G20200343030005/NOTE.md index 50de3041..6b79d951 100644 --- a/Week_01/G20200343030005/NOTE.md +++ b/Week_01/G20200343030005/NOTE.md @@ -1 +1,3 @@ -学习笔记 \ No newline at end of file +学习笔记 + +第一周的作业,求最大面积的有点晕,其他的还没时间慢慢研究! \ No newline at end of file diff --git a/Week_01/G20200343030007/LeetCode_007_11.js b/Week_01/G20200343030007/LeetCode_007_11.js new file mode 100644 index 00000000..a1714bf1 --- /dev/null +++ b/Week_01/G20200343030007/LeetCode_007_11.js @@ -0,0 +1,27 @@ +/** + * @param {number[]} height + * @return {number} + * 盛水最多的容器 + * 双指针法 + */ +var maxArea = function(height) { + let maxArea = 0; + + for (let i = 0, j = height.length - 1; i < j;) { + const minHeight = height[i] < height[j] ? height[i++] : height[j--]; + const area = (j - i + 1) * minHeight; + maxArea = Math.max(maxArea, area); + } + + return maxArea; +}; + + + +/** + * 双指针紧逼法 + * 原理:最大盛水面积取决于短边的长度 + * 指针1:最左边 + * 指针2:最右边 + * 如果左指针高度 < 右指针高度,左边往里缩,反之亦然 + */ \ No newline at end of file diff --git a/Week_01/G20200343030007/LeetCode_007_26.js b/Week_01/G20200343030007/LeetCode_007_26.js new file mode 100644 index 00000000..eced7439 --- /dev/null +++ b/Week_01/G20200343030007/LeetCode_007_26.js @@ -0,0 +1,51 @@ +/** + * @param {number[]} nums + * @return {number} + * 双指针法 + */ +var removeDuplicates = function (nums) { + if (nums.length <= 1) return nums.length; + // 定义慢指针 + let pos = 0; + + for (let i = 1; i < nums.length; i++) { + if (nums[i] !== nums[pos]) { + // 每次将 pos 指针对应位置的第二位作为不重复项 + nums[pos + 1] = nums[i]; + pos++; + } + } + + return pos + 1; +}; + + +// 预期:[1, 2, 3] +// var nums = [1, 1, 1, 2, 2, 3] +// 返回: 3 + +// const result = removeDuplicates(nums); +// console.log(nums, result); + +/** + * 优化一下 + */ +var removeDuplicates2 = function (nums) { + if (nums.length <= 1) return nums.length; + // 定义慢指针 + let pos = 0; + + for (let i = 1; i < nums.length; i++) { + // 会不会出现数组越界情况,不会,因为当前代码最大执行 5 次, ++pos 最大执行 5 次, + // 要是越界,pos = 6 ,但这一步时,for 循环已经结束 + if (nums[i] !== nums[pos]) nums[++pos] = nums[i]; + } + + return pos + 1; +}; + +var nums1 = [1, 2, 3, 4, 5, 6] +const result1 = removeDuplicates2(nums1); +console.log(nums1, result1); + + diff --git a/Week_01/G20200343030007/LeetCode_007_283.js b/Week_01/G20200343030007/LeetCode_007_283.js new file mode 100644 index 00000000..2604e618 --- /dev/null +++ b/Week_01/G20200343030007/LeetCode_007_283.js @@ -0,0 +1,47 @@ +/** + * @param {number[]} nums + * @return {void} Do not return anything, modify nums in-place instead. + * 双指针法 + */ +var moveZeroes = function(nums) { + if (nums.length <= 1) return; + // 慢指针 + let pos = 0; + // 将所有不为 0 的移到左边,并记录末尾所有 0 的第一个的位置 + for (let i = 1; i < nums.length; i++) { + if (nums[i] !== 0) nums[pos++] = nums[i]; + } + // 将末尾应该为 0 的置为 0 + while (pos < nums.length) { + nums[pos++] = 0; + } +} + +const nums = [0, 1, 0, 3, 12]; +moveZeroes(nums); +// 预期 [1, 3, 1, 0, 0, 0, 0] + +console.log(nums); + + +/** + * 双指针 + * 指针: + * 1. 将非 0 树放在前面 + * 2. 记录末尾 0 的开始位置 + * + * 第一步:将不为 0 的放到前面,记录指针变化 + * insertPos i nums + * 0 0 [0, 1, 0, 3, 12] + * 1 1 [1, 1, 0, 3, 12] + * 1 2 [1, 1, 0, 3, 12] + * 2 3 [1, 3, 0, 3, 12] + * 3 4 [1, 3, 12, 3, 12] + * + * 第二步:将末尾其它数据置为 0 + * insertPos nums + * 3 [1, 3, 12, 0, 12] + * 4 [1, 3, 12, 0, 0] + * + */ + diff --git a/Week_01/G20200343030007/NOTE.md b/Week_01/G20200343030007/NOTE.md index 50de3041..f63c2185 100644 --- a/Week_01/G20200343030007/NOTE.md +++ b/Week_01/G20200343030007/NOTE.md @@ -1 +1,69 @@ -学习笔记 \ No newline at end of file +## 学习笔记 + +### 数据结构与算法理解 + +计算机程序语言都是重复,究极就是重复的,是有规律的,所以所有的算法是可以找规律,套模板的。 + +### 如何学习 + +- **刻意练习** + + 就像打游戏一样,补兵不行一直练补兵,技能不行一直练技能,大神都是每一步基础都很扎实,所以基本功是制胜法宝。 + +- **刷题** + + 1. 敢于承认自己刷题时,***想不出来,不会做*** 的问题,因为优秀的算法时前人总结多年的经验,我们不是圣人,我们只是学习者,记下优秀的思路技巧,并做到熟能生巧时最重要的。 + 2. 刷题只做一遍是不可以的,以为看会了,照着写出来了就等于会了,**大错特错**!这是基本功,是需要达到见到这个题就可以立马想到解法,并且迅速写出来,达到这样的境界,只做一遍是万万不可的。 + - 第一遍:思路看懂,程序做熟 + - 第二遍:第二天重复默写,加强记忆 + - 第三遍:周天再写一遍,加强记忆 + - 第四遍:第二周写一遍 + - 第五遍:面试前突击练习 + +- **总结** + + 人脑记不住琐碎的知识,但可以归纳总结为脑图,**树**的形式 + + 将学习的算法和数据结构知识总结为脑图,并在阶段性学习完毕后,看一下自己的算法数据机构地图添加了哪些树枝,还有哪些知识点没有添加。 + +- **工欲善其事必先利其器** + + - 优秀的 IDE 和插件 + + - 可以使用 vscode top tips 这种关键词查询 + + - 基本的代码规范 + + - 缩行,关键词后跟空格等 + + - **自顶向下的编写方法** + + 先写大体主干,再写细节方法。 + + 比如计算盛水最大面积的题目,先 getMinHeight (求最小高度),再 getArea(求面积),最后 getMaxArea(求最大面积)。先写出大概框架思路,再补足方法细节。这样就不会套进纠结方法细节的误区,导致整个算法没有实现。 + + - 代码编写时的指法 + + - 快速到达行头行尾 + - 以单词为单位左右移动 + - 向上向下移动当前行代码 + - 整段删除或复制 + +### 本周刷题总结 + +- **思路** + + - 基本思路 + + 如果做不出来,可以尝试大脑中最基本的解法,一步一步程序执行的那种,或者暴力解法 for 循环这种。 + + - 其它思路 + + 本周影响最深刻的是对于双指针的理解,精妙 + + - 快慢指针法 + - 移动零 + - 双指针紧逼法 + - 计算最大盛水面积 + + **真的是有套路可言!** \ No newline at end of file diff --git a/Week_01/G20200343030009/LeetCode_1_009.js b/Week_01/G20200343030009/LeetCode_1_009.js new file mode 100644 index 00000000..0b064f9d --- /dev/null +++ b/Week_01/G20200343030009/LeetCode_1_009.js @@ -0,0 +1,29 @@ +/** + * @param {number[]} nums + * @param {number} target + * @return {number[]} + */ +var twoSum = function(nums, target) { + let hashObj = {} + // hash表法 + // 遍历一次数组,将所有元素存hash表中,再在表中查找是否存在值为target-nums[i] + for (let i = 0; i < nums.length; i++) { + // key存值, value存下标 + const t = target - nums[i] + // B: 放到一次循环里 + if (hashObj.hasOwnProperty(t) && hashObj[t] !== i) { + // 存在hash表中且不是本身元素 + return [hashObj[t], i] + } + hashObj[nums[i]] = i + } + // A: 分先后两次遍历 + // for (let i = 0; i < nums.length; i++) { + // const t = target - nums[i] + // if (hashObj.hasOwnProperty(t) && hashObj[t] !== i) { + // // 存在hash表中且不是本身元素 + // return [i, hashObj[t]] + // } + // } + return [] +}; \ No newline at end of file diff --git a/Week_01/G20200343030009/LeetCode_26_009.js b/Week_01/G20200343030009/LeetCode_26_009.js new file mode 100644 index 00000000..577c39d5 --- /dev/null +++ b/Week_01/G20200343030009/LeetCode_26_009.js @@ -0,0 +1,18 @@ +/** + * @param {number[]} nums + * @return {number} + */ +var removeDuplicates = function(nums) { + //快慢指针 + let slow = 0; + let quick = 1; + for (; quick < nums.length; quick++) { + if (nums[slow] !== nums[quick]) { + // 快慢指针指向的数据不等,快指针数据赋值到慢指针下个位置 + nums[++slow] = nums[quick] + } + // 当快慢指针指向的数据相等(重复数据), 只是快指针单独向右移动; + // 直到不等时,进入上面if,将快指针数据赋值到慢指针下个位置 + } + return slow+1 +}; \ No newline at end of file diff --git a/Week_01/G20200343030015/LeetCode_189_015.java b/Week_01/G20200343030015/LeetCode_189_015.java new file mode 100644 index 00000000..b3132a51 --- /dev/null +++ b/Week_01/G20200343030015/LeetCode_189_015.java @@ -0,0 +1,98 @@ +package G20200343030015.week_01; + +/** + * Created by majiancheng on 2020/2/16. + */ +public class LeetCode_189_015 { + + /** + * 第一种方法, 暴力求解 + * + * @param nums + * @param k + */ + public void rotate1(int[] nums, int k) { + for (int i = 0; i < k; i++) { + int prev = nums[nums.length - 1]; + for (int j = 0; j < nums.length; j++) { + int temp = nums[j]; + nums[j] = prev; + prev = temp; + } + } + } + + /** + * 第二种方法, 翻转数组 + * + * @param nums + * @param k + */ + public void rotate2(int[] nums, int k) { + k %= nums.length; + reverse2(nums, 0, nums.length - 1); + reverse2(nums, 0, k - 1); + reverse2(nums, k, nums.length - 1); + } + + /** + * 第三种方法, 环状替换 + * + * @param nums + * @param k + */ + public void rotate3(int[] nums, int k) { + k %= nums.length; + int count = 0; + for (int start = 0; count < nums.length; start++) { + int current = start; + int prev = nums[start]; + do { + int next = (current + k) % nums.length; + int tmp = nums[next]; + nums[next] = prev; + + current = next; + prev = tmp; + count++; + } while (start != current); + } + } + + public void reverse2(int[] nums, int start, int end) { + while (start < end) { + int tmp = nums[start]; + nums[start] = nums[end]; + nums[end] = tmp; + start++; + end--; + } + } + + public static void main(String[] args) { + int[] nums = { 1, 2, 3, 4, 5, 6, 7 }; + /*new LeetCode_189_015().rotate1(nums, 3);*/ + /*new LeetCode_189_015().rotate2(nums, 3);*/ + new LeetCode_189_015().rotate3(nums, 3); + for (int i : nums) { + System.out.print(i + ", "); + } + } +} + +/** + * 给定一个数组,将数组中的元素向右移动 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] + *

+ * 来源:力扣(LeetCode) + * 链接:https://leetcode-cn.com/problems/rotate-array + * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + */ diff --git a/Week_01/G20200343030015/LeetCode_1_015.java b/Week_01/G20200343030015/LeetCode_1_015.java new file mode 100644 index 00000000..51260415 --- /dev/null +++ b/Week_01/G20200343030015/LeetCode_1_015.java @@ -0,0 +1,44 @@ +package G20200343030015.week_01; + +import java.util.HashMap; +import java.util.Map; + +/** + * Created by majiancheng on 2020/2/16. + */ +public class LeetCode_1_015 { + + 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 two sum solution"); + } + + public static void main(String[] args) { + int[] result = new LeetCode_1_015().twoSum(new int[] { 2, 7, 11, 15 }, 9); + + for (int item : result) { + System.out.print(item + ", "); + } + } + +} + +/** + * 给定一个整数数组 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 + * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + */ diff --git a/Week_01/G20200343030015/LeetCode_21_015.java b/Week_01/G20200343030015/LeetCode_21_015.java new file mode 100644 index 00000000..d06e0473 --- /dev/null +++ b/Week_01/G20200343030015/LeetCode_21_015.java @@ -0,0 +1,79 @@ +package G20200343030015.week_01; + +/** + * Created by majiancheng on 2020/2/16. + */ +public class LeetCode_21_015 { + + 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; + } + + if (l1 != null) { + prev.next = l1; + } else { + prev.next = l2; + } + + return preHead.next; + } + + public static void main(String[] args) { + ListNode l1 = new ListNode(1); + ListNode l1Head = l1; + for (int i = 2; i < 5; i++) { + l1.next = new ListNode(i); + l1 = l1.next; + } + + ListNode l2 = new ListNode(2); + ListNode l2Head = l2; + for (int i = 3; i < 5; i++) { + l2.next = new ListNode(i); + l2 = l2.next; + } + + ListNode newHead = new LeetCode_21_015().mergeTwoLists(l1Head, l2Head); + while (newHead != null) { + System.out.print(newHead.val + ", "); + newHead = newHead.next; + } + + } +} + +class ListNode { + + int val; + + ListNode next; + + ListNode(int x) { + val = x; + } +} + +/** + * 将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。  + *

+ * 示例: + *

+ * 输入:1->2->4, 1->3->4 + * 输出:1->1->2->3->4->4 + *

+ * 来源:力扣(LeetCode) + * 链接:https://leetcode-cn.com/problems/merge-two-sorted-lists + * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + */ diff --git a/Week_01/G20200343030015/LeetCode_26_015.java b/Week_01/G20200343030015/LeetCode_26_015.java new file mode 100644 index 00000000..d0f954b5 --- /dev/null +++ b/Week_01/G20200343030015/LeetCode_26_015.java @@ -0,0 +1,54 @@ +package G20200343030015.week_01; + +/** + * Created by majiancheng on 2020/2/16. + */ +public class LeetCode_26_015 { + + public int removeDuplicates(int[] nums) { + if (nums == null || nums.length == 0) return 0; + int j = 0; + for (int i = 1; i < nums.length; i++) { + if (nums[j] != nums[i]) { + j++; + nums[j] = nums[i]; + } + } + + return j + 1; + } + + public static void main(String[] args) { + int[] nums = new int[] { 1, 1, 2 }; + int cnt = new LeetCode_26_015().removeDuplicates(nums); + for (int i = 0; i < cnt; i++) { + System.out.print(nums[i] + ", "); + } + + } +} + +/** + * 给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。 + *

+ * 不要使用额外的数组空间,你必须在原地修改输入数组并在使用 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。 + *

+ * 你不需要考虑数组中超出新长度后面的元素。 + *

+ * 来源:力扣(LeetCode) + * 链接:https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array + * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + */ diff --git a/Week_01/G20200343030015/LeetCode_283_015.java b/Week_01/G20200343030015/LeetCode_283_015.java new file mode 100644 index 00000000..741b537b --- /dev/null +++ b/Week_01/G20200343030015/LeetCode_283_015.java @@ -0,0 +1,49 @@ +package G20200343030015.week_01; + +/** + * Created by majiancheng on 2020/2/16. + */ +public class LeetCode_283_015 { + + public void moveZeroes(int[] nums) { + if (nums == null) { + return; + } + + int j = 0; + for (int i = 0; i < nums.length; i++) { + if (nums[i] != 0) { + int tmp = nums[j]; + nums[j] = nums[i]; + nums[i] = tmp; + + j++; + } + } + } + + public static void main(String[] args) { + int[] nums = new int[] { 0, 1, 0, 3, 12 }; + new LeetCode_283_015().moveZeroes(nums); + for (int num : nums) { + System.out.print(num + ", "); + } + } +} + +/** + * 给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。 + *

+ * 示例: + *

+ * 输入: [0,1,0,3,12] + * 输出: [1,3,12,0,0] + * 说明: + *

+ * 必须在原数组上操作,不能拷贝额外的数组。 + * 尽量减少操作次数。 + *

+ * 来源:力扣(LeetCode) + * 链接:https://leetcode-cn.com/problems/move-zeroes + * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + */ diff --git a/Week_01/G20200343030015/LeetCode_88_015.java b/Week_01/G20200343030015/LeetCode_88_015.java new file mode 100644 index 00000000..6df4cef1 --- /dev/null +++ b/Week_01/G20200343030015/LeetCode_88_015.java @@ -0,0 +1,50 @@ +package G20200343030015.week_01; + +import java.util.Arrays; + +/** + * Created by majiancheng on 2020/2/16. + */ +public class LeetCode_88_015 { + + public void merge(int[] nums1, int m, int[] nums2, int n) { + int[] copy_nums1 = Arrays.copyOf(nums1, m); + + int p = 0; + int p1 = 0; + int p2 = 0; + while (p1 < copy_nums1.length && p2 < nums2.length) { + nums1[p++] = (copy_nums1[p1] < nums2[p2]) ? copy_nums1[p1++] : nums2[p2++]; + } + + while (p1 < copy_nums1.length) { + nums1[p++] = copy_nums1[p1++]; + } + + while (p2 < nums2.length) { + nums1[p++] = nums2[p2++]; + } + + } +} + +/** + * 88. 合并两个有序数组 + * 给定两个有序整数数组 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] + *

+ * 来源:力扣(LeetCode) + * 链接:https://leetcode-cn.com/problems/merge-sorted-array + * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + */ diff --git a/Week_01/G20200343030015/NOTE.md b/Week_01/G20200343030015/NOTE.md index 50de3041..7a73125c 100644 --- a/Week_01/G20200343030015/NOTE.md +++ b/Week_01/G20200343030015/NOTE.md @@ -1 +1,5 @@ -学习笔记 \ No newline at end of file +学习笔记 + + 1、五毒神掌很重要,算法要多去做几遍,多看leetcode别人高票实现的算法和思路; + 2、重要的是要留有充足的时间做预习,反复听课,反复做题 以及及时复习,刻意练习; + 3、对不理解的题一定要多看代码实现以及debug代码,直到理解并且默写出代码; diff --git a/Week_01/G20200343030017/PriorityQueue.txt b/Week_01/G20200343030017/PriorityQueue.txt new file mode 100644 index 00000000..28e45b70 --- /dev/null +++ b/Week_01/G20200343030017/PriorityQueue.txt @@ -0,0 +1,13 @@ +属性:初始容量 11 +可以从其他Collection转化为PriorityQueue +SortedSet可以直接转化为PriorityQueue,排序保持不变 + +initElementsFromCollection方法: +把Collection转化为一个数组,然后遍历,如果有空的抛出异常,所以PriorityQueue不允许空值 + +扩容:如果小于64 增加 2,如果大于64增加一倍 +增加节点:siftUp ,先增加到队列最后,然后与前面比较进行交换 +peek:不操作节点返回做前面节点 +indexOf:遍历找到指定索引的值,O(n) +删除节点:删除指定节点,siftdown,节点和它的子节点比较,交换位置,用于调整结点 +heapify:建堆,用siftdown调整 \ No newline at end of file diff --git a/Week_01/G20200343030017/leetcode/src/design_circular_deque/MyCircularDeque.java b/Week_01/G20200343030017/leetcode/src/design_circular_deque/MyCircularDeque.java new file mode 100644 index 00000000..0e19dda2 --- /dev/null +++ b/Week_01/G20200343030017/leetcode/src/design_circular_deque/MyCircularDeque.java @@ -0,0 +1,167 @@ +package design_circular_deque; + +import java.util.Arrays; + +public class MyCircularDeque { + int[] deque; + int k; + /** Initialize your data structure here. Set the size of the deque to be k. */ + public MyCircularDeque(int k) { + this.deque=new int[k]; + this.k = k; + for (int n=0;n nums2[b]? nums2[b++]:nums1[a++]; + c++; + } + if (a=0;n--){ + if (digits[n]==9){ + digits[n]=0; + }else{ + digits[n]=digits[n]+1; + return digits; + } + } + int[] temp = new int[digits.length+1]; + System.arraycopy(digits,0,temp,1,digits.length); + temp[0] = 1; + return temp; + } + + public static void main(String[] args) { + int[] nums = {9,9,9}; + Solution s = new Solution(); + System.out.println(Arrays.toString(s.plusOne(nums))); + } +} diff --git a/Week_01/G20200343030017/leetcode/src/remove_duplicates_from_sorted_array/Solution.java b/Week_01/G20200343030017/leetcode/src/remove_duplicates_from_sorted_array/Solution.java new file mode 100644 index 00000000..42d424d0 --- /dev/null +++ b/Week_01/G20200343030017/leetcode/src/remove_duplicates_from_sorted_array/Solution.java @@ -0,0 +1,28 @@ +package remove_duplicates_from_sorted_array; +import java.util.Arrays; + +public class Solution { + public int removeDuplicates(int[] nums) { + int a = 0; + for (int n=0;n nums[n]){ + nums[n+1] = nums[j]; + a = a + 1; + break; + } + if (nums[j] == nums[nums.length-1]){ + return a+1; + } + } + } + return a+1; + } + + public static void main(String[] args) { + int[] a ={0,0,0}; + Solution s = new Solution(); + System.out.println(s.removeDuplicates(a)); + System.out.println(Arrays.toString(a)); + } +} diff --git a/Week_01/G20200343030017/leetcode/src/rotate_array/Solution.java b/Week_01/G20200343030017/leetcode/src/rotate_array/Solution.java new file mode 100644 index 00000000..7112a819 --- /dev/null +++ b/Week_01/G20200343030017/leetcode/src/rotate_array/Solution.java @@ -0,0 +1,24 @@ +package rotate_array; + +import java.util.Arrays; + +public class Solution { + public void rotate(int[] nums, int k) { + int temp = 0; + for (int n=0;n stack = new Stack<>(); + for (int n=0;n height[stack.peek()])){ + int wl = height[stack.pop()]; + if (stack.empty()){ + break; + } + water = water + (n-stack.peek()-1) * (Math.min(height[stack.peek()],height[n])-wl); + } + stack.push(n); + } + } + return water; + } + + public static void main(String[] args) { + //int[] nums = {0,1,0,2,1,0,1,3,2,1,2,1}; + int[] nums = {4,2,3}; + Solution s = new Solution(); + System.out.println(s.trap(nums)); + } +} diff --git a/Week_01/G20200343030017/leetcode/src/two_sum/Solution.java b/Week_01/G20200343030017/leetcode/src/two_sum/Solution.java new file mode 100644 index 00000000..ad57eff3 --- /dev/null +++ b/Week_01/G20200343030017/leetcode/src/two_sum/Solution.java @@ -0,0 +1,26 @@ +package two_sum; + +import java.util.Arrays; + +public class Solution { + public int[] twoSum(int[] nums, int target) { + int[] temp = new int[2]; + for (int a=0;a 0 && startIndex == index) { + index ++; + startIndex ++; + tmp = nums[index]; + } + nextIndex = (index + k) % nums.length; + tmp2 = nums[nextIndex]; + nums[nextIndex] = tmp; + index = nextIndex; + tmp = tmp2; + } + } +} \ No newline at end of file diff --git a/Week_01/G20200343030019/LeetCode_1_019.java b/Week_01/G20200343030019/LeetCode_1_019.java new file mode 100644 index 00000000..6d1223d1 --- /dev/null +++ b/Week_01/G20200343030019/LeetCode_1_019.java @@ -0,0 +1,13 @@ +class Solution { + public int[] twoSum(int[] nums, int target) { + Map map = new HashMap(); + for (int index = 0; index < nums.length; index ++) { + if (map.containsKey(target - nums[index])) { + return new int[]{map.get(target - nums[index]), index}; + } + map.put(nums[index], index); + } + + throw new RuntimeException("not have tow num sum to target!"); + } +} \ No newline at end of file diff --git a/Week_01/G20200343030019/LeetCode_21_019.java b/Week_01/G20200343030019/LeetCode_21_019.java new file mode 100644 index 00000000..98dd514e --- /dev/null +++ b/Week_01/G20200343030019/LeetCode_21_019.java @@ -0,0 +1,23 @@ +class Solution { + public ListNode mergeTwoLists(ListNode l1, ListNode l2) { + ListNode head = new ListNode(0); + ListNode node = head; + while (l1 != null && l2 != null) { + if (l1.val < l2.val) { + node.next = l1; + l1 = l1.next; + } else { + node.next = l2; + l2 = l2.next; + } + node = node.next; + } + if (l1 != null) { + node.next = l1; + } + if (l2 != null) { + node.next = l2; + } + return head.next; + } +} \ No newline at end of file diff --git a/Week_01/G20200343030019/LeetCode_26_019.java b/Week_01/G20200343030019/LeetCode_26_019.java new file mode 100644 index 00000000..2ea8cb9d --- /dev/null +++ b/Week_01/G20200343030019/LeetCode_26_019.java @@ -0,0 +1,19 @@ +class Solution { + public int removeDuplicates(int[] nums) { + if (nums == null || nums.length <= 0) { + return 0; + } + if (nums.length ==1) { + return 1; + } + int repeatNum = 0; + for (int index = 1; index < nums.length; index ++) { + if (nums[index] == nums[index -1]) { + repeatNum ++; + } else { + nums[index - repeatNum] = nums[index]; + } + } + return nums.length - repeatNum; + } +} \ No newline at end of file diff --git a/Week_01/G20200343030019/LeetCode_283_019.java b/Week_01/G20200343030019/LeetCode_283_019.java new file mode 100644 index 00000000..c58abfca --- /dev/null +++ b/Week_01/G20200343030019/LeetCode_283_019.java @@ -0,0 +1,15 @@ +class Solution { + public void moveZeroes(int[] nums) { + int zeroIndex = 0; + for (int index = 0; index < nums.length; index ++) { + if(nums[index] != 0) { + if (index == zeroIndex) { + zeroIndex ++; + continue; + } + nums[zeroIndex ++] = nums[index]; + nums[index] = 0; + } + } + } +} \ No newline at end of file diff --git a/Week_01/G20200343030019/LeetCode_42_019.java b/Week_01/G20200343030019/LeetCode_42_019.java new file mode 100644 index 00000000..196ce8a5 --- /dev/null +++ b/Week_01/G20200343030019/LeetCode_42_019.java @@ -0,0 +1,28 @@ +class Solution { + public int trap(int[] height) { + if (height.length < 3) { + return 0; + } + int left = 0; + int leftH = height[left]; + int right = height.length -1; + int rightH = height[right]; + int area = 0; + while (left < right) { + if (height[left] <= height[right]) { + area += leftH - height[left]; + left ++; + if (height[left] > leftH) { + leftH = height[left]; + } + } else { + area += rightH - height[right]; + right --; + if (height[right] > rightH) { + rightH = height[right]; + } + } + } + return area; + } +} \ No newline at end of file diff --git a/Week_01/G20200343030019/LeetCode_641_019.java b/Week_01/G20200343030019/LeetCode_641_019.java new file mode 100644 index 00000000..e359b0f5 --- /dev/null +++ b/Week_01/G20200343030019/LeetCode_641_019.java @@ -0,0 +1,99 @@ +class MyCircularDeque { + private int capacity; + private int size; + private int[] arr; + private int head; + private int tail; + /** Initialize your data structure here. Set the size of the deque to be k. */ + public MyCircularDeque(int k) { + arr = new int[k]; + capacity = k; + } + + /** Adds an item at the front of Deque. Return true if the operation is successful. */ + public boolean insertFront(int value) { + if (size >= capacity) { + return false; + } + head = (head + capacity - 1) % capacity; + arr[head] = 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; + } + arr[tail] = value; + tail = (tail + capacity + 1) % capacity; + 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; + } + head = (head + capacity + 1) % capacity; + 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; + } + tail = (tail + capacity - 1) % capacity; + size --; + return true; + } + + /** Get the front item from the deque. */ + public int getFront() { + if (size <= 0) { + return -1; + } + return arr[head]; + } + + /** Get the last item from the deque. */ + public int getRear() { + if (size <= 0) { + return -1; + } + return arr[(tail + capacity - 1) % capacity]; + } + + /** Checks whether the circular deque is empty or not. */ + public boolean isEmpty() { + if (size <= 0) { + return true; + } + return false; + } + + /** Checks whether the circular deque is full or not. */ + public boolean isFull() { + if (size >= capacity) { + return true; + } + 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(); + */ \ No newline at end of file diff --git a/Week_01/G20200343030019/LeetCode_66_019.java b/Week_01/G20200343030019/LeetCode_66_019.java new file mode 100644 index 00000000..d8db5384 --- /dev/null +++ b/Week_01/G20200343030019/LeetCode_66_019.java @@ -0,0 +1,20 @@ +class Solution { + public int[] plusOne(int[] digits) { + if (digits == null || digits.length <= 0) { + return digits; + } + digits[digits.length -1] ++; + for (int index = digits.length - 1; index >= 0 && digits[index] > 9; index --) { + digits[index] -= 10; + if (index == 0) { + int[] newArr = new int[digits.length + 1]; + System.arraycopy(digits, 0, newArr, 1, digits.length); + newArr[0] = 1; + digits = newArr; + break; + } + digits[index - 1] ++; + } + return digits; + } +} \ No newline at end of file diff --git a/Week_01/G20200343030019/LeetCode_88_019.java b/Week_01/G20200343030019/LeetCode_88_019.java new file mode 100644 index 00000000..83bc8fd2 --- /dev/null +++ b/Week_01/G20200343030019/LeetCode_88_019.java @@ -0,0 +1,18 @@ +class Solution { + public void merge(int[] nums1, int m, int[] nums2, int n) { + if (m == 0) { + System.arraycopy(nums2, 0, nums1, 0, n); + } + int index = m-- + n-- - 1; + while (m >=0 && n >= 0) { + if (nums1[m] > nums2[n]) { + nums1[index--] = nums1[m--]; + } else { + nums1[index--] = nums2[n--]; + } + } + while (n >= 0) { + nums1[index--] = nums2[n--]; + } + } +} \ No newline at end of file diff --git a/Week_01/G20200343030021/LeetCode_1_021.java b/Week_01/G20200343030021/LeetCode_1_021.java new file mode 100644 index 00000000..f152d0dd --- /dev/null +++ b/Week_01/G20200343030021/LeetCode_1_021.java @@ -0,0 +1,76 @@ +package ;/* + * @lc app=leetcode.cn id=1 lang=java + * + * [1] 两数之和 + * + * https://leetcode-cn.com/problems/two-sum/description/ + * + * algorithms + * Easy (47.53%) + * Likes: 7673 + * Dislikes: 0 + * Total Accepted: 828.2K + * Total Submissions: 1.7M + * 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] + * + * + */ + +import java.util.HashMap; +import java.util.HashSet; + +// @lc code=start +class Solution { + + //暴力枚举 + public int[] twoSum_1(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}; + } + } + } + throw new IllegalArgumentException("no"); + } + //两次hash + public int[] twoSum_2(int[] nums, int target) { + HashMap hashMap = new HashMap<>(); + for (int i = 0; i < nums.length; i++) { + hashMap.put(nums[i], i); + } + for (int i = 0; i < nums.length; i++) { + int complement = target - nums[i]; + if (hashMap.containsKey(complement) && hashMap.get(complement) != i) { + return new int [] {i,hashMap.get(complement)}; + } + } + throw new IllegalArgumentException("no"); + } + + //一次hash + public int[] twoSum_3(int[] nums,int target) { + HashMap 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}; + } + } + throw new IllegalArgumentException("null"); + } + +} +// @lc code=end + diff --git a/Week_01/G20200343030021/LeetCode_283_021.java b/Week_01/G20200343030021/LeetCode_283_021.java new file mode 100644 index 00000000..de981a66 --- /dev/null +++ b/Week_01/G20200343030021/LeetCode_283_021.java @@ -0,0 +1,49 @@ +package week_01;/* + * @lc app=leetcode.cn id=283 lang=java + * + * [283] 移动零 + */ + +// @lc code=start +class Solution { + public int[] moveZeroes(int[] nums) { + 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++; + } + } + return nums; + } + + public int[] moveZeroes2(int[] nums) { + int count = 0; + for (int i = 0; i < nums.length; i++) { + if (nums[i] == 0) { + count++; + }else if (count > 0) { + nums[i - count] = nums[i]; + nums[i] = 0; + } + } + return nums; + } + + public int[] moveZeroes_3(int[] nums) { + int count = 0; + for (int i = 0; i + * 示例: + * 给定 nums = [2, 7, 11, 15], target = 9 + * 因为 nums[0] + nums[1] = 2 + 7 = 9 + * 所以返回 [0, 1] + *

+ * 来源:力扣(LeetCode) + * 链接:https://leetcode-cn.com/problems/two-sum + * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + */ +public class TwoSum { + 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) { + continue; + } + return new int[]{i, j}; + } + } + return null; + } +} diff --git a/Week_01/G20200343030029/LeetCode_4_029.java b/Week_01/G20200343030029/LeetCode_4_029.java new file mode 100644 index 00000000..dd5c8675 --- /dev/null +++ b/Week_01/G20200343030029/LeetCode_4_029.java @@ -0,0 +1,48 @@ +import java.util.Arrays; +class LeetCode_4_029 { + //题解:给定两个有序整数数组 nums1 和 nums2,将 nums2 合并到 nums1 中,使得 num1 成为一个有序数组。 + //初始化 nums1 和 nums2 的元素数量分别为 m 和 n。 + //你可以假设 nums1 有足够的空间(空间大小大于或等于 m + n)来保存 nums2 中的元素。 + + public static void main(String[] args) { + solutionTest(); + } + + public static void solutionTest() { + int[] nums1 = {1, 2, 3, 0, 0, 0}; + int m = 3; + int[] nums2 = {2, 5, 6}; + int n = 3; + //System.out.println(Arrays.toString(violenceSolution(nums1, m, nums2, n))); + System.out.println(Arrays.toString(bigNumLastSolution(nums1, m, nums2, n))); + } + + /** + * 暴力求解,先拷贝数组,然后排序,,时间复杂度 O((n+m)log(n+m)) + */ + public static int[] violenceSolution(int[] nums1, int m, int[] nums2, int n) { + System.arraycopy(nums2, 0, nums1, m, n); + Arrays.sort(nums1); + return nums1; + } + + /** + *两个数组,从后往前遍历,最大的数相互比较,最大的数在nums1[]末尾 时间复杂度为O(n+m) + */ + public static int[] bigNumLastSolution(int[] nums1, int m, int[] nums2, int n) { + int endIndex = nums1.length - 1; + int endNums1Index = m - 1; + int endNums2Index = n - 1; + while (endNums2Index >= 0){ + if(endNums1Index < 0){ + nums1[endIndex--] = nums2[endNums2Index--]; + }else if(nums1[endNums1Index] > nums2[endNums2Index]){ + nums1[endIndex--] = nums1[endNums1Index--]; + }else{ + nums1[endIndex--] = nums2[endNums2Index--]; + } + } + return nums1; + } + +} \ No newline at end of file diff --git a/Week_01/G20200343030029/LeetCode_5_029.java b/Week_01/G20200343030029/LeetCode_5_029.java new file mode 100644 index 00000000..75fb2ecc --- /dev/null +++ b/Week_01/G20200343030029/LeetCode_5_029.java @@ -0,0 +1,49 @@ +import java.util.HashMap; +import java.util.Map; +import java.util.Arrays; +class LeetCode_5_029 { + // 解题: + //
给定一个整数数组 nums和一个目标值 target,请你在该数组中找出和为目标值的那两个整数, + //
并返回他们的数组下标。你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。 + + public static void main(String[] args) { + // test + solutionTest(); + } + + public static void solutionTest(){ + int[] nums = {2, 7, 11, 15}; + int target = 9; + System.out.println(Arrays.toString(hashSolution(nums, target))); + System.out.println(Arrays.toString(violenceSolution(nums, target))); + } + + // 1.暴力解法 时间复杂度为n^2 + public static int[] violenceSolution(int[] nums, int target) { + int[] indexArray = 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) { + indexArray[0] = i; + indexArray[1] = j; + return indexArray; + } + } + } + return indexArray; + } + + //2. hash 解法 时间复杂度为n + // map + public static int[] hashSolution(int[] nums, int target) { + Map map = new HashMap(); + for (int i = 0; i < nums.length; i++) { + int indexValue = target - nums[i]; + if (map.containsKey(indexValue)) { + return new int[]{map.get(target - nums[i]), i}; + } + map.put(nums[i], i); + } + throw new IllegalArgumentException("No two sum value"); + } +} \ No newline at end of file diff --git a/Week_01/G20200343030029/LeetCode_6_029.java b/Week_01/G20200343030029/LeetCode_6_029.java new file mode 100644 index 00000000..6ef196d2 --- /dev/null +++ b/Week_01/G20200343030029/LeetCode_6_029.java @@ -0,0 +1,51 @@ +import java.util.Arrays; + +class LeetCode_6_029 { + //题解: + //
给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。 + //输入: [0,1,0,3,12] + //输出: [1,3,12,0,0] + + public static void main(String[] args) { + solutionTest(); + } + + public static void solutionTest() { + int[] nums = {0, 1, 0, 3, 12}; + System.out.println(Arrays.toString(violenceSolution(nums))); + System.out.println(Arrays.toString(speedPointerSolution(nums))); + } + + /** + * 暴力求解 时间复杂度 n^2 + */ + public static int[] violenceSolution(int[] nums) { + for (int i = 0; i < nums.length - 1; i++) { + for (int j = i + 1; j < nums.length; j++) { + if (0 == nums[i] && 0 != nums[j]) { + swap(i, j, nums); + } + } + } + return nums; + } + + /** + * 快慢指针,快指针指向非零指针,慢指针指向零元素,交换, 时间复杂度为n + */ + public static int[] speedPointerSolution(int nums[]) { + for(int fast = 0, slow = 0; fast < nums.length; fast++){ + if(0 != nums[fast]){ + swap(fast, slow, nums); + slow++; + } + } + return nums; + } + + public static void swap(int index1, int index2, int[] nums) { + int tempvalue = nums[index1]; + nums[index1] = nums[index2]; + nums[index2] = tempvalue; + } +} \ No newline at end of file diff --git a/Week_01/G20200343030029/NOTE.md b/Week_01/G20200343030029/NOTE.md index 50de3041..f26bc6f8 100644 --- a/Week_01/G20200343030029/NOTE.md +++ b/Week_01/G20200343030029/NOTE.md @@ -1 +1,26 @@ -学习笔记 \ No newline at end of file +#第一周学习总结 +*** +* 复杂度 + * 时间复杂度: + * O(1):常数级复杂度 + * O(logn):仅仅次于常数数量级复杂度,用于二分查找,二叉树 + * O(n):线性复杂度,例如数组遍历 + * O(n^2):数组双重for循环 + * O(2^n):指数复杂度,例如递归 + * 空间复杂度: + * O(1):源空间操作,不开辟新空间 + * O(n):开辟新空间,例如新建数组 +* 数组 + * 空间连续 + * 查找,修改比较快 + * 增加,删除比较慢 +* 链表 (离散空间,查找慢,插入,删除比较快,优化算法跳表(时间复杂度O(logn))) + * 单链表:前一个元素指向后一个元素的索引,最后一个元素指向NULL + * 双向链表:前一个元素指向后一个元素的索引,后一个元素指向前一个元素的索引 + * 循环链表:前一个元素指向后一个元素的索引,最后一个元素指向头节点索引 +* 队列 + * 普通队列:先进先出 + * 双端队列:两端都可以入队和出队 + * 优先队列:根据优先规则出队 +* 栈:先进后出 + diff --git a/Week_01/G20200343030035/LeetCode_42_035.py b/Week_01/G20200343030035/LeetCode_42_035.py new file mode 100644 index 00000000..5bd1725a --- /dev/null +++ b/Week_01/G20200343030035/LeetCode_42_035.py @@ -0,0 +1,20 @@ +# LeetCode #42 接雨水 +# 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。 + + +class Solution: + def trap(self, block): + if not block or len(block) < 3: + return 0 + sum = 0 + left, right = 0, len(block) - 1 + l_max, r_max = block[left], block[right] + while left < right: + l_max, r_max = max(block[left], l_max), max(block[right], r_max) + if l_max <= r_max: + sum += l_max - block[left] + left += 1 + else: + sum += r_max - block[right] + right -= 1 + return sum \ No newline at end of file diff --git a/Week_01/G20200343030035/LeetCode_66_035.py b/Week_01/G20200343030035/LeetCode_66_035.py new file mode 100644 index 00000000..5f3649cb --- /dev/null +++ b/Week_01/G20200343030035/LeetCode_66_035.py @@ -0,0 +1,23 @@ +# LeetCode #66 加一 +# 给定一个由整数组成的非空数组所表示的非负整数,在该数的基础上加一。 +# 最高位数字存放在数组的首位, 数组中每个元素只存储单个数字。 +# 你可以假设除了整数 0 之外,这个整数不会以零开头。 + + +class Solution: + def plusOne(self, digits): + carry = 0 + digits[len(digits)-1] += 1 + for i in range(len(digits)-1,-1,-1): + digits[i] += carry + if digits[i] > 9 : + carry = 1 + digits[i] = 0 + else: + carry = 0 + if carry == 1: + digits = [1] + digits + res = '' + for i in range(len(digits)-1,-1,-1): + res = str(digits[i]) + res + return(res) \ No newline at end of file diff --git a/Week_01/G20200343030361/LeetCode_21_361.js b/Week_01/G20200343030361/LeetCode_21_361.js new file mode 100644 index 00000000..3b9c1564 --- /dev/null +++ b/Week_01/G20200343030361/LeetCode_21_361.js @@ -0,0 +1,20 @@ +var mergeTwoLists = function(l1, l2) { + let preHead = {}; + let prev = preHead; + + while (l1 && l2) { + 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/G20200343030361/LeetCode_283_361.rb b/Week_01/G20200343030361/LeetCode_283_361.rb new file mode 100644 index 00000000..29dacb09 --- /dev/null +++ b/Week_01/G20200343030361/LeetCode_283_361.rb @@ -0,0 +1,14 @@ +def move_zeroes(nums) + noneZeroIndex = 0 + + nums.each_with_index do |n, indx| + next unless n != 0 + nums[noneZeroIndex] = n + + nums[indx] = 0 if indx != noneZeroIndex + + noneZeroIndex += 1 + end + + nums +end diff --git a/Week_01/G20200343030363/LeetCode_189_363.java b/Week_01/G20200343030363/LeetCode_189_363.java new file mode 100644 index 00000000..c7de028b --- /dev/null +++ b/Week_01/G20200343030363/LeetCode_189_363.java @@ -0,0 +1,62 @@ +package cn.geet.week1; + +/** + * + * 旋转数组 + * + * @author lemon + * @version 1.0.0 + * @Description TODO + * @createTime 2020年02月14日 16:43:00 + */ +public class LeetCode_189_363 { + + /** + * Rotate. + * + * @param nums + * the nums + * @param k + * the k + */ + public void rotate(int[] nums, int k) { + + // 三种解决方式 要求使用空间复杂度为 O(1) 的原地算法 + + // 1、暴力解法 + + // 2、使用额外数组 时间O(n) 空间O(n) + // int[] tempArr = new int[nums.length]; + // for (int i = 0; i < nums.length; i++) { + // tempArr[(i + k) % nums.length] = nums[i]; + // } + // + // for (int i = 0; i < nums.length; i++) { + // nums[i] = tempArr[i]; + // } + + // 3、使用环状数组 + + + // 4、使用反转 + k = k % nums.length; + reverse(nums, 0, nums.length - 1); + reverse(nums, 0, k - 1); + reverse(nums, k, nums.length - 1); + } + + private 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) { + LeetCode_189_363 temp = new LeetCode_189_363(); + temp.rotate(new int[] {1, 2, 3, 4, 5, 6, 7}, 3); + } +} diff --git a/Week_01/G20200343030363/LeetCode_21_363.java b/Week_01/G20200343030363/LeetCode_21_363.java new file mode 100644 index 00000000..475f556b --- /dev/null +++ b/Week_01/G20200343030363/LeetCode_21_363.java @@ -0,0 +1,81 @@ +package cn.geet.week1; + +/** + * @author lemon + * @version 1.0.0 + * @Description TODO + * @createTime 2020年02月16日 08:42:00 + */ +public class LeetCode_21_363 { + + /** + * Merge two lists list node. 递归方式 + * + * @param node1 + * the node 1 + * @param node2 + * the node 2 + * @return the list node + */ + public ListNode mergeTwoLists(ListNode node1, ListNode node2) { + if (null == node1) { + return node2; + } else if (null == node2) { + return node1; + } else if ((int)node1.val < (int)node2.val) { + node1.next = mergeTwoLists(node1.next, node2); + return node1; + } else { + node2.next = mergeTwoLists(node1, node2.next); + return node2; + } + } + + /** + * Merge two lists 2 list node. 迭代方式 + * + * @param node1 + * the node 1 + * @param node2 + * the node 2 + * @return the list node + */ + public ListNode mergeTwoLists2(ListNode node1, ListNode node2) { + + ListNode prehead = new ListNode(-1); + ListNode prev = prehead; + + while (node1 != null && node2 != null) { + if ((int)node1.val > (int)node2.val) { + prev.next = node2; + node2 = node2.next; + } else { + prev.next = node1; + node1 = node1.next; + } + prev = prev.next; + } + + // 一个节点为空了, 另外一个node直接加在后面 + prev.next = node1 == null ? node2 : node1; + return prehead.next; + } + + public static void main(String[] args) { + LeetCode_21_363 temp = new LeetCode_21_363(); + + ListNode node1 = new ListNode(1); + node1.next = new ListNode(2); + node1.next.next = new ListNode(4); + + ListNode node2 = new ListNode(1); + node2.next = new ListNode(3); + node2.next.next = new ListNode(5); + + ListNode lastNode = temp.mergeTwoLists(node1, node2); + while (lastNode != null) { + System.out.println(lastNode.val); + lastNode = lastNode.next; + } + } +} diff --git a/Week_01/G20200343030363/LeetCode_26_363.java b/Week_01/G20200343030363/LeetCode_26_363.java new file mode 100644 index 00000000..1f62f050 --- /dev/null +++ b/Week_01/G20200343030363/LeetCode_26_363.java @@ -0,0 +1,39 @@ +package cn.geet.week1; + +/** + * @author lemon + * @version 1.0.0 + * @Description TODO + * @createTime 2020年02月14日 16:09:00 + */ +public class LeetCode_26_363 { + + /** + * Remove duplicates int. 不考虑新数组长度后面的数字 + * + * @param nums + * the nums + * @return the int + */ + public int removeDuplicates(int[] nums) { + + if (nums == null || (null != nums && nums.length == 0)) { + return 0; + } + + int index = 0; + for (int i = 1; i < nums.length; i++) { + if (nums[i] != nums[index]) { + index++; + nums[index] = nums[i]; + } + } + return index + 1; + } + + public static void main(String[] args) { + LeetCode_26_363 temp = new LeetCode_26_363(); + int result = temp.removeDuplicates(new int[] {0, 0, 1, 1, 1, 2, 2, 3, 3, 4}); + System.out.println(result); + } +} diff --git a/Week_01/G20200343030363/LeetCode_42_363.java b/Week_01/G20200343030363/LeetCode_42_363.java new file mode 100644 index 00000000..1894ebc6 --- /dev/null +++ b/Week_01/G20200343030363/LeetCode_42_363.java @@ -0,0 +1,49 @@ +package cn.geet.week1; + +/** + * + * 接雨水 + * + * @author lemon + * @version 1.0.0 + * @Description TODO + * @createTime 2020年02月16日 11:33:00 + * + */ +public class LeetCode_42_363 { + + /** + * Trap int. 按列求和, 暴力解法 O(n^2) + * + * @param height + * the height + * @return the int + */ + public int trap(int[] height) { + int sum = 0; + for (int i = 1; i < height.length - 1; i++) { + + int max_left = 0; + int max_right = 0; + + // 找出左边最高 + for (int j = 0; j < i; j++) { + if (height[j] > max_left) { + max_left = height[j]; + } + } + + // 找出右边最高 + for (int k = i + 1; k < height.length; k++) { + if (height[k] > max_right) { + max_right = height[k]; + } + } + int min = Math.min(max_left, max_right); + if (min > height[i]) { + sum = sum + (min - height[i]); + } + } + return sum; + } +} diff --git a/Week_01/G20200343030363/LeetCode_641_363.java b/Week_01/G20200343030363/LeetCode_641_363.java new file mode 100644 index 00000000..d30fecbb --- /dev/null +++ b/Week_01/G20200343030363/LeetCode_641_363.java @@ -0,0 +1,93 @@ +package cn.geet.week1; + +/** + * leetcode 641 循环双端队列 + * + * @author lemon + * @version 1.0.0 + * @Description TODO + * @createTime 2020年02月15日 13:23:00 + */ +public class LeetCode_641_363 { + + /** + * 双端队列 是栈和队列的组合模式, 可以两边同时操作 + */ + private int capacity; + private int[] arr; + private int head = 0; + private int tail = 0; + + /** Initialize your data structure here. Set the size of the deque to be k. */ + public LeetCode_641_363(int k) { + capacity = k + 1; + arr = new int[capacity]; + } + + /** 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 + capacity) % capacity; + arr[head] = 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; + } + arr[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() { + if (isEmpty()) { + return -1; + } + return arr[head]; + } + + /** Get the last item from the deque. */ + public int getRear() { + if (isEmpty()) { + return -1; + } + return arr[(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 head == (tail + 1) % capacity; + } + +} diff --git a/Week_01/G20200343030363/LeetCode_66_363.java b/Week_01/G20200343030363/LeetCode_66_363.java new file mode 100644 index 00000000..a0257d56 --- /dev/null +++ b/Week_01/G20200343030363/LeetCode_66_363.java @@ -0,0 +1,35 @@ +package cn.geet.week1; + +/** + * @author lemon + * @version 1.0.0 + * @Description TODO + * @createTime 2020年02月16日 10:16:00 + */ +public class LeetCode_66_363 { + + /** + * Plus one int [ ]. 重点在进位 + * + * @param digits + * the digits + * @return the int [ ] + */ + 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/G20200343030365/LeerCode_1_365.java b/Week_01/G20200343030365/LeerCode_1_365.java new file mode 100644 index 00000000..c6deacab --- /dev/null +++ b/Week_01/G20200343030365/LeerCode_1_365.java @@ -0,0 +1,21 @@ +package homework.week_01; + +import java.util.HashMap; +import java.util.Map; + +public class LeerCode_1_365 { + public int[] twoSum(int[] nums, int target) { + int[] result = new int[2]; + Map map = new HashMap(); + for(int i=0;i 0; j--){ + nums[j] = nums[j-1]; + } + nums[0] = last; + } + } + + // 反转 + public void rotate2(int[] nums, int k) { + + int length = nums.length; + k %= length; + reverse(nums,0,length-1); + reverse(nums,0,k-1); + reverse(nums,k,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; + start++; + end--; + } + } + +} diff --git a/Week_01/G20200343030365/LeetCode_21_365.java b/Week_01/G20200343030365/LeetCode_21_365.java new file mode 100644 index 00000000..b726632a --- /dev/null +++ b/Week_01/G20200343030365/LeetCode_21_365.java @@ -0,0 +1,35 @@ +package homework.week_01; + +public class LeetCode_21_365 { + + + public ListNode mergeTwoLists(ListNode l1, ListNode l2) { + ListNode lv = new ListNode(-1); + + //保存头 + ListNode pre = lv; + + while(l1 != null && l2 != null){ + if(l1.val <= l2.val){ + lv.next = l1; + l1 = l1.next; + }else{ + lv.next = l2; + l2 = l2.next; + } + lv = lv.next; + } + + lv.next = l1 == null ? l2 : l1; + + return pre.next; + + } + + + public class ListNode { + int val; + ListNode next; + ListNode(int x) { val = x; } + } +} diff --git a/Week_01/G20200343030365/LeetCode_26_365.java b/Week_01/G20200343030365/LeetCode_26_365.java new file mode 100644 index 00000000..aed0f38e --- /dev/null +++ b/Week_01/G20200343030365/LeetCode_26_365.java @@ -0,0 +1,21 @@ +package homework.week_01; + +/** + * 删除排序数组中的重复项 + */ +public class LeetCode_26_365 { + + public int removeDuplicates(int[] nums) { + + if(nums.length == 0) return 0; + int i = 0; + + for(int j = 1; j < nums.length; j++){ + if(nums[i] != nums[j]){ + i++; + nums[i] = nums[j]; + } + } + return i+1; + } +} diff --git a/Week_01/G20200343030365/LeetCode_283_365.java b/Week_01/G20200343030365/LeetCode_283_365.java new file mode 100644 index 00000000..fd01f952 --- /dev/null +++ b/Week_01/G20200343030365/LeetCode_283_365.java @@ -0,0 +1,19 @@ +package homework.week_01; + +public class LeetCode_283_365 { + + public void moveZeroes(int[] nums) { + + int j = 0; + for(int i = 0; i < nums.length; i++){ + if(nums[i] != 0){ + nums[j] = nums[i]; + j++; + } + } + for(; j < nums.length; j++){ + nums[j] = 0; + } + } + +} diff --git a/Week_01/G20200343030365/LeetCode_66_365.java b/Week_01/G20200343030365/LeetCode_66_365.java new file mode 100644 index 00000000..d2c7d46d --- /dev/null +++ b/Week_01/G20200343030365/LeetCode_66_365.java @@ -0,0 +1,19 @@ +package homework.week_01; + +public class LeetCode_66_365 { + + 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; + } + + public static void main(String[] args) { + new LeetCode_66_365().plusOne(new int[]{9,9,9,9}); + } +} diff --git a/Week_01/G20200343030365/LeetCode_88_365.java b/Week_01/G20200343030365/LeetCode_88_365.java new file mode 100644 index 00000000..7d8bcc8e --- /dev/null +++ b/Week_01/G20200343030365/LeetCode_88_365.java @@ -0,0 +1,22 @@ +package homework.week_01; + +import java.util.Arrays; + +/** + * 合并两个有序数组 + */ +public class LeetCode_88_365 { + + 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) { + // 注意--符号在后面,表示先进行计算再减1,这种缩写缩短了代码 + nums1[len--] = nums1[len1] > nums2[len2] ? nums1[len1--] : nums2[len2--]; + } + // 表示将nums2数组从下标0位置开始,拷贝到nums1数组中,从下标0位置开始,长度为len2+1 + System.arraycopy(nums2, 0, nums1, 0, len2 + 1); + } +} diff --git "a/Week_01/G20200343030369/189.\346\227\213\350\275\254\346\225\260\347\273\204.swift" "b/Week_01/G20200343030369/189.\346\227\213\350\275\254\346\225\260\347\273\204.swift" new file mode 100644 index 00000000..b0314962 --- /dev/null +++ "b/Week_01/G20200343030369/189.\346\227\213\350\275\254\346\225\260\347\273\204.swift" @@ -0,0 +1,58 @@ +/* + * @lc app=leetcode.cn id=189 lang=swift + * + * [189] 旋转数组 + * + * https://leetcode-cn.com/problems/rotate-array/description/ + * + * algorithms + * Easy (40.37%) + * Likes: 487 + * Dislikes: 0 + * Total Accepted: 97.1K + * Total Submissions: 240.2K + * 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) { + rotate0(&nums, k) + } + + private func rotate0(_ nums: inout [Int], _ k: Int) { + let mod = k % nums.count + nums.reverse() + nums[0.. Int { + return removeDuplicates0(&nums) + } + + private func removeDuplicates0(_ nums: inout [Int]) -> Int { + var i = 0 + if nums.count >= 1 { + for j in 1.. map = new HashMap<>(); +// //通过map来存储下标和值 +// for (int i = 0; i < nums.length; i++) { +// map.put(nums[i], i); +// } +// for (int i = 0; i < nums.length; i++) { +// int t = target - nums[i]; +// //不能是同一个位置 +// if (map.containsKey(t) && map.get(t) != i) {//&& map.get(t) != i 需要注意如果第一个是3 target = 6 那么 +// //得到的结果就是{0,0} 肯定是不对的 +// return new int[]{i, map.get(t)}; +// } +// } +// return new int[]{}; + // 执行耗时:4 ms,击败了72.73% 的Java用户 + // 内存消耗:46.4 MB,击败了5.04% 的Java用户 + + //解法3:上述解法优化了时间复杂度,但是上述解法中存在两个循环,能否只剩下一个循环呢? + //思考:int t = target - nums[i]; map.put(t,0) [2,17,7,15] target = 9 + //9 - 2 = 7 map.put(2,0), 9 - 17 = -8 map.put(17,1), 9 - 7 = 2, map.get(2) = 0 {0,2} + //从上述的解法中我们可以得到一个推论: + Map map = new HashMap<>(); + for (int i = 0; i < nums.length; i++) { + int t = target - nums[i]; + if (map.containsKey(t) && map.get(t) != i) { + return new int[]{map.get(t), i};//map.get(t) 肯定小于 i因为map 存储的都是i之前的 + } else { + //如果不存在记录 继续下一个 + map.put(nums[i], i); + } + } + return new int[]{}; + //在时间复杂度上差不多到了一个极致的优化 + //执行耗时:3 ms,击败了97.23% 的Java用户 + //内存消耗:46.8 MB,击败了5.04% 的Java用户 + } +} diff --git "a/Week_01/G20200343030371/\344\275\234\344\270\232/leetcode189.java" "b/Week_01/G20200343030371/\344\275\234\344\270\232/leetcode189.java" new file mode 100644 index 00000000..852fb92b --- /dev/null +++ "b/Week_01/G20200343030371/\344\275\234\344\270\232/leetcode189.java" @@ -0,0 +1,16 @@ +package com.week01; + +public class leetcode189 { + public void rotate(int[] nums, int k) { + int res; + //双循环旋转数组 + for (int i = 0; i < k; i++) { + res = nums[nums.length - 1]; + for (int j = 0; j < nums.length; j++) { + int temp = nums[j]; + nums[j] = res; + res = temp; + } + } + } +} diff --git "a/Week_01/G20200343030371/\344\275\234\344\270\232/leetcode26.java" "b/Week_01/G20200343030371/\344\275\234\344\270\232/leetcode26.java" new file mode 100644 index 00000000..2a7c404e --- /dev/null +++ "b/Week_01/G20200343030371/\344\275\234\344\270\232/leetcode26.java" @@ -0,0 +1,18 @@ +package com.week01; + +public class leetcode26 { + public int removeDuplicates(int[] nums) { + if (nums.length == 0) return 0; + //通过双指针法进行l指到第一个位置,遍历数组从第二个位置开始 + //如果遇到不想等到数组 则l+1 并且改变为l+1的值 + //这样重复的元素就可以被替换掉,同时相邻的不相等的元素也可以少去很多判断 + int l = 0; + for (int i = 1; i < nums.length; i++) { + if (nums[l] != nums[i]) { + l++; + nums[l] = nums[i]; + } + } + return l + 1; + } +} diff --git "a/Week_01/G20200343030371/\344\275\234\344\270\232/leetcode283.java" "b/Week_01/G20200343030371/\344\275\234\344\270\232/leetcode283.java" new file mode 100644 index 00000000..6cfa1dbf --- /dev/null +++ "b/Week_01/G20200343030371/\344\275\234\344\270\232/leetcode283.java" @@ -0,0 +1,39 @@ +package com; + +public class leetcode283 { + public void moveZeroes(int[] nums) { + //1 读懂题目要求: + // 将数组中 0 移动到数组的末尾,同时保持非零元素的相对顺序 + // 必须在原数组上操作,不能拷贝额外的数组 + // 尽量减少操作次数 + //2 解题思路: + + // 解法1: loop数组非0的当前loop count+1 一次从0开始替换不为0的元素,然后在loop 从count开始剩余的元素都是0 +// int count = 0; +// for (int i = 0; i < nums.length; i++) { +// if (nums[i] != 0) { +// nums[count++] = nums[i]; +// } +// } +// for (int i = count; i map = new HashMap<>(); +// //通过map来存储下标和值 +// for (int i = 0; i < nums.length; i++) { +// map.put(nums[i], i); +// } +// for (int i = 0; i < nums.length; i++) { +// int t = target - nums[i]; +// //不能是同一个位置 +// if (map.containsKey(t) && map.get(t) != i) {//&& map.get(t) != i 需要注意如果第一个是3 target = 6 那么 +// //得到的结果就是{0,0} 肯定是不对的 +// return new int[]{i, map.get(t)}; +// } +// } +// return new int[]{}; + // 执行耗时:4 ms,击败了72.73% 的Java用户 + // 内存消耗:46.4 MB,击败了5.04% 的Java用户 + + //解法3:上述解法优化了时间复杂度,但是上述解法中存在两个循环,能否只剩下一个循环呢? + //思考:int t = target - nums[i]; map.put(t,0) [2,17,7,15] target = 9 + //9 - 2 = 7 map.put(2,0), 9 - 17 = -8 map.put(17,1), 9 - 7 = 2, map.get(2) = 0 {0,2} + //从上述的解法中我们可以得到一个推论: + Map map = new HashMap<>(); + for (int i = 0; i < nums.length; i++) { + int t = target - nums[i]; + if (map.containsKey(t) && map.get(t) != i) { + return new int[]{map.get(t), i};//map.get(t) 肯定小于 i因为map 存储的都是i之前的 + } else { + //如果不存在记录 继续下一个 + map.put(nums[i], i); + } + } + return new int[]{}; + //在时间复杂度上差不多到了一个极致的优化 + //执行耗时:3 ms,击败了97.23% 的Java用户 + //内存消耗:46.8 MB,击败了5.04% 的Java用户 + } +} diff --git "a/Week_01/G20200343030371/\350\257\276\344\270\212\350\256\262\350\247\243\347\256\227\346\263\225\346\200\273\347\273\223\344\270\216\345\275\222\347\272\263/leetcode11.java" "b/Week_01/G20200343030371/\350\257\276\344\270\212\350\256\262\350\247\243\347\256\227\346\263\225\346\200\273\347\273\223\344\270\216\345\275\222\347\272\263/leetcode11.java" new file mode 100644 index 00000000..5bf23d5e --- /dev/null +++ "b/Week_01/G20200343030371/\350\257\276\344\270\212\350\256\262\350\247\243\347\256\227\346\263\225\346\200\273\347\273\223\344\270\216\345\275\222\347\272\263/leetcode11.java" @@ -0,0 +1,24 @@ +package com; + +public class leetcode11 { + public int maxArea(int[] height) { + //思考:容器的宽度(j-i) * 容器的高度是最小的柱子 = 容器的面积 + //解法1 : 通过枚举法 循环嵌套比较 时间复杂度较高O(n^2) + int max = 0; +// for (int i = 0; i < height.length; i++) { +// //从第一根柱子开始跟所有柱子进行比较 +// for (int j = i; j < height.length; j++) { +// int area = (j - i) * Math.min(height[i],height[j]); +// max = Math.max(max,area); +// } +// } + //解法2:通过左右夹逼法,两个指针一个在最左侧,一个在最右侧,往中间移动,时间复杂度为O(n) + for (int i = 0, j = height.length-1; i < j; ) { + int h = (height[i] < height[j]) ? height[i++] : height[j--];//获取最小的高度 然后移动其中的一个指针 + int area = (j-i+1) * h;//注意在计算高度时候已经将 i + 1 或 j - 1 了 + max = Math.max(max,area); + } + return max; + + } +} diff --git "a/Week_01/G20200343030371/\350\257\276\344\270\212\350\256\262\350\247\243\347\256\227\346\263\225\346\200\273\347\273\223\344\270\216\345\275\222\347\272\263/leetcode15.java" "b/Week_01/G20200343030371/\350\257\276\344\270\212\350\256\262\350\247\243\347\256\227\346\263\225\346\200\273\347\273\223\344\270\216\345\275\222\347\272\263/leetcode15.java" new file mode 100644 index 00000000..92f8cf7f --- /dev/null +++ "b/Week_01/G20200343030371/\350\257\276\344\270\212\350\256\262\350\247\243\347\256\227\346\263\225\346\200\273\347\273\223\344\270\216\345\275\222\347\272\263/leetcode15.java" @@ -0,0 +1,165 @@ +package com; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; +//给定一个包含 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 数组 双指针 +public class leetcode15 { + public static void main(String[] args) { + int[] ints = new int[]{-13,10,11,-3,8,11,-4,8,12,-13,5,-6,-4,-2,12,11,7,-7,-3,10,12,13,-3,-2,6,-1,14,7,-13,8,14,-10,-4,10,-6,11,-2,-3,4,-13,0,-14,-3,3,-9,-6,-9,13,-6,3,1,-9,-6,13,-4,-15,-11,-12,7,-9,3,-2,-12,6,-15,-10,2,-2,-6,13,1,9,14,5,-11,-10,14,-5,11,-6,6,-3,-8,-15,-13,-4,7,13,-1,-9,11,-13,-4,-15,9,-4,12,-4,1,-9,-5,9,8,-14,-1,4,14}; + // -5 -5 -4 -4 -3 -2 -2 0 0 1 2 2 2 2 + List> lists = threeSum(ints); + System.out.println(lists.toString()); + } + + public static List> threeSum(int[] nums) { +// List> lists = new LinkedList<>(); +// if (nums == null || nums.length < 3) return lists; +// // 先对数组排序 否则在后面的从小到大添加到数组中存在问题 +// Arrays.sort(nums);//-4 -1 -1 0 1 2 + // 答案中不可以包含重复的三元组。 + // 思考 a + b = -c 类似两数之和 target = -c + + // 最优解法:通过一层循环来进行判断 优化循环嵌套 内部采用两个指针的方式进行 左右下标往中间推进 + // 注意 双指针一定是排序好的。 + // 排完序之后 首先进行边界判断 要实现 a + b+ c =0 那么nums[0] 一定是小于0的 nums[nums.length-1] 一定是大于0的否则这个数组就不能成立 + // 整个数组符号相同肯定是无解的 +// if (nums[0] <= 0 && nums[nums.length - 1] >= 0) { +// for (int i = 0; i < nums.length - 2; i++) { +// //移动左右下标 +// //优化边界 如果最最值为正值肯定无解 因为左右下标都在最左值的右边 肯定比最左值大 +// if (nums[i] > 0) break; +// if (i > 0 && nums[i] == nums[i - 1]) continue;//对比完第一个以后移动i ++ 同时注意跳过重复的 +// int first = i + 1; +// int last = nums.length - 1; +// //-4 -1 -1 0 1 2 举例 first = 1 ; last = 5 first 和 last 重合时停止 开始查找 +// while (first < last) { +// int result = nums[i] + nums[first] + nums[last]; +// if (result == 0) { +// lists.add(Arrays.asList(nums[i], nums[first], nums[last])); +// //注意去重之后 first还是之前的值,还需要+1 last还是之前的值,还需要-1 +// while (first < last && nums[first] == nums[first + 1]) { +// first++;//first++还是之前的值 +// } +// while (first < last && nums[last] == nums[last - 1]) { +// last--;//last--还是之前的值 +// } +// //变换值 +// first++; +// last--; +// } else if (result < 0) { +// //说明first的值较小 继续往右移动 同时如果first == first+1 跳过 +// //去重 +// while (first < last && nums[first] == nums[first + 1]) { +// first++;//first++还是之前的值 +// } +// first++; +// } else { +// //说明last的值较大 继续往左移动 同时跳过重复的数据 +// //去重 +// while (first < last && nums[last] == nums[last - 1]) { +// last--;//last--还是之前的值 +// } +// last--; +// } +// } +// } +// } + // 简化最优解法: + List> result = new LinkedList<>(); + if(nums==null || nums.length < 3){ + return result; + } + Arrays.sort(nums);//双指针法必须对数组进行排序 + for(int i = 0; i < nums.length - 2;i++){ + if(i==0 || (nums[i]!=nums[i-1])){ + int l = i+1; + int r = nums.length - 1; + while(l < r){ + int target = nums[l] + nums[r] + nums[i]; + if(target == 0){ + result.add(Arrays.asList(nums[i],nums[l],nums[r])); + while(l < r && nums[l] == nums[l+1]) l++; + while(l < r && nums[r] == nums[r-1]) r--; + l++;r--; + }else if(target < 0){ + l++; + }else{ + r--; + } + } + } + } + return result; + + // hash表记录解法 :将数组的值记录到hash表中 这种解法存在这一定的边界问题和重复问题判断相当麻烦 + // Map map = new HashMap<>(); +// for (int i = 0; i < nums.length - 2; i++) { +// for (int j = i + 1; j < nums.length - 1; j++) { +// if (map.get(nums[j]) != null) { +// Integer[] integers = map.get(nums[j]); +// List nodeList = new ArrayList<>(Arrays.asList(integers)); +// lists.add(nodeList); +// map.put(nums[j], null); +// //重复问题和边界问题如何解决? +// } else { +// int traget = 0 - (nums[i] + nums[j]);//目标值 +// Integer[] integers = new Integer[]{nums[i], nums[j],traget}; +// Arrays.sort(integers); +// map.put(traget, integers);//存储着 key 目标值 value:两个数 +// } +// } +// } + + // 暴力破解法:通过三层循环来进行判断 但是LeetCode 会报超时 主要用于理解本题的逻辑 n ^ 3 +// 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++) { +// //如何排除重复的呢? +// int result = nums[i] + nums[j] + nums[k]; +// if (result == 0) { +// List nodeList = new ArrayList<>(); +// //i < j < k +// nodeList.add(nums[i]); +// nodeList.add(nums[j]); +// nodeList.add(nums[k]); +// lists.add(nodeList); +// //如果i的下一个和i相等 则跳过,因为结果是一样的 +// //全是0 的情况如何解决?[0,0,0,0,0,0,0,0] +// while (i < nums.length - 2 && nums[i] == nums[i + 1]) {// 判断i 后面是否重复 如果重复 +1 +// i = i + 1; +// } +// while (j < nums.length - 1 && nums[j] == nums[j + 1]) {// 判断j后面是否重复 如果重复 +1 +// j = j + 1; +// } +// while (k < nums.length - 1 && nums[k] == nums[k + 1]) {//判断k后面是否重复 如果重复 +1 +// k = k + 1; +// } +// if (i == nums.length - 2) {// i 已经循环完毕 +// return lists; +// } +// } +// } +// } +// } +// return lists; + } +} diff --git "a/Week_01/G20200343030371/\350\257\276\344\270\212\350\256\262\350\247\243\347\256\227\346\263\225\346\200\273\347\273\223\344\270\216\345\275\222\347\272\263/leetcode155.java" "b/Week_01/G20200343030371/\350\257\276\344\270\212\350\256\262\350\247\243\347\256\227\346\263\225\346\200\273\347\273\223\344\270\216\345\275\222\347\272\263/leetcode155.java" new file mode 100644 index 00000000..0b461d19 --- /dev/null +++ "b/Week_01/G20200343030371/\350\257\276\344\270\212\350\256\262\350\247\243\347\256\227\346\263\225\346\200\273\347\273\223\344\270\216\345\275\222\347\272\263/leetcode155.java" @@ -0,0 +1,49 @@ +package com; + +import java.util.Stack; +//最小栈 +public class leetcode155 { + class MinStack { + Stack stack; + Stack minStack; + + /** + * initialize your data structure here. + */ + public MinStack() { + stack = new Stack<>(); + minStack = new Stack<>(); + } + + public void push(int x) { + //入栈 + stack.push(x); + //判断是否入最小栈 + if (minStack.isEmpty() || minStack.peek() >= x){ + minStack.push(x); + } + } + + public void pop() { + if (!stack.empty()){ + int top = stack.pop(); + if (!minStack.isEmpty() && top == minStack.peek()){ + minStack.pop(); + } + } + } + + public int top() { + if (!stack.empty()) + return stack.peek(); + return 0; + } + + public int getMin() { + if (!minStack.empty()){ + return minStack.peek(); + } + return 0; + } + } +} diff --git "a/Week_01/G20200343030371/\350\257\276\344\270\212\350\256\262\350\247\243\347\256\227\346\263\225\346\200\273\347\273\223\344\270\216\345\275\222\347\272\263/leetcode20.java" "b/Week_01/G20200343030371/\350\257\276\344\270\212\350\256\262\350\247\243\347\256\227\346\263\225\346\200\273\347\273\223\344\270\216\345\275\222\347\272\263/leetcode20.java" new file mode 100644 index 00000000..8b22b69c --- /dev/null +++ "b/Week_01/G20200343030371/\350\257\276\344\270\212\350\256\262\350\247\243\347\256\227\346\263\225\346\200\273\347\273\223\344\270\216\345\275\222\347\272\263/leetcode20.java" @@ -0,0 +1,27 @@ +package com; + +import java.util.HashMap; +import java.util.Map; +import java.util.Stack; + +public class leetcode20 { + public boolean isValid(String s) { + //通过栈来解决问题 + Stack stack = new Stack<>(); + Map map = new HashMap<>(); + map.put('}', '{'); + map.put(']', '['); + map.put(')', '('); + for (char c : s.toCharArray()) { + if (map.containsKey(c)) { + char top = stack.empty() ? '#' : stack.pop(); + if (top != map.get(c)){ + return false; + } + } else { + stack.push(c); + } + } + return stack.isEmpty(); + } +} diff --git "a/Week_01/G20200343030371/\350\257\276\344\270\212\350\256\262\350\247\243\347\256\227\346\263\225\346\200\273\347\273\223\344\270\216\345\275\222\347\272\263/leetcode283.java" "b/Week_01/G20200343030371/\350\257\276\344\270\212\350\256\262\350\247\243\347\256\227\346\263\225\346\200\273\347\273\223\344\270\216\345\275\222\347\272\263/leetcode283.java" new file mode 100644 index 00000000..6cfa1dbf --- /dev/null +++ "b/Week_01/G20200343030371/\350\257\276\344\270\212\350\256\262\350\247\243\347\256\227\346\263\225\346\200\273\347\273\223\344\270\216\345\275\222\347\272\263/leetcode283.java" @@ -0,0 +1,39 @@ +package com; + +public class leetcode283 { + public void moveZeroes(int[] nums) { + //1 读懂题目要求: + // 将数组中 0 移动到数组的末尾,同时保持非零元素的相对顺序 + // 必须在原数组上操作,不能拷贝额外的数组 + // 尽量减少操作次数 + //2 解题思路: + + // 解法1: loop数组非0的当前loop count+1 一次从0开始替换不为0的元素,然后在loop 从count开始剩余的元素都是0 +// int count = 0; +// for (int i = 0; i < nums.length; i++) { +// if (nums[i] != 0) { +// nums[count++] = nums[i]; +// } +// } +// for (int i = count; i b { + return a + } + return b +} + +//暴力求解 +//从左到右,对于每一个元素,枚举出与其右边元素组成的面积,比较最大值 +//O(n^2) +func enumArea(height []int) int { + maxArea := 0 + for i := 0; i < len(height); i++ { + for j := i + 1; j < len(height); j++ { + maxArea = max(maxArea, (j-i)*min(height[i], height[j])) + } + } + return maxArea +} + +//左右夹逼 +//最左侧到最右侧的宽度最长,具有第一优势,然后左右分别向中间收敛,收敛的过程中比较最大值 +//收敛时,左右两个边界中的较小值,才需要去移动寻找下一个值 +//O(n) +func shrinkArea(height []int) int { + maxArea := 0 + for i, j := 0, len(height)-1; i < j; { + maxArea = max(maxArea, (j-i)*min(height[i], height[j])) + if height[i] < height[j] { + i++ + } else { + j-- + } + } + return maxArea +} diff --git a/Week_01/G20200343030373/LeetCode_141_373/LeetCode_141_373_test.go b/Week_01/G20200343030373/LeetCode_141_373/LeetCode_141_373_test.go new file mode 100644 index 00000000..1154ced0 --- /dev/null +++ b/Week_01/G20200343030373/LeetCode_141_373/LeetCode_141_373_test.go @@ -0,0 +1,110 @@ +//https://leetcode-cn.com/problems/linked-list-cycle/ +package linkedlist_cycle_test + +import ( + "github.com/stretchr/testify/assert" + "testing" + "time" +) + +func TestLinkedListCycle(t *testing.T) { + t.Log("Linked List Cycle") + + head := new(ListNode) + head.Val = 1 + ln2 := new(ListNode) + ln2.Val = 2 + ln3 := new(ListNode) + ln3.Val = 3 + ln4 := new(ListNode) + ln4.Val = 4 + head.Next = ln2 + ln2.Next = ln3 + ln3.Next = ln4 + + headC := new(ListNode) + headC.Val = 1 + cln2 := new(ListNode) + cln2.Val = 2 + cln3 := new(ListNode) + cln3.Val = 3 + cln4 := new(ListNode) + cln4.Val = 4 + headC.Next = cln2 + cln2.Next = cln3 + cln3.Next = cln4 + cln4.Next = cln2 //Cycle + + assert.Equal(t, false, hasCycle(head)) + assert.Equal(t, false, hasCycleChangeVal(head)) + assert.Equal(t, false, hasCycleFindNil(head)) + assert.Equal(t, false, hasCycleSetUnique(head)) + assert.Equal(t, true, hasCycle(headC)) + assert.Equal(t, true, hasCycleChangeVal(headC)) + assert.Equal(t, true, hasCycleFindNil(headC)) + assert.Equal(t, true, hasCycleSetUnique(headC)) +} + +type ListNode struct { + Val int + Next *ListNode +} + +//TC:O(n), SC:O(1) +func hasCycle(head *ListNode) bool { + fast, slow := head, head + for fast != nil && slow != nil && fast.Next != nil { + fast = fast.Next.Next + slow = slow.Next + if fast == slow { + return true + } + } + return false +} + +//Not Good, 10086! head changed! +func hasCycleChangeVal(head *ListNode) bool { + for head != nil { + if head.Val == 10086 { + return true + } + + head.Val = 10086 + head = head.Next + } + return false +} + +//Not Good, infinite! head changed! +func hasCycleFindNil(head *ListNode) bool { + timeFlag := false + timer := time.NewTimer(1 * time.Second) + go func() { + <-timer.C + timeFlag = true + }() + + for head != nil { + if timeFlag { + return true + } + + head = head.Next + } + return false +} + +//Not Good, Need Set Store, TC:O(n), SC: O(n) +func hasCycleSetUnique(head *ListNode) bool { + hash := make(map[*ListNode]int) + for head != nil { + if _, ok := hash[head]; ok { + return true + } + + hash[head] = head.Val + head = head.Next + } + return false +} diff --git a/Week_01/G20200343030373/LeetCode_142_373/LeetCode_142_373_test.go b/Week_01/G20200343030373/LeetCode_142_373/LeetCode_142_373_test.go new file mode 100644 index 00000000..5c5f8218 --- /dev/null +++ b/Week_01/G20200343030373/LeetCode_142_373/LeetCode_142_373_test.go @@ -0,0 +1,80 @@ +//https://leetcode-cn.com/problems/linked-list-cycle-ii/ +package linkedlist_cycle_detect_test + +import ( + "fmt" + "github.com/stretchr/testify/assert" + "testing" +) + +func TestLinkedListCycleBegin(t *testing.T) { + fmt.Println("Linked List Cycle Begin") + + head := new(ListNode) + head.Val = 1 + ln2 := new(ListNode) + ln2.Val = 2 + ln3 := new(ListNode) + ln3.Val = 3 + ln4 := new(ListNode) + ln4.Val = 4 + head.Next = ln2 + ln2.Next = ln3 + ln3.Next = ln4 + + headC := new(ListNode) + headC.Val = 1 + cln2 := new(ListNode) + cln2.Val = 2 + cln3 := new(ListNode) + cln3.Val = 3 + cln4 := new(ListNode) + cln4.Val = 4 + headC.Next = cln2 + cln2.Next = cln3 + cln3.Next = cln4 + cln4.Next = headC //Cycle + + assert.Equal(t, (*ListNode)(nil), detectCycle(head)) //注意nil的表示 + assert.Equal(t, (*ListNode)(nil), detectCycleHash(head)) + assert.Equal(t, headC, detectCycleHash(headC)) + assert.Equal(t, headC, detectCycleHash(headC)) +} + +type ListNode struct { + Val int + Next *ListNode +} + +func detectCycle(head *ListNode) *ListNode { + fast, slow := head, head + + for fast != nil && slow != nil && fast.Next != nil { + fast, slow = fast.Next.Next, slow.Next + //当快指针和慢指针相遇了 + if fast == slow { + //head节点开始走,fast指针改成每次走一步,相遇的时候 就是环形的起点 + for head != fast { + fast, head = fast.Next, head.Next + } + return head + } + } + return nil +} + +//Not Good, Need Extra Space +func detectCycleHash(head *ListNode) *ListNode { + hash := make(map[*ListNode]int) + + for head != nil { + //如果遇到同一个地址,就是环入口 + if _, ok := hash[head]; ok { + return head + } + hash[head] = head.Val + head = head.Next + } + + return nil +} diff --git a/Week_01/G20200343030373/LeetCode_155_373/LeetCode_155_373_test.go b/Week_01/G20200343030373/LeetCode_155_373/LeetCode_155_373_test.go new file mode 100644 index 00000000..ead90c0d --- /dev/null +++ b/Week_01/G20200343030373/LeetCode_155_373/LeetCode_155_373_test.go @@ -0,0 +1,63 @@ +//https://leetcode-cn.com/problems/min-stack/ +package mini_stack_test + +import ( + "github.com/stretchr/testify/assert" + "testing" +) + +func TestMiniStack(t *testing.T) { + t.Log("Mini Stack") + obj := Constructor() + obj.Push(-2) + obj.Push(0) + obj.Push(-3) + assert.Equal(t, -3, obj.GetMin()) + obj.Pop() + assert.Equal(t, 0, obj.Top()) + assert.Equal(t, -2, obj.GetMin()) +} + +//当辅助栈为空的时候直接放入新数据 +//push的时候如果该元素小于等于辅助栈顶元素,则将其推入辅助栈 +//出栈的时候如果出栈元素等于辅助栈栈顶元素辅助栈也跟着出栈 +//O(1), O(n) +type MinStack struct { + data []int + help []int +} + +/** initialize your data structure here. */ +func Constructor() MinStack { + return MinStack{ + data: []int{}, + help: []int{}, + } +} + +//辅助栈的栈顶元素永远是最小值 +func (this *MinStack) GetMin() int { + return this.help[len(this.help)-1] +} + +func (this *MinStack) Push(x int) { + //如果辅助栈之前为空,则直接放入 + //如果新值小于等于最小值,则将新值加入辅助栈,作为辅助栈栈顶 + if len(this.help) == 0 || x <= this.GetMin() { + this.help = append(this.help, x) + } + this.data = append(this.data, x) +} + +func (this *MinStack) Pop() { + x := this.data[len(this.data)-1] + this.data = this.data[:len(this.data)-1] + //出栈时,如果值刚好等于最小值,辅助栈也跟随出栈 + if x == this.GetMin() { + this.help = this.help[:len(this.help)-1] + } +} + +func (this *MinStack) Top() int { + return this.data[len(this.data)-1] +} diff --git a/Week_01/G20200343030373/LeetCode_15_373/LeetCode_15_373_test.go b/Week_01/G20200343030373/LeetCode_15_373/LeetCode_15_373_test.go new file mode 100644 index 00000000..74eb5df4 --- /dev/null +++ b/Week_01/G20200343030373/LeetCode_15_373/LeetCode_15_373_test.go @@ -0,0 +1,80 @@ +//https://leetcode-cn.com/problems/3sum/ +package three_sum_test + +import ( + "github.com/stretchr/testify/assert" + "sort" + "testing" +) + +func TestThreeSum(t *testing.T) { + t.Log("Three Sum") + + nums1 := []int{-1, 0, 1, 2, -1, -4} + except1 := [][]int{ + {-1, -1, 2}, + {-1, 0, 1}, + } + assert.Equal(t, except1, threeSum(nums1)) + + nums2 := []int{0, 0, 0, 0} + except2 := [][]int{{0, 0, 0}} + assert.Equal(t, except2, threeSum(nums2)) + + nums3 := []int{-2, 0, 1, 1, 2} + except3 := [][]int{ + {-2, 0, 2}, + {-2, 1, 1}, + } + assert.Equal(t, except3, threeSum(nums3)) +} + +func threeSum(nums []int) [][]int { + var ret [][]int + if len(nums) < 3 { + return ret + } + + sort.Ints(nums) //需要排序,容易忘记 + + //注意i的取值,肯定会留出两个值给l和r + for i := 0; i <= len(nums)-3; i++ { + l, r := i+1, len(nums)-1 + + //i并不是跟后面的去重,而是跟前面的去重,已经处理过相同的i + //-1, -1, 0, 1 + if i-1 >= 0 && nums[i] == nums[i-1] { //与后面r+1<=len(nums)-1相同的意思,都是要在数组边界内 + continue + } + + if nums[i] > 0 || nums[i]+nums[l] > 0 { + break + } + + //移动l,r去重,肯定会剩下至少三个元素分别是i,l,r去求和,所以退出条件是l i && nums[l] == nums[l-1] { //l必须大于i + l++ + continue //每移动一次,就要去判断l与r + } + if r+1 <= len(nums)-1 && nums[r] == nums[r+1] { //在数组边界内 + r-- + continue + } + + if nums[i]+nums[l]+nums[r] > 0 { + r-- + } else if nums[i]+nums[l]+nums[r] < 0 { + l++ + } else { + ret = append(ret, []int{nums[i], nums[l], nums[r]}) + r-- + l++ + } + } + } + + return ret +} diff --git a/Week_01/G20200343030373/LeetCode_189_373/LeetCode_189_373_test.go b/Week_01/G20200343030373/LeetCode_189_373/LeetCode_189_373_test.go new file mode 100644 index 00000000..ffe6b715 --- /dev/null +++ b/Week_01/G20200343030373/LeetCode_189_373/LeetCode_189_373_test.go @@ -0,0 +1,81 @@ +//https://leetcode-cn.com/problems/rotate-array/ +package rotate_array_test + +import ( + "github.com/stretchr/testify/assert" + "testing" +) + +func TestRotateArray(t *testing.T) { + t.Log("Rotate Array") + + nums1 := []int{1, 2, 3, 4, 5, 6, 7} + expect1 := []int{5, 6, 7, 1, 2, 3, 4} + rotate(nums1, 3) + assert.Equal(t, expect1, nums1) + + nums2 := []int{1, 2} + expect2 := []int{2, 1} + rotate(nums2, 3) + assert.Equal(t, expect2, nums2) + + nums3 := []int{-1} + expect3 := nums3 + rotate(nums3, 2) + assert.Equal(t, expect3, nums3) +} + +func rotate(nums []int, k int) { + //Best + reverseRotate(nums, k) +} + +//暴力反转 +//将最后一个元素移动到第一位,移动k次 +//TC:O(kn), SC:O(1) - AC but Not Good +func bruteRotate(nums []int, k int) { + length := len(nums) + k %= length //k为非负数,取余后为最后需要移动的步数 + + for i := 0; i < k; i++ { + //将最后一个元素移动到首位 + //方法:取数组最后一个元素,遍历一遍数组,与最后一个元素进行交换 + end := nums[length-1] + for j := 0; j < length; j++ { + nums[j], end = end, nums[j] + } + } +} + +//切片分割 +//取后k个作为切片的初始,取前面的逐个累加到其后 - 直接得到结果 +//题目要求在数组原地修改,所以就将结果直接复制进去 +//TC:O(n), SC:O(n), not O(1) - AC but Not Good +func sliceRotate(nums []int, k int) { + length := len(nums) + k %= length + + res := append(nums[length-k:], nums[:length-k]...) + nums = append(nums[:0], res...) +} + +//多次反转 +//先将所有元素进行反转 +//将前k个反转恢复,k个是0~k-1,切片的右边是[:k] +//将之后的反转恢复 +//TC:O(n), SC:O(1), Good +func reverseRotate(nums []int, k int) { + k %= len(nums) + reverse(nums) + reverse(nums[:k]) + reverse(nums[k:]) +} + +//反转数组 +//左右夹逼 +//左右交换 +func reverse(nums []int) { + for i, j := 0, len(nums)-1; i < j; i, j = i+1, j-1 { + nums[i], nums[j] = nums[j], nums[i] + } +} diff --git a/Week_01/G20200343030373/LeetCode_1_373/LeetCode_1_373_test.go b/Week_01/G20200343030373/LeetCode_1_373/LeetCode_1_373_test.go new file mode 100644 index 00000000..968bf063 --- /dev/null +++ b/Week_01/G20200343030373/LeetCode_1_373/LeetCode_1_373_test.go @@ -0,0 +1,36 @@ +//https://leetcode-cn.com/problems/two-sum/ +package two_sum_test + +import ( + "github.com/stretchr/testify/assert" + "testing" +) + +func TestTwoSum(t *testing.T) { + t.Log("Two Sum") + + target := 9 + nums := []int{2, 7, 11, 15} + expect := []int{0, 1} + assert.Equal(t, expect, twoSum(nums, target)) + + target1 := 6 + nums1 := []int{3, 3} + expect1 := []int{0, 1} + assert.Equal(t, expect1, twoSum(nums1, target1)) +} + +func twoSum(nums []int, target int) []int { + myMap := make(map[int]int) + for index, value := range nums { + //TwoSum: 将'target-当前值'作为key存入Map,当前值的索引作为value存入Map; + //遍历后面的元素,如果'后面的元素值'作为Map的key已经存在,则找到,返回索引 + //Special: '后面的元素值'存在于Map的既有索引值,例如3+3=6,不应该覆盖 + if vIndexOld, ok := myMap[value]; !ok { + myMap[target-value] = index + } else { + return []int{vIndexOld, index} + } + } + return nil +} diff --git a/Week_01/G20200343030373/LeetCode_206_373/LeetCode_206_373_test.go b/Week_01/G20200343030373/LeetCode_206_373/LeetCode_206_373_test.go new file mode 100644 index 00000000..9229ad06 --- /dev/null +++ b/Week_01/G20200343030373/LeetCode_206_373/LeetCode_206_373_test.go @@ -0,0 +1,148 @@ +//https://leetcode-cn.com/problems/reverse-linked-list/ +package reverse_linkedlist_test + +import ( + "github.com/stretchr/testify/assert" + "testing" +) + +func TestReverseList(t *testing.T) { + t.Log("Reverse Linked List") + head := &ListNode{ + Val: 1, + Next: &ListNode{ + Val: 2, + Next: &ListNode{ + Val: 3, + Next: &ListNode{ + Val: 4, + Next: &ListNode{ + Val: 5, + Next: nil, + }, + }, + }, + }, + } + + res1 := reverseListInGoGrammar(head) + assert.Equal(t, []int{5, 4, 3, 2, 1}, traversalList(res1)) + + res2 := reverseListInGeneral(res1) + assert.Equal(t, []int{1, 2, 3, 4, 5}, traversalList(res2)) + + res3 := reverseListRecursively1(res2) + assert.Equal(t, []int{5, 4, 3, 2, 1}, traversalList(res3)) + + res4 := reverseListRecursively2(res3) + assert.Equal(t, []int{1, 2, 3, 4, 5}, traversalList(res4)) + + res5 := reverseListRecursively3(res4) + assert.Equal(t, []int{5, 4, 3, 2, 1}, traversalList(res5)) +} + +type ListNode struct { + Val int + Next *ListNode +} + +func traversalList(head *ListNode) []int { + var res []int + for head != nil { + res = append(res, head.Val) + head = head.Next + } + return res +} + +func reverseList(head *ListNode) *ListNode { + //answer1 - best iteration + return reverseListInGoGrammar(head) + + //answer2 - best recursion + //return reverseListRecursively2(head) +} + +//iteratively reverse linked list (迭代),循环5次, O(n) +func reverseListInGoGrammar(head *ListNode) *ListNode { + var pre *ListNode = nil + for head != nil { + //将当前节点的next指向上一个节点 + //则上一个节点更新成当前节点 + //再将当前节点更新为下一个节点 + head.Next, pre, head = pre, head, head.Next + } + return pre +} + +func reverseListInGeneral(head *ListNode) *ListNode { + var pre *ListNode = nil + for head != nil { + tempNext := head.Next //先存储下一个节点,否则会被覆盖 + head.Next = pre //将当前节点的next指向上一个节点 + pre = head //则上一个节点更新成当前节点 + head = tempNext //再将当前节点更新为下一个节点,进行下一次循环 + } + return pre +} + +//Recursively reverse linked list (递归),递归5次, O(n) +//尾递归? +//在当前层处理反转,然后再下沉 - 其实就是迭代 +func reverseListRecursively1(head *ListNode) *ListNode { + var pre *ListNode = nil + return reverse1(pre, head) +} + +func reverse1(pre, head *ListNode) *ListNode { + //terminator + //如果当前节点为空,要么没有元素,要么循环完毕;循环完毕,则返回前驱节点pre作为结果 + if head == nil { + return pre + } + //precess - 在当前level的处理! + tempNext := head.Next //如果head不是nil,则head.next不为空,暂存 + head.Next = pre //将当前节点head的Next指向前驱节点pre - 递归的操作 + //drill down + //clear - no + + //递归终止条件时把pre返回,一层一层的将这个pre返回即可 + return reverse1(head, tempNext) //进入下一次递归、反转 +} + +//递归-method1: 将当前节点的Next指向前一节点 +//当前层什么也不干,就下沉:递;沉到底之后再返回,并反转:归 +//递归的理解:后面的都处理完了,就剩本层了 +func reverseListRecursively2(head *ListNode) *ListNode { + return reverse2(nil, head) +} + +func reverse2(pre, head *ListNode) *ListNode { + //terminator + if head == nil { + return pre + } + //process - no + //drill down + cur := reverse2(head, head.Next) + head.Next = pre + return cur +} + +//递归-method2:将下一节点的Next指向当前节点 +//其实method1就挺好,符合思维:每一步只做反转 +//本方法需要每次都把当前节点指向nil,多了n次操作,但好在就一个方法 +func reverseListRecursively3(head *ListNode) *ListNode { + //terminator + if head == nil || head.Next == nil { + return head + } + //递归下去,当到最后一个,他的Next已经是nil,则将最后一个返回 + cur := reverseListRecursively3(head.Next) + //归来上一层(本层),在本层的操作是: + //1. 将下一个节点的Next指向当前节点 + //2。为防止循环,将当前节点的Next指向nil + head.Next.Next, head.Next = head, nil + //返回递归传递的最后一个节点 + return cur +} diff --git a/Week_01/G20200343030373/LeetCode_20_373/LeetCode_20_373_test.go b/Week_01/G20200343030373/LeetCode_20_373/LeetCode_20_373_test.go new file mode 100644 index 00000000..e6c4e59b --- /dev/null +++ b/Week_01/G20200343030373/LeetCode_20_373/LeetCode_20_373_test.go @@ -0,0 +1,71 @@ +//https://leetcode-cn.com/problems/valid-parentheses/description/ +package valid_parentheses_test + +import ( + _ "fmt" + "github.com/stretchr/testify/assert" + "testing" +) + +func TestValidParentheses(t *testing.T) { + str1 := "()" + str2 := "()[]{}" + str3 := "(]" + str4 := "([)]" + str5 := "{[]}" + + assert.Equal(t, true, isValid(str1)) + assert.Equal(t, true, isValid(str2)) + assert.Equal(t, false, isValid(str3)) + assert.Equal(t, false, isValid(str4)) + assert.Equal(t, true, isValid(str5)) +} + +//Define a Stack: Push, Pop, IsEmpty +type Stack struct { + strSlice []string +} + +func (stack *Stack) Push(str string) { + stack.strSlice = append(stack.strSlice, str) +} + +func (stack *Stack) Pop() string { + lenSlice := len(stack.strSlice) + if lenSlice == 0 { + return "" + } + + str := stack.strSlice[lenSlice-1] + stack.strSlice = stack.strSlice[:lenSlice-1] //截取的边界是[), 左包含右不包含 + + return str +} + +func (stack *Stack) IsEmpty() bool { + return len(stack.strSlice) == 0 +} + +var hash = map[string]string{ + ")": "(", + "]": "[", + "}": "{", +} + +//Judge with a Stack +func isValid(s string) bool { + stack := new(Stack) + + for _, b := range s { //range出的是key,value;如果只有一个值,则是key or index + str := string(b) //range string 出的是rune,int32类型,需要类型转换 + if left, ok := hash[str]; !ok { //map的是value, ok, 即对应key的value + //判断map的key是否存在,如果不存在,即为左字符,则入栈 + stack.Push(str) + } else if stack.IsEmpty() || stack.Pop() != left { //如果存在,则为右字符,先判断是否为空,再出栈判断是否匹配 + return false + } + } + + //如果为空(配对全部出栈、无其他字符),则有效 + return stack.IsEmpty() +} diff --git a/Week_01/G20200343030373/LeetCode_21_373/LeetCode_21_373_test.go b/Week_01/G20200343030373/LeetCode_21_373/LeetCode_21_373_test.go new file mode 100644 index 00000000..07a7e23d --- /dev/null +++ b/Week_01/G20200343030373/LeetCode_21_373/LeetCode_21_373_test.go @@ -0,0 +1,94 @@ +//https://leetcode-cn.com/problems/merge-two-sorted-lists/ +package merge_two_sorted_lists + +import ( + "github.com/stretchr/testify/assert" + "testing" +) + +func TestMergeList(t *testing.T) { + l1 := &ListNode{ + Val: 1, + Next: &ListNode{ + Val: 2, + Next: &ListNode{ + Val: 4, + Next: nil, + }, + }, + } + + l2 := &ListNode{ + Val: 1, + Next: &ListNode{ + Val: 3, + Next: &ListNode{ + Val: 4, + Next: nil, + }, + }, + } + + expect := &ListNode{ + Val: 1, + Next: &ListNode{ + Val: 1, + Next: &ListNode{ + Val: 2, + Next: &ListNode{ + Val: 3, + Next: &ListNode{ + Val: 4, + Next: &ListNode{ + Val: 4, + Next: nil, + }, + }, + }, + }, + }, + } + + assert.Equal(t, traversalList(expect), traversalList(mergeTwoLists(l1, l2))) +} + +type ListNode struct { + Val int + Next *ListNode +} + +func traversalList(head *ListNode) []int { + var res []int + for head != nil { + res = append(res, head.Val) + head = head.Next + } + return res +} + +func mergeTwoLists(l1 *ListNode, l2 *ListNode) *ListNode { + pre := &ListNode{} + hint := pre //哨兵或锚点 + + //迭代开始,退出时肯定是l1或l2为空了 + for l1 != nil && l2 != nil { + if l1.Val < l2.Val { + pre.Next = l1 //将pre指向l1当前节点 + l1 = l1.Next //l1后移 + } else { + pre.Next = l2 + l2 = l2.Next + } + pre = pre.Next //当前pre已经有了指向,则将pre后移一个元素 + } + + //l1或l2为空之后,跳出上面循环 + //将不为空的那个直接合并 + if l1 != nil { + pre.Next = l1 + } else { + pre.Next = l2 + } + + return hint.Next +} diff --git a/Week_01/G20200343030373/LeetCode_239_373/LeetCode_239_373_test.go b/Week_01/G20200343030373/LeetCode_239_373/LeetCode_239_373_test.go new file mode 100644 index 00000000..58175fd6 --- /dev/null +++ b/Week_01/G20200343030373/LeetCode_239_373/LeetCode_239_373_test.go @@ -0,0 +1,57 @@ +//https://leetcode-cn.com/problems/sliding-window-maximum/ +package sliding_window_maximum_test + +import ( + "github.com/stretchr/testify/assert" + "testing" +) + +func TestDeque(t *testing.T) { + t.Log("Sliding Window Maximum - Deque") + + nums := []int{1, 3, -1, -3, 5, 3, 6, 7} + k := 3 + expect := []int{3, 3, 5, 5, 6, 7} + assert.Equal(t, expect, maxSlidingWindow(nums, k)) +} + +func maxSlidingWindow(nums []int, k int) []int { + //追求严谨 + if len(nums) == 0 || len(nums) < k { + return nums + } + + //既然k固定,就定义好slice的最大容量 + window := make([]int, 0, k) + result := make([]int, 0, len(nums)-k+1) + + for index, value := range nums { + //3.1.处理:维护其最大长度为k + //index>=k,遍历k次后,如果再append,窗口长度就会超过k + //window中存储的是索引,如果满了(第一个索引window[0]比当前索引index之间小了k), 则将最左侧元素切去 + //举例:{5,4,3}, 下一个value是2,需要将5从左侧移除,以保持长度 + if index >= k && window[0] <= index-k { + window = window[1:] + } + + //3.2.处理:保证每遍历一次后第一个元素值最大,循环处理 + //len(window)>0, 仅第一次index=0时不处理,之后保证window中肯定有至少一个最大值 + //从window切片的最后一个元素对应的数值开始比较,如果比当前遍历的数值小,则切去,之后会append当前遍历的数值 + //如果仅剩一个,也可切去,然后再append + //举例:{1,2,3}, 下一个value是4,需要将1,2,3都移除,在下一步将4append上 + for len(window) > 0 && nums[window[len(window)-1]] < value { + window = window[:len(window)-1] + } + + //1.遍历并将下标注入双端队列 + //之前要有条件处理:维护其长度最大为k;保证每遍历一次后第一个元素值最大 + //之后当足够k个时没遍历一次保存一次结果,存储的是下标,因此能快速定位到元素 + window = append(window, index) + + //2. 当index等于k-1开始,产生结果,双端队列新的头总是当前窗口中最大的那个数 + if index >= k-1 { + result = append(result, nums[window[0]]) + } + } + return result +} diff --git a/Week_01/G20200343030373/LeetCode_24_373/LeetCode_24_373_test.go b/Week_01/G20200343030373/LeetCode_24_373/LeetCode_24_373_test.go new file mode 100644 index 00000000..3f656bad --- /dev/null +++ b/Week_01/G20200343030373/LeetCode_24_373/LeetCode_24_373_test.go @@ -0,0 +1,68 @@ +//https://leetcode-cn.com/problems/swap-nodes-in-pairs/ +package swap_nodes_in_pairs_test + +import ( + "github.com/stretchr/testify/assert" + "testing" +) + +func TestSwapNodesInPairs(t *testing.T) { + t.Log("Swap Nodes in Pairs") + + head := &ListNode{ + Val: 1, + Next: &ListNode{ + Val: 2, + Next: &ListNode{ + Val: 3, + Next: &ListNode{ + Val: 4, + Next: &ListNode{ + Val: 5, + Next: nil, + }, + }, + }, + }, + } + + res1 := swapPairs(head) + assert.Equal(t, []int{2, 1, 4, 3, 5}, traversalList(res1)) + + res2 := swapPairsRecursively(res1) + assert.Equal(t, []int{1, 2, 3, 4, 5}, traversalList(res2)) +} + +type ListNode struct { + Val int + Next *ListNode +} + +func traversalList(head *ListNode) []int { + var res []int + for head != nil { + res = append(res, head.Val) + head = head.Next + } + return res +} + +func swapPairs(head *ListNode) *ListNode { + prev := &ListNode{0, head} //构造指向head的前置指针 + hint := prev //因为prev指针需要移动,留存一个备份 + for prev.Next != nil && prev.Next.Next != nil { + //前三个都是调换的步骤,第四个是移动pre进行一下调换 + prev.Next.Next.Next, prev.Next.Next, prev.Next, prev = prev.Next, prev.Next.Next.Next, prev.Next.Next, prev.Next + } + return hint.Next //注意不是返回hint +} + +func swapPairsRecursively(head *ListNode) *ListNode { + if head == nil || head.Next == nil { + return head + } + + hint := head.Next + head.Next.Next, head.Next = head, swapPairsRecursively(head.Next.Next) + return hint +} diff --git a/Week_01/G20200343030373/LeetCode_25_373/LeetCode_25_373_test.go b/Week_01/G20200343030373/LeetCode_25_373/LeetCode_25_373_test.go new file mode 100644 index 00000000..6af987ae --- /dev/null +++ b/Week_01/G20200343030373/LeetCode_25_373/LeetCode_25_373_test.go @@ -0,0 +1,87 @@ +//https://leetcode-cn.com/problems/reverse-nodes-in-k-group/ +package reverse_nodes_in_k_group_test + +import ( + "github.com/stretchr/testify/assert" + "testing" +) + +func TestReverseNodesInKGroup(t *testing.T) { + t.Log("Reverse Nodes in K-Group") + + head := &ListNode{ + Val: 1, + Next: &ListNode{ + Val: 2, + Next: &ListNode{ + Val: 3, + Next: &ListNode{ + Val: 4, + Next: &ListNode{ + Val: 5, + Next: nil, + }, + }, + }, + }, + } + + assert.Equal(t, []int{2, 1, 4, 3, 5}, traversalList(reverseKGroup(head, 2))) +} + +type ListNode struct { + Val int + Next *ListNode +} + +func traversalList(head *ListNode) []int { + var res []int + for head != nil { + res = append(res, head.Val) + head = head.Next + } + return res +} + +//TC: O(n*k), SC:O(1) +//优化:无需k次循环确定是否结束。可边翻转边判断,如果提前结束,再做一次翻转。只有最后一部分会多做一次翻转,但少nk次循环。 +func reverseKGroup(head *ListNode, k int) *ListNode { + if k <= 1 { //注意不要遗漏边界条件 + return head + } + + pre := &ListNode{0, head} //因为dummy指向head,head指针不能有变化,所以需要一个pre + hint := pre + for pre.Next != nil { + start, end := pre.Next, pre.Next + + for i := 1; i < k; i++ { //注意end已经有一个了,从1开始,k个,所以要小于k + end = end.Next + if end == nil { + break + } + } + if end == nil { //剩余的不够K个,结束 + break + } + + next := end.Next + + //翻转 start 与 end 区间,end.Next结束,一个完整链表区间 + end.Next = nil + pre.Next = reverse(start) //已翻转部分与前驱连接 + start.Next = next //未翻转部分与后区连接 + + //重置变量 - 注意不能是pre.Next = next,会遗漏数据 + pre = start + } + return hint.Next +} + +func reverse(head *ListNode) *ListNode { + var pre *ListNode = nil + for head != nil { + head.Next, head, pre = pre, head.Next, head + } + return pre +} diff --git a/Week_01/G20200343030373/LeetCode_26_373/LeetCode_26_373_test.go b/Week_01/G20200343030373/LeetCode_26_373/LeetCode_26_373_test.go new file mode 100644 index 00000000..3e2f4bf0 --- /dev/null +++ b/Week_01/G20200343030373/LeetCode_26_373/LeetCode_26_373_test.go @@ -0,0 +1,64 @@ +//https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array/ +package remove_duplicates_from_sorted_array_test + +import ( + "github.com/stretchr/testify/assert" + "testing" +) + +func TestArray(t *testing.T) { + t.Log("Array: Remove Duplicates from Sorted Array") + + nums1 := []int{1, 1, 2} + expect1 := []int{1, 2} + assert.Equal(t, expect1, nums1[:removeDuplicates(nums1)]) + nums1 = []int{1, 1, 2} + assert.Equal(t, expect1, nums1[:doublePointer(nums1)]) + nums1 = []int{1, 1, 2} + assert.Equal(t, expect1, nums1[:reverseTraversal(nums1)]) + + nums2 := []int{0, 0, 1, 1, 1, 2, 2, 3, 3, 4} + expect2 := []int{0, 1, 2, 3, 4} + assert.Equal(t, expect2, nums2[:removeDuplicates(nums2)]) + nums2 = []int{0, 0, 1, 1, 1, 2, 2, 3, 3, 4} + assert.Equal(t, expect2, nums2[:doublePointer(nums2)]) + nums2 = []int{0, 0, 1, 1, 1, 2, 2, 3, 3, 4} + assert.Equal(t, expect2, nums2[:reverseTraversal(nums2)]) +} + +func removeDuplicates(nums []int) int { + //Best + return doublePointer(nums) +} + +//快慢指针 +//快慢指针初始值相等,快指针先遍历,不相等时,慢指针右移一个后赋值 +//最终返回个数,慢指针从零开始,所以加一 +func doublePointer(nums []int) int { + fast, slow := 0, 0 + for ; fast < len(nums); fast++ { + if nums[slow] != nums[fast] { + slow++ + nums[slow] = nums[fast] + } + } + return slow + 1 +} + +//反向遍历 +//从最后一个元素遍历到第二个元素 +//如果后一个元素i与前一个元素i-1相等,则 +//切片操作,将后一个元素i从切片中间拔除 +//切片重复操作,最坏O(n^2),劣于双指针方法 +func reverseTraversal(nums []int) int { + if len(nums) == 0 { + return 0 + } + + for i := len(nums) - 1; i >= 1; i-- { + if nums[i] == nums[i-1] { + nums = append(nums[:i], nums[i+1:]...) + } + } + return len(nums) +} diff --git a/Week_01/G20200343030373/LeetCode_283_373/LeetCode_283_373_test.go b/Week_01/G20200343030373/LeetCode_283_373/LeetCode_283_373_test.go new file mode 100644 index 00000000..65bbd056 --- /dev/null +++ b/Week_01/G20200343030373/LeetCode_283_373/LeetCode_283_373_test.go @@ -0,0 +1,84 @@ +//https://leetcode-cn.com/problems/move-zeroes/ +package move_zeroes_test + +import ( + "github.com/stretchr/testify/assert" + "testing" +) + +func TestMoveZeroes(t *testing.T) { + nums := []int{0, 1, 0, 3, 12} + expect := []int{1, 3, 12, 0, 0} + moveZeroes(nums) + assert.Equal(t, expect, nums) + + nums = []int{0, 1, 0, 3, 12} + countNoneZero(nums) + assert.Equal(t, expect, nums) + + nums = []int{0, 1, 0, 3, 12} + dualPointerChange(nums) + assert.Equal(t, expect, nums) + + nums = []int{0, 1, 0, 3, 12} + dualPointerSwap(nums) + assert.Equal(t, expect, nums) + + nums1 := []int{1} + moveZeroes(nums1) + assert.Equal(t, nums1, nums1) +} + +func moveZeroes(nums []int) { + //Best + //其实dualPointerChange就是countNoneZero考虑在一次遍历里解决问题; + //dualPointerSwap就是dualPointerChange的更直接、简洁版本 + dualPointerSwap(nums) +} + +//method1: 两层循环 +//第一层循环将非零元素放到数组前面 +//第二层循环后面补零 +//worst: O(2n) +func countNoneZero(nums []int) { + fast, slow := 0, 0 + for ; fast < len(nums); fast++ { + if nums[fast] != 0 { //对于每一个快指针元素值不为0,要做两步操作,先将非零元素替换,再移动慢指针 + if fast != slow { //优化,不加这句判断也对,加这句减少一次交换 + nums[slow] = nums[fast] + } + slow++ //注意,每一次不为零都需要移动slow,否则[]int{1}错误 + } + } + for ; slow < len(nums); slow++ { + nums[slow] = 0 + } +} + +//method2: 双指针 +//快指针遇到 非零 就和慢指针的数字做交换,慢指针做过一次交换后就累加,保持顺序 +//O(n) +func dualPointerChange(nums []int) { + fast, slow := 0, 0 + for ; fast < len(nums); fast++ { + if nums[fast] != 0 { + if fast != slow { //如果fast等于slow,则在原地,将slow后移保留即可 + nums[slow] = nums[fast] //如果fast不等于slow,fast在slow的后面;fast的值又是非零,则与slow的值交换,fast的值改成零,slow后移 + nums[fast] = 0 + } + slow++ + } + } +} + +func dualPointerSwap(nums []int) { + fast, slow := 0, 0 + for ; fast < len(nums); fast++ { + if nums[fast] != 0 { + if fast != slow { + nums[slow], nums[fast] = nums[fast], nums[slow] //slow把每一个非零值都做了交换,则剩下的fast自然而然就都是零 + } + slow++ + } + } +} diff --git a/Week_01/G20200343030373/LeetCode_42_373/LeetCode_42_373_test.go b/Week_01/G20200343030373/LeetCode_42_373/LeetCode_42_373_test.go new file mode 100644 index 00000000..a98c30d1 --- /dev/null +++ b/Week_01/G20200343030373/LeetCode_42_373/LeetCode_42_373_test.go @@ -0,0 +1,202 @@ +//https://leetcode-cn.com/problems/trapping-rain-water/ +package trapping_rain_water_test + +import ( + "github.com/stretchr/testify/assert" + "testing" +) + +func TestTrap(t *testing.T) { + height1 := []int{0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1} + assert.Equal(t, 6, trap(height1)) + assert.Equal(t, 6, rowTrap(height1)) + assert.Equal(t, 6, colTrap(height1)) + assert.Equal(t, 6, dpTrap(height1)) + assert.Equal(t, 6, dualPointerTrap(height1)) + assert.Equal(t, 6, stackTrap(height1)) + + height2 := []int{2, 0, 2} + assert.Equal(t, 2, trap(height2)) + assert.Equal(t, 2, rowTrap(height2)) + assert.Equal(t, 2, colTrap(height2)) + assert.Equal(t, 2, dpTrap(height2)) + assert.Equal(t, 2, dualPointerTrap(height2)) + assert.Equal(t, 2, stackTrap(height2)) +} + +//参考:https://leetcode-cn.com/problems/trapping-rain-water/solution/xiang-xi-tong-su-de-si-lu-fen-xi-duo-jie-fa-by-w-8/ + +func trap(height []int) int { + //Most Understandable + return dpTrap(height) +} + +//common +func min(a, b int) int { + if a < b { + return a + } + return b +} + +func max(a, b int) int { + if a > b { + return a + } + return b +} + +//method1: 按行求 +//原则:高度i, 遇到高度小于i的先存起来temp++; 遇到大于等于i的就把存起来的水放到答案sum+=temp中并temp=0置零 +//TC: O(mn), SC: O(1) +//AC, 1160ms, too long +func rowTrap(height []int) int { + sum := 0 + max := maxHeight(height) //最大高度,遍历 + for i := 1; i <= max; i++ { //第一行,i从1开始 + isStart := false //标记是否开始更新temp,因为需要找到第一个h>=i的才能开始蓄水 + temp := 0 //暂存的水 + //原则:h=i, sum += temp, temp=0 + for _, h := range height { + if isStart && h < i { + temp++ + } + if h >= i { + sum += temp + temp = 0 + isStart = true + } + } + } + return sum +} + +func maxHeight(height []int) int { + max := 0 + for _, h := range height { + if h > max { + max = h + } + } + return max +} + +//method2: 按列求 +//原则:当前列,蓄水量:min(左边最高、右边最高)-h;如果较小值比当前列 小或相等,当前列不会蓄水 +//TC: O(n^2), SC: O(1) +//AC, 88ms, Good +func colTrap(height []int) int { + sum := 0 + length := len(height) + //两端的列无需考虑 + for i := 1; i <= length-2; i++ { + maxLeft, maxRight := 0, 0 + for j := i - 1; j >= 0; j-- { + if height[j] > maxLeft { + maxLeft = height[j] + } + } + for j := i + 1; j <= length-1; j++ { + if height[j] > maxRight { + maxRight = height[j] + } + } + + min := min(maxLeft, maxRight) + + if min > height[i] { + sum += min - height[i] + } + } + return sum +} + +//method3: 动态规划 +//原则:对于当前列找左右的最大值,可以记忆 +//状态定义:dpMaxLeft[i],i左边的最高值;dpMaxRight[i],i右边的最高值,不包括当前列i +//状态方程:dpMaxLeft[i] = max(dpMaxLeft[i-1], height[i-1]); dpMaxRight[i]同理 +//TC: O(n), SC: O(n) - 加速:空间换时间 +//AC, 4ms, Better +func dpTrap(height []int) int { + sum := 0 + length := len(height) + + dpMaxLeft, dpMaxRight := make([]int, length), make([]int, length) + for i := 1; i <= length-2; i++ { + dpMaxLeft[i] = max(dpMaxLeft[i-1], height[i-1]) + } + for i := length - 2; i >= 1; i-- { + dpMaxRight[i] = max(dpMaxRight[i+1], height[i+1]) + } + + for i := 1; i <= length-2; i++ { + min := min(dpMaxLeft[i], dpMaxRight[i]) + if min > height[i] { + sum += min - height[i] + } + } + return sum +} + +//method4: 双指针法 +//动态规划中,常常可以对最大值、最小值的状态方程过程,进行空间复杂度的优化 +//dpMaxLeft[i],dpMaxRight[i]在整个遍历过程中仅使用1次,可以不用数组挨个记录,用一个元素重复刷新 +//状态定义:dpMaxLeft: i左边的最高值 +//状态方程:dpMaxLeft = math(dpMapLeft, height[i-1]) +//问题:数组dpMaxRight不能降维到一个元素,因为最终的遍历是从左到右 -> 因此使用双指针left、right, 从两个方向遍历 +//如果一端有更高的条形块(例如右端),积水的高度依赖于当前方向的高度(从左到右)。当发现另一侧(右侧)的条形块高度不是最高的,则开始从相反的方向遍历(从右到左) +//TC: O(n), SC: O(1) +func dualPointerTrap(height []int) int { + sum := 0 + length := len(height) + dpMaxLeft, dpMaxRight := 0, 0 + pLeft, pRight := 1, length-2 + for i := 1; i <= length-2; i++ { + if height[pLeft-1] < height[pRight+1] { + //从左到右遍历,则dpMaxLeft也小于dpMaxRight + dpMaxLeft = max(dpMaxLeft, height[pLeft-1]) + min := dpMaxLeft + if min > height[pLeft] { + sum += min - height[pLeft] + } + pLeft++ + } else { + dpMaxRight = max(dpMaxRight, height[pRight+1]) + min := dpMaxRight + if min > height[pRight] { + sum += min - height[pRight] + } + pRight-- + } + } + return sum +} + +//method5: 栈 +//用栈保存每堵墙 +//1. 当前高度小于等于栈顶高度,入栈,指针后移 +//2. 当前高度大于栈顶高度,出栈,计算当前墙与栈顶墙之间的水,继续判断当前墙与新的栈顶的关系 +//O(n), O(n) +func stackTrap(height []int) int { + length := len(height) + if length <= 2 { + return 0 + } + + sum := 0 + var stack []int + for i := 0; i < length; i++ { + for len(stack) > 0 && height[i] > height[stack[len(stack)-1]] { + cur := stack[len(stack)-1] + stack = stack[:len(stack)-1] + if len(stack) <= 0 { + break + } + dis := i - stack[len(stack)-1] - 1 + h := min(height[stack[len(stack)-1]], height[i]) - height[cur] + sum += h * dis + } + stack = append(stack, i) + } + return sum +} diff --git a/Week_01/G20200343030373/LeetCode_641_373/LeetCode_641_373_test.go b/Week_01/G20200343030373/LeetCode_641_373/LeetCode_641_373_test.go new file mode 100644 index 00000000..6c54feb1 --- /dev/null +++ b/Week_01/G20200343030373/LeetCode_641_373/LeetCode_641_373_test.go @@ -0,0 +1,126 @@ +//https://leetcode-cn.com/problems/design-circular-deque/ +package circular_deque_test + +//ToDo +import ( + "github.com/stretchr/testify/assert" + "testing" +) + +func TestDeque(t *testing.T) { + t.Log("Design Circular Deque") + circularDeque := Constructor(3) //设置容量大小为3 + assert.Equal(t, true, circularDeque.InsertLast(1)) + assert.Equal(t, true, circularDeque.InsertLast(2)) + assert.Equal(t, true, circularDeque.InsertFront(3)) + assert.Equal(t, false, circularDeque.InsertFront(4)) + assert.Equal(t, 2, circularDeque.GetRear()) + assert.Equal(t, true, circularDeque.IsFull()) + assert.Equal(t, true, circularDeque.DeleteLast()) + assert.Equal(t, true, circularDeque.InsertFront(4)) + assert.Equal(t, 4, circularDeque.GetFront()) +} + +type MyCircularDeque struct { + data []int //数组(切片)存储数据 + front int //“头指针”数组下标 + last int //“尾指针”数组下标 +} + +//MyCircularDeque(k):构造函数,双端队列的大小为k。 +func Constructor(k int) MyCircularDeque { + return MyCircularDeque{ + //构造长度容量都为k+1的切片;当然也可以初始化为长度为0,容量为k+1; + data: make([]int, k+1, k+1), //初始值全0 + front: 0, + last: 0, + } +} + +//insertFront():将一个元素添加到双端队列头部。 如果操作成功返回 true。 +func (this *MyCircularDeque) InsertFront(value int) bool { + //检查队列是否已满 + if this.IsFull() { + return false + } + + //插入元素。 + this.front = (len(this.data) + this.front - 1) % len(this.data) //先循环左移一位 + this.data[this.front] = value //填入数据 + + return true +} + +//insertLast():将一个元素添加到双端队列尾部。如果操作成功返回 true。 +func (this *MyCircularDeque) InsertLast(value int) bool { + //检查队列是否已满 + if this.IsFull() { + return false + } + + //插入元素 + this.data[this.last] = value //填入数据 + this.last = (this.last + 1) % len(this.data) //循环右移一位 + + return true +} + +//deleteFront():从双端队列头部删除一个元素。 如果操作成功返回 true。 +func (this *MyCircularDeque) DeleteFront() bool { + //检查队列是否为空 + if this.IsEmpty() { + return false + } + + //删除头部元素 + //this.data[this.front] = 0 //置0,这一部完全不是必须,只是为了方便输出调试。可以将这句直接注释 + this.front = (this.front + 1) % len(this.data) //循环右移一位 + + return true +} + +//deleteLast():从双端队列尾部删除一个元素。如果操作成功返回 true。 +func (this *MyCircularDeque) DeleteLast() bool { + //检查队列是否为空 + if this.IsEmpty() { + return false + } + + //删除头部元素 + this.last = (len(this.data) + this.last - 1) % len(this.data) //循环左移一位 + //this.data[this.last] = 0 //置0,这一部完全不是必须,只是为了方便输出调试。可以将这句直接注释 + + return true +} + +//getFront():从双端队列头部获得一个元素。如果双端队列为空,返回 -1。 +func (this *MyCircularDeque) GetFront() int { + //检查队列是否为空 + if this.IsEmpty() { + return -1 + } + + //获取头部元素 + return this.data[this.front] +} + +//getRear():获得双端队列的最后一个元素。 如果双端队列为空,返回 -1。 +func (this *MyCircularDeque) GetRear() int { + //检查队列是否为空 + if this.IsEmpty() { + return -1 + } + + //获取尾部元素。这里要注意下,last应该循环左移一位得到数据下标 + return this.data[(len(this.data)+this.last-1)%len(this.data)] +} + +//isEmpty():检查双端队列是否为空。 +func (this *MyCircularDeque) IsEmpty() bool { + return this.last == this.front +} + +//isFull():检查双端队列是否满了。 +func (this *MyCircularDeque) IsFull() bool { + return (this.last+1)%len(this.data) == this.front +} diff --git a/Week_01/G20200343030373/LeetCode_66_373/LeetCode_66_373_test.go b/Week_01/G20200343030373/LeetCode_66_373/LeetCode_66_373_test.go new file mode 100644 index 00000000..0d3f108e --- /dev/null +++ b/Week_01/G20200343030373/LeetCode_66_373/LeetCode_66_373_test.go @@ -0,0 +1,38 @@ +//https://leetcode-cn.com/problems/plus-one/ +package plus_one_test + +import ( + "github.com/stretchr/testify/assert" + "testing" +) + +func TestPlusOne(t *testing.T) { + digits1 := []int{1, 2, 3} + expect1 := []int{1, 2, 4} + assert.Equal(t, expect1, plusOne(digits1)) + + digits2 := []int{1, 2, 9} + expect2 := []int{1, 3, 0} + assert.Equal(t, expect2, plusOne(digits2)) + + digits3 := []int{9, 9} + expect3 := []int{1, 0, 0} + assert.Equal(t, expect3, plusOne(digits3)) +} + +//模拟进位 +//从后往前遍历 +//如果数字小于9,直接加一,直接返回 +//如果数字等于9。本位变零,向前看一位,同样与9判断大小 +//如果没有在小于9的地方返回,即每一位都是9。在遍历结束后首位加个1 +func plusOne(digits []int) []int { + for i := len(digits) - 1; i >= 0; i-- { + if digits[i] < 9 { + digits[i]++ + return digits + } else { + digits[i] = 0 + } + } + return append([]int{1}, digits...) +} diff --git a/Week_01/G20200343030373/LeetCode_70_373/LeetCode_70_373_test.go b/Week_01/G20200343030373/LeetCode_70_373/LeetCode_70_373_test.go new file mode 100644 index 00000000..9d96fce5 --- /dev/null +++ b/Week_01/G20200343030373/LeetCode_70_373/LeetCode_70_373_test.go @@ -0,0 +1,142 @@ +//https://leetcode-cn.com/problems/climbing-stairs/description/ +package climb_stair_test + +import ( + "github.com/stretchr/testify/assert" + "math" + "testing" +) + +func TestDP(t *testing.T) { + t.Log("Climbing Stairs: DP Fibonacci") + //题目描述,给定n是一个正整数,即n从1开始 + //n: 1, 2, 3, 4, 5... + //f: 1, 2, 3, 5, 8... + //区别Fibonacci, 爬楼梯n从1开始,斐波那次n从0开始;爬楼梯题目的 i和n 分别要比斐波那契 多1 + assert.Equal(t, 2, climbStairs(2)) + assert.Equal(t, 5, climbStairs(4)) + assert.Equal(t, 5, resOriginal(4)) + assert.Equal(t, 5, resMemoOut(4)) + assert.Equal(t, 5, resMemoIn(4)) + assert.Equal(t, 5, dpOriginal(4)) + assert.Equal(t, 5, dpShrink(4)) + assert.Equal(t, 5, formula(4)) + assert.Equal(t, 5, matrix(4)) +} + +func climbStairs(n int) int { + return matrix(n) +} + +//1. original recursion +//Not AC, TimeOut +func resOriginal(n int) int { + if n <= 2 { //区别Fibonacci + return n + } + return resOriginal(n-1) + resOriginal(n-2) +} + +//2.1. recursion + memory +var hash = make(map[int]int) + +func resMemoOut(n int) int { + if n <= 2 { + return n + } + if _, ok := hash[n]; !ok { + hash[n] = resMemoOut(n-1) + resMemoOut(n-2) + } + return hash[n] +} + +//2.2. recursion + memory + drill down the memory +func resMemoIn(n int) int { + hash := make(map[int]int) + return resMemo(n, hash) +} + +func resMemo(n int, hash map[int]int) int { + if n <= 2 { + hash[n] = n + return hash[n] + } + if _, ok := hash[n]; !ok { + hash[n] = resMemo(n-1, hash) + resMemo(n-2, hash) + } + return hash[n] +} + +//3. dp original +func dpOriginal(n int) int { + if n <= 2 { + return n + } + dp := make([]int, n+1) + dp[1], dp[2] = 1, 2 //区别Fibonacci + for i := 3; i <= n; i++ { //区别Fibonacci + dp[i] = dp[i-1] + dp[i-2] + } + return dp[n] +} + +//4. dp + shrink space +func dpShrink(n int) int { + if n <= 2 { + return n + } + low, high := 1, 2 + for i := 3; i <= n; i++ { + high, low = high+low, high + } + return high +} + +//5. formula +func formula(n int) int { + goldenRation := (1 + math.Sqrt(5)) / 2 + res := math.Pow(goldenRation, float64(n+1)) / math.Sqrt(5) //区别 Fibonacci + return int(math.Round(res)) +} + +//6. matrix +func matrix(n int) int { + if n <= 2 { + return n + } + + A := [2][2]int{ + {1, 1}, + {1, 0}, + } + + A = pow(A, n) //区别Fibonacci + return A[0][0] +} + +func pow(A [2][2]int, n int) [2][2]int { + if n <= 1 { + return A + } //递归终止条件,n<=1;与Power n==0 不同 + + R := pow(A, n/2) + + if n&1 == 1 { + return mul(A, mul(R, R)) + } + return mul(R, R) +} + +func mul(A, B [2][2]int) [2][2]int { + x := A[0][0]*B[0][0] + A[0][1]*B[1][0] + y := A[0][0]*B[0][1] + A[0][1]*B[1][1] + z := A[1][0]*B[0][0] + A[1][1]*B[0][1] + w := A[1][0]*B[0][1] + A[1][1]*B[1][1] + + A[0][0] = x + A[0][1] = y + A[1][0] = z + A[1][1] = w + + return A +} diff --git a/Week_01/G20200343030373/LeetCode_84_373/LeetCode_84_373_test.go b/Week_01/G20200343030373/LeetCode_84_373/LeetCode_84_373_test.go new file mode 100644 index 00000000..934ca2b0 --- /dev/null +++ b/Week_01/G20200343030373/LeetCode_84_373/LeetCode_84_373_test.go @@ -0,0 +1,122 @@ +//https://leetcode-cn.com/problems/largest-rectangle-in-histogram/ +package largest_rectangle_in_histogram_t_test + +import ( + "github.com/stretchr/testify/assert" + "testing" +) + +func TestLargestArea(t *testing.T) { + t.Log("Largest Rectangle in Histogram") + heights := []int{2, 1, 5, 6, 2, 3} + assert.Equal(t, 10, largestRectangleArea(heights)) +} + +func largestRectangleArea(heights []int) int { + return stackIncrease(heights) +} + +//暴力求解1 +//找到左边界 +//找到右边界 +//找到左右边界中面积最大的情况 +//O(n^3) +//Not AC, Time Out +func bruteForce1(heights []int) int { + maxArea := 0 + n := len(heights) + for i := 0; i <= n-1; i++ { //左边界 //要考虑只有一个元素的情况, i可达右边界 + for j := n - 1; j >= i; j-- { //右边界 //要考虑只有一个元素的情况, j可达左边界 + minHeight := heights[i] + for k := i; k <= j; k++ { //中间最低 //k可达边界 + if heights[k] < minHeight { + minHeight = heights[k] + } + } + if area := minHeight * (j - i + 1); area > maxArea { + maxArea = area + } + } + } + return maxArea +} + +//暴力求解2 +//遍历柱子 +//和其他柱子的面积的所有组合,找到最大 +//O(n^2) +//AC, 776ms +func bruteForce2(heights []int) int { + maxArea := 0 + n := len(heights) + for i := 0; i < n; i++ { + minHeight := heights[i] + for j := i; j < n; j++ { + if heights[j] < minHeight { + minHeight = heights[j] + } + if area := minHeight * (j - i + 1); area > maxArea { + maxArea = area + } + } + } + return maxArea +} + +//左右发散 +//先确定高度,再确定宽度 +//遍历每个值作为高度,向左向右查找小于该高度或超出边界为止 +//l和r对应是取不到的边界值,宽度为r-l-1 +//O(n^2), 548ms +func leftRightOut(heights []int) int { + maxArea := 0 + n := len(heights) + for i := 0; i < n; i++ { + l, r := i, i //左右边界 + for l >= 0 && heights[l] >= heights[i] { + l-- + } + for r < n && heights[r] >= heights[i] { + r++ + } + if area := heights[i] * (r - l - 1); area > maxArea { + maxArea = area + } + } + return maxArea +} + +//辅助栈 +//栈维护一个 下标 序列,对应直方图高度依次递增 +//把 -1 放进栈的顶部来表示开始 +//当下一个值right小于栈顶下表的值cur,对于栈顶下标这个柱子来说 +//- right是cur的右边界 +//- cur的前一个元素left是它的左边界 +//O{n), 8ms; O(n) +func stackIncrease(heights []int) int { + maxArea := 0 + n := len(heights) + var stack []int //用切片实现栈 + for r := 0; r <= n; r++ { + h := 0 //高度,右边界越界时为0 + if r < n { //右边界不越界 + h = heights[r] + } + + for len(stack) > 0 && h < heights[stack[len(stack)-1]] { + cur := stack[len(stack)-1] //栈顶元素 + stack = stack[:len(stack)-1] //弹出栈顶元素 + + l := -1 //左边界越界时为-1 + if len(stack) > 0 { //左边界不越界 + l = stack[len(stack)-1] + } + + if area := heights[cur] * (r - l - 1); area > maxArea { + maxArea = area + } + } + stack = append(stack, r) + } + return maxArea +} diff --git a/Week_01/G20200343030373/LeetCode_88_373/LeetCode_88_373_test.go b/Week_01/G20200343030373/LeetCode_88_373/LeetCode_88_373_test.go new file mode 100644 index 00000000..d53d2cdd --- /dev/null +++ b/Week_01/G20200343030373/LeetCode_88_373/LeetCode_88_373_test.go @@ -0,0 +1,62 @@ +package merge_two_sorted_array_test + +import ( + "github.com/stretchr/testify/assert" + "sort" + "testing" +) + +func TestMergeArray(t *testing.T) { + nums1 := []int{1, 2, 3, 0, 0, 0} + nums2 := []int{2, 5, 6} + m, n := 3, 3 + expect := []int{1, 2, 2, 3, 5, 6} + merge(nums1, m, nums2, n) + assert.Equal(t, expect, nums1) +} + +func merge(nums1 []int, m int, nums2 []int, n int) { + arrayMerge(nums1, m, nums2, n) +} + +//双指针法 +//处理数组,而不是处理切片 +//从后往前遍历,可以原地进行处理,直接将最后面的数放到nums1后面,已放好的数组无需再次移动 +func arrayMerge(nums1 []int, m int, nums2 []int, n int) { + //直接返回,nums1 + if n == 0 { + return + } + //直接将n个元素添加到nums1 + if m == 0 { + for i := 0; i < n; i++ { + nums1[i] = nums2[i] + } + return + } + + for m > 0 && n > 0 { + //从后往前,进行比较 + if nums1[m-1] < nums2[n-1] { + nums1[m+n-1] = nums2[n-1] //nums1数字比nums2小,则将nums2数字放到较后面 + n-- + } else { + nums1[m+n-1] = nums1[m-1] + m-- + } + //m总比n大 + if m == 0 && n > 0 { + for n > 0 { + nums1[m+n-1] = nums2[n-1] + n-- + } + } + } +} + +//切片排序 +//go语言特性 +func sliceMerge(nums1 []int, m int, nums2 []int, n int) { + nums1 = append(nums1[:m], nums2[:n]...) + sort.Ints(nums1) +} diff --git a/Week_01/G20200343030375/LeetCode_189_375.java b/Week_01/G20200343030375/LeetCode_189_375.java new file mode 100644 index 00000000..b2d261b2 --- /dev/null +++ b/Week_01/G20200343030375/LeetCode_189_375.java @@ -0,0 +1,17 @@ +package G20200343030375; + +/** + * 第一种实现方式 + * 暴力实现 + */ +class LeetCode_189_375 { + public void rotate(int[] nums, int k) { + for(int i=1;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; + } + } +} diff --git a/Week_01/G20200343030375/LeetCode_641_375.java b/Week_01/G20200343030375/LeetCode_641_375.java new file mode 100644 index 00000000..45586741 --- /dev/null +++ b/Week_01/G20200343030375/LeetCode_641_375.java @@ -0,0 +1,140 @@ +package G20200343030375; + +import java.util.LinkedList; + +class LeetCode_641_375 { + private int size; + private int length; + private Node header; + private Node end; + + /** Initialize your data structure here. Set the size of the deque to be k. */ + public LeetCode_641_375(int k) { + this.size =k; + LinkedList linkedList = new LinkedList(); + + } + + /** Adds an item at the front of Deque. Return true if the operation is successful. */ + public boolean insertFront(int value) { + if(size>length){ + + Node node = new Node(value); + if(header == null){ + this.init(node); + }else { + node.next = header; + header.pr = node; + header = node; + } + length++; + return true; + }else{ + return false; + } + + } + + /** Adds an item at the rear of Deque. Return true if the operation is successful. */ + public boolean insertLast(int value) { + if(!isFull()){ + Node node = new Node(value); + if(end == null){ + this.init(node); + }else { + node.pr = end; + end.next = node; + end=node; + } + length++; + return true; + }else{ + return false; + } + } + + /** Deletes an item from the front of Deque. Return true if the operation is successful. */ + public boolean deleteFront() { + if(length>1&&length!=1){ + header = header.next; + header.pr = null; + length--; + return true; + } else if(length == 1){ + header=null; + end =null; + length--; + return true; + } + return false; + + + } + + /** Deletes an item from the rear of Deque. Return true if the operation is successful. */ + public boolean deleteLast() { + if(length>0&&length!=1){ + end = end.pr; + end.next = null; + + length--; + return true; + }else if(length == 1){ + header = null; + end = null; + length--; + return true; + } + return false; + + } + + /** Get the front item from the deque. */ + public int getFront() { + if(isEmpty()){ + return -1; + } + int result = header.value; + return result; + } + + /** Get the last item from the deque. */ + public int getRear() { + if(isEmpty()){ + return -1; + } + int result = end.value; + return result; + } + + /** Checks whether the circular deque is empty or not. */ + public boolean isEmpty() { + if(length>0){ + return false; + } + return true; + } + + /** Checks whether the circular deque is full or not. */ + public boolean isFull() { + if(size >length ){ + return false; + }else { + return true; + } + } + private void init(Node node){ + header = node; + end = node; + } + + private class Node { + Node next; + Node pr; + int value ; + public Node(int value){ + this.value = value; + } + } + +} diff --git a/Week_01/G20200343030377/LeetCode_15_377.java b/Week_01/G20200343030377/LeetCode_15_377.java new file mode 100644 index 00000000..bbc5d8f9 --- /dev/null +++ b/Week_01/G20200343030377/LeetCode_15_377.java @@ -0,0 +1,80 @@ +import java.util.*; + +//leetcode submit region begin(Prohibit modification and deletion) +class Solution { + + public List> threeSum(int[] nums) { + if (null == nums || nums.length < 3) { + return Collections.EMPTY_LIST; + } + List> res = new ArrayList<>(); + Arrays.sort(nums); + for (int i = 0; i < nums.length - 2; i++) { + if (nums[i] > 0) { + return res; + } + if (i > 0 && nums[i] == nums[i - 1]) { + continue; + } + int j = i + 1; + int k = nums.length - 1; + while ((j < k)) { + int sum = nums[i] + nums[j] + nums[k]; + if (sum == 0) { + res.add(Arrays.asList(nums[i], nums[j], nums[k])); + while (j < k && nums[j] == nums[j + 1]) { + j++; + } + while ((j < k && nums[k] == nums[k - 1])) { + k--; + } + j++; + k--; + } else if (sum < 0) { + j++; + } else if (sum > 0) { + k--; + } + } + } + return res; + } + + // n * two sum + public List> threeSum2(int[] nums) { + Set> res = new HashSet<>(); + for (int i = 0; i < nums.length - 2; i++) { + int target = -nums[i]; + Set set = new HashSet<>(); + for (int j = i + 1; j < nums.length; j++) { + if (set.contains(nums[j])) { + List temp = Arrays.asList(nums[i], nums[j], target - nums[j]); + Collections.sort(temp); + res.add(temp); + } else { + set.add(target - nums[j]); + } + } + } + return new ArrayList<>(res); + } + + + //暴力 三重循环 + public List> threeSum1(int[] nums) { + Set> res = new HashSet<>(); + 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] == 0) { + List temp = Arrays.asList(nums[i], nums[j], nums[k]); + Collections.sort(temp); + ((HashSet) res).add(temp); + } + + } + } + } + return new ArrayList<>(res); + } +} diff --git a/Week_01/G20200343030377/LeetCode_189_377.java b/Week_01/G20200343030377/LeetCode_189_377.java new file mode 100644 index 00000000..40da37d5 --- /dev/null +++ b/Week_01/G20200343030377/LeetCode_189_377.java @@ -0,0 +1,29 @@ +public class LeetCode_189_377 { + + 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); + } + + private void reverse(int[] nums, int start, int end) { + int length = end - start + 1; + for (int i = 0; i < length / 2; i++) { + int temp = nums[start + i]; + nums[start + i] = nums[end - i]; + nums[end - i] = temp; + } + } + + public void rotate1(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; + } + } +} + diff --git a/Week_01/G20200343030377/LeetCode_1_377.java b/Week_01/G20200343030377/LeetCode_1_377.java new file mode 100644 index 00000000..85d16d48 --- /dev/null +++ b/Week_01/G20200343030377/LeetCode_1_377.java @@ -0,0 +1,31 @@ + +import java.util.HashMap; +import java.util.Map; + +public class LeetCode_1_377 { + + public int[] twoSum(int[] nums, int target) { + Map map = new HashMap<>(); + for (int i = 0; i < nums.length; i++) { + Integer left = map.get(nums[i]); + if (null != left) { + return new int[]{left, i}; + } else { + map.put(target - nums[i], i); + } + } + return new int[]{}; + } + + 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 (target == (nums[i] + nums[j])) { + return new int[]{i, j}; + } + } + } + return new int[]{}; + } +} + diff --git a/Week_01/G20200343030377/LeetCode_25_377.java b/Week_01/G20200343030377/LeetCode_25_377.java new file mode 100644 index 00000000..35fc4f34 --- /dev/null +++ b/Week_01/G20200343030377/LeetCode_25_377.java @@ -0,0 +1,16 @@ +public class LeetCode_25_377 { + + public int removeDuplicates(int[] nums) { + int i = 0; + for (int j = 1; j < nums.length; j++) { + if (nums[j] != nums[i]) { + if (j - i > 1) { + nums[i + 1] = nums[j]; + } + i++; + } + } + return i + 1; + } + +} diff --git a/Week_01/G20200343030377/LeetCode_289_377.java b/Week_01/G20200343030377/LeetCode_289_377.java new file mode 100644 index 00000000..f7adeea7 --- /dev/null +++ b/Week_01/G20200343030377/LeetCode_289_377.java @@ -0,0 +1,20 @@ +public class LeetCode_289_377 { + + public void moveZeroes(int[] nums) { + if (null == nums) { + 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/G20200343030379/LeetCode_1_379.java b/Week_01/G20200343030379/LeetCode_1_379.java new file mode 100644 index 00000000..0092d341 --- /dev/null +++ b/Week_01/G20200343030379/LeetCode_1_379.java @@ -0,0 +1,65 @@ +package G20200343030379; + +import java.util.HashMap; +import java.util.Stack; + +/** + * @ClassName: + * @Description: TODO + * @author ban + * @date + */ +public class LeetCode_1_379 { + public class ListNode { + int val; + ListNode next; + ListNode(int x) { val = x; } + } + //ݹ鷨 + public ListNode mergeTwoLists(ListNode l1, ListNode l2) { + if(l1==null){ + return l2; + } + + if(l2==null){ + return l1; + } + + if(l1.val1){ + // head=0; + // tail=1; + // }else{ + // //ֻһԭ + // return count; + // } + int c=0; + for(;tailnums.length-1){ + return count; + } + + //ͬƶhead + if(nums[head]!=nums[tail]){ //System.out.print(""); + head++; + nums[head]=nums[tail]; + count++; + tail++; + } + //c++; + } + //System.out.print(""); + //System.out.print(c); + return count; + } +} diff --git a/Week_01/G20200343030383/LeetCode_189_383.go b/Week_01/G20200343030383/LeetCode_189_383.go new file mode 100644 index 00000000..d8c8f370 --- /dev/null +++ b/Week_01/G20200343030383/LeetCode_189_383.go @@ -0,0 +1,55 @@ +// https://leetcode-cn.com/problems/rotate-array/ +package leetcode + +func rotate(nums []int, k int) { + if len(nums) == 0 || k == 0 || k%len(nums) == 0 { + return + } + k = k % len(nums) + reverseSlice(nums, 0, len(nums)-1) + reverseSlice(nums, 0, k-1) + reverseSlice(nums, k, len(nums)-1) +} + +func reverseSlice(nums []int, i, j int) { + for i < j { + nums[i], nums[j] = nums[j], nums[i] + i++ + j-- + } +} + +/* + 1. save start element for every loop round, keep its positon i + 2. find who-should-take-my-positon e.g. position j + 3. set j's value to i's position and set i=j (if j is not start position) + 4. set start element to i's position and start next round (if j is start position) + 5. exit if move len(nums) times +*/ +func rotate2(nums []int, k int) { + size := len(nums) + if size == 0 || k == 0 || k%size == 0 { + return + } + k = k % size + start, startV := -1, 0 + for cnt, i := 0, 0; cnt < size; cnt++ { + if start == -1 { + start = i + startV = nums[i] + } + j := whoShouldTakeMyPosition(size, k, i) + if j == start { + nums[i] = startV + start = -1 + i++ + } else { + nums[i] = nums[j] + i = j + } + } +} + +func whoShouldTakeMyPosition(size, k, i int) int { + return (i - k + size) % size +} diff --git a/Week_01/G20200343030383/LeetCode_21_383.go b/Week_01/G20200343030383/LeetCode_21_383.go new file mode 100644 index 00000000..207373b2 --- /dev/null +++ b/Week_01/G20200343030383/LeetCode_21_383.go @@ -0,0 +1,25 @@ +// https://leetcode-cn.com/problems/merge-two-sorted-lists/submissions/ +package leetcode + +func mergeTwoLists(l1 *ListNode, l2 *ListNode) *ListNode { + head := &ListNode{} + cur := head + for l1 != nil && l2 != nil { + if l1.Val < l2.Val { + cur.Next = l1 + cur = l1 + l1 = l1.Next + } else { + cur.Next = l2 + cur = l2 + l2 = l2.Next + } + + } + if l1 == nil { + cur.Next = l2 + } else { + cur.Next = l1 + } + return head.Next +} diff --git a/Week_01/G20200343030383/LeetCode_26_383.go b/Week_01/G20200343030383/LeetCode_26_383.go new file mode 100644 index 00000000..9780adb7 --- /dev/null +++ b/Week_01/G20200343030383/LeetCode_26_383.go @@ -0,0 +1,14 @@ +// https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array/ +package leetcode + +func removeDuplicates(nums []int) int { + var delCount int + for i := 1; i < len(nums); i++ { + if nums[i] == nums[i-1] { + delCount++ + } else if delCount > 0 { + nums[i-delCount] = nums[i] + } + } + return len(nums) - delCount +} diff --git a/Week_01/G20200343030383/LeetCode_283_383.go b/Week_01/G20200343030383/LeetCode_283_383.go new file mode 100644 index 00000000..f4de66d1 --- /dev/null +++ b/Week_01/G20200343030383/LeetCode_283_383.go @@ -0,0 +1,14 @@ +// https://leetcode-cn.com/problems/move-zeroes/submissions/ +package leetcode + +func moveZeroes(nums []int) { + var zeroCount int + for i := 0; i < len(nums); i++ { + if nums[i] == 0 { + zeroCount++ + } else if j := i - zeroCount; i != j { + nums[j] = nums[i] + nums[i] = 0 + } + } +} diff --git a/Week_01/G20200343030383/LeetCode_42_383.go b/Week_01/G20200343030383/LeetCode_42_383.go new file mode 100644 index 00000000..229b5e2c --- /dev/null +++ b/Week_01/G20200343030383/LeetCode_42_383.go @@ -0,0 +1,62 @@ +// https://leetcode.com/problems/trapping-rain-water/submissions/ +package leetcode + +func trap(height []int) int { + left, right := 0, len(height)-1 + var maxLeft, maxRight int + var sum int + for left <= right { + if height[left] <= height[right] { + if maxLeft >= height[left] { + sum += maxLeft - height[left] + } else { + maxLeft = height[left] + } + left++ + } else { + + if maxRight >= height[right] { + sum += maxRight - height[right] + } else { + maxRight = height[right] + } + right-- + } + } + return sum +} + +func trap2(height []int) int { + size := len(height) + if size < 3 { + return 0 + } + leftHighest, righHighest := make([]int, size), make([]int, size) + leftHighest[0] = height[0] + righHighest[size-1] = height[size-1] + for i := 1; i < size-1; i++ { + leftHighest[i] = max(height[i], leftHighest[i-1]) + j := size - 1 - i + righHighest[j] = max(height[j], righHighest[j+1]) + } + + var count int + for i := 1; i < size-1; i++ { + count += max(min(leftHighest[i-1], righHighest[i+1])-height[i], 0) + } + return count +} + +func max(a, b int) int { + if a > b { + return a + } + return b +} + +func min(a, b int) int { + if a > b { + return b + } + return a +} diff --git a/Week_01/G20200343030383/LeetCode_641_383.go b/Week_01/G20200343030383/LeetCode_641_383.go new file mode 100644 index 00000000..935e9b69 --- /dev/null +++ b/Week_01/G20200343030383/LeetCode_641_383.go @@ -0,0 +1,87 @@ +// https://leetcode.com/problems/design-circular-deque +package leetcode + +type MyCircularDeque struct { + head, rear, size int + data []int + mod func(int) int +} + +/** Initialize your data structure here. Set the size of the deque to be k. */ +func Constructor(k int) MyCircularDeque { + cd := MyCircularDeque{ + data: make([]int, k+1), + size: k + 1, + } + if k&(k+1) == 0 { + cd.mod = func(v int) int { return v & k } + } else { + k++ + cd.mod = func(v int) int { return v % k } + } + return cd +} + +/** 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.mod(this.head - 1 + this.size) + this.data[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.data[this.rear] = value + this.rear = this.mod(this.rear + 1) + 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.mod(this.head + 1) + 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.rear = this.mod(this.rear - 1 + this.size) + return true +} + +/** Get the front item from the deque. */ +func (this *MyCircularDeque) GetFront() int { + if this.IsEmpty() { + return -1 + } + return this.data[this.head] +} + +/** Get the last item from the deque. */ +func (this *MyCircularDeque) GetRear() int { + if this.IsEmpty() { + return -1 + } + return this.data[this.mod(this.rear-1+this.size)] +} + +/** Checks whether the circular deque is empty or not. */ +func (this *MyCircularDeque) IsEmpty() bool { + return this.head == this.rear +} + +/** Checks whether the circular deque is full or not. */ +func (this *MyCircularDeque) IsFull() bool { + return this.mod(this.rear+1) == this.head +} diff --git a/Week_01/G20200343030383/NOTE.md b/Week_01/G20200343030383/NOTE.md index 50de3041..3bad48b5 100644 --- a/Week_01/G20200343030383/NOTE.md +++ b/Week_01/G20200343030383/NOTE.md @@ -1 +1,14 @@ -学习笔记 \ No newline at end of file +## 学习笔记 + +### 个人收益 + +感觉本周最大的收获主要是学习到了正确的方法,"五步刷题法",以前自己做leetcode总是容易忘,理解不深,用"五步刷题法"感觉坚持下去明显好很多 + +### 个人不足 + +最近开始复工,本周投入时间精力不足,其实没有对每道样题做到五步刷题,希望后续自己能逐步优化 + +### 课程建议 + +#### 1.微信群信噪比太低,除非主动@的消息,否则很容易很无效信息刷屏,班主任可以换一种沟通方式 +### 2.老师的课程虽然一直在强调授人以渔,但是实际节奏有点快,并且感觉是为了帮助学员攻克面试,教授"术"的感觉大于"道" diff --git a/Week_01/G20200343030383/stubs.go b/Week_01/G20200343030383/stubs.go new file mode 100644 index 00000000..d853f04c --- /dev/null +++ b/Week_01/G20200343030383/stubs.go @@ -0,0 +1,6 @@ +package leetcode + +type ListNode struct { + Val int + Next *ListNode +} diff --git a/Week_01/G20200343030383/week_test.go b/Week_01/G20200343030383/week_test.go new file mode 100644 index 00000000..a7c7955b --- /dev/null +++ b/Week_01/G20200343030383/week_test.go @@ -0,0 +1,152 @@ +package leetcode + +import ( + "testing" + + "math/rand" + "sort" + + "github.com/stretchr/testify/assert" +) + +/* test for https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array/ */ +func TestRemoveDuplicates(t *testing.T) { + assert := assert.New(t) + /* test 1000 samples */ + for i := 0; i < 100; i++ { + slice, dupCount := makeDuplicateSliceSample(i) + assert.Equal(removeDuplicates(slice), len(slice)-dupCount) + } +} + +func makeDuplicateSliceSample(sampleSize int) (sample []int, dupCount int) { + sample = make([]int, sampleSize) + numsMap := make(map[int]bool) + for i := 0; i < sampleSize; i++ { + v := rand.Intn(10000) + sample[i] = v + if _, ok := numsMap[v]; ok { + dupCount++ + } else { + numsMap[v] = true + } + } + sort.Ints(sample) + return +} + +/* test for https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array/ */ +func TestRotate(t *testing.T) { + assert := assert.New(t) + for i := 0; i < 100; i++ { + sample := makeRotateSample(i) + sample2 := make([]int, i) + copy(sample2, sample) + k := rand.Intn(37) + /* cross test for rotate & rotate2 */ + rotate(sample, k) + rotate2(sample2, k) + assert.Equal(sample, sample2) + } +} + +func makeRotateSample(size int) []int { + sample := make([]int, size) + for i := 0; i < size; i++ { + v := rand.Intn(10000) + sample[i] = v + } + return sample +} + +/* test for https://leetcode-cn.com/problems/rotate-array/ */ +func TestMergeLinkedList(t *testing.T) { + assert := assert.New(t) + l1, l2 := makeLinkedList([]int{}), makeLinkedList([]int{1}) + out := linkedListToSlice(mergeTwoLists(l1, l2)) + assert.Equal([]int{1}, out) + + l1, l2 = makeLinkedList([]int{1, 1, 3, 4}), makeLinkedList([]int{1, 2, 3, 3, 5}) + out = linkedListToSlice(mergeTwoLists(l1, l2)) + assert.Equal([]int{1, 1, 1, 2, 3, 3, 3, 4, 5}, out) +} + +func makeLinkedList(nums []int) *ListNode { + var node, head *ListNode + for _, v := range nums { + n := &ListNode{Val: v} + if node != nil { + node.Next = n + node = n + } else { + node = n + head = n + } + } + return head +} + +func linkedListToSlice(n *ListNode) (s []int) { + for cur := n; cur != nil; { + s = append(s, cur.Val) + cur = cur.Next + } + return +} + +/* test for https://leetcode-cn.com/problems/move-zeroes/submissions/ */ +func TestMoveZeros(t *testing.T) { + assert := assert.New(t) + for i := 0; i < 100; i++ { + s1 := makeSliceWithZeros(i) + s2 := make([]int, i) + copy(s2, s1) + + moveZeroes(s1) + s3 := make([]int, i) + var j int + for _, v := range s2 { + if v != 0 { + s3[j] = v + j++ + } + } + + assert.Equal(s1, s3) + } +} + +func makeSliceWithZeros(sampleSize int) (sample []int) { + sample = make([]int, sampleSize) + for i := 0; i < sampleSize; i++ { + if rand.Int()%2 == 0 { + sample[i] = 0 + } else { + sample[i] = rand.Intn(10000) + } + } + return +} + +/* test for https://leetcode-cn.com/problems/design-circular-deque/ */ +func TestCircularDeque(t *testing.T) { + assert := assert.New(t) + q := Constructor(3) + assert.True(q.InsertLast(1)) + assert.True(q.InsertLast(2)) + assert.True(q.InsertFront(3)) + assert.False(q.InsertFront(4)) + assert.Equal(2, q.GetRear()) + assert.True(q.IsFull()) + assert.True(q.DeleteLast()) + assert.True(q.InsertFront(4)) + assert.Equal(4, q.GetFront()) +} + +/* test for https://leetcode.com/problems/trapping-rain-water/submissions/ */ +func TestTrap(t *testing.T) { + height := []int{0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1} + assert := assert.New(t) + assert.Equal(6, trap(height)) + assert.Equal(6, trap2(height)) +} diff --git a/Week_01/G20200343030385/LeetCode_001_385.go b/Week_01/G20200343030385/LeetCode_001_385.go new file mode 100644 index 00000000..1e0f72cc --- /dev/null +++ b/Week_01/G20200343030385/LeetCode_001_385.go @@ -0,0 +1,16 @@ +func twoSum(nums []int, target int) []int { + var b []int + for j := 0; j < len(nums);j ++ { + var b []int + b = append(b, j) + c := target - nums[j] + for i := j + 1; i < len(nums);i ++ { + + if c == nums[i]{ + b = append(b, i) + return b + } + } + } + return b +} diff --git a/Week_01/G20200343030385/LeetCode_021_385.go b/Week_01/G20200343030385/LeetCode_021_385.go new file mode 100644 index 00000000..1118126e --- /dev/null +++ b/Week_01/G20200343030385/LeetCode_021_385.go @@ -0,0 +1,50 @@ +/** + * Definition for singly-linked list. + * type ListNode struct { + * Val int + * Next *ListNode + * } + */ +func mergeTwoLists(l1 *ListNode, l2 *ListNode) *ListNode { + if l1 == nil { + return l2 + } else if l2 == nil { + return l1 + } + + var l3Fast *ListNode = nil //新的链表第一个节点 + var l3Last *ListNode = nil //新链表最后节点 + var newNode *ListNode = nil //新创建节点 + + for true { + //对比l1和l2当前值,取较小值,取值链表前进一步 + if l1.Val > l2.Val { + newNode = l2 + l2 = l2.Next + } else { + newNode = l1 + l1 = l1.Next + } + + //较小值链接到l3 + if l3Last == nil { + l3Fast = newNode + l3Last = newNode + } else { + l3Last.Next = newNode + l3Last = newNode + } + + //如果l1和l2其中一个已经遍历完,另一个剩余部分直接拼接到新链表尾部 + if l1 == nil { + l3Last.Next = l2 + break + } else if l2 == nil { + l3Last.Next = l1 + break + } + } + + return l3Fast + +} diff --git a/Week_01/G20200343030385/LeetCode_283_385.go b/Week_01/G20200343030385/LeetCode_283_385.go new file mode 100644 index 00000000..415f8957 --- /dev/null +++ b/Week_01/G20200343030385/LeetCode_283_385.go @@ -0,0 +1,15 @@ +func moveZeroes(nums []int) { + a := 0 + b := 0 + for ; b < len(nums);b ++ { + if nums[b] != 0 { + c := nums[b] + nums[a] = c + if b > a { + nums[b] = 0 + } + a++ + } + + } +} diff --git a/Week_01/G20200343030387/LeetCode_189_387.js b/Week_01/G20200343030387/LeetCode_189_387.js new file mode 100644 index 00000000..771891a3 --- /dev/null +++ b/Week_01/G20200343030387/LeetCode_189_387.js @@ -0,0 +1,56 @@ +/** + * @param {number[]} nums + * @param {number} k + * @return {void} Do not return anything, modify nums in-place instead. + */ +// 方法1:暴力解法 +var rotate1 = function(nums, k) { + // 循环k次移动,每次遍历整个数组且每个元素旋转一位 + let temp, previous + for (let i = 0; i < k; i++) { + previous = nums[nums.length - 1] // 当前要移到元素的上一个元素 + for (let j = 0; j < nums.length; j++) { + temp = nums[j] + nums[j] = previous + previous = temp + } + } +} + +// 方法2:多数组法 +// 空间复杂度:O(n) +var rotate2 = function(nums, k) { + let newArr = [] + for (let i = 0; i < nums.length; i++) { + newArr[(i + k) % nums.length] = nums[i] + } + for (let j = 0; j < newArr.length; j++) { + nums[j] = newArr[j] + } +} + +// 方法3:多次反转数组 +var rotate3 = function(nums, k) { + var reverse = function(arr, start, end) { + while (start < end) { + swap(arr, start, end) + start++ + end-- + } + } + var swap = function(arr, a, b) { + let temp = arr[a] + arr[a] = arr[b] + arr[b] = temp + } + k %= nums.length // 取余数是因为数组旋转了本身长度后还是原样,所以只要余数部分就行 + reverse(nums, 0, nums.length - 1) + reverse(nums, 0, k - 1) + reverse(nums, k, nums.length - 1) +} + +// 方法4:切片替换 +// 切割数组末k位的元素,添加到数组头部 +var rotate = function(nums, k) { + nums.unshift(...nums.splice(nums.length - k)) +} diff --git a/Week_01/G20200343030387/LeetCode_26_387.js b/Week_01/G20200343030387/LeetCode_26_387.js new file mode 100644 index 00000000..db30e1a3 --- /dev/null +++ b/Week_01/G20200343030387/LeetCode_26_387.js @@ -0,0 +1,22 @@ +/** + * 双指针法 + * 时间复杂度:O(n) + * 空间复杂度:O(1) + */ +/** + * @param {number[]} nums + * @return {number} + */ +var removeDuplicates = function(nums) { + if (nums.length === 0) return 0 // 边界条件判断 + let i = 0 // 慢指针 + for (let j = 1; j < nums.length; j++) { + // 快指针遍历 + if (nums[i] !== nums[j]) { + // 两者所在位置的值不等时,将快指针的值赋值给慢指针后一个位置,同时慢指针后移一位 + i++ + nums[i] = nums[j] + } + } + return i + 1 +} diff --git a/Week_01/G20200343030387/LeetCode_283_387.js b/Week_01/G20200343030387/LeetCode_283_387.js new file mode 100644 index 00000000..0b457a5a --- /dev/null +++ b/Week_01/G20200343030387/LeetCode_283_387.js @@ -0,0 +1,22 @@ +/** + * @param {number[]} nums + * @return {void} Do not return anything, modify nums in-place instead. + */ +/** + * 双指针法 + * 一个指针指向当前遍历到的最后一个零元素,另一个是自然遍历的; + * 如果两指针指向的值不等(即当前指针指向非零元素),交换两指针的值,两指针同时往后移一位; + * 否则只是当前指针移一位; + */ +var moveZeroes = function(nums) { + let lastNonZeroFoundAt = 0 + for (let current = 0; current < nums.length; current++) { + if (nums[current] !== 0) { + if (current !== lastNonZeroFoundAt) { + nums[lastNonZeroFoundAt] = nums[current] + nums[current] = 0 + } + lastNonZeroFoundAt++ + } + } +} diff --git a/Week_01/G20200343030387/NOTE.md b/Week_01/G20200343030387/NOTE.md index 50de3041..c25abe5d 100644 --- a/Week_01/G20200343030387/NOTE.md +++ b/Week_01/G20200343030387/NOTE.md @@ -1 +1,2 @@ -学习笔记 \ No newline at end of file +解题思路确实稍微比之前开阔了一些,但是很多题目依然无法用较好的方法入手,大多数的时候想到的依旧是用暴力法去解决, +可能因为题目做的还不够多,不够熟吧。还有就是一些数据结构依然不是很理解,比如跳表这种,希望接下来再接再厉。 diff --git a/Week_01/G20200343030389/MergeTwoSortedLists.java b/Week_01/G20200343030389/MergeTwoSortedLists.java new file mode 100644 index 00000000..a718b143 --- /dev/null +++ b/Week_01/G20200343030389/MergeTwoSortedLists.java @@ -0,0 +1,102 @@ +package follow.phenix.ice.algorithm.weekone; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; +import java.util.List; + +class ListNode { + int val; + ListNode next; + + ListNode(int x) { + val = x; + } + + @Override + public String toString() { + StringBuilder result = new StringBuilder(String.valueOf(val)); + ListNode nextNode = next; + while (nextNode != null) { + result.append(", ").append(nextNode.val); + nextNode = nextNode.next; + } + return result.toString(); + } +} + + +/** + * @author iceiceice + */ +public class MergeTwoSortedLists { + + public static void main(String[] args) { + ListNode nodeOne = getListNode(new ListNode(1), Arrays.asList(2, 3)); + ListNode nodeTwo = getListNode(new ListNode(1), Arrays.asList(3, 4)); + System.out.println(nodeOne); + System.out.println(nodeTwo); +// ListNode newNodeOne = methodOne(nodeOne, nodeTwo); + ListNode newNodeTwo = methodTwo(nodeOne, nodeTwo); + System.out.println(newNodeTwo); + + } + + private static ListNode methodTwo(ListNode l1, ListNode l2) { + if (l1 == null) { + return l2; + } + if (l2 == null) { + return l1; + } + if (l1.val < l2.val) { + l1.next = methodTwo(l1.next, l2); + return l1; + } else { + l2.next = methodTwo(l2.next, l1); + return l2; + } + } + + /********************************************************************/ + + private static ListNode methodOne(ListNode l1, ListNode l2) { + List l1ValueList = getAllValues(l1); + List l2ValueList = getAllValues(l2); + List allValueList = new ArrayList<>(); + allValueList.addAll(l1ValueList); + allValueList.addAll(l2ValueList); + allValueList.sort(Comparator.comparingInt(o -> o)); + if (allValueList.size() == 0) { + return null; + } + ListNode head = new ListNode(allValueList.get(0)); + allValueList.remove(0); + return getListNode(head, allValueList); + } + + private static ListNode getListNode(ListNode head, List list) { + if (list == null || list.size() == 0) { + return head; + } + ListNode next = head; + for (int i : list) { + next.next = new ListNode(i); + next = next.next; + } + return head; + } + + private static List getAllValues(ListNode node) { + if (node == null) { + return new ArrayList<>(); + } + List result = new ArrayList<>(); + ListNode next = node; + while (next != null) { + result.add(next.val); + next = next.next; + } + return result; + } +} diff --git a/Week_01/G20200343030389/NOTE.md b/Week_01/G20200343030389/NOTE.md index 50de3041..3e103c33 100644 --- a/Week_01/G20200343030389/NOTE.md +++ b/Week_01/G20200343030389/NOTE.md @@ -1 +1,56 @@ -学习笔记 \ No newline at end of file +## 学习笔记 +### 数组 +- 数组是内存中用一组连续的内存单元保存相同类型元素的数据集合 +- 数据可以根据下标随机访问数据,原因在于内存中的内存管理器管理着每一个数组元素的内存地址 +- 数组的时间复杂度 + 1. 根据下表访问元素:O(1) + 2. 根据值访问元素:O(n) + 3. 插入:O(n) + 4. 删除:O(n) + 5. 使用二分法在有序数组中根据值访问元素:O(logn) + +### 链表 +- 链表是一种线性的数据结构,除了保存自身节点外,还保存了一个或两个指针指向它旁边的节点 +- 根据指针的数量和指针的方法可以分为 + 1. 单向链表 + 2. 双向链表 + 3. 单向循环链表 + 4. 双向循环链表 +- 单向链表的时间复杂度 + 1. 根据值查找:O(n) + 3. 删除:O(1) + 2. 插入:O(1) + +### 跳表 +- 跳表可以优化链表的查询效率,比如单向有序链表的查询是O(n)的,通过跳表优化后查询的时间复杂度位O(logn) +- 跳表=链表+索引 +- 将链表优化位跳表的前提是链表必须是有序的,因为索引的操作是通过比较索引元素的值来确定索引走向的 +- 时间复杂度 + 1. 查找:O(logn) + 2. 插入:O(logn) + 3. 删除:O(logn)。因为跳表插入数据和删除数据时都要同步更新索引,所以其插入和删除的复杂度比俩表要大,都是O(logn) +- 空间复杂度:O(n) + +### Stack(栈) +- 先进后出,后进先出 +- 时间复杂度 + 1. 进栈:O(1) + 3. 出栈:O(1) + +### Queue(队列) +- 先进先出,后进后出 +- 时间复杂度 + 1. 进栈:O(1) + 3. 出栈:O(1) + +### Deque(双端队列) +- 两端都可以入队、出队。可以将deque理解为了一个加强版的stack +- 时间复杂度 + 1. 进栈:O(1) + 3. 出栈:O(1) + +### PriorityQueue(优先队列) +- 优先队列是队列的一种,不同点在于其取出操作不是按顺序取出的,而是按照优先级取出的,优先级越高的元素优先出队 +- 时间复杂度 +1. 入队:O(1) +2. 出队:O(logn) diff --git a/Week_01/G20200343030389/RemoveDuplicatesFromSortedArray.java b/Week_01/G20200343030389/RemoveDuplicatesFromSortedArray.java new file mode 100644 index 00000000..25db783e --- /dev/null +++ b/Week_01/G20200343030389/RemoveDuplicatesFromSortedArray.java @@ -0,0 +1,26 @@ +package follow.phenix.ice.algorithm.weekone; + +/** + * @author iceiceice + */ +public class RemoveDuplicatesFromSortedArray { + + public static void main(String[] args) { + int[] nums = new int[]{0, 0, 1, 1, 1, 2, 2, 3, 3, 4}; + System.out.println("methodOne result: " + methodOne(nums)); + } + + private static int methodOne(int[] nums) { + if (nums == null || nums.length == 0) { + return 0; + } + int index = 0; + for (int i = 1; i < nums.length; i++) { + if (nums[i] != nums[index]) { + nums[index + 1] = nums[i]; + index = index + 1; + } + } + return index + 1; + } +} diff --git a/Week_01/G20200343030389/RotateArray.java b/Week_01/G20200343030389/RotateArray.java new file mode 100644 index 00000000..833beeac --- /dev/null +++ b/Week_01/G20200343030389/RotateArray.java @@ -0,0 +1,29 @@ +package follow.phenix.ice.algorithm.weekone; + +import java.util.Arrays; + +/** + * @author iceiceice + */ +public class RotateArray { + public static void main(String[] args) { + int[] nums = new int[]{1, 2, 3, 4, 5, 6, 7}; + int k = 3; + rotate(nums, k); + } + + private static void rotate(int[] nums, int k) { + int rotateCount = 0; + while (rotateCount < k) { + int temp; + int prev = nums[nums.length - 1]; + for (int i = 0; i < nums.length; i++) { + temp = nums[i]; + nums[i] = prev; + prev = temp; + } + rotateCount++; + } + System.out.println(Arrays.toString(nums)); + } +} diff --git a/Week_01/G20200343030391/LeetCode_155_391.java b/Week_01/G20200343030391/LeetCode_155_391.java new file mode 100644 index 00000000..48b5f99a --- /dev/null +++ b/Week_01/G20200343030391/LeetCode_155_391.java @@ -0,0 +1,64 @@ +package G20200343030391; + +import java.util.Stack; + +public class LeetCode_155_391 { + + public static void main(String[] args) { + MinStack minStack = new MinStack(); + minStack.push(-2); + minStack.push(0); + minStack.push(-3); + minStack.getMin(); // 返回 -3. + minStack.pop(); + minStack.top(); // 返回 0. + minStack.getMin(); // 返回 -2. + + } + + public static class MinStack { + Stack dataStack; + Stack minStack; + + + /** initialize your data structure here. */ + public MinStack() { + dataStack = new Stack<>(); + minStack = new Stack<>(); + } + + public void push(int x) { + dataStack.push(x); + if (minStack.isEmpty() || minStack.peek() >= x) { + minStack.push(x); + } else { + minStack.push(minStack.peek()); + } + + } + + public void pop() { + if (!dataStack.isEmpty()) { + dataStack.pop(); + minStack.pop(); + } + } + + public int top() { + if (!dataStack.isEmpty()) { + return dataStack.peek(); + } else { + throw new RuntimeException("stack is empty"); + } + } + + public int getMin() { + if (!dataStack.isEmpty()) { + return minStack.peek(); + } else { + throw new RuntimeException("stack is empty"); + } + } + } + +} diff --git a/Week_01/G20200343030391/LeetCode_189_391.java b/Week_01/G20200343030391/LeetCode_189_391.java new file mode 100644 index 00000000..89d7eed6 --- /dev/null +++ b/Week_01/G20200343030391/LeetCode_189_391.java @@ -0,0 +1,36 @@ +package G20200343030391; + +import java.util.Arrays; + +public class LeetCode_189_391 { + + public static void main(String[] args) { + int[] nums = {1, 2, 3, 4, 5, 6}; + int k = 2; + rotate(nums, k); + System.out.println(Arrays.toString(nums)); + } + + /** + * 环状替换:从开始位置连续替换,发生碰撞则开启下一轮替换 + * 时间复杂度:O(n) + * @param nums + * @param k + */ + public static void rotate(int[] nums, int k) { + k = k % nums.length; + int count = 0; + for (int start = 0; count < nums.length; start++) { + int current = start; + int currentVal = nums[start]; + do { + int newIndex = (current + k) % (nums.length); + int temp = nums[newIndex]; + nums[newIndex] = currentVal; + currentVal = temp; + current = newIndex; + count++; + } while (start != current); + } + } +} diff --git a/Week_01/G20200343030391/LeetCode_1_391.java b/Week_01/G20200343030391/LeetCode_1_391.java new file mode 100644 index 00000000..23bf5fe6 --- /dev/null +++ b/Week_01/G20200343030391/LeetCode_1_391.java @@ -0,0 +1,50 @@ +package G20200343030391; + +import java.util.Arrays; +import java.util.HashMap; + +public class LeetCode_1_391 { + + public static void main(String[] args) { + int[] nums = {2, 7, 11, 15}; + int target = 9; + int[] ints = twoSum_2(nums, target); + System.out.println(Arrays.toString(ints)); + } + + /** + * 解法1:暴力求解 + * 时间复杂度:O(n^2) + * @param nums + * @param target + * @return + */ + public static int[] twoSum_1(int[] nums, int target) { + for (int i = 0; i < nums.length; i++) { + for (int j = i; j < nums.length; j++) { + if (nums[i] + nums[j] == target) { + return new int[]{i, j}; + } + } + } + return null; + } + /** + * 解法2:hash表 + * 时间复杂度:O(n) + * @param nums + * @param target + * @return + */ + public static int[] twoSum_2(int[] nums, int target) { + HashMap hashMap = new HashMap<>(); + for (int i = 0; i < nums.length; i++) { + int n2 = target - nums[i]; + if (hashMap.containsKey(n2)) { + return new int[]{i, hashMap.get(n2)}; + } + hashMap.put(nums[i], i); + } + return null; + } +} diff --git a/Week_01/G20200343030391/LeetCode_20_391.java b/Week_01/G20200343030391/LeetCode_20_391.java new file mode 100644 index 00000000..31665c99 --- /dev/null +++ b/Week_01/G20200343030391/LeetCode_20_391.java @@ -0,0 +1,39 @@ +package G20200343030391; + +import java.util.HashMap; +import java.util.Stack; + +public class LeetCode_20_391 { + + public static void main(String[] args) { + String s = "()[]{}"; + boolean valid = isValid(s); + System.out.println(valid); + } + + /** + * 最近相关性:使用栈先进先出的特性 + * @param s + * @return + */ + public static boolean isValid(String s) { + HashMap hashMap = new HashMap<>(); + hashMap.put(')', '('); + hashMap.put(']', '['); + hashMap.put('}', '{'); + char[] charArray = s.toCharArray(); + Stack stack = new Stack<>(); + for (int i = 0; i < charArray.length; i++) { + if (hashMap.containsKey(charArray[i])) { + if (stack.isEmpty()) { + return false; + } else if (stack.pop() != hashMap.get(charArray[i])) { + return false; + } + } else { + stack.push(charArray[i]); + } + } + return stack.isEmpty(); + } +} diff --git a/Week_01/G20200343030391/LeetCode_21_391.java b/Week_01/G20200343030391/LeetCode_21_391.java new file mode 100644 index 00000000..47ed8f46 --- /dev/null +++ b/Week_01/G20200343030391/LeetCode_21_391.java @@ -0,0 +1,90 @@ +package G20200343030391; + +public class LeetCode_21_391 { + + public static void main(String[] args) { + + // 1->2->4 + ListNode l11 = new ListNode(1); + ListNode l12 = new ListNode(2); + ListNode l14 = new ListNode(4); + l11.next = l12; + l12.next = l14; + // 1->3->4 + ListNode l21 = new ListNode(1); + ListNode l23 = new ListNode(3); + ListNode l24 = new ListNode(4); + l21.next = l23; + l23.next = l24; + + ListNode listNode = mergeTwoLists_2(l11, l21); + System.out.println(listNode); + } + + /** + * 解法1:allNode为合并后的结果,currentNode连接l1和l2的最小的next节点 + * 时间复杂度:O(n) + * @param l1 + * @param l2 + * @return + */ + public static ListNode mergeTwoLists_1(ListNode l1, ListNode l2) { + ListNode allNode = new ListNode(-1); + + ListNode currentNode = allNode; + while (l1 != null && l2 != null) { + if (l1.val <= l2.val) { + currentNode.next = l1; + l1 = l1.next; + } else { + currentNode.next = l2; + l2 = l2.next; + } + currentNode = currentNode.next; + } + + currentNode.next = l1 == null ? l2 : l1; + + return allNode.next; + + } + /** + * 解法2:递归查找 + * 时间复杂度:O(n) + * @param l1 + * @param l2 + * @return + */ + public static ListNode mergeTwoLists_2(ListNode l1, ListNode l2) { + if (l1 == null) { + return l2; + } else if (l2 == null) { + return l1; + } else if (l1.val <= l2.val) { + l1.next = mergeTwoLists_2(l1.next, l2); + return l1; + } else { + l2.next = mergeTwoLists_2(l1, l2.next); + return l2; + } + } + + public static class ListNode { + int val; + ListNode next; + + ListNode(int x) { + val = x; + } + @Override + public String toString() { + String toString = this.val + "->"; + ListNode next = this.next; + while (next != null) { + toString = toString + next.val + "->"; + next = next.next; + } + return toString + "null"; + } + } +} diff --git a/Week_01/G20200343030391/LeetCode_26_391.java b/Week_01/G20200343030391/LeetCode_26_391.java new file mode 100644 index 00000000..2ace01db --- /dev/null +++ b/Week_01/G20200343030391/LeetCode_26_391.java @@ -0,0 +1,29 @@ +package G20200343030391; + +import java.util.Arrays; + +public class LeetCode_26_391 { + + public static void main(String[] args) { + int[] nums = {0, 0, 1, 1, 1, 2, 2, 3, 3, 4}; + int i = removeDuplicates_1(nums); + System.out.println(i + ":" + Arrays.toString(nums)); + } + + /** + * 双指针:慢指针j保留去重后下标,快指针i寻找下一个数字 + * 时间复杂度:O(n) + * @param nums + * @return + */ + public static int removeDuplicates_1(int[] nums) { + 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/G20200343030391/LeetCode_283_391.java b/Week_01/G20200343030391/LeetCode_283_391.java new file mode 100644 index 00000000..5669bd2d --- /dev/null +++ b/Week_01/G20200343030391/LeetCode_283_391.java @@ -0,0 +1,51 @@ +package G20200343030391; + +import java.util.Arrays; + +public class LeetCode_283_391 { + + public static void main(String[] args) { + int[] nums = {0, 0, 1}; + moveZeroesDoubleCursor(nums); + System.out.println(Arrays.toString(nums)); + } + + /** + * 暴力补0 + * index记录非0下标,若有0则直接向前移动;最后补0 + * 时间复杂度O(n) + * @param nums + */ + public static void moveZeroes_1(int[] nums) { + int index = 0; + for (int i = 0; i < nums.length; i++) { + if (nums[i] != 0) { + nums[index] = nums[i]; + index++; + } + } + for (int i = index; i < nums.length; i++) { + nums[i] = 0; + } + } + + /** + * 双指针: + * 快指针i 满指针j 非0元素直接前移 + * 时间复杂度O(n) + * @param nums + */ + public static void moveZeroesDoubleCursor(int[] nums) { + + int j = 0; + for (int i = 0; i < nums.length; i++) { + if (nums[i] != 0) { + int tmp = nums[i]; + nums[i] = nums[j]; + nums[j] = tmp; + j++; + } + } + } + +} diff --git a/Week_01/G20200343030391/LeetCode_42_391.java b/Week_01/G20200343030391/LeetCode_42_391.java new file mode 100644 index 00000000..23e62e6d --- /dev/null +++ b/Week_01/G20200343030391/LeetCode_42_391.java @@ -0,0 +1,34 @@ +package G20200343030391; + +import java.util.Stack; + +public class LeetCode_42_391 { + + 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); + } + + public static 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; + } +} diff --git a/Week_01/G20200343030391/LeetCode_641_391.java b/Week_01/G20200343030391/LeetCode_641_391.java new file mode 100644 index 00000000..051f41ef --- /dev/null +++ b/Week_01/G20200343030391/LeetCode_641_391.java @@ -0,0 +1,182 @@ +package G20200343030391; + +public class LeetCode_641_391 { + public static void main(String[] args) { + MyCircularDeque myCircularDeque = new MyCircularDeque(8); + boolean b = myCircularDeque.insertFront(5); + assert b; + boolean empty22 = myCircularDeque.isEmpty(); + assert !empty22; + int front = myCircularDeque.getFront(); + assert front == 5; + boolean empty = myCircularDeque.isEmpty(); + assert !empty; + boolean b1 = myCircularDeque.deleteFront(); + assert b1; + boolean b2 = myCircularDeque.insertLast(3); + assert b2; + int rear = myCircularDeque.getRear(); + assert rear == 3; + boolean empty1 = myCircularDeque.isEmpty(); + assert !empty1; + boolean b3 = myCircularDeque.insertLast(7); + assert b3; + boolean b4 = myCircularDeque.insertFront(7); + assert b4; + boolean b5 = myCircularDeque.deleteLast(); + assert b5; + boolean b6 = myCircularDeque.insertLast(4); + assert b6; + boolean empty2 = myCircularDeque.isEmpty(); + assert !empty2; + } + + public static class MyCircularDeque { + + int size; + int count; + MyCircularDequeNode first; + MyCircularDequeNode last; + + public static class MyCircularDequeNode{ + int val; + MyCircularDequeNode prev; + MyCircularDequeNode next; + public MyCircularDequeNode(int val) { + this.val = val; + } + } + + /** + * Initialize your data structure here. Set the size of the deque to be k. + */ + public MyCircularDeque(int k) { + this.count = 0; + this.size = k; + } + + /** + * Adds an item at the front of Deque. Return true if the operation is successful. + */ + public boolean insertFront(int value) { + if (count < size) { + MyCircularDequeNode node = new MyCircularDequeNode(value); + if (count == 0) { + this.first = node; + this.last = node; + } else { + MyCircularDequeNode currentFirst = this.first; + node.next = currentFirst; + currentFirst.prev = node; + this.first = node; + } + count++; + return true; + } else { + return false; + } + } + + /** + * Adds an item at the rear of Deque. Return true if the operation is successful. + */ + public boolean insertLast(int value) { + if (count < size) { + MyCircularDequeNode node = new MyCircularDequeNode(value); + if (count == 0) { + this.first = node; + this.last = node; + } else { + MyCircularDequeNode currentLast = this.last; + currentLast.next = node; + node.prev = currentLast; + this.last = node; + } + count++; + return true; + } else { + return false; + } + } + + /** + * Deletes an item from the front of Deque. Return true if the operation is successful. + */ + public boolean deleteFront() { + if (count > 0) { + if (count == 1) { + this.first = null; + this.last = null; + } else { + MyCircularDequeNode first = this.first; + MyCircularDequeNode second = first.next; + second.prev = null; + first = null; + this.first = second; + } + count--; + return true; + } else { + return false; + } + } + + /** + * Deletes an item from the rear of Deque. Return true if the operation is successful. + */ + public boolean deleteLast() { + if (count > 0) { + if (count == 1) { + this.first = null; + this.last = null; + } else { + MyCircularDequeNode currentLast = this.last; + MyCircularDequeNode second_to_last = currentLast.prev; + second_to_last.next = null; + this.last = second_to_last; + currentLast = null; + } + count--; + return true; + } else { + return false; + } + } + + /** + * Get the front item from the deque. + */ + public int getFront() { + if (count > 0) { + return this.first.val; + } else { + return -1; + } + } + + /** + * Get the last item from the deque. + */ + public int getRear() { + if (count > 0) { + return this.last.val; + } else { + return -1; + } + } + + /** + * Checks whether the circular deque is empty or not. + */ + public boolean isEmpty() { + return count == 0; + } + + /** + * Checks whether the circular deque is full or not. + */ + public boolean isFull() { + return count == size; + } + } +} diff --git a/Week_01/G20200343030391/LeetCode_66_391.java b/Week_01/G20200343030391/LeetCode_66_391.java new file mode 100644 index 00000000..6062326a --- /dev/null +++ b/Week_01/G20200343030391/LeetCode_66_391.java @@ -0,0 +1,36 @@ +package G20200343030391; + +import java.util.Arrays; + +public class LeetCode_66_391 { + + public static void main(String[] args) { + int[] nums = {9, 8, 7, 6, 5, 4, 3, 2, 1, 0}; + int[] plusOne = plusOne(nums); + System.out.println(Arrays.toString(plusOne)); + + } + + /** + * 末位无进位,直接加一; + * 末位有进位,则末位=0,下一位继续加一,直到!=0,结束进位, + * 进位全为0,位数+1 + * 时间复杂度:O(n) + * @param digits + * @return + */ + public static 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/G20200343030391/LeetCode_88_391.java b/Week_01/G20200343030391/LeetCode_88_391.java new file mode 100644 index 00000000..aa376788 --- /dev/null +++ b/Week_01/G20200343030391/LeetCode_88_391.java @@ -0,0 +1,42 @@ +package G20200343030391; + +import java.util.Arrays; + +public class LeetCode_88_391 { + + 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)); + } + + /** + * 双指针:从尾部开始遍历,最大的放到最尾巴;最后补充num2未遍历到的 + * 时间复杂度 : O(n) + * + * @param nums1 + * @param m + * @param nums2 + * @param n + */ + public static void merge(int[] nums1, int m, int[] nums2, int n) { + int nums1Tail = m - 1; + int nums2Tail = n - 1; + int mergeTail = m + n - 1; + while (nums1Tail >= 0 && nums2Tail >= 0) { + if (nums1[nums1Tail] < nums2[nums2Tail]) { + nums1[mergeTail] = nums2[nums2Tail]; + mergeTail--; + nums2Tail--; + } else { + nums1[mergeTail] = nums1[nums1Tail]; + mergeTail--; + nums1Tail--; + } + } + System.arraycopy(nums2, 0, nums1, 0, nums2Tail + 1); + } +} diff --git a/Week_01/G20200343030391/NOTE.md b/Week_01/G20200343030391/NOTE.md index 50de3041..0befe0d1 100644 --- a/Week_01/G20200343030391/NOTE.md +++ b/Week_01/G20200343030391/NOTE.md @@ -1 +1,63 @@ -学习笔记 \ No newline at end of file +# 学习笔记 + +## 1.数组 + ### 概念 + - 数组是一种线性表的数据结构,用一组连续的内存空间存储相同类型的数据 + - 线性表:每个数据最多只有一个前驱和后继节点如数组、链表、队列、栈 + - 非线性表:树、图、堆 + - 连续的内存空间和相同的数据类型保证了可以实现随机访问 + ### 操作 + - 随机访问:时间复杂度O(1) + - 插入:尾部插入O(1);随机插入O(n) + - 删除:删除最后一个O(1);随机删除O(n) + +## 2. 链表 + ### 概念 + - 链表是一种物理存储单元谁给你非连续、非顺序的存储结构,数据元素的逻辑顺序通过链表中的指针实现 + - 循环链表:尾结点只想头结点,可以是单链表也可以是双链表 + - 单向链表:值、指针;插入删除:O(1);随机访问:O(n) + - 双向链表: 值、prev、next;头部、尾部、给定节点操作O(1) + - 静态链表: 值、指针、下标;用数组描述链表 + ### 操作 + - 随机访问:O(n) + - 插入:随机插入O(n) + - 删除:随机删除O(n) + +## 3.跳表 + ### 概念 + - 在有序的链表的基础上,通过维护对层次的索引链加快查询、插入、删除速度 + ### 操作 + - 查询:O(log(n)) + - 插入:O(log(n)) + - 删除:O(log(n)) +## 4.栈 + ### 概念 + - 栈是一种操作受限的线性表,体现在只能在一端插入删除数据,先进后出 FILO + - 数组实现:顺序栈;链表实现:链式栈 + ### 操作 + - 入栈push:栈顶压入O(1) + - 出栈pop:栈顶取出O(1) + - 访问栈顶:peekO(1) +## 5.队列 + ### 概念 + - 队列是一种操作受限的线性表,先进先出FILO + - head指针+tail指针 + - 顺序队列:isFull = tail==capacity;isEmpty = head==tail; + - 双端对垒:同时具有队列和栈的特性,支持从两端添加、取出元素 + ### 操作 + - 入队:队尾加入O(1) + - 出队:队首取出O(1) +## 6.优先队列 + ### 概念 + - 使用堆实现,元素具有优先级,入队最大(最小)优先级加入堆顶,出队最大(最小)优先级弹出 + ### 操作 + - 入队:堆实现log(n) + - 出队:堆实现log(n) + + +## 算法套路 + - 五毒神掌 + - 升维思想 + - 空间换时间 + - 阅读代码添加注释 + - 变量命名辅助理解 \ No newline at end of file diff --git a/Week_01/G20200343030393/LeetCode_21_393.py b/Week_01/G20200343030393/LeetCode_21_393.py new file mode 100644 index 00000000..966aa336 --- /dev/null +++ b/Week_01/G20200343030393/LeetCode_21_393.py @@ -0,0 +1,22 @@ +class Solution: + def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode: + """ + 第一种解法在交换l1.l2的时候比较费时,执行时间为56ms + 第二种执行时间为44ms + :param l1: + :param l2: + :return: + """ + # if l1 and l2: + # if l1.val > l2.val: l1, l2 = l2, l1 + # l1.next = self.mergeTwoLists(l1.next, l2) + # return l1 or l2 + + if l1 and l2: + if l1.val < l2.val: + l1.next = self.mergeTwoLists(l1.next, l2) + return l1 + else: + l2.next = self.mergeTwoLists(l2.next, l1) + return l2 + return l1 or l2 \ No newline at end of file diff --git a/Week_01/G20200343030393/LeetCode_641_393.py b/Week_01/G20200343030393/LeetCode_641_393.py new file mode 100644 index 00000000..e51ca4f8 --- /dev/null +++ b/Week_01/G20200343030393/LeetCode_641_393.py @@ -0,0 +1,194 @@ +""" +很好奇,我写的MyCircularDeque_my运行官方最终测试的时候,跟官方给的答案运行的结果完全相同,不知道为啥就是运行不通过 +""" +class MyCircularDeque_my: + + def __init__(self, k: int): + """ + Initialize your data structure here. Set the size of the deque to be k. + """ + self.front = 0 + self.capacity = k + self.rear = self.capacity + self.arr = [0 for _ in range(self.capacity + 1)] + + 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 + + self.arr[self.front] = value + self.front += 1 + 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 + self.arr[self.rear] = value + self.rear -= 1 + 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 + if self.front == 0: + self.rear += 1 + else: + self.front -= 1 + 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 + if self.rear == self.capacity: + self.front -= 1 + else: + self.rear += 1 + return True + + def getFront(self) -> int: + """ + Get the front item from the deque. + """ + if self.isEmpty(): + return -1 + if self.front == 0: + return self.arr[self.rear + 1] + else: + return self.arr[self.front - 1] + + def getRear(self) -> int: + """ + Get the last item from the deque. + """ + if self.isEmpty(): + return -1 + if self.rear == self.capacity: + return self.arr[0] + else: + return self.arr[self.rear + 1] + + def isEmpty(self) -> bool: + """ + Checks whether the circular deque is empty or not. + """ + return self.rear == self.capacity and self.front == 0 + + def isFull(self) -> bool: + """ + Checks whether the circular deque is full or not. + """ + return self.rear == self.front + + def isArr(self) -> list: + return self.arr + +class MyCircularDeque: + + def __init__(self, k: int): + """ + Initialize your data structure here. Set the size of the deque to be k. + """ + self.front = 0 + self.rear = 0 + self.capacity = k + 1 + self.arr = [0 for _ in range(self.capacity)] + + 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 + self.front = (self.front - 1 + self.capacity) % self.capacity + self.arr[self.front] = 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 + self.arr[self.rear] = value + self.rear = (self.rear + 1) % self.capacity + 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 + self.front = (self.front + 1) % self.capacity + 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 + self.rear = (self.rear - 1 + self.capacity) % self.capacity; + return True + + def getFront(self) -> int: + """ + Get the front item from the deque. + """ + if self.isEmpty(): + return -1 + return self.arr[self.front] + + def getRear(self) -> int: + """ + Get the last item from the deque. + """ + if self.isEmpty(): + return -1 + return self.arr[(self.rear - 1 + self.capacity) % self.capacity] + + def isEmpty(self) -> bool: + """ + Checks whether the circular deque is empty or not. + """ + return self.front == self.rear + + def isFull(self) -> bool: + """ + Checks whether the circular deque is full or not. + """ + return (self.rear + 1) % self.capacity == self.front + + def isArr(self) -> list: + return self.arr + +circularDeque = MyCircularDeque(77) +result1 = [circularDeque.insertFront(89), circularDeque.getRear(), circularDeque.deleteLast(), circularDeque.getRear(), + circularDeque.insertFront(19), circularDeque.insertFront(23), circularDeque.insertFront(23), + circularDeque.insertFront(82), circularDeque.isFull(), circularDeque.insertFront(45), circularDeque.isFull(), + circularDeque.getRear(), circularDeque.deleteFront(), circularDeque.getFront(), circularDeque.getFront(), + circularDeque.insertLast(74), circularDeque.deleteFront(), circularDeque.getFront(), circularDeque.insertLast(98)] + +circularDeque_my = MyCircularDeque_my(77) +result2 = [circularDeque_my.insertFront(89), circularDeque_my.getRear(), circularDeque_my.deleteLast(), circularDeque_my.getRear(), + circularDeque_my.insertFront(19), circularDeque_my.insertFront(23), circularDeque_my.insertFront(23), + circularDeque_my.insertFront(82), circularDeque_my.isFull(), circularDeque_my.insertFront(45), circularDeque_my.isFull(), + circularDeque_my.getRear(), circularDeque_my.deleteFront(), circularDeque_my.getFront(), circularDeque_my.getFront(), + circularDeque_my.insertLast(74), circularDeque_my.deleteFront(), circularDeque_my.getFront(), circularDeque_my.insertLast(98)] + +if result1 == result2: + print(True) +else: + print(False) \ No newline at end of file diff --git a/Week_01/G20200343030393/LeetCode_88_393.py b/Week_01/G20200343030393/LeetCode_88_393.py new file mode 100644 index 00000000..b734684c --- /dev/null +++ b/Week_01/G20200343030393/LeetCode_88_393.py @@ -0,0 +1,24 @@ +def merge(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. + """ + i = 0 + x = 0 + nums1_copy = nums1[:m] + nums1[:] = [] + while i < m and x < n: + if nums1_copy[i] < nums2[x]: + nums1.append(nums1_copy[i]) + i += 1 + else: + nums1.append(nums2[x]) + x += 1 + + if i < m: + nums1 += nums1_copy[i:m] + if x < n: + nums1 += nums2[x:n] \ No newline at end of file diff --git a/Week_01/G20200343030395/LeetCode_141.java b/Week_01/G20200343030395/LeetCode_141.java new file mode 100644 index 00000000..8fa1b3d4 --- /dev/null +++ b/Week_01/G20200343030395/LeetCode_141.java @@ -0,0 +1,49 @@ +package Week_01.G20200343030395; + +import java.util.List; + +public class LeetCode_141 { + + static class ListNode { + int val; + ListNode next; + ListNode(int x) { + val = x; + next = null; + } + } + + public static void main(String[] args) { + ListNode head = new ListNode(1); + ListNode p = new ListNode(2); + head.next = p; + p.next = null; + + boolean bool = hasCycle(head); + System.out.print(bool); + + } + + public static boolean hasCycle(ListNode head) { + if(head == null || head.next == null){ + return false; + } + + ListNode p = head; + ListNode q = head.next; + + while(p != q) { + if(q.next == null || q.next.next == null){ + return false; + } + + p = p.next; + q = q.next.next; + } + + return true; + } +} + + + diff --git a/Week_01/G20200343030395/LeetCode_1_395.java b/Week_01/G20200343030395/LeetCode_1_395.java new file mode 100644 index 00000000..1b6b4b30 --- /dev/null +++ b/Week_01/G20200343030395/LeetCode_1_395.java @@ -0,0 +1,34 @@ +package Week_01.G20200343030395; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class LeetCode_1_395 { + public static void main(String[] args) { + int[] nums = new int[]{0,0,0,0,1,1,2,3}; + int num = removeDuplicates(nums); + System.out.println(num); + } + + public static int removeDuplicates(int[] nums) { + if(nums.length == 1) { + return 1; + } + + int i = 0; + for(int j=1; j 0; j--) { + nums[j] = nums[j-1]; + } + + //脑袋赋值为最后一个 + nums[0] = temp; + } + + + } +} diff --git a/Week_01/G20200343030395/LeetCode_3_395.java b/Week_01/G20200343030395/LeetCode_3_395.java new file mode 100644 index 00000000..62d4f3e7 --- /dev/null +++ b/Week_01/G20200343030395/LeetCode_3_395.java @@ -0,0 +1,60 @@ +package Week_01.G20200343030395; + +public class LeetCode_3_395 { +// public static void main(String[] args) { +// ListNode l1 = new ListNode(1); +// ListNode l2 = new ListNode(1); +// +// ListNode ret; +// //l1是空的,直接返回l2 +// if(l1 == null) { +// return l2; +// } +// //同上 +// if(l2 == null) { +// return l1; +// } +// +// //先取个头 +// if(l1.val < l2.val) { +// ret = l1; +// l1 = l1.next; +// } else { +// ret = l2; +// l2 = l2.next; +// } +// +// //保存头,返回用 +// ListNode head = ret; +// +// //循环,到其中一个到尾为止,谁小取谁 +// while(l1 != null && l2 != null) { +// if(l1.val < l2.val) { +// ret.next = l1; +// ret = ret.next; +// l1 = l1.next; +// } else { +// ret.next = l2; +// ret = ret.next; +// l2 = l2.next; +// } +// } +// +// //把剩下的接上去 +// if(l1 != null) { +// ret.next = l1; +// } +// //把剩下的接上去 +// if(l2 != null) { +// ret.next = l2; +// } +// +// //return head; +// } + + public static class ListNode { + int val; + ListNode next; + ListNode(int x) { val = x; } + } +} diff --git a/Week_01/G20200343030395/LeetCode_3sum.java b/Week_01/G20200343030395/LeetCode_3sum.java new file mode 100644 index 00000000..fc4a45a3 --- /dev/null +++ b/Week_01/G20200343030395/LeetCode_3sum.java @@ -0,0 +1,60 @@ +package Week_01.G20200343030395; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class LeetCode_3sum { + + public static void main(String[] args) { + int[] nums = new int[]{-1, 0, 1, 2, -1, -4}; + //List> x = s.threeSum(nums); + List> x = threeSum(nums); + System.out.print(x); + } + + public static List> threeSum(int[] nums) { + List> x = new ArrayList(); + for(int i=0;i> threeSum2(int[] nums) { + Arrays.sort(nums); + List> ls = new ArrayList<>(); + + for (int i = 0; i < nums.length - 2; i++) { + if (i == 0 || (i > 0 && nums[i] != nums[i - 1])) { // 跳过可能重复的答案 + + int l = i + 1, r = nums.length - 1, sum = 0 - nums[i]; + while (l < r) { + if (nums[l] + nums[r] == sum) { + ls.add(Arrays.asList(nums[i], nums[l], nums[r])); + while (l < r && nums[l] == nums[l + 1]) l++; + while (l < r && nums[r] == nums[r - 1]) r--; + l++; + r--; + } else if (nums[l] + nums[r] < sum) { + while (l < r && nums[l] == nums[l + 1]) l++; // 跳过重复值 + l++; + } else { + while (l < r && nums[r] == nums[r - 1]) r--; + r--; + } + } + } + } + return ls; + } + + +} diff --git a/Week_01/G20200343030395/LeetCode_4_395.java b/Week_01/G20200343030395/LeetCode_4_395.java new file mode 100644 index 00000000..9c970f34 --- /dev/null +++ b/Week_01/G20200343030395/LeetCode_4_395.java @@ -0,0 +1,38 @@ +package Week_01.G20200343030395; + +import java.util.Arrays; + +public class LeetCode_4_395 { + 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); + System.out.println(Arrays.toString(nums1)); + + } + + public static void merge(int[] nums1, int m, int[] nums2, int n) { + //复制一个一样的nums1 + int [] nums1Copy = new int[m]; + System.arraycopy(nums1, 0, nums1Copy, 0, m); + + int p1 = 0; + int p2 = 0; + int p = 0; + + //循环比较两个数组里面的值,直到有其中一个用完为止 + while ((p1 < m) && (p2 < n)) { + nums1[p++] = (nums1Copy[p1] < nums2[p2]) ? nums1Copy[p1++] : nums2[p2++]; + } + + //把两个数组剩下的数据丢到num1 + if (p1 < m) { + System.arraycopy(nums1Copy, 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/G20200343030395/LeetCode_5_395.java b/Week_01/G20200343030395/LeetCode_5_395.java new file mode 100644 index 00000000..46184bfd --- /dev/null +++ b/Week_01/G20200343030395/LeetCode_5_395.java @@ -0,0 +1,45 @@ +package Week_01.G20200343030395; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +public class LeetCode_5_395 { + public static void main(String[] args) { + int[] nums1 = new int[]{2, 7, 11, 15}; + + int[] ret = twoSum(nums1, 9); + System.out.println(Arrays.toString(ret)); + + } + + public static int[] twoSum(int[] nums, int target) { + int[] x = new int[2]; + for(int i = 0;i 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"); + } +} diff --git a/Week_01/G20200343030395/LeetCode_6_395.java b/Week_01/G20200343030395/LeetCode_6_395.java new file mode 100644 index 00000000..de305cae --- /dev/null +++ b/Week_01/G20200343030395/LeetCode_6_395.java @@ -0,0 +1,17 @@ +package Week_01.G20200343030395; + +public class LeetCode_6_395 { + + public static void moveZeroes(int[] nums) { + int j = 0; + for(int i=0; i=0;i--) { + //9的时候,进位,继续循环 + if(digits[i] == 9) { + digits[i] = 0; + } else { + //不是0,直接加,返回 + digits[i] ++; + return digits; + } + } + + digits = new int[digits.length +1]; + digits[0] = 1; + return digits; + } +} diff --git a/Week_01/G20200343030395/LeetCode_8_395.java b/Week_01/G20200343030395/LeetCode_8_395.java new file mode 100644 index 00000000..04940b8d --- /dev/null +++ b/Week_01/G20200343030395/LeetCode_8_395.java @@ -0,0 +1,101 @@ +package Week_01.G20200343030395; + +public class LeetCode_8_395 { + + class MyCircularDeque { + + int[] deque; + int size; + + /** Initialize your data structure here. Set the size of the deque to be k. */ + public MyCircularDeque(int k) { + deque = new int[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; + } + + for (int i = size-1; i>=0; i--) { + deque[i+1] = deque[i]; + } + + deque[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(isFull()) { + return false; + } + + deque[size] = value; + 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; + } + + deque[0] = 0; + for(int i=0; i 1 时,才进行复制 + if(q - p > 1){ + nums[p + 1] = nums[q]; + } + p++; + } + q++; + } + return p + 1; + } +} diff --git a/Week_01/G20200343030401/NOTE.md b/Week_01/G20200343030401/NOTE.md index 50de3041..f538f536 100644 --- a/Week_01/G20200343030401/NOTE.md +++ b/Week_01/G20200343030401/NOTE.md @@ -1 +1,23 @@ -学习笔记 \ No newline at end of file +###极客大学算法训练营week01学习笔记 +#####1.学习方法 + * (1)切碎知识点;(2)刻意练习;(3)反馈; + * 五毒神掌(五遍刷题法) + * 任何领域就像一棵树,需要形成自己的知识脑图 + * 升维,空间换时间 + #####2.工具 + * 搜索引擎为 Google + * IDE: VSCode; Java:IntelliJ, Python: Pycharm; -> 需要安装LeetCode插件 + * 刷题网站: 国内-> https://leetcode-cn.com/ 国外-> https://leetcode.com/ + +#####3.数据结构分类 +* 一维数据结构 +* 二维数据结构 +* 特殊数据结构 + +#####4.算法 +* if-else, switch -> branch +* for, while loop -> Iteration +* 递归 +任何算法到最后都会转化为上面三种基石算法,算法到最后就是找重复单元 + +#####4.源码以及原理分析 \ No newline at end of file diff --git a/Week_01/G20200343030403/leetcode189.java b/Week_01/G20200343030403/leetcode189.java new file mode 100644 index 00000000..0624fa5f --- /dev/null +++ b/Week_01/G20200343030403/leetcode189.java @@ -0,0 +1,39 @@ +class Solution { + + // 环状替换法 + public void rotate1(int[] nums, int k) { + k = k % nums.length; + if (k == 0 || k == nums.length) return; + int count = 0; + + for (int st = 0;count < nums.length; st ++){ + int current = st; + int prev = nums[st]; + do { + int next = (current + k) % nums.length; + int tmp = nums[next]; + nums[next] = prev; + prev = tmp; + current = next; + count++; + } while (current != st); + } + } + + // 反转 + public void rotate2(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); + } + + private void reverse(int[] nums, int st, int ed) { + int tmp; + while (st < ed) { + tmp = nums[st]; + nums[st++] = nums[ed]; + nums[ed--] = tmp; + } + } +} \ No newline at end of file diff --git a/Week_01/G20200343030403/leetcode26.java b/Week_01/G20200343030403/leetcode26.java new file mode 100644 index 00000000..b6774b4b --- /dev/null +++ b/Week_01/G20200343030403/leetcode26.java @@ -0,0 +1,16 @@ +class Solution { + + // 双指针法 + public int removeDuplicates(int[] nums) { + if (nums.length == 0) { + return 0; + } + int pos = 0; + for (int i = 1; i < nums.length; i++) { + if (nums[pos] != nums[i]) { + nums[++pos] = nums[i]; + } + } + return pos + 1; + } +} \ No newline at end of file diff --git "a/Week_01/G20200343030407/[189]\346\227\213\350\275\254\346\225\260\347\273\204.py" "b/Week_01/G20200343030407/[189]\346\227\213\350\275\254\346\225\260\347\273\204.py" new file mode 100644 index 00000000..c29bc0d9 --- /dev/null +++ "b/Week_01/G20200343030407/[189]\346\227\213\350\275\254\346\225\260\347\273\204.py" @@ -0,0 +1,52 @@ +# 给定一个数组,将数组中的元素向右移动 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) +from typing import List + + +class Solution: + def rotate(self, nums: List[int], k: int) -> None: + """ + Do not return anything, modify nums in-place instead. + """ + move_step = k % nums.__len__() + if move_step == 0: + pass + else: + nums1 = nums[nums.__len__() - move_step:] + for idx in range(0, nums.__len__())[::-1]: + + if idx <= move_step - 1: + nums[idx] = nums1[idx] + else: + nums[idx] = nums[idx - move_step] + + +# leetcode submit region end(Prohibit modification and deletion) diff --git "a/Week_01/G20200343030407/[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/G20200343030407/[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 00000000..88f2b5d1 --- /dev/null +++ "b/Week_01/G20200343030407/[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,57 @@ +# 给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。 +# +# 不要使用额外的数组空间,你必须在原地修改输入数组并在使用 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 数组 双指针 +from typing import List + + +# leetcode submit region begin(Prohibit modification and deletion) +class Solution: + def removeDuplicates(self, nums: List[int]) -> int: + count_duplicates = 0 + exist_set = set() + for idx, num in enumerate(nums): + if num in exist_set: + count_duplicates += 1 + else: + exist_set.add(num) + if count_duplicates > 0: + nums[idx - count_duplicates] = num + return len(nums) - count_duplicates + +# leetcode submit region end(Prohibit modification and deletion) diff --git a/Week_01/G20200343030409/LeetCode_189_409.java b/Week_01/G20200343030409/LeetCode_189_409.java new file mode 100644 index 00000000..8e508dd7 --- /dev/null +++ b/Week_01/G20200343030409/LeetCode_189_409.java @@ -0,0 +1,26 @@ +/* + it's really magic... + 1. reverse entire array + 2. reverse the partial array of 0 ~ k-1 + 3. reverse the partial array of k ~ end + 4. it's the answer + + time complexity: O(n), space complexity: O(1) + +*/ +class Solution { + public void rotate(int[] nums, int k) { + int len = nums.length; + k %= len; + reverse(nums, 0, len - 1); + reverse(nums, 0, k -1); + reverse(nums, k, len - 1); + } + private void reverse(int[] nums, int start, int end) { + while (start < end) { + int temp = nums[start]; + nums[start++] = nums[end]; + nums[end--] = temp; + } + } +} \ No newline at end of file diff --git a/Week_01/G20200343030409/LeetCode_1_409.java b/Week_01/G20200343030409/LeetCode_1_409.java new file mode 100644 index 00000000..f9730536 --- /dev/null +++ b/Week_01/G20200343030409/LeetCode_1_409.java @@ -0,0 +1,23 @@ +/* + in order to nums[0] + nums[1] = 2 + 7 = 9, return [0, 1]. + use hashmap to store each number + find target - num in hashmap, that's the answer: (now index, hashmap's index) + + time complexity: O(n), space complexity: O(n) + +*/ +class Solution { + public int[] twoSum(int nums[], int target) { + Map map = new HashMap<>(); + + for (int i = 0; i < nums.length; i++) { + int num = nums[i]; + + if (map.containsKey(target - num)) { + return new int[]{map.get(target - num), i}; + } + map.put(num, i); + } + return new int[]{}; + } +} \ No newline at end of file diff --git a/Week_01/G20200343030409/LeetCode_21_409.java b/Week_01/G20200343030409/LeetCode_21_409.java new file mode 100644 index 00000000..edda7f76 --- /dev/null +++ b/Week_01/G20200343030409/LeetCode_21_409.java @@ -0,0 +1,41 @@ + +// recursion +// time complexity: O(n+m), space complexity: O(n+m) +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; + } + } +} + +// iteration +// time complexity: O(n+m), space complexity: O(1) +class Solution { + public ListNode mergeTwoLists(ListNode list1, ListNode list2) { + ListNode prevHead = new ListNode(-1); + + ListNode prev = prevHead; + + while (list1 != null && list2 != null) { + if (list1.val < list2.val) { + prev.next = list1; + list1 = list1.next; + } else { + prev.next = list2; + list2 = list2.next; + } + prev = prev.next; + } + + prev.next = (list1 == null) ? list2 : list1; + + return prevHead.next; + } +} \ No newline at end of file diff --git a/Week_01/G20200343030409/LeetCode_26_409.java b/Week_01/G20200343030409/LeetCode_26_409.java new file mode 100644 index 00000000..8b6f449f --- /dev/null +++ b/Week_01/G20200343030409/LeetCode_26_409.java @@ -0,0 +1,16 @@ +// time complexity: O(n), space complexity: O(1) + +class Solution { + public int removeDuplicates(int[] nums) { + int size = 0; + if (nums == null) return size; + + for (int num : nums) { + if(nums[size] != num) { + nums[++size] = num; // only need to know the size at last + } + } + + return size+1; + } +} \ No newline at end of file diff --git a/Week_01/G20200343030409/LeetCode_283_409.java b/Week_01/G20200343030409/LeetCode_283_409.java new file mode 100644 index 00000000..7d397f47 --- /dev/null +++ b/Week_01/G20200343030409/LeetCode_283_409.java @@ -0,0 +1,18 @@ +/* + time complexity: O(n), space complexity: O(1) + */ +class Solution { + public static void moveZeroes(int[] nums) { + int leftMostZeroIndex = 0; // The index of the leftmost zero + for (int i = 0; i < nums.length; i++) { + if (nums[i] != 0) { + if (i > leftMostZeroIndex) { // There are zero(s) on the left side of the current non-zero number, swap! + nums[leftMostZeroIndex] = nums[i]; //do swap!! so smart + nums[i] = 0; + } + + leftMostZeroIndex++; // notice this poistion here + } + } + } +} \ No newline at end of file diff --git a/Week_01/G20200343030409/LeetCode_42_409.java b/Week_01/G20200343030409/LeetCode_42_409.java new file mode 100644 index 00000000..4f2cb4e8 --- /dev/null +++ b/Week_01/G20200343030409/LeetCode_42_409.java @@ -0,0 +1,35 @@ +/* + using stack to record index + when should we caculate area? => when current height > stack's top elemnt height + + time complexity: O(n), space complexity: O(n) stack's size + */ +class Solution { + public int trap(int[] height) { + if (height == null) return 0; + + Stack s = new Stack<>(); // stack stores index + int curr = 0; // current index + int maxWater = 0; // result + + while (curr < height.length) { + // stack is empty ot current <= stack top, push current + if (s.isEmpty() || height[curr] <= height[s.peek()]) { + s.push(curr++); + } else { + int top = s.pop(); // current height > stack top's height, pop current + int water = 0; + + if (!s.isEmpty()) { //stack is not empty, then we caculate area + int distance = curr - s.peek() - 1; + int minHeight = Math.min(height[s.peek()], height[curr]) - height[top]; // find the offset with 1. lowest height between curr and stack top's height, 2. pop's element hight + water = distance * minHeight; + } + //stack is empty, water is 0 + + maxWater += water; + } + } + return maxWater; + } +} \ No newline at end of file diff --git a/Week_01/G20200343030409/LeetCode_641_409.java b/Week_01/G20200343030409/LeetCode_641_409.java new file mode 100644 index 00000000..b9f074fb --- /dev/null +++ b/Week_01/G20200343030409/LeetCode_641_409.java @@ -0,0 +1,80 @@ +class MyCircularDeque { + + int[] circularDeque; + int front, rear, cap; + + /** Initialize your data structure here. Set the size of the deque to be k. */ + public MyCircularDeque(int k) { + circularDeque = new int[k + 1]; + front = 0; + rear = 0; + cap = 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; + + circularDeque[front] = value; + front = (front + 1) % cap; + 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 + cap) % cap; + circularDeque[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 + cap) % cap; + 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) % cap; + return true; + } + + /** Get the front item from the deque. */ + public int getFront() { + return isEmpty() ? -1 : circularDeque[(front - 1 + cap) % cap]; + } + + /** Get the last item from the deque. */ + public int getRear() { + return isEmpty() ? -1 : circularDeque[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) % cap == 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/G20200343030409/LeetCode_66_409.java b/Week_01/G20200343030409/LeetCode_66_409.java new file mode 100644 index 00000000..2febdf6c --- /dev/null +++ b/Week_01/G20200343030409/LeetCode_66_409.java @@ -0,0 +1,33 @@ +class Solution { + /* + 998 + 999 + 899 + 119 + 111 + Observing these numbers, we will find only 9 + 1 will carry to next digits + and become 0 + + 1. so if any digit pluses one and doesnt carry, it's answer + 2. or keep doing next digit + 3. if loop all for loop, it means it's a all 9 digits number, add one more leading digit one in the index 0 of result + + time complexity: O(n), space complexity: O(n) ans's size + */ + public int[] plusOne(int[] digits) { + + int len = digits.length; + for (int i = len - 1; i >= 0 ; i--) { + if (digits[i] < 9) { + digits[i]++; + return digits; + } + digits[i] = 0; + } + + int result[] = new int[len+1]; + result[0] = 1; + + return result; + } +} \ No newline at end of file diff --git a/Week_01/G20200343030409/LeetCode_88_409.java b/Week_01/G20200343030409/LeetCode_88_409.java new file mode 100644 index 00000000..a580e915 --- /dev/null +++ b/Week_01/G20200343030409/LeetCode_88_409.java @@ -0,0 +1,24 @@ +/* +1. use two pointer +2. there is a enough space of nums1 to put nums1's data and nums2's data, + so create a m+n index to store the result +3. compare element from array's last, and then put them to m+n nums1's from last index +4. at last, if nums2 still has element, put them all into nums1 + + time complexity: O(n), space complexity: O(1) + +*/ +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) { + nums1[p--] = nums1[p1] < nums2[p2] ? nums2[p2--] : nums1[p1--]; + } + while (p2 >= 0) { + nums1[p--] = nums2[p2--]; + } + } +} \ No newline at end of file diff --git a/Week_01/G20200343030413/LeetCode_001_413.java b/Week_01/G20200343030413/LeetCode_001_413.java new file mode 100644 index 00000000..b6b17370 --- /dev/null +++ b/Week_01/G20200343030413/LeetCode_001_413.java @@ -0,0 +1,32 @@ +package com.kidand.homework; + +import java.util.HashMap; +/** +* +* ██╗ ██╗██╗██████╗ █████╗ ███╗ ██╗██████╗ +* ██║ ██╔╝██║██╔══██╗██╔══██╗████╗ ██║██╔══██╗ +* █████╔╝ ██║██║ ██║███████║██╔██╗ ██║██║ ██║ +* ██╔═██╗ ██║██║ ██║██╔══██║██║╚██╗██║██║ ██║ +* ██║ ██╗██║██████╔╝██║ ██║██║ ╚████║██████╔╝ +* ╚═╝ ╚═╝╚═╝╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═══╝╚═════╝ +* +* @description:LeetCode_001_413 两数之和 +* @author: Kidand +* @date: 2020/2/15 1:42 下午 +* Copyright © 2019-Kidand. +*/ +public class LeetCode_001_413 { + public int[] twoSum(int[] nums, int target) { + HashMap map = new HashMap<>(); + for (int i = 0; i < nums.length; i++) { + // 将原本为两个目标值切换为一个目标值,只需要每次从 map 中寻找目标值即可 + int num = target - nums[i]; + if (map.containsKey(num)) { + return new int[]{map.get(num), i}; + } + // 每次遍历过的值都存储到 map 中,这样之后就能从 map 中寻找需要的目标值 + map.put(nums[i], i); + } + return null; + } +} diff --git a/Week_01/G20200343030413/LeetCode_283_413.java b/Week_01/G20200343030413/LeetCode_283_413.java new file mode 100644 index 00000000..1d22e88f --- /dev/null +++ b/Week_01/G20200343030413/LeetCode_283_413.java @@ -0,0 +1,29 @@ +package com.kidand.homework; +/** +* +* ██╗ ██╗██╗██████╗ █████╗ ███╗ ██╗██████╗ +* ██║ ██╔╝██║██╔══██╗██╔══██╗████╗ ██║██╔══██╗ +* █████╔╝ ██║██║ ██║███████║██╔██╗ ██║██║ ██║ +* ██╔═██╗ ██║██║ ██║██╔══██║██║╚██╗██║██║ ██║ +* ██║ ██╗██║██████╔╝██║ ██║██║ ╚████║██████╔╝ +* ╚═╝ ╚═╝╚═╝╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═══╝╚═════╝ +* +* @description:LeetCode_283_413 移动零 +* @author: Kidand +* @date: 2020/2/15 1:42 下午 +* Copyright © 2019-Kidand. +*/ +public class LeetCode_283_413 { + public void moveZeroes(int[] nums) { + for(int i=0,count=0;i=0 && len2 >= 0){ + //谁大就放到nums1的末尾 + nums1[len--] = nums1[len1] > nums2[len2] ? nums1[len1--] : nums2[len2--]; + } + //遍历完nums1,把nums2剩余的数拷贝到nums1前面 + System.arraycopy(nums2,0,nums1,0,len2 + 1); + } +} \ No newline at end of file diff --git a/Week_01/G20200343030519/NOTE.md b/Week_01/G20200343030417/417-week01/NOTE.md similarity index 100% rename from Week_01/G20200343030519/NOTE.md rename to Week_01/G20200343030417/417-week01/NOTE.md diff --git a/Week_01/G20200343030417/417-week01/circle_deque.py b/Week_01/G20200343030417/417-week01/circle_deque.py new file mode 100644 index 00000000..f1eddb79 --- /dev/null +++ b/Week_01/G20200343030417/417-week01/circle_deque.py @@ -0,0 +1,56 @@ +# 设计实现双段队列 +# import collections + +class MyCircularDeque: + def __init__(self,k:int): + self.k = k + self.q = [] + + # 前端插入 + def insertFront(self,value:int) -> bool: + if len(self.q) < self.k: + self.q.insert(0,value) + return True + return False + + # 后端插入 + def insertLast(self,value:int) -> bool: + if len(self.q) < self.k: + self.q += [value] + return True + return False + + # 前段删除 + def deleteFront(self) -> bool: + if self.q: + self.q.pop(0) + return True + return False + + # 后端删除 + def deleteLast(self) -> bool: + if self.q: + self.q.pop() + return True + return False + + # 获取前端数据 + def getFront(self) -> int: + if self.q: + return self.q[0] + return -1 + + # 获取后端数据 + def getRear(self) -> int: + if self.q: + return self.q[-1] + return -1 + + # 判断是否已空 + def isEmpty(self) -> bool: + return len(self.q) == 0 + + # 判断是否已满 + def isFull(self) -> bool: + return len(self.q) == self.k + diff --git a/Week_01/G20200343030417/417-week01/mergelist.py b/Week_01/G20200343030417/417-week01/mergelist.py new file mode 100644 index 00000000..9ab75598 --- /dev/null +++ b/Week_01/G20200343030417/417-week01/mergelist.py @@ -0,0 +1,21 @@ +# 合并两个有序链表 +# 将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 + +# 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 not l1: + return l2 + elif not l2: + return l1 + elif l1.val < l2.val: + l1.next = self.mergeTwoLists(l1.next,l2) + return l1 + else: + l2.next = self.mergeTwoLists(l1,l2.next) + return l2 \ No newline at end of file diff --git a/Week_01/G20200343030423/LeetCode_189_423.java b/Week_01/G20200343030423/LeetCode_189_423.java new file mode 100644 index 00000000..576db085 --- /dev/null +++ b/Week_01/G20200343030423/LeetCode_189_423.java @@ -0,0 +1,28 @@ +package G20200343030423; +import java.util.Arrays; + +public class LeetCode_189_423 { + + public static void main(String[] args) { + int[] a = {1,2,3,4,5,6,7}; + rotate(a, 3); + System.out.println(Arrays.toString(a)); + int[] b = {-1,-100,3,99}; + rotate(b, 2); + System.out.println(Arrays.toString(b)); + + } + + public static void rotate(int[] nums, int k) { + k = k % nums.length; + int[] b = new int[nums.length]; + for (int i = nums.length - k, j = 0; j < nums.length; j++, i++ ) { + b[j] = nums[i % nums.length]; + } + for (int i = 0; i < nums.length; i++) { + nums[i] = b[i]; + } + } + + +} diff --git a/Week_01/G20200343030423/LeetCode_26_423.java b/Week_01/G20200343030423/LeetCode_26_423.java new file mode 100644 index 00000000..5541ad09 --- /dev/null +++ b/Week_01/G20200343030423/LeetCode_26_423.java @@ -0,0 +1,33 @@ +package G20200343030423; + +import java.util.Arrays; + +public class LeetCode_26_423 { + + public static void main(String[] args) { + + int[] a = {1, 1, 2}; + printResult(a); + + int[] b = {0,0,1,1,1,2,2,3,3,4}; + printResult(b); + } + + private static void printResult(int[] a) { + int size = removeDuplicates(a); + System.out.println("left size: " + size); + System.out.println(Arrays.toString(a)); + } + + public static 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/G20200343030425/LeetCode_01_425/LeetCode_01_425.js b/Week_01/G20200343030425/LeetCode_01_425/LeetCode_01_425.js new file mode 100644 index 00000000..9a9a114d --- /dev/null +++ b/Week_01/G20200343030425/LeetCode_01_425/LeetCode_01_425.js @@ -0,0 +1,72 @@ +/* + |address: https://leetcode-cn.com/problems/two-sum/ + |-------------------------------------------------- + | Question: Given an array of integers, + | return indices of the two numbers such that they add up to a specific target. + |-------------------------------------------------- + */ +const nums = [3, 2, 3]; +const target = 6; //should return [0,1] +/** + |-------------------------------------------------- + | Method 1: + |-------------------------------------------------- + */ +const removeDuplicate = array => { + array.sort((a, b) => a - b); + array.forEach((el, index) => { + if (array[index] === array[index + 1]) { + array.splice(index, 1); + } + }); + return array; +}; +const twoSum = (nums, target) => { + let first = ""; + let sortNums = removeDuplicate([...nums]); + for (let i = 0; i < sortNums.length; i++) { + if (nums.includes(target - sortNums[i])) { + first = sortNums[i]; + break; + } + } + let second = target - first; + let secondIndex = nums.lastIndexOf(second); + let firstIndex = nums.findIndex(el => el === first); + + return [firstIndex, secondIndex]; +}; +console.log(twoSum(nums, target)); +/** + |-------------------------------------------------- + | Method 2: use Map + |-------------------------------------------------- + */ +const twoSum_v2 = function(nums, target) { + const map = new Map(); + for (let i = 0; i < nums.length; i++) { + const otherIndex = map.get(target - nums[i]); + if (otherIndex !== undefined) return [otherIndex, i]; + map.set(nums[i], i); + console.log("map", map); + } +}; +twoSum_v2(nums, target); + +/* +* Method 3: using two loops => two pointers +* */ +const twoSum3=(nums,target)=>{ + let a=0; + let b=0; + for (let i = 0; i { + let checkDuplicateArray = []; + array.forEach((el, index) => { + if (array[index] === array[index + 1]) { + checkDuplicateArray.push(el); + } + }); + return checkDuplicateArray.length; +}; +const removeDuplicate = array => { + array.sort((a, b) => a - b); + array.forEach((el, index) => { + if (array[index] === array[index + 1]) { + array.splice(index, 1); + } + }); + if (checkDuplicate(array) > 0) { + removeDuplicate(array); + } + return array; +}; +//console.log(removeDuplicate(nums)); + + +/* +* Method 2: 快慢指针 +* */ +const removeDuplicate4 = (nums) => { + if (nums.length === 0) return 0; + let i = 0; + for (let j = 1; j < nums.length; j++) { + if (nums[j] !== nums[i]) { + i++; + nums[i] = nums[j]; + } + } + while (nums.length !== i + 1) { + nums.splice(i + 1, 1) + } + return i + 1; +}; +console.log(removeDuplicate4(nums)); diff --git a/Week_01/G20200343030429/LeetCode_1_429.java b/Week_01/G20200343030429/LeetCode_1_429.java new file mode 100644 index 00000000..19e0f330 --- /dev/null +++ b/Week_01/G20200343030429/LeetCode_1_429.java @@ -0,0 +1,27 @@ +package leetcode.week01; + +/** + * @author Abner.S + * @date 2020/2/16 14:47 + * @description No.26 remove-duplicates-from-sorted-array + * 删除排序数组中的重复项 + */ +public class LeetCode_26_429 { + + // 思路1:暴力解法 双重循环,发现不妥,可能需要额外的空间 + // 思路2:双指针,快慢指针 + public int removeDuplicates(int[] nums) { + if (nums.length < 2) { + return nums.length; + } + int temp = 0; + for (int i = 1; i < nums.length; i++) { + if (nums[i] != nums[temp]) { + temp++; + nums[temp] = nums[i]; + } + } + return temp + 1; + } + +} diff --git a/Week_01/G20200343030429/LeetCode_2_429.java b/Week_01/G20200343030429/LeetCode_2_429.java new file mode 100644 index 00000000..c1344da9 --- /dev/null +++ b/Week_01/G20200343030429/LeetCode_2_429.java @@ -0,0 +1,67 @@ +package leetcode.week01; + +/** + * @author Abner.S + * @date 2020/2/16 16:17 + * @description No. 189 rotate-array + * 旋转数组 + */ +public class LeetCode_189_429 { + + /** + * 思路1:每次将数组依次移动一位,循环 k 次 + * @param nums + * @param k + */ + public void rotate1(int[] nums, int k) { + int temp; + int 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; + } + } + } + + /** + * 思路2:反转,移动 k 次, k % length 对应的元素即成为首个元素, k = k % length + * 有可能存在 k > length 的情况 + * 1、将所有元素反转 + * 2、反转前 k 个元素,这 k 个元素恰好是从原数组末端要移动到数组前端的元素 + * 3、将 n - k 个元素反转,即原来的顺序 + * 4、得到结果 + * @param nums + * @param k + */ + public void rotate2(int[] nums, int k) { + // 得到旋转的具体位置 + k %= nums.length; + // 反转所有元素 + reverse(nums, 0, nums.length); + // 反转前 k 个元素 + reverse(nums, 0, k - 1); + // 反转剩下元素 + reverse(nums, k, nums.length - 1); + } + + /** + * 反转数组元素 + * @param nums 传入数组 + * @param start 反转起始位置 + * @param end 反转结束位置 + */ + private 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/G20200343030431/LeetCode_026_431.java b/Week_01/G20200343030431/LeetCode_026_431.java new file mode 100644 index 00000000..153b2ed7 --- /dev/null +++ b/Week_01/G20200343030431/LeetCode_026_431.java @@ -0,0 +1,21 @@ +package FistWork; +// 1 遍历数组,找到重复的元素--java中有现成的函数吧 +// 2 删除重复元素,返回新数组 +// 3 思路尝试不通,估使用(copy)的是leetcode上的解法 +public class Solution01 { + public int removeDuplicates(int[] nums) { + if (nums == null || nums.length == 1) { + return nums.length; + } + int i = 0, j = 1; + while (j < nums.length) { + if (nums[i] == nums[j]) { + j++; + } else { + i++; + nums[i] = nums[j]; + } + } + return i + 1; + } +} diff --git a/Week_01/G20200343030431/LeetCode_088_431.java b/Week_01/G20200343030431/LeetCode_088_431.java new file mode 100644 index 00000000..624c537f --- /dev/null +++ b/Week_01/G20200343030431/LeetCode_088_431.java @@ -0,0 +1,15 @@ +package FistWork; +// 自己思路: 分别遍历数组1 ,数组2 , 合并到一起组成数组3, 在遍历一次,排序,成数组4 +// 最终还是使用(copy代码)leetCode的代码 +public class Solution02 { + 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/G20200343030433/LeetCode_01_433.py b/Week_01/G20200343030433/LeetCode_01_433.py new file mode 100644 index 00000000..fe93c17f --- /dev/null +++ b/Week_01/G20200343030433/LeetCode_01_433.py @@ -0,0 +1,17 @@ +# +# @lc app=leetcode.cn id=1 lang=python3 +# +# [1] 两数之和 +# + +# @lc code=start +class Solution: + def twoSum(self, nums: List[int], target: int) -> List[int]: + dict = {} + for i in range(len(nums)): + if target-nums[i] not in dict: + dict[nums[i]] = i + else: + return [dict[target-nums[i]], i] +# @lc code=end + diff --git a/Week_01/G20200343030433/LeetCode_189_433.py b/Week_01/G20200343030433/LeetCode_189_433.py new file mode 100644 index 00000000..b6c6706b --- /dev/null +++ b/Week_01/G20200343030433/LeetCode_189_433.py @@ -0,0 +1,29 @@ +# +# @lc app=leetcode.cn id=189 lang=python3 +# +# [189] 旋转数组 +# + +# @lc code=start +class Solution: + def rotate(self, nums: List[int], k: int) -> None: + """ + Do not return anything, modify nums in-place instead. + """ + """ + Do not return anything, modify nums in-place instead. + """ + n = len(nums) + k = k % n + nums[:] = nums[n-k:] + nums[:n-k] + + """ + for i in range(len(nums)): + if i < k: + result.append(nums[len(nums)-k + i]) + + if i >= k: + result.append(nums[i-k]) + return result +# @lc code=end + diff --git a/Week_01/G20200343030433/LeetCode_26_433.py b/Week_01/G20200343030433/LeetCode_26_433.py new file mode 100644 index 00000000..9c3e6bbf --- /dev/null +++ b/Week_01/G20200343030433/LeetCode_26_433.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 + first_point = 0 + for sencond_point in range(1, len(nums)): + if nums[sencond_point] != nums[first_point]: + first_point += 1 + nums[first_point] = nums[sencond_point] + print(first_point) + return first_point + 1 +# @lc code=end + diff --git a/Week_01/G20200343030435/LeetCode_189_435.js b/Week_01/G20200343030435/LeetCode_189_435.js new file mode 100644 index 00000000..162cb429 --- /dev/null +++ b/Week_01/G20200343030435/LeetCode_189_435.js @@ -0,0 +1,17 @@ +let rotate = function(nums, k) { + const n = nums.length; + k %= n; + const reverse = (start, end) => { + while (start < end) { + const tmp = nums[start]; + nums[start] = nums[end]; + nums[end] = tmp; + start++; + end--; + } + }; + reverse(0, n - 1); + reverse(0, k - 1); + reverse(k, n - 1); + return nums; +}; diff --git a/Week_01/G20200343030435/LeetCode_1_435.js b/Week_01/G20200343030435/LeetCode_1_435.js new file mode 100644 index 00000000..0949413e --- /dev/null +++ b/Week_01/G20200343030435/LeetCode_1_435.js @@ -0,0 +1,10 @@ +let twoSum = function(nums, target) { + const items = []; + for (let i = 0; i < nums.length; i++) { + const diff = target - nums[i]; + if (items[diff] !== undefined) { + return [i, items[diff]]; + } + items[nums[i]] = i; + } +}; diff --git a/Week_01/G20200343030435/LeetCode_21_435.js b/Week_01/G20200343030435/LeetCode_21_435.js new file mode 100644 index 00000000..06df7243 --- /dev/null +++ b/Week_01/G20200343030435/LeetCode_21_435.js @@ -0,0 +1,16 @@ +const mergeTwoLists = function(l1, l2) { + const prevHead = new ListNode(-1); + let prevNode = prevHead; + while (l1 !== null && l2 !== null) { + if (l1.val < l2.val) { + prevNode.next = l1; + l1 = l1.next; + } else { + prevNode.next = l2; + l2 = l2.next; + } + prevNode = prevNode.next; + } + prevNode.next = l1 || l2; + return prevHead.next; +}; diff --git a/Week_01/G20200343030435/LeetCode_26_435.js b/Week_01/G20200343030435/LeetCode_26_435.js new file mode 100644 index 00000000..2374a3ea --- /dev/null +++ b/Week_01/G20200343030435/LeetCode_26_435.js @@ -0,0 +1,10 @@ +let removeDuplicates = function(nums) { + let j = 0; + for (let i = 0; i < nums.length; i++) { + if (nums[i] !== nums[i + 1]) { + nums[j] = nums[i]; + j++; + } + } + return j; +}; diff --git a/Week_01/G20200343030435/LeetCode_283_435.js b/Week_01/G20200343030435/LeetCode_283_435.js new file mode 100644 index 00000000..1967e14e --- /dev/null +++ b/Week_01/G20200343030435/LeetCode_283_435.js @@ -0,0 +1,11 @@ +const moveZeroes = function(nums) { + let idx = 0; + for (let i = 0; i < nums.length; i++) { + if (nums[i] !== 0) { + nums[idx] = nums[i]; + nums[i] = idx === i ? nums[i] : 0; + idx++; + } + } + return nums; +}; diff --git a/Week_01/G20200343030435/LeetCode_88_435.js b/Week_01/G20200343030435/LeetCode_88_435.js new file mode 100644 index 00000000..6fd252bf --- /dev/null +++ b/Week_01/G20200343030435/LeetCode_88_435.js @@ -0,0 +1,7 @@ +let count = m + n; +while (m > 0 && n > 0) { + nums1[--count] = nums1[m - 1] < nums2[n - 1] ? nums2[--n] : nums1[--m]; +} +if (n > 0) { + nums1.splice(0, n, ...nums2.splice(0, n)); +} diff --git a/Week_01/G20200343030437/NOTE.md b/Week_01/G20200343030437/NOTE.md index 50de3041..3cf131b9 100644 --- a/Week_01/G20200343030437/NOTE.md +++ b/Week_01/G20200343030437/NOTE.md @@ -1 +1,5 @@ -学习笔记 \ No newline at end of file +学习笔记 + +1、爬楼梯这里可以实际想像,跨出第一步时有f(n-1)种可能,跨出第二步时有f(n-2)种可能。 + +2、 diff --git a/Week_01/G20200343030437/climbing-stairs.java b/Week_01/G20200343030437/climbing-stairs.java new file mode 100644 index 00000000..2b2ad372 --- /dev/null +++ b/Week_01/G20200343030437/climbing-stairs.java @@ -0,0 +1,16 @@ +public int climbStairs(int n) { + //根据反证法得出 该题是求斐波那契函数 + //单纯用菲波那切函数会有n^2的时间复杂度,所以换用简单方法 + if (n == 0) return 0; + if (n == 1) return 1; + + int s0 = 1; + int s1 = 1; + int sum = 2; + for (int i = 2; i < n; i++) { + s0 = s1; + s1 = sum; + sum = s0 + s1; + } + return sum; + } diff --git a/Week_01/G20200343030437/container-with-most-water.java b/Week_01/G20200343030437/container-with-most-water.java new file mode 100644 index 00000000..8ef35a83 --- /dev/null +++ b/Week_01/G20200343030437/container-with-most-water.java @@ -0,0 +1,17 @@ +public int maxArea(int[] height) { + //常规双指针写法 + int length = height.length; + int maxarea = 0; + int l = 0; + int r = length-1; + + while(l != r){ + maxarea = Math.max(maxarea, (r - l) * Math.min(height[l], height[r])); + if (height[l] < height[r]){ + l ++; + }else { + r --; + } + } + return maxarea; + } diff --git a/Week_01/G20200343030437/design-circular-deque.java b/Week_01/G20200343030437/design-circular-deque.java new file mode 100644 index 00000000..7d1918b8 --- /dev/null +++ b/Week_01/G20200343030437/design-circular-deque.java @@ -0,0 +1,136 @@ +class MyCircularDeque { + + private int count = 0; + + private int sum = 0; + + private Node first; + + private Node last; + + /** + * 自定义链表 + */ + private static class Node { + int data; + Node prev; + Node next; + public Node (int data, Node prev, Node next) { + this.data = data; + this.prev = prev; + this.next = next; + } + } + + /** + * Initialize your data structure here. Set the size of the deque to be k. + */ + public MyCircularDeque(int k) { + this.sum = k; + } + + /** + * Adds an item at the front of Deque. Return true if the operation is successful. + */ + public boolean insertFront(int value) { + if (count >= sum) { + return false; + } + Node newNode = new Node(value, null, first); + + + if(first == null) last = newNode; //同步尾节点 + else first.prev = newNode; + + first = newNode; + count++; + return true; + } + + /** + * Adds an item at the rear of Deque. Return true if the operation is successful. + */ + public boolean insertLast(int value) { + if (count >= sum) return false; + + Node newNode = new Node(value, last, null); + if(last == null) first = newNode; //同步首节点 + else last.next = newNode; + + last = newNode; + count++; + return true; + } + + /** + * Deletes an item from the front of Deque. Return true if the operation is successful. + */ + public boolean deleteFront() { + if (first == null) return false; + + if (first.next == null) { + first = null; + last = null; + } else if (count == 2){ + first = first.next; + first.prev = null; + last = first; + } else { + first = first.next; + first.prev = null; + } + count--; + return true; + } + + /** + * Deletes an item from the rear of Deque. Return true if the operation is successful. + */ + public boolean deleteLast() { + if (last == null) return false; + + if(last.prev == null) { + first = null; + last = null; + } else if (count == 2) { + last = last.prev; + last.next = null; + first = last; + } else { + last = last.prev; + last.next = null; + } + count--; + return true; + } + + /** + * Get the front item from the deque. + */ + public int getFront() { + if (first == null) return -1; + return first.data; + } + + /** + * Get the last item from the deque. + */ + public int getRear() { + if (last == null) return -1; + return last.data; + } + + /** + * Checks whether the circular deque is empty or not. + */ + public boolean isEmpty() { + return first == null; + } + + /** + * Checks whether the circular deque is full or not. + */ + public boolean isFull() { + return count == sum; + } + } diff --git a/Week_01/G20200343030437/linked-list-cycle.java b/Week_01/G20200343030437/linked-list-cycle.java new file mode 100644 index 00000000..ad9fc7ec --- /dev/null +++ b/Week_01/G20200343030437/linked-list-cycle.java @@ -0,0 +1,13 @@ +public boolean hasCycle(ListNode head) { + ListNode slow = head; + if (head == null) return false; + ListNode fast = head.next; + while (fast != slow) { + if (fast == null || fast.next == null) { + return false; + } + slow = slow.next; + fast = fast.next.next; + } + return true; + } diff --git a/Week_01/G20200343030437/merge-two-sorted-lists.java b/Week_01/G20200343030437/merge-two-sorted-lists.java new file mode 100644 index 00000000..f5f5f1f0 --- /dev/null +++ b/Week_01/G20200343030437/merge-two-sorted-lists.java @@ -0,0 +1,33 @@ +public ListNode mergeTwoLists(ListNode l1, ListNode l2) { + //本题没有多大技巧,无非就是利用几个o(1)的变量进行相互转换 + if (l1 == null) return l2; + if (l2 == null) return l1; + ListNode merge; + if (l1.val < l2.val) { + merge = l1; + l1 = l1.next; + } else { + merge = l2; + l2 = l2.next; + } + ListNode index = merge; + while (l1 != null && l2 != null) { + ListNode max; + if (l1.val < l2.val) { + max = l1; + l1 = l1.next; + } else { + max = l2; + l2 = l2.next; + } + index.next = max; + index = max; + } + if (l1 != null) { + index.next = l1; + } + if (l2 != null) { + index.next = l2; + } + return merge; + } diff --git a/Week_01/G20200343030437/move-zero.java b/Week_01/G20200343030437/move-zero.java new file mode 100644 index 00000000..e8b41eb4 --- /dev/null +++ b/Week_01/G20200343030437/move-zero.java @@ -0,0 +1,34 @@ + public void moveZeroes(int[] array) { + int length = array.length; + int num = 0; // 代表0的个数 + //指针2 + int j = 0; + //循环数组 + for (int i = 0; j < length; i++) { //指针1 + //判断是否为0 + if (array[j] == 0) { + num++; + //如果为0,先判断下一个数是否为0, + for (j++; j < length; j++) { + if (array[j] != 0) { + // 下一个数超前移动 + array[i] = array[j]; + break; + } + num++; + + } + } + if (j < length) { + array[i] = array[j]; + } + j++; + } + //遍历完成后将num个0更新至数组末尾 + for (int k = 0; k < num; k++) { + array[length - 1 - k] = 0; + } + for (int t = 0; t < length; t++) { + System.out.println(array[t]); + } + } diff --git a/Week_01/G20200343030437/move-zeroes.java b/Week_01/G20200343030437/move-zeroes.java new file mode 100644 index 00000000..e8b41eb4 --- /dev/null +++ b/Week_01/G20200343030437/move-zeroes.java @@ -0,0 +1,34 @@ + public void moveZeroes(int[] array) { + int length = array.length; + int num = 0; // 代表0的个数 + //指针2 + int j = 0; + //循环数组 + for (int i = 0; j < length; i++) { //指针1 + //判断是否为0 + if (array[j] == 0) { + num++; + //如果为0,先判断下一个数是否为0, + for (j++; j < length; j++) { + if (array[j] != 0) { + // 下一个数超前移动 + array[i] = array[j]; + break; + } + num++; + + } + } + if (j < length) { + array[i] = array[j]; + } + j++; + } + //遍历完成后将num个0更新至数组末尾 + for (int k = 0; k < num; k++) { + array[length - 1 - k] = 0; + } + for (int t = 0; t < length; t++) { + System.out.println(array[t]); + } + } diff --git a/Week_01/G20200343030437/remove-duplicates-from-sort-array.java b/Week_01/G20200343030437/remove-duplicates-from-sort-array.java new file mode 100644 index 00000000..58ae25ad --- /dev/null +++ b/Week_01/G20200343030437/remove-duplicates-from-sort-array.java @@ -0,0 +1,23 @@ +public int removeDuplicates(int[] nums) { + if (nums.length == 0 || nums.length == 1) return nums.length; + int j = 1; + int i = 0; + int index = 0; + for (; i < j; i++) { + + while (nums[i] == nums[j]){ + index++; + if(j >= nums.length - 1){ + break; + } + j++; + } + nums[i+1] = nums[j]; + j++; + if(j >= nums.length){ + break; + } + } + return nums.length - index; + + } diff --git a/Week_01/G20200343030437/reverse-linked-list.java b/Week_01/G20200343030437/reverse-linked-list.java new file mode 100644 index 00000000..afea7d52 --- /dev/null +++ b/Week_01/G20200343030437/reverse-linked-list.java @@ -0,0 +1,16 @@ +public ListNode reverseList(ListNode head) { + ListNode newhead = head; + ListNode newhead2 = head; + Stack stack = new Stack<>(); + + while (newhead != null) { + stack.push(newhead.val); + newhead = newhead.next; + } + + while(newhead2 != null) { + newhead2.val = stack.pop(); + newhead2 = newhead2.next; + } + return head; + } diff --git a/Week_01/G20200343030437/rotate-array.java b/Week_01/G20200343030437/rotate-array.java new file mode 100644 index 00000000..ef273ed9 --- /dev/null +++ b/Week_01/G20200343030437/rotate-array.java @@ -0,0 +1,20 @@ + public void rotate(int[] nums, int k) { + int length = nums.length; + k = k % length; + + int current; + int count = 0; + for (int i = 0; count < length; i++) { + int pre = nums[i]; + current = i; + do { + int next = (current + k) % length; + int temp = nums[next]; + + nums[next] = pre; + pre = temp; + current = next; + count++; + } while (i != current); + } + } diff --git a/Week_01/G20200343030437/three-sum.java b/Week_01/G20200343030437/three-sum.java new file mode 100644 index 00000000..ad5a884b --- /dev/null +++ b/Week_01/G20200343030437/three-sum.java @@ -0,0 +1,29 @@ +public List> threeSum(int[] nums) { + List> ans = new ArrayList<>(); + int length = nums.length; + if (nums == null || length < 3) return ans; + Arrays.sort(nums); + if (nums[0] > 0) return ans; + + int newlen = length - 2; //减少计算次数 + for (int i = 0; i < newlen; i++) { + int l = i + 1; + int r = length-1; + if (i > 0 && nums[i] == nums[i-1]) continue; + while (l < r){ + int sum = nums[i] + nums[l] + nums[r]; + if (sum == 0){ + ans.add(Arrays.asList(nums[i], nums[l], nums[r])); + while (l < r && nums[l] == nums[l + 1]) l++; //去重 + while (l < r && nums[r] == nums[r - 1]) r--; + l++; + r--; + } else if (sum > 0) { + r--; + } else { + l++; + } + } + } + return ans; + } diff --git a/Week_01/G20200343030439/LeetCode_189_439.java b/Week_01/G20200343030439/LeetCode_189_439.java new file mode 100644 index 00000000..9132c804 --- /dev/null +++ b/Week_01/G20200343030439/LeetCode_189_439.java @@ -0,0 +1,78 @@ +/* + * @lc app=leetcode.cn id=189 lang=java + * + * [189] 旋转数组 + */ + +// @lc code=start +class Solution { + + public static void main(String[] args) { + int[] nums = { 0, 1, 2, 3, 4, 5 }; + rotate(nums, 2); + for (int i = 0; i < nums.length; i++) { + System.out.println(nums[i]); + } + } + + // 方法 1:暴力 + public static void rotate(int[] nums, int k) { + int temp; + int previouse; + + for (int i = 0; i < k; i++) { + previouse = nums[nums.length - 1]; + for (int j = 0; j < nums.length; j++) { + temp = nums[j]; + nums[j] = previouse; + previouse = temp; + } + } +} + +// 方法 2:使用额外的数组 +public static void rotate2(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 i = 0; i < nums.length; i++) { + nums[i] = newNums[i]; + } +} + +// 方法 3:使用环状替换 +public static void rotate3(int[] nums, int k) { + 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); + } +} +// 方法 4:使用反转 +public static void rotate4(int[] nums, int k) { + k %= nums.length; + 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--; + } +} +} +// @lc code=end diff --git a/Week_01/G20200343030439/LeetCode_1_439.java b/Week_01/G20200343030439/LeetCode_1_439.java new file mode 100644 index 00000000..031892c2 --- /dev/null +++ b/Week_01/G20200343030439/LeetCode_1_439.java @@ -0,0 +1,40 @@ +import java.util.HashMap; +import java.util.Map; + +/* + * @lc app=leetcode.cn id=1 lang=java + * + * [1] 两数之和 + */ + +// @lc code=start +class Solution { + // 暴力 + public static 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 }; + } + } + } + throw new IllegalArgumentException("无"); + +} + +// 哈希表 +public static int[] twoSum2(int[] nums, int target) { + Map map = new HashMap<>(); + for (int i = 0; i < nums.length; i++) { + int numB = target - nums[i]; + if (map.containsKey(numB)) { + return new int[] { map.get(numB), i }; + } + map.put(nums[i], i); + } + throw new IllegalArgumentException("无"); + +} +} +// @lc code=end + diff --git a/Week_01/G20200343030439/LeetCode_21_439.java b/Week_01/G20200343030439/LeetCode_21_439.java new file mode 100644 index 00000000..b3566d42 --- /dev/null +++ b/Week_01/G20200343030439/LeetCode_21_439.java @@ -0,0 +1,69 @@ +/* + * @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 static void main(String[] args) { + ListNode l1 = new ListNode(1); + ListNode l12 = new ListNode(2); + ListNode l13 = new ListNode(4); + l1.next = l12; + l12.next = l13; + + ListNode l2 = new ListNode(1); + ListNode l22 = new ListNode(3); + ListNode l23 = new ListNode(4); + l2.next = l22; + l22.next = l23; + + ListNode result = mergeTwoLists(l1, l2); + while (result != null) { + System.out.println(result.val); + result = result.next; + } + } + + // 方法 1:递归 + public static 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; + } + + } + + // 方法 2:迭代 + public static 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; + } +} +// @lc code=end diff --git a/Week_01/G20200343030439/LeetCode_26_439.java b/Week_01/G20200343030439/LeetCode_26_439.java new file mode 100644 index 00000000..e515793b --- /dev/null +++ b/Week_01/G20200343030439/LeetCode_26_439.java @@ -0,0 +1,46 @@ +/* + * @lc app=leetcode.cn id=26 lang=java + * + * [26] 删除排序数组中的重复项 + */ + +// @lc code=start +class Solution12 { + public static void main(String[] args) { + int[] nums = { 0, 0, 1, 1, 2, 2 }; + int result = removeDuplicates2(nums); + System.out.println(result); + for (int i = 0; i < result; i++) { + System.out.println(nums[i]); + } + } + + public static 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; + } + + public static int removeDuplicates2(int[] nums) { + if (nums.length == 0) + return 0; + int i = 0; + int j = 1; + while (j < nums.length) { + if (nums[i] != nums[j]) { + i++; + nums[i] = nums[j]; + } + j++; + } + return i + 1; + } +} +// @lc code=end diff --git a/Week_01/G20200343030439/LeetCode_283_439.java b/Week_01/G20200343030439/LeetCode_283_439.java new file mode 100644 index 00000000..d6bb70ac --- /dev/null +++ b/Week_01/G20200343030439/LeetCode_283_439.java @@ -0,0 +1,47 @@ +/* + * @lc app=leetcode.cn id=283 lang=java + * + * [283] 移动零 + */ + +// @lc code=start +class Solution { + + public static void moveZeroes(int[] nums) { + int zeroeCount = 0; + int[] tempNums = new int[nums.length]; + int tempIndex = 0; + for (int i = 0; i < nums.length; i++) { + if (nums[i] == 0) { + zeroeCount++; + } else { + tempNums[tempIndex] = nums[i]; + tempIndex++; + } + } + for (int i = 0; i < nums.length; i++) { + if (i < nums.length - zeroeCount) { + nums[i] = tempNums[i]; + } + else{ + nums[i]=0; + } + } + } + + // 快慢指针 + public static void moveZeroes2(int[] nums) { + int slow = 0; + for (int i = 0; i < nums.length; i++) { + if (nums[i] != 0) { + int temp = nums[slow]; + nums[slow] = nums[i]; + nums[i] = temp; + slow++; + + } + } + } +} +// @lc code=end + diff --git a/Week_01/G20200343030439/LeetCode_641_439.java b/Week_01/G20200343030439/LeetCode_641_439.java new file mode 100644 index 00000000..97311451 --- /dev/null +++ b/Week_01/G20200343030439/LeetCode_641_439.java @@ -0,0 +1,139 @@ +/* + * @lc app=leetcode.cn id=641 lang=java + * + * [641] 设计循环双端队列 + * + * https://leetcode-cn.com/problems/design-circular-deque/description/ + * + */ + +// @lc code=start +class MyCircularDeque { + + ListNode dequeFirst; + ListNode dequeLast; + int maxLength; + int currentLength; + + /** Initialize your data structure here. Set the size of the deque to be k. */ + public MyCircularDeque(int k) { + currentLength = 0; + maxLength = k; + dequeFirst = new ListNode(0); + dequeLast = new ListNode(0); + } + + /** + * Adds an item at the front of Deque. Return true if the operation is + * successful. + */ + public boolean insertFront(int value) { + if (currentLength == maxLength) { + return false; + } + ListNode node = new ListNode(value); + if (isEmpty()) { + dequeFirst.next = node; + node.previous =dequeFirst; + node.next = dequeLast; + dequeLast.previous = node; + } else { + node.next = dequeFirst.next; + node.previous = dequeFirst; + node.next.previous = node; + dequeFirst.next=node; + } + currentLength++; + return true; + } + + /** + * Adds an item at the rear of Deque. Return true if the operation is + * successful. + */ + public boolean insertLast(int value) { + if (currentLength == maxLength) { + return false; + } + ListNode node = new ListNode(value); + if (isEmpty()) { + dequeLast.previous = node; + node.previous =dequeFirst; + node.next = dequeLast; + dequeFirst.next = node; + } else { + node.previous = dequeLast.previous; + node.next = dequeLast; + node.previous.next = node; + dequeLast.previous = node; + } + currentLength++; + return true; + } + + /** + * Deletes an item from the front of Deque. Return true if the operation is + * successful. + */ + public boolean deleteFront() { + if (currentLength == 0) { + return false; + } + if (!isEmpty()) { + dequeFirst.next = dequeFirst.next.next; + dequeFirst.next.previous = null; + dequeFirst.next.previous = dequeFirst; + currentLength--; + return true; + } + return false; + } + + /** + * Deletes an item from the rear of Deque. Return true if the operation is + * successful. + */ + public boolean deleteLast() { + if (currentLength == 0) { + return false; + } + if (!isEmpty()) { + dequeLast.previous = dequeLast.previous.previous; + dequeLast.previous.next = null; + dequeLast.previous.next = dequeLast; + currentLength--; + return true; + } + return false; + } + + /** Get the front item from the deque. */ + public int getFront() { + return isEmpty() ? -1 : dequeFirst.next.val; + } + + /** Get the last item from the deque. */ + public int getRear() { + return isEmpty() ? -1 : dequeLast.previous.val; + } + + /** Checks whether the circular deque is empty or not. */ + public boolean isEmpty() { + return currentLength == 0; + } + + /** Checks whether the circular deque is full or not. */ + public boolean isFull() { + return maxLength == currentLength; + } +} + +/** + * 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/G20200343030439/LeetCode_66_439.java b/Week_01/G20200343030439/LeetCode_66_439.java new file mode 100644 index 00000000..bda08c37 --- /dev/null +++ b/Week_01/G20200343030439/LeetCode_66_439.java @@ -0,0 +1,22 @@ +/* + * @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] + 1) % 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/G20200343030439/LeetCode_88_439.java b/Week_01/G20200343030439/LeetCode_88_439.java new file mode 100644 index 00000000..d54e413c --- /dev/null +++ b/Week_01/G20200343030439/LeetCode_88_439.java @@ -0,0 +1,54 @@ +import java.util.Arrays; + +/* + * @lc app=leetcode.cn id=88 lang=java + * + * [88] 合并两个有序数组 + */ + +// @lc code=start +class Solution { + // 使用类库方法 + public static void merge(int[] nums1, int m, int[] nums2, int n) { + System.arraycopy(nums2, 0, nums1, m, n); + Arrays.sort(nums1); +} + +// 双指针 / 从前往后 +public static void merge2(int[] nums1, int m, int[] nums2, int n) { + int[] nums1_copy = new int[m]; + System.arraycopy(nums1, 0, nums1_copy, 0, m); + int p1 = 0; + int p2 = 0; + + int p = 0; + + while (p1 < m && p2 < n) { + nums1[p++] = nums1_copy[p1] < nums2[p2] ? nums1_copy[p1++] : nums2[p2++]; + } + + if (p1 < m) { + System.arraycopy(nums1_copy, p1, nums1, p, m - p1); + } else if (p2 < n) { + System.arraycopy(nums2, p2, nums1, p, n - p2); + } +} + +// 方法三 : 双指针 / 从后往前 +public static void merge3(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) { + nums1[p--] = nums1[p1] > nums2[p2] ? nums1[p1--] : nums2[p2--]; + } + if (p2 >= 0){ + for (int i = 0; i <= p2; i++){ + nums1[i] = nums2[i]; + } + } +} +} +// @lc code=end + diff --git a/Week_01/G20200343030439/ListNode.java b/Week_01/G20200343030439/ListNode.java new file mode 100644 index 00000000..f84b6bd0 --- /dev/null +++ b/Week_01/G20200343030439/ListNode.java @@ -0,0 +1,9 @@ +public class ListNode { + int val; + ListNode previous; + ListNode next; + + ListNode(int x) { + val = x; + } +} \ No newline at end of file diff --git a/Week_01/G20200343030441/LeetCode_01_441.java b/Week_01/G20200343030441/LeetCode_01_441.java new file mode 100644 index 00000000..66c35e8a --- /dev/null +++ b/Week_01/G20200343030441/LeetCode_01_441.java @@ -0,0 +1,25 @@ +/* + * @lc app=leetcode.cn id=1 lang=java + * + * [1] 两数之和 + */ + +// @lc code=start +class Solution { + public int[] twoSum(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; + } +} +// @lc code=end + diff --git a/Week_01/G20200343030441/LeetCode_189_441.java b/Week_01/G20200343030441/LeetCode_189_441.java new file mode 100644 index 00000000..c7d92d09 --- /dev/null +++ b/Week_01/G20200343030441/LeetCode_189_441.java @@ -0,0 +1,39 @@ +/* + * @lc app=leetcode.cn id=189 lang=java + * + * [189] 旋转数组 + */ + +// @lc code=start +class Solution { + public void rotate(int[] nums, int k) { + // 暴力法,直接移动,复杂度为O(kn) + // int last_element = nums[nums.length-1]; + + // for (int i = 0; i < k; ++i){ + // for (int j = nums.length-1; j > 0; --j){ + // nums[j] = nums[j-1]; + // } + // nums[0] = last_element; + // last_element = nums[nums.length-1]; + // } + + // 反转方法 + k %= nums.length; + swap_array(nums, 0, nums.length-1); + swap_array(nums, 0, k-1); + swap_array(nums, k, nums.length-1); + } + + private void swap_array(int[] nums, int start, int end) { + while (start < end) { + int temp = nums[start]; + nums[start] = nums[end]; + nums[end] = temp; + start++; + end--; + } + } +} +// @lc code=end + diff --git a/Week_01/G20200343030441/LeetCode_21_441.java b/Week_01/G20200343030441/LeetCode_21_441.java new file mode 100644 index 00000000..b82d8679 --- /dev/null +++ b/Week_01/G20200343030441/LeetCode_21_441.java @@ -0,0 +1,53 @@ +/* + * @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 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; + } + + while (l1 != null){ + prev.next = l1; + l1 = l1.next; + prev = prev.next; + } + + while (l2 != null){ + prev.next = l2; + l2 = l2.next; + prev = prev.next; + } + + // 简洁写法 + // prev.next = l1 == null ? l2 : l1; + + return prehead.next; + } +} +// @lc code=end + diff --git a/Week_01/G20200343030441/LeetCode_26_441.java b/Week_01/G20200343030441/LeetCode_26_441.java new file mode 100644 index 00000000..4fb7f80b --- /dev/null +++ b/Week_01/G20200343030441/LeetCode_26_441.java @@ -0,0 +1,28 @@ +/* + * @lc app=leetcode.cn id=26 lang=java + * + * [26] 删除排序数组中的重复项 + */ + +// @lc code=start +class Solution { + public int removeDuplicates(int[] nums) { + + if (nums.length == 0) return 0; + + int current_num = nums[0]; + int current_index = 1; + + for (int i = 0; i < nums.length; ++i){ + if (nums[i] != current_num){ + current_num = nums[i]; + nums[current_index] = nums[i]; + current_index++; + } + } + + return current_index; + } +} +// @lc code=end + diff --git a/Week_01/G20200343030441/LeetCode_283_441.java b/Week_01/G20200343030441/LeetCode_283_441.java new file mode 100644 index 00000000..00f3e4ba --- /dev/null +++ b/Week_01/G20200343030441/LeetCode_283_441.java @@ -0,0 +1,70 @@ +/* + * @lc app=leetcode.cn id=283 lang=java + * + * [283] 移动零 + */ + +// @lc code=start +class Solution { + public void moveZeroes(int[] nums) { + // 方案一 + // int len_nums = nums.length; + + // for (int i = 0; i < len_nums; i++){ + // if (nums[i] == 0){ + // for (int j = i; j < len_nums; j++){ + // if (j == len_nums-1){ + // break; + // } + // if(nums[j+1] != 0){ + // nums[i] = nums[j+1]; + // nums[j+1] = 0; + // break; + // } + // } + // } + // } + //============================================= + + // 方案二 28% + // int len_nums = nums.length; + // int count_zeros = 0; + // for (int i = 0; i < len_nums; i++){ + // if (nums[i] == 0){ + // count_zeros++; + // } + // } + + // int count_nums = 0; + // for (int j = 0; j < len_nums; j++){ + // if (nums[j] != 0){ + // nums[count_nums] = nums[j]; + // count_nums++; + // } + // } + + // for (int q = len_nums-count_zeros; q < len_nums; q++){ + // nums[q] = 0; + // } + //=============================================== + + // 方案三,双指针,和方案二其实差不多 + if(nums==null) { + return; + } + //第一次遍历的时候,j指针记录非0的个数,只要是非0的统统都赋给nums[j] + int j = 0; + for(int i=0;i s = new Stack(); + // int i = 0, maxWater = 0, maxBotWater = 0; + // while (i < height.length){ + // if (s.isEmpty() || height[i] <= height[s.peek()]){ + // s.push(i++); + // } + // else { + // int bot = s.pop(); + // maxBotWater = s.isEmpty()? + // 0:(Math.min(height[s.peek()],height[i])-height[bot])*(i-s.peek()-1); + // maxWater += maxBotWater; + // } + // } + // return maxWater; + } +} +// @lc code=end + diff --git a/Week_01/G20200343030441/LeetCode_641_441.java b/Week_01/G20200343030441/LeetCode_641_441.java new file mode 100644 index 00000000..df16126e --- /dev/null +++ b/Week_01/G20200343030441/LeetCode_641_441.java @@ -0,0 +1,106 @@ +/* + * @lc app=leetcode.cn id=641 lang=java + * + * [641] 设计循环双端队列 + */ + +// @lc code=start +class MyCircularDeque { + + private int capacity; + private int[] arr; + private int front; + private int rear; + + /** Initialize your data structure here. Set the size of the deque to be k. */ + public MyCircularDeque(int k) { + // front == rear判断队列为空; + // (rear + 1) % capacity == front判断队列为满; + capacity = k + 1; + arr = new int[capacity]; + front = 0; + rear = 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; + } + front = (front - 1 + capacity) % capacity; + arr[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()) { + return false; + } + arr[rear] = value; + rear = (rear + 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; + } + // front 被设计在数组的开头,所以是 +1 + front = (front + 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; + } + // rear 被设计在数组的末尾,所以是 -1 + rear = (rear - 1 + capacity) % capacity; + return true; + } + + /** Get the front item from the deque. */ + public int getFront() { + if (isEmpty()) { + return -1; + } + return arr[front]; + } + + /** Get the last item from the deque. */ + public int getRear() { + if (isEmpty()) { + return -1; + } + // 当 rear 为 0 时防止数组越界 + return arr[(rear - 1 + capacity) % capacity]; + } + + /** 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 (rear + 1) % capacity == front; + } +} + +/** + * 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/G20200343030441/LeetCode_66_441.java b/Week_01/G20200343030441/LeetCode_66_441.java new file mode 100644 index 00000000..5cef3a45 --- /dev/null +++ b/Week_01/G20200343030441/LeetCode_66_441.java @@ -0,0 +1,27 @@ +/* + * @lc app=leetcode.cn id=66 lang=java + * + * [66] 加一 + */ + +// @lc code=start +class Solution { + public int[] plusOne(int[] digits) { + int n = digits.length; + for(int i = n-1; i >= 0; i--) { + if(digits[i] < 9) { + digits[i]++; + return digits; + } + + digits[i] = 0; + } + + int[] newNumber = new int [n+1]; + newNumber[0] = 1; + + return newNumber; + } +} +// @lc code=end + diff --git a/Week_01/G20200343030441/LeetCode_88_441.java b/Week_01/G20200343030441/LeetCode_88_441.java new file mode 100644 index 00000000..9cf8c7c3 --- /dev/null +++ b/Week_01/G20200343030441/LeetCode_88_441.java @@ -0,0 +1,67 @@ +/* + * @lc app=leetcode.cn id=88 lang=java + * + * [88] 合并两个有序数组 + */ + +// @lc code=start +class Solution { + public void merge(int[] nums1, int m, int[] nums2, int n) { + // 方案一,先把nums2中元素放在nums1的后端,再快速排序 + + // 方案二,比较后把大的交换至nums2中,最后再合并 + // for (int i = 0; i < m; ++i){ + // for (int j = 0; j < n; ++j){ + // if (nums1[i] > nums2[j]){ + // int temp = nums1[i]; + // nums1[i] = nums2[j]; + // nums2[j] = temp; + + // // 调整nums2[j]的位置 + // for (int p = j; p < n-1; ++p){ + // if (nums2[p] > nums2[p+1]){ + // int temp2 = nums2[p]; + // nums2[p] = nums2[p+1]; + // nums2[p+1] = temp2; + // }else{ + // break; + // } + // } + + // break; + // } + // } + // } + + // for (int i = 0; i < n; ++i){ + // nums1[m+i] = nums2[i]; + // } + + // 方案三,双指针,拷贝数组 + // Make a copy of nums1. + int [] nums1_copy = new int[m]; + System.arraycopy(nums1, 0, nums1_copy, 0, m); + + // Two get pointers for nums1_copy and nums2. + int p1 = 0; + int p2 = 0; + + // Set pointer for nums1 + int p = 0; + + // Compare elements from nums1_copy and nums2 + // and add the smallest one into nums1. + while ((p1 < m) && (p2 < n)) + nums1[p++] = (nums1_copy[p1] < nums2[p2]) ? nums1_copy[p1++] : nums2[p2++]; + + // if there are still elements to add + 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); + } + + +} +// @lc code=end + diff --git "a/Week_01/G20200343030441/Queue \345\222\214 Priority Queue\346\272\220\347\240\201\345\210\206\346\236\220" "b/Week_01/G20200343030441/Queue \345\222\214 Priority Queue\346\272\220\347\240\201\345\210\206\346\236\220" new file mode 100644 index 00000000..066aaba1 --- /dev/null +++ "b/Week_01/G20200343030441/Queue \345\222\214 Priority Queue\346\272\220\347\240\201\345\210\206\346\236\220" @@ -0,0 +1,9 @@ +Queue源码分析 +1. Queue接口与List、Set同一级别,都是继承了Collection接口,LinkedList实现了Deque接口 +2. 方法有add, remove, element为throw exception方法;offer, poll, peek为return special value方法 +3. 实现类有双端队列Deque,阻塞队列BlockingQueue,非阻塞队列AbstractQueue;PriorityQueue为AbstractQueue的子类 + +Priority Queue源码分析 +1. 方法有add(E e)插入, clear()清空,contains(Object o)检查是否包含,offer(E e)也是插入,peek()读取元素,poll()获取元素,remove(Object o)删除元素 +2. boolean add(E e) 和boolean offer(E e)区别: +实际上add方法的内部调用的还是offer方法,所以我们主要看看offer是如何实现添加一个元素到堆结构中并维持这种结构不被破坏的。首先该方法定义了一 变量获取queue中实际存放的元素个数,紧接着一个if判断,如果该数组已经被完全使用了(没有可用空间了),会调用grow方法进行扩容,grow方法会根据具体情况判断,如果原数组较大则会扩大两倍+2,否则增加50%容量。 diff --git "a/Week_01/G20200343030441/\346\224\271\345\206\231deque.java" "b/Week_01/G20200343030441/\346\224\271\345\206\231deque.java" new file mode 100644 index 00000000..4c86ad2d --- /dev/null +++ "b/Week_01/G20200343030441/\346\224\271\345\206\231deque.java" @@ -0,0 +1,24 @@ +import java.util.Deque; +import java.util.LinkedList; + +public class DoubleQueue { + 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.pop()); + } + + System.out.println(deque); + + + } +} \ No newline at end of file diff --git a/Week_01/G20200343030443/NOTE.md b/Week_01/G20200343030443/NOTE.md index 50de3041..73eaa214 100644 --- a/Week_01/G20200343030443/NOTE.md +++ b/Week_01/G20200343030443/NOTE.md @@ -1 +1,31 @@ -学习笔记 \ No newline at end of file +问题1:重写DequeDemo + +import java.util.Deque; +import java.util.LinkedList; +public class DequeDemo { + public static void main(String[] args) { + Deque deque = new LinkedList(); + deque.offerFirst("a"); + deque.offerFirst("b"); + deque.offerFirst("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); + } +} + +问题2:分析queue源码: + 接口Queue继承于Collection接口,除Collection中声明方法外,增加声明了六个针对队列的基本操作,根据功能性分为三组:新增元素add()/offer()、出队元素remove()/poll()、复制队首元素element()/peek(),其中 add()/remove()/element()会在操作失败时抛出相应异常。 + PriorityQueue为类,实现了基本的Queue操作,还支持在添加或删除元素时根据权值来排序,对自定义类可通过传入构造器来进行权值判定。 + 1. 在添加元素时,其内部调用链为:add->offer->siftUp->siftUpUsingComparator(提供构造器)/siftUpComparable(元素自然顺序) + 2. 在删除元素时,其内部调用链为:poll->siftDownComparable(元素自然顺序)/siftDownUsingComparator(提供构造器) + 另外,在源码中,队列是以Object[] 数组来存储,以二叉树实现排序存储.在sift* 中均设定了排序及调整策略。 + PriorityQueue类支持动态扩容(grow函数),当当前容量为64以内时,每次扩容为2倍+2,大于等于64时,每次扩为1.5倍。内部设定元素最大值为2^31-8。如果扩容后大于最大值,则会判断当前所需数组大小是否大于最大值,如大于最大值,则返回2^31作为扩容后大小。 + +课后总结:第一周主要为线性结构,理解上难点不多,但是做题时经常第一想法要复杂很多,需要经过详细验算才能得出一个较为复杂的方案,还需要根据老师提供的思想进行多练习。从分析源码的过程中,对JAVA源代码的写作风格也有所学习,对自顶向下的编程思想有了更多的感悟,后续在遇到复杂编程时还需要多加练习。 + diff --git a/Week_01/G20200343030443/move-zeroes-code-443.java b/Week_01/G20200343030443/move-zeroes-code-443.java new file mode 100644 index 00000000..32f104a8 --- /dev/null +++ b/Week_01/G20200343030443/move-zeroes-code-443.java @@ -0,0 +1,15 @@ +class Solution { + public void moveZeroes(int[] nums) { + int i, j;// i:全递增,j:非零递增 + for (i = 0, j = 0; i < nums.length; i++) { + if (nums[i] != 0) { + nums[j] = nums[i]; + j++; + } + } + // i结束遍历后,从j开始后面全部赋值0 + for (; j < nums.length; j++) { + nums[j] = 0; + } + } +} diff --git a/Week_01/G20200343030443/plus-one-code-442.java b/Week_01/G20200343030443/plus-one-code-442.java new file mode 100644 index 00000000..83af56f7 --- /dev/null +++ b/Week_01/G20200343030443/plus-one-code-442.java @@ -0,0 +1,17 @@ +class Solution { + public int[] plusOne(int[] digits) { + if (digits[0] == 0) + return new int[] { 1 }; + if (++digits[digits.length - 1] < 10) + return digits; + for (int i = digits.length - 1; i >= 1 && digits[i] >= 10; i--) { + digits[i] -= 10; + digits[i - 1]++; + } + if (digits[0] < 10) + return digits; + int[] result = new int[digits.length + 1]; + result[0] = 1; + return result; + } +} diff --git a/Week_01/G20200343030445/LeetCode_189_445.py b/Week_01/G20200343030445/LeetCode_189_445.py new file mode 100644 index 00000000..64bf4a30 --- /dev/null +++ b/Week_01/G20200343030445/LeetCode_189_445.py @@ -0,0 +1,20 @@ +# +# @lc app=leetcode.cn id=189 lang=python3 +# +# [189] 旋转数组 +# + +# @lc code=start +class Solution: + def rotate(self, nums: List[int], k: int) -> None: + """ + Do not return anything, modify nums in-place instead. + """ + k %= len(nums) + nums.reverse() + nums[0:k] = nums[0:k][::-1] + nums[k:] = nums[k:][::-1] + + +# @lc code=end + diff --git a/Week_01/G20200343030445/LeetCode_1_445.py b/Week_01/G20200343030445/LeetCode_1_445.py new file mode 100644 index 00000000..47ea7ea2 --- /dev/null +++ b/Week_01/G20200343030445/LeetCode_1_445.py @@ -0,0 +1,18 @@ +# +# @lc app=leetcode.cn id=1 lang=python3 +# +# [1] 两数之和 +# + +# @lc code=start +class Solution: + def twoSum(self, nums: List[int], target: int) -> List[int]: + d = {} + for i in range(len(nums)): + if nums[i] in d: + return [d[nums[i]], i] + else: + d[target - nums[i]] = i + +# @lc code=end + diff --git a/Week_01/G20200343030445/LeetCode_26_445.py b/Week_01/G20200343030445/LeetCode_26_445.py new file mode 100644 index 00000000..3b55c98f --- /dev/null +++ b/Week_01/G20200343030445/LeetCode_26_445.py @@ -0,0 +1,29 @@ +# +# @lc app=leetcode.cn id=26 lang=python3 +# +# [26] 删除排序数组中的重复项 +# + +# @lc code=start +class Solution: + def removeDuplicates(self, nums: List[int]) -> int: + ptr = 0 + ptr2 = 0 + count = 0 + while ptr < len(nums): + curr = nums[ptr] + count += 1 + ptr2 += 1 + + while ptr2 < len(nums) and nums[ptr2] == curr: + ptr2 += 1 + + ptr += 1 + if ptr >= len(nums) or ptr2 >= len(nums): + break + + nums[ptr] = nums[ptr2] + + return count +# @lc code=end + diff --git a/Week_01/G20200343030445/LeetCode_283_445.py b/Week_01/G20200343030445/LeetCode_283_445.py new file mode 100644 index 00000000..3e7d19a2 --- /dev/null +++ b/Week_01/G20200343030445/LeetCode_283_445.py @@ -0,0 +1,41 @@ +# +# @lc app=leetcode.cn id=283 lang=python3 +# +# [283] 移动零 +# + +# @lc code=start +class Solution: + def moveZeroes(self, nums: List[int]) -> None: + """ + Do not return anything, modify nums in-place instead. + """ + + n = len(nums) + if (n <= 1): + return nums + + # # bubble sort version + # for i in range(n): + # # 提前退出冒泡循环的标志位 + # flag = False + # for j in range(n-i-1): + # if (nums[j] == 0 and nums[j+1] != 0): + # nums[j], nums[j+1] = nums[j+1], nums[j] + # flag = True + # if not flag: + # break + + # insertion sort version + for i in range(1, n): + value = nums[i] + j = i - 1 + while j >= 0 and nums[j] == 0 and value != 0: + nums[j+1] = nums[j] + j -= 1 + nums[j+1] = value + + return nums + +# @lc code=end + diff --git a/Week_01/G20200343030445/LeetCode_42_445.py b/Week_01/G20200343030445/LeetCode_42_445.py new file mode 100644 index 00000000..de6a3cea --- /dev/null +++ b/Week_01/G20200343030445/LeetCode_42_445.py @@ -0,0 +1,27 @@ +# +# @lc app=leetcode.cn id=42 lang=python3 +# +# [42] 接雨水 +# + +# @lc code=start +class Solution: + def trap(self, height: List[int]) -> int: + output = 0 + stack = [] + ptr = 0 + while ptr < len(height): + while len(stack) > 0 and height[ptr] > height[stack[-1]]: + tmp = height[stack[-1]] + stack.pop() + if len(stack)==0: + break + distance = ptr - stack[-1] - 1 + output += distance * (min(height[stack[-1]], height[ptr]) - tmp) + stack.append(ptr) + ptr += 1 + return output + + +# @lc code=end + diff --git a/Week_01/G20200343030445/LeetCode_641_445.py b/Week_01/G20200343030445/LeetCode_641_445.py new file mode 100644 index 00000000..6e1fc348 --- /dev/null +++ b/Week_01/G20200343030445/LeetCode_641_445.py @@ -0,0 +1,104 @@ +# +# @lc app=leetcode.cn id=641 lang=python3 +# +# [641] 设计循环双端队列 +# + +# @lc code=start +from collections import deque +class MyCircularDeque: + + def __init__(self, k: int): + """ + Initialize your data structure here. Set the size of the deque to be k. + """ + self.size = k + self.q = deque() + + + + def insertFront(self, value: int) -> bool: + """ + Adds an item at the front of Deque. Return true if the operation is successful. + """ + if len(self.q) >= self.size: + return False + self.q.appendleft(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 len(self.q) >= self.size: + return False + 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 len(self.q) == 0: + return False + self.q.popleft() + return True + + + def deleteLast(self) -> bool: + """ + Deletes an item from the rear of Deque. Return true if the operation is successful. + """ + if len(self.q) == 0: + return False + self.q.pop() + return True + + + def getFront(self) -> int: + """ + Get the front item from the deque. + """ + if len(self.q) == 0: + return -1 + return self.q[0] + + + def getRear(self) -> int: + """ + Get the last item from the deque. + """ + if len(self.q) == 0: + return -1 + return 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.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() +# @lc code=end + diff --git a/Week_01/G20200343030449/LeetCode_189_449.cpp b/Week_01/G20200343030449/LeetCode_189_449.cpp new file mode 100644 index 00000000..435ea72f --- /dev/null +++ b/Week_01/G20200343030449/LeetCode_189_449.cpp @@ -0,0 +1,26 @@ +class Solution { +public: + void rotate(vector& nums, int k) { + if(nums.size()==0) return; + + auto move = k%nums.size(); + + reverse(nums, 0, nums.size()); + reverse(nums, 0, move); + reverse(nums, move, nums.size()); + } + + void reverse(vector& nums, int start, int end) { + auto i = start; + auto j = end-1; + + while (i twoSum(vector& nums, int target) { + unordered_map var2index; + + for (auto i = 0; i < nums.size(); i++) { + auto iter = var2index.find(target-nums[i]); + if (iter!=var2index.end()) { + return vector({iter->second, i}); + } + + var2index.insert(make_pair(nums[i],i)); + } + + return vector(0); + } +}; diff --git a/Week_01/G20200343030449/LeetCode_21_449.cpp b/Week_01/G20200343030449/LeetCode_21_449.cpp new file mode 100644 index 00000000..9381cf77 --- /dev/null +++ b/Week_01/G20200343030449/LeetCode_21_449.cpp @@ -0,0 +1,33 @@ +class Solution { +public: + ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) { + if (l1 == nullptr) return l2; + if (l2 == nullptr) return l1; + + ListNode* newHead = (l1->val < l2->val)?l1:l2; + ListNode* sub = (newHead==l1)?l2:l1; + ListNode* main = newHead; + ListNode* last = main; + + while (main!=nullptr && sub!=nullptr) { + if (main->val > sub->val) { + last->next = sub; + sub = sub->next; + last->next->next = main; + last = last->next; + } + else { + last = main; + main = main->next; + } + + } + + if (sub!=nullptr) { + last->next = sub; + } + + return newHead; + + } +}; diff --git a/Week_01/G20200343030449/LeetCode_26_449.cpp b/Week_01/G20200343030449/LeetCode_26_449.cpp new file mode 100644 index 00000000..0c904cad --- /dev/null +++ b/Week_01/G20200343030449/LeetCode_26_449.cpp @@ -0,0 +1,16 @@ +class Solution { +public: + int removeDuplicates(vector& nums) { + + if (nums.size()==0) return 0; + + auto i = 0; + for (auto j=0; j& nums) { + int zeroNums = 0; + for(auto i = 0; i& height) { + if (height.size()==0) { + return 0; + } + + auto maxWater = 0; + + auto maxLeft = height[0]; + int* maxRight = new int[height.size()+1](); + + // Init right highest. + for (int i=height.size()-1; i>=0; i--) { + maxRight[i] = max(maxRight[i+1],height[i]); + } + + for (int i=1; i < height.size()-1;i++) { + auto maxHeight = maxLeftheight[i]?(maxHeight-height[i]):(0); + + maxLeft = max(maxLeft, height[i]); + } + + return maxWater; + } +}; diff --git a/Week_01/G20200343030449/LeetCode_641_449.cpp b/Week_01/G20200343030449/LeetCode_641_449.cpp new file mode 100644 index 00000000..ff75987b --- /dev/null +++ b/Week_01/G20200343030449/LeetCode_641_449.cpp @@ -0,0 +1,148 @@ +class DoubleListNode { +public: + DoubleListNode() {val=0,next=nullptr,pre=nullptr;} + DoubleListNode(int _val):val(_val) {next=nullptr,pre=nullptr;} + ~DoubleListNode() {} + int val; + DoubleListNode* next; + DoubleListNode* pre; +}; + +class MyCircularDeque { +public: + /** Initialize your data structure here. Set the size of the deque to be k. */ + MyCircularDeque(int k) { + capacity = k; + size = 0; + head = new DoubleListNode(); + tail = new DoubleListNode(); + } + + /** 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++; + + DoubleListNode* oldFirst = head->next; + DoubleListNode* newNode = new DoubleListNode(value); + + if (oldFirst==nullptr) { + head->next = newNode; + newNode->pre = head; + newNode->next = tail; + tail->pre = newNode; + } + else { + head->next = newNode; + newNode->pre = head; + newNode->next = oldFirst; + oldFirst->pre = newNode; + } + + 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++; + + DoubleListNode* oldLast = tail->pre; + DoubleListNode* newNode = new DoubleListNode(value); + + if (oldLast==nullptr) { + head->next = newNode; + newNode->pre = head; + newNode->next = tail; + tail->pre = newNode; + } + else { + oldLast->next = newNode; + newNode->pre = oldLast; + newNode->next = tail; + tail->pre = newNode; + } + + 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--; + + DoubleListNode* node = head->next; + + head->next = node->next; + node->next->pre=head; + + delete node; + + 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--; + + DoubleListNode* node = tail->pre; + + node->pre->next = tail; + tail->pre = node->pre; + + delete node; + + return true; + } + + /** Get the front item from the deque. */ + int getFront() { + return size==0?-1:head->next->val; + } + + /** Get the last item from the deque. */ + int getRear() { + return size==0?-1:tail->pre->val; + } + + /** Checks whether the circular deque is empty or not. */ + bool isEmpty() { + return size==0?true:false; + } + + /** Checks whether the circular deque is full or not. */ + bool isFull() { + return size==capacity?true:false; + } +private: + unsigned int capacity; + unsigned int size; + DoubleListNode* head; + DoubleListNode* tail; +}; + +/** + * 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/G20200343030449/LeetCode_66_449.cpp b/Week_01/G20200343030449/LeetCode_66_449.cpp new file mode 100644 index 00000000..ab666b17 --- /dev/null +++ b/Week_01/G20200343030449/LeetCode_66_449.cpp @@ -0,0 +1,43 @@ +class Solution { +public: + vector plusOne(vector& digits) { + stack resultTemp; + vector result; + + if (digits.size()==0) { + digits.push_back(0); + } + + auto isIncrement = true; + + for (int i = digits.size()-1; i >= 0; i--) { + auto num = digits[i]; + + isIncrement?num++:num; + + if (num > 9) { + isIncrement = true; + num -= 10; + } + else { + isIncrement = false; + } + + resultTemp.push(num); + } + + if (isIncrement) { + resultTemp.push(1); + } + + while (!resultTemp.empty()) { + auto i = resultTemp.top(); + resultTemp.pop(); + result.push_back(i); + } + + return result; + } +}; + + diff --git a/Week_01/G20200343030449/LeetCode_88_449.cpp b/Week_01/G20200343030449/LeetCode_88_449.cpp new file mode 100644 index 00000000..5d527cd5 --- /dev/null +++ b/Week_01/G20200343030449/LeetCode_88_449.cpp @@ -0,0 +1,14 @@ +class Solution { +public: + void merge(vector& nums1, int m, vector& nums2, int n) { + auto i = m-1; + auto j = n-1; + auto k = m+n-1; + while (i>=0&&j>=0) nums1[k--]=nums1[i]>nums2[j]?nums1[i--]:nums2[j--]; + while (i>=0) nums1[k--]=nums1[i--]; + while (j>=0) nums1[k--]=nums2[j--]; + + return; + + } +}; diff --git a/Week_01/G20200343030449/NOTE.md b/Week_01/G20200343030449/NOTE.md index 50de3041..c3d7d35e 100644 --- a/Week_01/G20200343030449/NOTE.md +++ b/Week_01/G20200343030449/NOTE.md @@ -1 +1,30 @@ -学习笔记 \ No newline at end of file +学习笔记 + +066 加一: +因为数字的排列是从高位到低位,要处理的时候要从vector的最后开始处理,有点奇怪。 +所以一开始用了两个Stack来实现。 +第一步将数字压栈,这样得到的栈里的数字就是从低位到高位的,然后循环处理栈里的元素。 +第二步将处理好的数字压栈,这样得到的数字又是从高位到低位的,最后循环把栈里的元素push back到vector里。 + +时间复杂度o(n) 空间复杂度o(n),使用了两个额外的元素。 + +LeetCode的解答是在原数组上进行+1,当发现不需要再进行进位的时候直接返回,否则继续一直到最后如果没有返回说明还需要进一位。 +这时候有个技巧是在最后一位补0后在第一位补1。 + +在原vector基础上操作的问题是最后补1的时候需要移动整个数组,即使这样空间复杂度应该比我的也要更好一些。 +我上传了自己的实现方法,在下一次刷题的时候会使用like最多的方法。 + +641 设计循环双端队列: +我用了循环列表的方式实现的双端队列: +优点:插入,删除,查询第一个和最后一个的操作都可以在o(1)时间内完成。 +缺点:链表的代码比较复杂,需要经常申请与回收内存空间。需要额外的变量来存储当前使用的大小与最大容量。没有把最大容量的概念给用上去。 + +力扣推荐方法:动态数组。 +使用固定大小的数组,使用first和rear两个指针来控制元素的插入删除,当first+1=last的时候说明容量已经耗尽。 +优点:代码实现更简单,不需要额外的参数来保存已经使用的大小和容量。 +缺点:需要额外的1个数组元素来判断容量是否满。 + + +42 接雨水: +接雨水能想到的最简单的方法就是按列来处理,每次都找左边和右边最小的列,比较容易想到的方法就是用一个数组来保存最小高度的状态,比较容易理解的是当我们从左向右遍历的时候,我们可以在这个基础上更新左边的最小高度,而右边的最小高度依然需要一个数组来保存,虽然后续有将右边的最小高度以一个变量取代已经用栈的方式来实现,这两种方式还没有完全理解的情况下,第三种解法是目前自己掌握的最熟练的。 +后续五毒再刷这道题目的时候,会深入理解第四种解法和栈的方式实现的解法。 diff --git a/Week_01/G20200343030451/LeetCode_21_451.c b/Week_01/G20200343030451/LeetCode_21_451.c new file mode 100644 index 00000000..ce31de83 --- /dev/null +++ b/Week_01/G20200343030451/LeetCode_21_451.c @@ -0,0 +1,32 @@ +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * struct ListNode *next; + * }; + */ +//21 merge-two-sorted-lists, LeetCode_21_451.c + +struct ListNode* mergeTwoLists(struct ListNode* l1, struct ListNode* l2) { + if ( l1 == NULL ) return l2; + if ( l2 == NULL ) return l1; + + struct ListNode newlist; + struct ListNode* head = &newlist; + + while ( l1 && l2 ) { + if ( l1->val < l2->val ) { + head->next = l1; + l1 = l1->next; + } else { + head->next = l2; + l2 = l2->next; + } + head = head->next; + } + if ( l1 != NULL ) head->next = l1; + if ( l2 != NULL ) head->next = l2; + + head = newlist.next; + return head; +} \ No newline at end of file diff --git a/Week_01/G20200343030451/LeetCode_283_451.c b/Week_01/G20200343030451/LeetCode_283_451.c new file mode 100644 index 00000000..b90bde95 --- /dev/null +++ b/Week_01/G20200343030451/LeetCode_283_451.c @@ -0,0 +1,16 @@ +//283_move-zeroes.c +//代码文件命名规则:**LeetCode_题目序号_学号 Leetcode_283_451.c + +void moveZeroes(int* nums, int numsSize){ + int i = 0,j = 0; + for ( i = 0,j = 0; i < numsSize; i++ ) { + if ( *(nums+i) != 0 && i != j ) { + *(nums+j) = *(nums+i); + *(nums+i) = 0; + j++; + + } else if ( *(nums+i) != 0 && i == j) { + j++; + } + } +} \ No newline at end of file diff --git a/Week_01/G20200343030451/NOTE.md b/Week_01/G20200343030451/NOTE.md index 50de3041..a8081b68 100644 --- a/Week_01/G20200343030451/NOTE.md +++ b/Week_01/G20200343030451/NOTE.md @@ -1 +1,6 @@ -学习笔记 \ No newline at end of file +学习笔记 + +283 move_zeroes,对老师已经讲的题需要更快速度编写出来 +21 merge-two-sorted-lists,常用题写的更快一些 + + diff --git a/Week_01/G20200343030453/LeetCode_21_453 b/Week_01/G20200343030453/LeetCode_21_453 new file mode 100644 index 00000000..327c89b4 --- /dev/null +++ b/Week_01/G20200343030453/LeetCode_21_453 @@ -0,0 +1,71 @@ +/* + * @lc app=leetcode.cn id=21 lang=c + * + * [21] 合并两个有序链表 + */ + +// @lc code=start +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * struct ListNode *next; + * }; + */ + +// 解法一 迭代 +struct ListNode* mergeTwoLists(struct ListNode* l1, struct ListNode* l2){ + if(!l1 || !l2) { + return l1 == NULL ? l2 : l1; + } + struct ListNode *head = NULL; + if(l1 -> val < l2 -> val) { + head = l1; + l1 = l1 -> next; + } + else { + head = l2; + l2 = l2 -> next; + } + struct ListNode *p = head; + while(l1 || l2) { + if(!l1) { + p -> next = l2; + break; + } + else if(!l2) { + p -> next = l1; + break; + } + else if(l1 -> val < l2 -> val) { + p -> next = l1; + p = p -> next; + l1 = l1 -> next; + } + else { + p -> next = l2; + p = p -> next; + l2 = l2 -> next; + } + } + return head; +} + + +// 解法二 递归 +struct ListNode* mergeTwoLists(struct ListNode* l1, struct ListNode* l2){ + if(!l1) { + return l2; + } + else if(!l2) { + 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; + } +} \ No newline at end of file diff --git a/Week_01/G20200343030453/LeetCode_26_453 b/Week_01/G20200343030453/LeetCode_26_453 new file mode 100644 index 00000000..ad9d7262 --- /dev/null +++ b/Week_01/G20200343030453/LeetCode_26_453 @@ -0,0 +1,16 @@ +//[26] 删除排序数组中的重复项 +int removeDuplicates(int* nums, int numsSize){ + // 1. 暴力法 + // 2. 双指针 O(n) + if(numsSize < 2) { + return numsSize; + } + int i = 0; + int j = 0; + for(i = 1; i < numsSize; i++) { + if(nums[i] != nums[j]) { + nums[++j] = nums[i]; + } + } + return j + 1; +} \ No newline at end of file diff --git a/Week_01/G20200343030453/LeetCode_42_453 b/Week_01/G20200343030453/LeetCode_42_453 new file mode 100644 index 00000000..25d8d5f6 --- /dev/null +++ b/Week_01/G20200343030453/LeetCode_42_453 @@ -0,0 +1,22 @@ +// [42] 接雨水 + +int trap(int* height, int heightSize){ + + // 暴力法 + int i, j; + int size = 0; + for(i = 0; i < heightSize; i++) { + int leftmax = 0, rightmax = 0; + for(j = 0; j < i; j++) { + leftmax = leftmax < height[j] ? height[j] : leftmax; + } + for(j = i + 1; j < heightSize; j++) { + rightmax = rightmax < height[j] ? height[j] : rightmax; + } + int temp = leftmax < rightmax ? leftmax : rightmax; + if(temp > height[i]) { + size += temp - height[i]; + } + } + return size; +} \ No newline at end of file diff --git a/Week_01/G20200343030453/LeetCode_641_453 b/Week_01/G20200343030453/LeetCode_641_453 new file mode 100644 index 00000000..c7720274 --- /dev/null +++ b/Week_01/G20200343030453/LeetCode_641_453 @@ -0,0 +1,123 @@ +// [641] 设计循环双端队列 + +typedef struct { + int *data; + int capacity; + int head; + int tail; +} MyCircularDeque; + +/** Initialize your data structure here. Set the size of the deque to be k. */ + +bool myCircularDequeIsEmpty(MyCircularDeque* obj); +bool myCircularDequeIsFull(MyCircularDeque* obj); + +MyCircularDeque* myCircularDequeCreate(int k) { + MyCircularDeque *Dq = (MyCircularDeque *)calloc(1 , sizeof(MyCircularDeque)); + Dq -> data = (int *)calloc(k + 1, sizeof(int)); + Dq -> capacity = k + 1; + Dq -> head = Dq -> tail = 0; + return Dq; +} + +/** Adds an item at the front of Deque. Return true if the operation is successful. */ +bool myCircularDequeInsertFront(MyCircularDeque* obj, int value) { + if(!myCircularDequeIsFull(obj)) { + obj -> head = (obj -> head - 1 + obj -> capacity) % obj -> capacity; + obj -> data[obj -> head] = value; + return true; + } + return false; +} + +/** Adds an item at the rear of Deque. Return true if the operation is successful. */ +bool myCircularDequeInsertLast(MyCircularDeque* obj, int value) { + + if(!myCircularDequeIsFull(obj)) { + obj -> data[obj -> tail] = value; + obj -> tail = (obj -> tail + 1) % obj -> capacity; + return true; + } + return false; +} + +/** Deletes an item from the front of Deque. Return true if the operation is successful. */ +bool myCircularDequeDeleteFront(MyCircularDeque* obj) { + + if(!myCircularDequeIsEmpty(obj)) { + obj -> head = (obj -> head + 1) % obj -> capacity; // 问题 + return true; + } + return false; +} + +/** Deletes an item from the rear of Deque. Return true if the operation is successful. */ +bool myCircularDequeDeleteLast(MyCircularDeque* obj) { + + if(!myCircularDequeIsEmpty(obj)) { + obj -> tail = (obj -> tail - 1 + obj -> capacity) % obj -> capacity; + return true; + } + return false; +} + +/** Get the front item from the deque. */ +int myCircularDequeGetFront(MyCircularDeque* obj) { + if(myCircularDequeIsEmpty(obj)) { + return -1; + } + + return obj -> data[obj -> head]; +} + +/** Get the last item from the deque. */ +int myCircularDequeGetRear(MyCircularDeque* obj) { + + if(myCircularDequeIsEmpty(obj)) { + return -1; + } + return obj -> data[(obj -> tail - 1 + obj -> capacity) % obj -> capacity]; +} + +/** Checks whether the circular deque is empty or not. */ +bool myCircularDequeIsEmpty(MyCircularDeque* obj) { + + return obj -> head == obj -> tail ? true : false; +} + +/** Checks whether the circular deque is full or not. */ +bool myCircularDequeIsFull(MyCircularDeque* obj) { + + return (obj -> tail + 1) % obj -> capacity == obj -> head ? true : false; +} + +void myCircularDequeFree(MyCircularDeque* obj) { + if(obj != NULL) { + free(obj -> data); + obj -> data = NULL; + free(obj); + obj = NULL; + } +} + +/** + * Your MyCircularDeque struct will be instantiated and called as such: + * MyCircularDeque* obj = myCircularDequeCreate(k); + * bool param_1 = myCircularDequeInsertFront(obj, value); + + * bool param_2 = myCircularDequeInsertLast(obj, value); + + * bool param_3 = myCircularDequeDeleteFront(obj); + + * bool param_4 = myCircularDequeDeleteLast(obj); + + * int param_5 = myCircularDequeGetFront(obj); + + * int param_6 = myCircularDequeGetRear(obj); + + * bool param_7 = myCircularDequeIsEmpty(obj); + + * bool param_8 = myCircularDequeIsFull(obj); + + * myCircularDequeFree(obj); +*/ \ No newline at end of file diff --git a/Week_01/G20200343030453/NOTE.md b/Week_01/G20200343030453/NOTE.md index 50de3041..fdec6200 100644 --- a/Week_01/G20200343030453/NOTE.md +++ b/Week_01/G20200343030453/NOTE.md @@ -1 +1,35 @@ -学习笔记 \ No newline at end of file +学习笔记 + +学号:G20200343030453 姓名: 马辉明 + +日期: 2020.2.16 + +[21] 合并两个有序链表 题目总结 +(1)迭代法: +归并排序的思想,因为两个链表有序,只做一次排序即可,稍作改进,当其中一个有序表结束时,可以将 next 指向另一个链表的剩余节点,不需要遍历完之后作判断,这样节省了比较时间,时间复杂度 O(n + m) +(2)递归法:终止条件:当 l1 或 l2 为空时,返回剩余 l2 或 l1 结束; +返回值为每一层都已排好序的头指针; +递归内容:当 l1 的值 val 较小时,l1 的 next 指向之后排完序的链表头,否则,l2 的 next 指向排好序的链表头; +时间复杂度:O(n + m)空间复杂度也是一样,递归会消耗(n + m)个栈空间 + +[42] 接雨水 题目总结 +(1) 暴力法 遍历每一根柱子,找出该柱子左右两边最高的柱子取较小值,较小值与当前柱子差值为接雨水数 +此题有很多解法,后续抽空总结... + +[641] 设计循环双端队列 题目总结 https://blog.csdn.net/xiaoma_2018/article/details/103997820 +实现该循环队列,需要注意以下几点: + +1.判断队列为空? 当收尾指针相等,队列为空,head == tail +2.判断队列已满? 当尾指针的下一位等于头指针,队列已满,(tail + 1 + capacity) % capacity == head; +3.初始化队列时? 首尾指针从0开始, head = tail = 0 +4.从头部插入数据? head 指针向前移动, head = (head - 1 + capacity) % capacity +5.从尾部插入数据? tail 指针向后移动, tail = (tail + 1) % capacity +6.从头部删除数据? head 指针向后移动, head = (head + 1) % capacity +7.从尾部删除数据? tail 指针向前移动, tail = (tail - 1 + capacity) % capacity +8.从尾部读取数据? 考虑头部插入(head 前移一位)和尾部插入(插入后,tail后移一位),所以读取data[(tail - 1 + capacity) % capacity] + +[26] 删除排序数组中的重复项 题目总结 + +用双指针遍历 + + diff --git a/Week_01/G20200343030457/moveZeroes.php b/Week_01/G20200343030457/moveZeroes.php new file mode 100644 index 00000000..8e991182 --- /dev/null +++ b/Week_01/G20200343030457/moveZeroes.php @@ -0,0 +1,20 @@ + List[int]: +# if not nums: +# return [-1, -1] +# nums.sort() +# left = 0 +# right = len(nums) - 1 +# while left < right: +# if nums[left] + nums[right] == target: +# return [left, right] +# elif nums[left] + nums[right] > target: +# right -= 1 +# else: +# left += 1 +# return None +# @lc code=end + + +""" + 用字典记录的做法 +""" +class Solution: + def twoSum(self, nums: List[int], target: int) -> List[int]: + if not nums or len(nums) == 1: + return [-1, -1] + hash = {} + for index in range(len(nums)): + num = nums[index] + if num in hash: + return [hash[num], index] + hash[target - num] = index + return [-1, -1] diff --git "a/Week_01/G20200343030459/138.\345\244\215\345\210\266\345\270\246\351\232\217\346\234\272\346\214\207\351\222\210\347\232\204\351\223\276\350\241\250.py" "b/Week_01/G20200343030459/138.\345\244\215\345\210\266\345\270\246\351\232\217\346\234\272\346\214\207\351\222\210\347\232\204\351\223\276\350\241\250.py" new file mode 100644 index 00000000..b9b030a0 --- /dev/null +++ "b/Week_01/G20200343030459/138.\345\244\215\345\210\266\345\270\246\351\232\217\346\234\272\346\214\207\351\222\210\347\232\204\351\223\276\350\241\250.py" @@ -0,0 +1,136 @@ +# +# @lc app=leetcode.cn id=138 lang=python3 +# +# [138] 复制带随机指针的链表 +# +# https://leetcode-cn.com/problems/copy-list-with-random-pointer/description/ +# +# algorithms +# Medium (47.18%) +# Likes: 225 +# Dislikes: 0 +# Total Accepted: 23.7K +# Total Submissions: 50.1K +# Testcase Example: '[[7,null],[13,0],[11,4],[10,2],[1,0]]' +# +# 给定一个链表,每个节点包含一个额外增加的随机指针,该指针可以指向链表中的任何节点或空节点。 +# +# 要求返回这个链表的 深拷贝。  +# +# 我们用一个由 n 个节点组成的链表来表示输入/输出中的链表。每个节点用一个 [val, random_index] 表示: +# +# +# val:一个表示 Node.val 的整数。 +# random_index:随机指针指向的节点索引(范围从 0 到 n-1);如果不指向任何节点,则为  null 。 +# +# +# +# +# 示例 1: +# +# +# +# 输入:head = [[7,null],[13,0],[11,4],[10,2],[1,0]] +# 输出:[[7,null],[13,0],[11,4],[10,2],[1,0]] +# +# +# 示例 2: +# +# +# +# 输入:head = [[1,1],[2,1]] +# 输出:[[1,1],[2,1]] +# +# +# 示例 3: +# +# +# +# 输入:head = [[3,null],[3,0],[3,null]] +# 输出:[[3,null],[3,0],[3,null]] +# +# +# 示例 4: +# +# 输入:head = [] +# 输出:[] +# 解释:给定的链表为空(空指针),因此返回 null。 +# +# +# +# +# 提示: +# +# +# -10000 <= Node.val <= 10000 +# Node.random 为空(null)或指向链表中的节点。 +# 节点数目不超过 1000 。 +# +# +# + +# @lc code=start +""" +# Definition for a Node. +class Node: + def __init__(self, x: int, next: 'Node' = None, random: 'Node' = None): + self.val = int(x) + self.next = next + self.random = random +""" + +# 方法一: 用一个 hashmap +class Solution: + def copyRandomList(self, head: 'Node') -> 'Node': + if not head: + return None + mapping = self.get_mapping(head) + self.copy_nodes(head, mapping) + return mapping[head] + + def get_mapping(self, head): + mapping = {} + node = head + while node: + new_node = Node(node.val) + mapping[node] = new_node + node = node.next + return mapping + + def copy_nodes(self, head, mapping): + node = head + while node: + new_node = mapping[node] + new_next, new_random = None, None + if node.random: + new_random = mapping[node.random] + if node.next: + new_next = mapping[node.next] + new_node.next = new_next + new_node.random = new_random + node = node.next + +# 方法二: 改变链表结构 +class Solution: + def copyRandomList(self, head: 'Node') -> 'Node': + if not head: + return None + root = self.generate_new_head(head) + while root: + next_original = root.next.next + root.next.next = next_original.next if next_original else None + root.next.random = root.random.next if root.random else None + root = next_original + return head.next + + def generate_new_head(self, head): + node = head + while node: + new_node = Node(node.val) + new_node.next = node.next + node.next = new_node + node = new_node.next + return head + +# @lc code=end + diff --git a/Week_01/G20200343030459/189.rotate-array.py b/Week_01/G20200343030459/189.rotate-array.py new file mode 100644 index 00000000..bef39a7c --- /dev/null +++ b/Week_01/G20200343030459/189.rotate-array.py @@ -0,0 +1,66 @@ +# +# @lc app=leetcode id=189 lang=python3 +# +# [189] Rotate Array +# +# https://leetcode.com/problems/rotate-array/description/ +# +# algorithms +# Easy (32.95%) +# Likes: 2184 +# Dislikes: 749 +# Total Accepted: 414.3K +# Total Submissions: 1.3M +# 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? +# +# + +# @lc code=start +# 经典三步翻转法 +class Solution: + def rotate(self, nums: List[int], k: int) -> None: + """ + Do not return anything, modify nums in-place instead. + """ + k = k % len(nums) + self.reverse(nums, 0, len(nums) - 1) + self.reverse(nums, 0, k - 1) + self.reverse(nums, k, len(nums) - 1) + + def reverse(self, nums: List[int], start: int, end: int): + while start < end: + nums[start], nums[end] = nums[end], nums[start] + start, end = start + 1, end - 1 +# @lc code=end + diff --git a/Week_01/G20200343030459/206.reverse-linked-list.py b/Week_01/G20200343030459/206.reverse-linked-list.py new file mode 100644 index 00000000..570901f3 --- /dev/null +++ b/Week_01/G20200343030459/206.reverse-linked-list.py @@ -0,0 +1,52 @@ +# +# @lc app=leetcode id=206 lang=python3 +# +# [206] Reverse Linked List +# +# https://leetcode.com/problems/reverse-linked-list/description/ +# +# algorithms +# Easy (59.55%) +# Likes: 3581 +# Dislikes: 82 +# Total Accepted: 835.2K +# Total Submissions: 1.4M +# 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? +# +# + +# @lc code=start +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, x): +# self.val = x +# self.next = None + +class Solution: + def reverseList(self, head: ListNode) -> ListNode: + if not head: + return None + prev = None + curt = head + while curt: + temp = curt.next + curt.next = prev + prev = curt + curt = temp + return prev +# @lc code=end + diff --git a/Week_01/G20200343030459/25.reverse-nodes-in-k-group.py b/Week_01/G20200343030459/25.reverse-nodes-in-k-group.py new file mode 100644 index 00000000..ef7c41b5 --- /dev/null +++ b/Week_01/G20200343030459/25.reverse-nodes-in-k-group.py @@ -0,0 +1,93 @@ +# +# @lc app=leetcode id=25 lang=python3 +# +# [25] Reverse Nodes in k-Group +# +# https://leetcode.com/problems/reverse-nodes-in-k-group/description/ +# +# algorithms +# Hard (39.53%) +# Likes: 1732 +# Dislikes: 337 +# Total Accepted: 236.4K +# Total Submissions: 596.2K +# Testcase Example: '[1,2,3,4,5]\n2' +# +# Given a linked list, reverse the nodes of a linked list k at a time and +# return its modified list. +# +# k is a positive integer and is less than or equal to the length of the linked +# list. If the number of nodes is not a multiple of k then left-out nodes in +# the end should remain as it is. +# +# +# +# +# Example: +# +# Given this linked list: 1->2->3->4->5 +# +# For k = 2, you should return: 2->1->4->3->5 +# +# For k = 3, you should return: 3->2->1->4->5 +# +# Note: +# +# +# Only constant extra memory is allowed. +# You may not alter the values in the list's nodes, only nodes itself may be +# changed. +# +# +# + +# @lc code=start +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, x): +# self.val = x +# self.next = None + +class Solution: + def reverseKGroup(self, head: ListNode, k: int) -> ListNode: + dummy = ListNode(0) + dummy.next = head + + prev = dummy + while prev: + prev = self.reverse_k(prev,k) + + return dummy.next + + def reverse_k(self, prev: ListNode, k: int) -> ListNode: + if k <= 0: + return None + if prev == None: + return None + + node_1, node_k = prev.next, prev + head = prev + for i in range(k): + if not node_k: + return None + node_k = node_k.next + if not node_k: + return None + + node_kplus = node_k.next + self.reverse(head, head.next,k) + node_1.next = node_kplus + prev.next = node_k + + return node_1 + + def reverse(self, prev: ListNode, curt: ListNode, k: int): + for i in range(k): + temp = curt.next + curt.next = prev + prev = curt + curt = temp + + +# @lc code=end + diff --git a/Week_01/G20200343030459/26.remove-duplicates-from-sorted-array.py b/Week_01/G20200343030459/26.remove-duplicates-from-sorted-array.py new file mode 100644 index 00000000..f7749093 --- /dev/null +++ b/Week_01/G20200343030459/26.remove-duplicates-from-sorted-array.py @@ -0,0 +1,80 @@ +# +# @lc app=leetcode id=26 lang=python3 +# +# [26] Remove Duplicates from Sorted Array +# +# https://leetcode.com/problems/remove-duplicates-from-sorted-array/description/ +# +# algorithms +# Easy (43.31%) +# Likes: 2067 +# Dislikes: 4395 +# Total Accepted: 816.1K +# Total Submissions: 1.9M +# 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: + def removeDuplicates(self, nums: List[int]) -> int: + if not nums: + return 0 + index = 0 + for i in range(len(nums)): + if nums[i] == nums[index]: + i += 1 + else: + index += 1 + nums[index], nums[i] = nums[i], nums[index] + i += 1 + return index + 1 + +# @lc code=end + diff --git a/Week_01/G20200343030459/283.move-zeroes.py b/Week_01/G20200343030459/283.move-zeroes.py new file mode 100644 index 00000000..1e25de32 --- /dev/null +++ b/Week_01/G20200343030459/283.move-zeroes.py @@ -0,0 +1,56 @@ +# +# @lc app=leetcode id=283 lang=python3 +# +# [283] Move Zeroes +# +# https://leetcode.com/problems/move-zeroes/description/ +# +# algorithms +# Easy (56.24%) +# Likes: 2955 +# Dislikes: 99 +# Total Accepted: 622.3K +# Total Submissions: 1.1M +# Testcase Example: '[0,1,0,3,12]' +# +# Given an array nums, write a function to move all 0's to the end of it while +# maintaining the relative order of the non-zero elements. +# +# Example: +# +# +# Input: [0,1,0,3,12] +# Output: [1,3,12,0,0] +# +# Note: +# +# +# You must do this in-place without making a copy of the array. +# Minimize the total number of operations. +# +# + +# @lc code=start +class Solution: + def moveZeroes(self, nums: List[int]) -> None: + """ + Do not return anything, modify nums in-place instead. + """ + # 自己写的 感觉逻辑有点冗余 + # none_zero_index = 0 + # for index in range(len(nums)): + # if nums[index] and not nums[none_zero_index]: + # nums[index], nums[none_zero_index] = nums[none_zero_index], nums[index] + # none_zero_index += 1 + # elif nums[none_zero_index]: + # none_zero_index += 1 + + # discuss 里的高分代码 + zero = 0 + for index in range(len(nums)): + if nums[index]: + nums[zero], nums[index] = nums[index], nums[zero] + zero += 1 + +# @lc code=end + diff --git a/Week_01/G20200343030459/88.merge-sorted-array.py b/Week_01/G20200343030459/88.merge-sorted-array.py new file mode 100644 index 00000000..dbeacfb8 --- /dev/null +++ b/Week_01/G20200343030459/88.merge-sorted-array.py @@ -0,0 +1,83 @@ +# +# @lc app=leetcode id=88 lang=python3 +# +# [88] Merge Sorted Array +# +# https://leetcode.com/problems/merge-sorted-array/description/ +# +# algorithms +# Easy (38.06%) +# Likes: 1702 +# Dislikes: 3612 +# Total Accepted: 497.1K +# Total Submissions: 1.3M +# Testcase Example: '[1,2,3,0,0,0]\n3\n[2,5,6]\n3' +# +# Given two sorted integer arrays nums1 and nums2, merge nums2 into nums1 as +# one sorted array. +# +# Note: +# +# +# The number of elements initialized in nums1 and nums2 are m and n +# respectively. +# You may assume that nums1 has enough space (size that is greater or equal to +# m + n) to hold additional elements from nums2. +# +# +# Example: +# +# +# Input: +# nums1 = [1,2,3,0,0,0], m = 3 +# nums2 = [2,5,6], n = 3 +# +# Output: [1,2,2,3,5,6] +# +# + +# @lc code=start +# 自己的解法 没有抓住 python 的精髓 +# class Solution: +# def merge(self, nums1: List[int], m: int, nums2: List[int], n: int) -> None: +# """ +# Do not return anything, modify nums1 in-place instead. +# """ +# i, j = m - 1, n - 1 +# index = m + n - 1 +# while i >= 0 and j >= 0: +# if nums1[i] > nums2[j]: +# nums1[i], nums1[index] = nums1[index], nums1[i] +# i, index = i - 1, index - 1 +# elif nums1[i] < nums2[j]: +# nums1[index] = nums2[j] +# j, index = j - 1, index - 1 +# else: +# nums1[i], nums1[index] = nums1[index], nums1[i] +# i, index = i - 1, index - 1 +# nums1[index] = nums2[j] +# j, index = j - 1, index - 1 + +# while j >= 0: +# nums1[index] = nums2[j] +# j, index = j - 1, index - 1 + + +class Solution: + def merge(self, nums1: List[int], m: int, nums2: List[int], n: int) -> None: + """ + Do not return anything, modify nums1 in-place instead. + """ + while m > 0 and n > 0: + if nums1[m - 1] >= nums2[n - 1]: + nums1[m + n - 1] = nums1[m - 1] + m -= 1 + else: + nums1[m + n - 1] = nums2[n - 1] + n -= 1 + + if n > 0: + nums1[:n] = nums2[:n] + +# @lc code=end + diff --git a/Week_01/G20200343030463/463-Week 01/LeetCode_189_463.cpp b/Week_01/G20200343030463/463-Week 01/LeetCode_189_463.cpp new file mode 100644 index 00000000..44b704e0 --- /dev/null +++ b/Week_01/G20200343030463/463-Week 01/LeetCode_189_463.cpp @@ -0,0 +1,27 @@ +课后作业 + +002 https://leetcode-cn.com/problems/rotate-array/ + +解法一: +解题思路: +001 找到最后一个元素, +002 整体元素往后挪一位 +003 001和002 循环K次 +执行结果:运行超时 +class Solution { +public: +void rotate(vector& nums, int k) { +int N = nums.size(); +int previous =0; +int temp = 0; +for (int i=0;i0;j--){ +nums[j] = nums[j-1]; +} +nums[0] = previous; +} +} +}; + + diff --git a/Week_01/G20200343030463/463-Week 01/LeetCode_1_463.cpp b/Week_01/G20200343030463/463-Week 01/LeetCode_1_463.cpp new file mode 100644 index 00000000..3e9d0308 --- /dev/null +++ b/Week_01/G20200343030463/463-Week 01/LeetCode_1_463.cpp @@ -0,0 +1,25 @@ +课后作业 + +005 https://leetcode-cn.com/problems/two-sum/ +解法一: +暴力求解 +解法二:利用unordered_map key是num[i] value是i +如果target-nums[i]在map中找得到那么就返回value 和 i + +class Solution { +public: +vector twoSum(vector& nums, int target) { + +unordered_map newM; + +for(int i =0; i < nums.size();i++){ +if(newM.find(target-nums[i]) != newM.end()){ +return {newM[target-nums[i]],i}; +} +newM[nums[i]] = i; +} + +return {}; +} +}; + diff --git a/Week_01/G20200343030463/463-Week 01/LeetCode_21_463.cpp b/Week_01/G20200343030463/463-Week 01/LeetCode_21_463.cpp new file mode 100644 index 00000000..634d61a1 --- /dev/null +++ b/Week_01/G20200343030463/463-Week 01/LeetCode_21_463.cpp @@ -0,0 +1,32 @@ +课后作业 + +003 +解题思路: +001 新建一个头节点 代理节点 +002 代理节点指向l1 l2中元素较小的点 +003 代理节点更新到新增加的节点 +004 返回头节点 + +class Solution { +public: +ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) { +ListNode *preHead = new ListNode(-1); +ListNode *pre = preHead; + +while(l1&&l2){ +if(l1->val >= l2->val){ //代理指针指向元素较小的节点 +pre->next = l2; +l2 = l2->next; //l2指针指向下一个地址 +}else{ +pre->next = l1; +l1 = l1->next; //l1指针指向下一个地址 +} +pre = pre->next; //代理指针指向新加节点的位置 +} + +pre->next=l1 == NULL? l2 : l1; //判断l1 为空 那么返回l2 反之返回l1 + +return preHead->next; //返回新链表 + +} +}; diff --git a/Week_01/G20200343030463/463-Week 01/LeetCode_26_463.cpp b/Week_01/G20200343030463/463-Week 01/LeetCode_26_463.cpp new file mode 100644 index 00000000..a328b4ba --- /dev/null +++ b/Week_01/G20200343030463/463-Week 01/LeetCode_26_463.cpp @@ -0,0 +1,27 @@ +课后作业 +001 +https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array/ +解题思路: +快指针 慢指针 还有一个标记位用于存放最后一个不一样的元素索引. +注意点:C++一定要注意数组越界问题 +参考连接:https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array/solution/shuang-zhi-zhen-shan-chu-zhong-fu-xiang-dai-you-hu/ +解答如下: +class Solution { +public: +int removeDuplicates(vector& nums) { +if(nums.size() ==0) return 0; +int j = 1; +int k = 0; +int N = nums.size(); + +for (int i =0; i & nums) { +int j =0; +int N = nums.size(); + +for (int i =0;i& nums1, int m, vector& nums2, int n) { + +int i = m - 1, j = n - 1, newvector = m + n - 1; +while (j >= 0) { +nums1[newvector--] = i >= 0 && nums1[i] > nums2[j] ? nums1[i--] : nums2[j--]; +} +} +}; diff --git a/Week_01/G20200343030463/463-Week 01/NOTE.md b/Week_01/G20200343030463/463-Week 01/NOTE.md new file mode 100644 index 00000000..9c0aad09 --- /dev/null +++ b/Week_01/G20200343030463/463-Week 01/NOTE.md @@ -0,0 +1,6 @@ +学习笔记 +1.一道题要做好几遍才会懂 参考别人的思路自己写 跑不过 再改 再写 最后挑出个人最好的解法放到作业本里 +2.一开始 看着别人的思路 自己动手写就出现各种错误 原因还是自己不够熟练💪 +3.C++在操作数组的时候一定要检查数组越界 +4.在有序线性数据结构中可以使用一快一慢的指针来处理很多问题 +5.可以利用空间换时间来提高速度 例如unordered_map heap 等 diff --git a/Week_01/G20200343030465/LeetCode_21_465.java b/Week_01/G20200343030465/LeetCode_21_465.java new file mode 100644 index 00000000..60262bda --- /dev/null +++ b/Week_01/G20200343030465/LeetCode_21_465.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; + if (l2 == null) return l1; + if (l1.val > l2.val) { + ListNode tmp = l2; + tmp.next = mergeTwoLists(l1, l2.next); + return tmp; + } else { + ListNode tmp = l1; + tmp.next = mergeTwoLists(l1.next, l2); + return tmp; + } + + } +} \ No newline at end of file diff --git a/Week_01/G20200343030465/LeetCode_66_465.java b/Week_01/G20200343030465/LeetCode_66_465.java new file mode 100644 index 00000000..10ffdb96 --- /dev/null +++ b/Week_01/G20200343030465/LeetCode_66_465.java @@ -0,0 +1,18 @@ +class Solution { + public int[] plusOne(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/G20200343030485/LeetCode_189_485.cs b/Week_01/G20200343030485/LeetCode_189_485.cs new file mode 100644 index 00000000..52f522bb --- /dev/null +++ b/Week_01/G20200343030485/LeetCode_189_485.cs @@ -0,0 +1,18 @@ +public class Solution { + public void Rotate(int[] nums, int k) { + int count = 0; + for (int i = 0; count < nums.Length; i++) { + int targetIndex = i; + int numLast = nums[i]; + do { + targetIndex = (targetIndex + k) % nums.Length; + int numTmp = nums[targetIndex]; + nums[targetIndex] = numLast; + + numLast = numTmp; + + count++; + } while (targetIndex != i); + } + } +} \ No newline at end of file diff --git a/Week_01/G20200343030485/LeetCode_26_485.cs b/Week_01/G20200343030485/LeetCode_26_485.cs new file mode 100644 index 00000000..e1e8e683 --- /dev/null +++ b/Week_01/G20200343030485/LeetCode_26_485.cs @@ -0,0 +1,23 @@ +public class Solution { + public int RemoveDuplicates(int[] nums) + { + if (nums.Length == 0) + { + return 0; + } + + int j = 1; + int trackInt = nums[0]; + for (int i = 1; i < nums.Length; i++) + { + if (nums[i] != trackInt) + { + nums[j] = nums[i]; + j++; + trackInt = nums[i]; + } + } + + return j; + } +} \ No newline at end of file diff --git a/Week_01/G20200343030485/LeetCode_42_485.cs b/Week_01/G20200343030485/LeetCode_42_485.cs new file mode 100644 index 00000000..5c184016 --- /dev/null +++ b/Week_01/G20200343030485/LeetCode_42_485.cs @@ -0,0 +1,24 @@ + +public class Solution { + public int Trap(int[] height) { + int region = 0; + Stack stack = new Stack(); + for (int i = 0; i < height.Length; i++) { + int h = height[i]; + while (stack.Count != 0 && h > height[stack.Peek()]) { + int indexToRemove = stack.Pop(); + if (stack.Count == 0) { + break; + } + + int colWidth = i - stack.Peek() - 1; + int colHeight = Math.Min(h, height[stack.Peek()]) - height[indexToRemove]; + region += colWidth * colHeight; + } + + stack.Push(i); + } + + return region; + } +} \ No newline at end of file diff --git a/Week_01/G20200343030485/LeetCode_641_485.cs b/Week_01/G20200343030485/LeetCode_641_485.cs new file mode 100644 index 00000000..f84c58b5 --- /dev/null +++ b/Week_01/G20200343030485/LeetCode_641_485.cs @@ -0,0 +1,111 @@ +public class MyCircularDeque + { + private LinkedList ll; + private readonly int capacity; + + /** Initialize your data structure here. Set the size of the deque to be k. */ + public MyCircularDeque(int k) + { + ll = new LinkedList(); + capacity = k; + } + + /** Adds an item at the front of Deque. Return true if the operation is successful. */ + public bool InsertFront(int value) + { + if (ll.Count >= capacity) + { + return false; + } + + ll.AddFirst(value); + + return true; + } + + /** Adds an item at the rear of Deque. Return true if the operation is successful. */ + public bool InsertLast(int value) + { + if (ll.Count >= capacity) + { + return false; + } + + ll.AddLast(value); + + return true; + } + + /** Deletes an item from the front of Deque. Return true if the operation is successful. */ + public bool DeleteFront() + { + if (ll.Count == 0) + { + return false; + } + + ll.RemoveFirst(); + + return true; + } + + /** Deletes an item from the rear of Deque. Return true if the operation is successful. */ + public bool DeleteLast() + { + if (ll.Count == 0) + { + return false; + } + + ll.RemoveLast(); + + return true; + } + + /** Get the front item from the deque. */ + public int GetFront() + { + if (ll.Count == 0) + { + return -1; + } + + return ll.First.Value; + } + + /** Get the last item from the deque. */ + public int GetRear() + { + if (ll.Count == 0) + { + return -1; + } + + return ll.Last.Value; + } + + /** Checks whether the circular deque is empty or not. */ + public bool IsEmpty() + { + return (ll.Count == 0); + } + + /** Checks whether the circular deque is full or not. */ + public bool IsFull() + { + return ll.Count == capacity; + } + + /** + * 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(); + */ + } \ No newline at end of file diff --git a/Week_01/G20200343030485/LeetCode_66_485.cs b/Week_01/G20200343030485/LeetCode_66_485.cs new file mode 100644 index 00000000..92737a21 --- /dev/null +++ b/Week_01/G20200343030485/LeetCode_66_485.cs @@ -0,0 +1,18 @@ +public class Solution { + public int[] PlusOne(int[] digits) { + for (int i = digits.Length - 1; i >= 0; i--) { + digits[i]++; + if (digits[i] == 10) { + digits[i] = 0; + } + else { + return digits; + } + } + + digits = new int[digits.Length + 1]; + digits[0] = 1; + + return digits; + } +} \ No newline at end of file diff --git a/Week_01/G20200343030485/LeetCode_84_485.cs b/Week_01/G20200343030485/LeetCode_84_485.cs new file mode 100644 index 00000000..13dfc56b --- /dev/null +++ b/Week_01/G20200343030485/LeetCode_84_485.cs @@ -0,0 +1,40 @@ +public class Solution { + public int LargestRectangleArea(int[] heights) { + int areaMax = 0; + + Stack stack = new Stack(); + stack.Push(-1); + + for (int i = 0; i < heights.Length; i++) + { + int height = heights[i]; + while (stack.Peek() != -1 && heights[stack.Peek()] >= height) + { + int index = stack.Pop(); + int leftIndex = stack.Peek(); + int area = heights[index] * (i - leftIndex - 1); + if (area > areaMax) + { + areaMax = area; + } + } + + stack.Push(i); + } + + // clear stack + while (stack.Peek() != -1) + { + int index = stack.Pop(); + int left = stack.Peek(); + int right = heights.Length; + int area = heights[index] * (right - left - 1); + if (area > areaMax) + { + areaMax = area; + } + } + + return areaMax; + } +} \ No newline at end of file diff --git a/Week_01/G20200343030487/leetcode_189_487.js b/Week_01/G20200343030487/leetcode_189_487.js new file mode 100644 index 00000000..44c80c72 --- /dev/null +++ b/Week_01/G20200343030487/leetcode_189_487.js @@ -0,0 +1,11 @@ +// 暴力法:双重循环每次移动数组一步 +function rotateArr(nums, k) { + for (let i = 0; i < k; i++) { + let temp = nums[nums.length - 1] + for (let j = nums.length - 1; j > 0; j--) { + nums[j] = nums[j - 1] + } + nums[0] = temp + } + return nums +} diff --git a/Week_01/G20200343030487/leetcode_1_487.js b/Week_01/G20200343030487/leetcode_1_487.js new file mode 100644 index 00000000..a958d354 --- /dev/null +++ b/Week_01/G20200343030487/leetcode_1_487.js @@ -0,0 +1,39 @@ +// 暴力法 +function twoSum1(arr, target) { + const len = arr.length + for (let i = 0; i < len - 1; i++) { + for (let j = i + 1; j < len; j++) { + if (arr[i] + arr[j] === target) { + return [i, j] + } + } + } + return [] +} + +// 第一次遍历把所有元素存进map中,然后判断差值是否存在map中 +function twoSum2(arr, target) { + const len = arr.length + const map = new Map() + for (let i = 0; i < len; i++) { + map.set(arr[i], i) + } + for (let i = 0; i < len - 1; i++) { + if (map.has(target - arr[i]) && map.get(target - arr[i]) !== i) { + return [i, map.get(target - arr[i])] + } + } + return [] +} + +// 优化上方代码直接一遍循环,不存在就存,但是这里第二部循环需要到len +function twoSum3(arr, target) { + const map = new Map() + for (let i = 0; i < len; i++) { + if (map.has(target - arr[i]) && map.get(target - arr[i]) !== i) { + return [i, map.get(target - arr[i])] + } + map.set(arr[i], i) + } + return [] +} diff --git a/Week_01/G20200343030487/leetcode_21_487.js b/Week_01/G20200343030487/leetcode_21_487.js new file mode 100644 index 00000000..e69de29b diff --git a/Week_01/G20200343030487/leetcode_26_487.js b/Week_01/G20200343030487/leetcode_26_487.js new file mode 100644 index 00000000..13e99dfc --- /dev/null +++ b/Week_01/G20200343030487/leetcode_26_487.js @@ -0,0 +1,22 @@ +// 暴力法,反向遍历,重复就删除,最后返回数组长度 +function removeDuplicates1(nums) { + for (let i = nums.length - 1; i > -1; i--) { + let index = nums.indexOf(nums[i]) + if ( index !== i) { + nums.splice(i, 1) + } + } + return nums.length +} + +// 题目只需要前面元素按顺序排列,所以遇到非重复的元素就将count + 1,同时第count个元素等于当前元素 +function removeDuplicates2(nums) { + let count = 0 + for (let i = 0, len = nums.length; i < len; i++) { + if (nums[count] !== nums[i]) { + count++ + nums[count] = nums[i] + } + } + return ++count +} \ No newline at end of file diff --git a/Week_01/G20200343030487/leetcode_283_487.js b/Week_01/G20200343030487/leetcode_283_487.js new file mode 100644 index 00000000..cb6f160b --- /dev/null +++ b/Week_01/G20200343030487/leetcode_283_487.js @@ -0,0 +1,31 @@ +// 快慢指针 +function moveZeros2(arr) { + let slow = 0 + for (let fast = 0; fast < arr.length; fast++) { + if (arr[fast] !== 0) { + swap(arr, slow, fast) + slow++ + } + } +} + +function swap(arr, i, j) { + let temp = arr[i] + arr[i] = arr[j] + arr[j] = temp +} + +// 用一个下标先把所有非0元素往前放,最后在将下标以及之后的位置元素置为0 +function moveZeros3(arr) { + let count = 0 + for (let i = 0; i < arr.length; i++) { + if (arr[i] !== 0) { + arr[index] === arr[i] + index++ + } + } + for (let i = index; i < arr.length; i++) { + arr[i] = 0 + } + return arr +} \ No newline at end of file diff --git a/Week_01/G20200343030487/leetcode_641_487.js b/Week_01/G20200343030487/leetcode_641_487.js new file mode 100644 index 00000000..e7100da8 --- /dev/null +++ b/Week_01/G20200343030487/leetcode_641_487.js @@ -0,0 +1,109 @@ +/** + * Initialize your data structure here. Set the size of the deque to be k. + * @param {number} k + */ +var MyCircularDeque = function(k) { + this.len = k + this.value = [] +}; + +/** +* Adds an item at the front of Deque. Return true if the operation is successful. +* @param {number} value +* @return {boolean} +*/ +MyCircularDeque.prototype.insertFront = function(value) { + if (this.isFull()) { + return false + } + this.value.unshift(value) + return true +}; + +/** +* Adds an item at the rear of Deque. Return true if the operation is successful. +* @param {number} value +* @return {boolean} +*/ +MyCircularDeque.prototype.insertLast = function(value) { + if (this.isFull()) { + return false + } + this.value.push(value) + return true +}; + +/** +* Deletes an item from the front of Deque. Return true if the operation is successful. +* @return {boolean} +*/ +MyCircularDeque.prototype.deleteFront = function() { + if (this.isEmpty()) { + return false + } + this.value.splice(0, 1) + return true +}; + +/** +* Deletes an item from the rear of Deque. Return true if the operation is successful. +* @return {boolean} +*/ +MyCircularDeque.prototype.deleteLast = function() { + if (this.isEmpty()) { + return false + } + this.value.splice(this.value.length - 1, 1) + return true +}; + +/** +* Get the front item from the deque. +* @return {number} +*/ +MyCircularDeque.prototype.getFront = function() { + if (this.isEmpty()) { + return -1 + } + return this.value[0] +}; + +/** +* Get the last item from the deque. +* @return {number} +*/ +MyCircularDeque.prototype.getRear = function() { + if (this.isEmpty()) { + return -1 + } + return this.value[this.value.length - 1] +}; + +/** +* Checks whether the circular deque is empty or not. +* @return {boolean} +*/ +MyCircularDeque.prototype.isEmpty = function() { + return this.value.length === 0 +}; + +/** +* Checks whether the circular deque is full or not. +* @return {boolean} +*/ +MyCircularDeque.prototype.isFull = function() { + return this.value.length === this.len +}; + +/** +* Your MyCircularDeque object will be instantiated and called as such: +* var obj = new MyCircularDeque(k) +* var param_1 = obj.insertFront(value) +* var param_2 = obj.insertLast(value) +* var param_3 = obj.deleteFront() +* var param_4 = obj.deleteLast() +* var param_5 = obj.getFront() +* var param_6 = obj.getRear() +* var param_7 = obj.isEmpty() +* var param_8 = obj.isFull() +*/ \ No newline at end of file diff --git a/Week_01/G20200343030487/leetcode_88_487.js b/Week_01/G20200343030487/leetcode_88_487.js new file mode 100644 index 00000000..70747fc4 --- /dev/null +++ b/Week_01/G20200343030487/leetcode_88_487.js @@ -0,0 +1,7 @@ +// 不是很理解第一个数组后面的0 +function mergeSortedArray(arr1, m, arr2, n) { + arr1.splice(m, n, ...arr2) + arr1.sort((a, b) => { + return a - b + }) +} \ No newline at end of file diff --git a/Week_01/G20200343030489/LeetCode_189_489.cpp b/Week_01/G20200343030489/LeetCode_189_489.cpp new file mode 100644 index 00000000..47318f08 --- /dev/null +++ b/Week_01/G20200343030489/LeetCode_189_489.cpp @@ -0,0 +1,58 @@ +/*һ*/ +/*class Solution { +public: + void rotate(vector& nums, int k) { + int tmp[nums.size()]; + + for (int i = 0; i < nums.size(); i++) + { + tmp[(i+k)%nums.size()]=nums[i]; + } + for (int i = 0; i < nums.size(); i++) + { + nums[i]=tmp[i]; + } + + + } +};*/ +/*˷Ϊһ飬¿ռ临ӶȲΪO1*/ + +/**/ + +/* +class Solution { +public: + void rotate(vector& nums, int k) { + int tmp; + for (int i = 0; i < k%nums.size(); i++) + { + tmp=nums[nums.size()-1]; + for (int j = nums.size()-1; j >0; j--) + { + nums[j]=nums[j-1]; + } + nums[0]=tmp; + } + } +}; +*/ +/*˷ʱ临ӶȹߣΪO(k*n)*/ + +/**/ +class Solution { +public: + void rotate(vector& nums, int k) { + int leng=nums.size(); + k%=nums.size(); + reverse(&nums[0],&nums[leng]); + reverse(&nums[0],&nums[k]); + reverse(&nums[k],&nums[leng]); + } +}; + +/*˷˷תתreverse +ʵת k Σ k\%nk%n βԪػᱻƶͷʣµԪػᱻƶ + +УȽԪطתȻתǰ k Ԫأٷת n-kn?k ԪأܵõҪĽ +*/ \ No newline at end of file diff --git a/Week_01/G20200343030489/LeetCode_1_489.cpp b/Week_01/G20200343030489/LeetCode_1_489.cpp new file mode 100644 index 00000000..42e32f95 --- /dev/null +++ b/Week_01/G20200343030489/LeetCode_1_489.cpp @@ -0,0 +1,57 @@ +/*һ*/ +/*class Solution { +public: + vector twoSum(vector& nums, int target) { + int i,j; + for (i = 0; i < nums.size(); i++) + { + for (j = i+1 ; j < nums.size(); j++) + { + if (nums[i]+nums[j]==target) + { + return {i,j}; + } + + } + + } + return {}; + + } +};*/ + +/*ϣ*/ +/* +class Solution { +public: + vector twoSum(vector& nums, int target) { + unordered_map hash; + for(int i=0;i twoSum(vector& nums, int target) { + map hash; + vector a(2,-1);//ؽʼһСΪ2ֵΪ-1 + for (int i = 0; i < nums.size(); i++) + { + if (hash.count(target-nums[i])>0) + { + /* code */a[0]=hash[target-nums[i]]; + a[1]=i; + break; + } + hash[nums[i]]=i;//mapУȡ± + } + return a; + + } +}; \ No newline at end of file diff --git a/Week_01/G20200343030489/LeetCode_21_489.cpp b/Week_01/G20200343030489/LeetCode_21_489.cpp new file mode 100644 index 00000000..784b485e --- /dev/null +++ b/Week_01/G20200343030489/LeetCode_21_489.cpp @@ -0,0 +1,28 @@ +class Solution { +public: + ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) { + ListNode* temp=new ListNode(-1); + ListNode* tmp=temp; + + + while (l1!=NULL&&l2!=NULL) + { + /* code */if (l1->val<=l2->val) + { + /* code */tmp->next=l1; + l1=l1->next; + }else + { + tmp->next=l2; + l2=l2->next; + } + tmp=tmp->next; + } + tmp->next=l1 != NULL?l1:l2; + + return temp->next; + + + } +}; +/*˷Ϊ*/ \ No newline at end of file diff --git a/Week_01/G20200343030489/LeetCode_26_489.cpp b/Week_01/G20200343030489/LeetCode_26_489.cpp new file mode 100644 index 00000000..44af093f --- /dev/null +++ b/Week_01/G20200343030489/LeetCode_26_489.cpp @@ -0,0 +1,22 @@ +class Solution { +public: + int removeDuplicates(vector& nums) { + if (nums.size()==0) + { + /* code */return 0; + } + int a=0; + for (int i = 0; i < nums.size(); i++) + { + /* code */if (nums[i]!=nums[a]) + { + /* code */a++; + nums[a]=nums[i]; + } + + } + return a+1; + + + } +}; \ No newline at end of file diff --git a/Week_01/G20200343030489/LeetCode_283_489.cpp b/Week_01/G20200343030489/LeetCode_283_489.cpp new file mode 100644 index 00000000..951a2f9a --- /dev/null +++ b/Week_01/G20200343030489/LeetCode_283_489.cpp @@ -0,0 +1,22 @@ +class Solution +{ +public: + void moveZeroes(vector &nums) + { + int temp=0; + for (int j = 0; j < nums.size(); j++) + { + if (nums[j]==0) + { + temp++; + } + else if(temp>0) + { + nums[j-temp]=nums[j]; + nums[j]=0; + } + + + } + } +}; \ No newline at end of file diff --git a/Week_01/G20200343030489/LeetCode_66_489.cpp b/Week_01/G20200343030489/LeetCode_66_489.cpp new file mode 100644 index 00000000..ec3b6739 --- /dev/null +++ b/Week_01/G20200343030489/LeetCode_66_489.cpp @@ -0,0 +1,24 @@ +class Solution { +public: + vector plusOne(vector& digits) { + int size=digits.size(); + for (int i = size-1; i >=0; i--) + { + /* code */if (digits[i]==9) + { + /* code */digits[i]=0; + } + else + { + digits[i]++; + return digits; + } + + + } + digits.push_back(0); + digits[0]=1; + return digits; + + } +}; \ No newline at end of file diff --git a/Week_01/G20200343030489/LeetCode_88_489.cpp b/Week_01/G20200343030489/LeetCode_88_489.cpp new file mode 100644 index 00000000..dc385ef5 --- /dev/null +++ b/Week_01/G20200343030489/LeetCode_88_489.cpp @@ -0,0 +1,12 @@ +class Solution { +public: + void merge(vector& nums1, int m, vector& nums2, int n) { + for (int i = m; i < m+n; i++) + { + nums1[i]=nums2[i-m]; + } + sort(nums1.begin(),nums1.end()); + + } +}; +/*˷ʱ临Ӷȵͣռ临Ӷȸ*/ \ No newline at end of file diff --git a/Week_01/G20200343030489/NOTE.md b/Week_01/G20200343030489/NOTE.md index 50de3041..d0d0312b 100644 --- a/Week_01/G20200343030489/NOTE.md +++ b/Week_01/G20200343030489/NOTE.md @@ -1 +1,36 @@ -学习笔记 \ No newline at end of file +学习笔记 + +### 删除排序数组中的重复项 + +刚开始拿到这个题的时候我的第一反应便是用另一个数组来存放数字,但是犯了一个致命错误,就是没有仔细审题。题目说道要在原地修改数组,所以我改变了思路。题目说道不需要考虑超出新长度后面的元素,也就是说在输出的时候我只要输出前面部分的数字即可,所以想到通过循环,与前面数字对比,若不相同,则把前面重复数字替换掉,例如112这情况,在第三个位置发现与第一个位置数字不同的时候,替换第二个位置的数字,使成为122,输出的时候只要将前面两个位置输出即可。 + +### 旋转数组 + +看到题目上说了要求使用空间复杂度为O(1)算法,但第一次还是尝试了通过存放到另一个数组来先将排序排好,再将临时的数组依次存回原来原来数组中。 + +但毕竟这方法的空间复杂度高了,不符合题意。所以用第二个方法,就是一位一位移动。先将最后一个数字临时存起,再将整个表右移动一位,最后把临时存的数字放置第一位,以此循环k次,实现旋转。但这个方法的时间复杂度高,为O(k*n)。 + +最后看了别人的题解,学会了用reverse这个函数,即反转。这个方法是基于这样的事实:当旋转数组k次的时候,k%n个尾部元素就会被移到头部,剩下向后移动。这个方法首先将所有元素反转,接着反转前k个元素,最后反转n-k个元素,就能得到相应的结果。此方法时间复杂度为O(n)。 + +### 合并两个有序链表 + +由于在链表上面还不太熟悉,所以直接看了别人的题解。在这题上,运用了迭代的方法。创建一个存储元素的链表,设置一个哨兵点,这样可以在后面容易返回合并后的链表。对比两个链表中的元素大小,存储在创建的链表中,排序后输出哨兵点后的元素,得到最终结果。 + +### 合并两个有序数组 + +由于题目中说明了第一个数组有足够空间存放第二个数组的元素,所以我在这先将第一个数组后面无关的数字进行替换,替换成第二组的数字,接着通过sort函数,直接对替换后的第一个数组排序,得到最终结果。 + +### 两数之和 + +看到题目后第一反应便是通过暴力方法,逐一排查,如果有相等情况,记录下相应位置。但是暴力法导致的就是时间复杂度高,为n^2^ + +所以看了别人的方法,运用哈希表。通过空间换时间的方式,可以将时间复杂度降到O(1)。在进行迭代并把元素放到列表中的同时,,还会回头来检查表是否已经存在当前元素对应的目标元素。 + +### 移动零 + +此题其实方法也简单,只需要在遍历过程中记录下数为0的个数,再进行数组中位置交换,将0移动到后方。 + +### 加一 + +第一次拿到这题就理解错误了,我将它理解为只需要改变最后一个数字即可,但此题的意思是这个数组就是整个数字,加上一就相当于总数加一得到新的总数。所以要考虑到9+1进一位的情况。这题可能会出现9999这样的所有位数上都为9的情况。所以需要从数组最后一位进行遍历,如果无9,直接加一并返回数组即可,若出现上面说的情况,则数组上所有的数都换为0。遍历结束后,将数组增加一位,并放上0,将数组第一个数字换为1即可得到答案。 + diff --git a/Week_01/G20200343030491/LeetCode_189_491.py b/Week_01/G20200343030491/LeetCode_189_491.py new file mode 100644 index 00000000..db6a3505 --- /dev/null +++ b/Week_01/G20200343030491/LeetCode_189_491.py @@ -0,0 +1,10 @@ +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 + temp = (nums + nums)[n-k:2*n-k] + for i in range(n): + nums[i] = temp[i] \ No newline at end of file diff --git a/Week_01/G20200343030491/LeetCode_21_491.py b/Week_01/G20200343030491/LeetCode_21_491.py new file mode 100644 index 00000000..80b31bdd --- /dev/null +++ b/Week_01/G20200343030491/LeetCode_21_491.py @@ -0,0 +1,37 @@ +# Definition for singly-linked list. +class ListNode: + def __init__(self, x): + self.val = x + self.next = None + +def mergeTwoLists(l1, l2): + dummy = ListNode(-1) + newHead = dummy + while l1 and l2: + if l1.val<=l2.val: + newHead.next = l1 + l1 = l1.next + else: + newHead.next = l2 + l2 = l2.next + newHead = newHead.next + newHead.next = l1 if l1 is not None else l2 + return dummy.next + +def mergeTwoListsRec(l1,l2): + if not l1 or not l2: + return l1 or l2 + + if l1.val <= l2.val: + l1.next = mergeTwoListsRec(l1.next, l2) + return l1 + else: + l2.next = mergeTwoListsRec(l1, l2.next) + return l2 + +def mergeTwoListsRecSimple(l1, l2): + if l1 and l2: + if l1.val > l2.val: + l1, l2 = l2, l1 + l1.next = mergeTwoListsRecSimple(l1.next, l2) + return l1 or l2 \ No newline at end of file diff --git a/Week_01/G20200343030491/LeetCode_641_491.py b/Week_01/G20200343030491/LeetCode_641_491.py new file mode 100644 index 00000000..e9393adf --- /dev/null +++ b/Week_01/G20200343030491/LeetCode_641_491.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.list = [] + self.length = k + self.current = 0 + + 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.list.insert(0,value) + self.current += 1 + 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.list.append(value) + self.current += 1 + return True + + def deleteFront(self) -> bool: + """ + Deletes an item from the front of Deque. Return true if the operation is successful. + """ + if not self.isEmpty(): + self.list.pop(0) + self.current -= 1 + return True + else: + return False + + + def deleteLast(self) -> bool: + """ + Deletes an item from the rear of Deque. Return true if the operation is successful. + """ + if not self.isEmpty(): + self.list.pop() + self.current -= 1 + return True + else: + return False + + + def getFront(self) -> int: + """ + Get the front item from the deque. + """ + return -1 if self.isEmpty() else self.list[0] + + + def getRear(self) -> int: + """ + Get the last item from the deque. + """ + return -1 if self.isEmpty() else self.list[-1] + + + def isEmpty(self) -> bool: + """ + Checks whether the circular deque is empty or not. + """ + return self.current==0 + + + def isFull(self) -> bool: + """ + Checks whether the circular deque is full or not. + """ + return True if self.current>=self.length else False \ No newline at end of file diff --git a/Week_01/G20200343030491/LeetCode_66_491.py b/Week_01/G20200343030491/LeetCode_66_491.py new file mode 100644 index 00000000..2b63807a --- /dev/null +++ b/Week_01/G20200343030491/LeetCode_66_491.py @@ -0,0 +1,21 @@ +import math + +def plusOneRec(digits): + if not digits: + digits = [0] + if digits[-1] != 9: + digits[-1] += 1 + return digits + return plusOneRec(digits[:len(digits)-1]) + [0] + +def plusOne(digits): + n = len(digits) + for i in range(n): + if digits[n-i-1]<9: + digits[n-i-1] += 1 + return digits + digits[n-i-1] = 0 + + digits[0] = 1 + digits.append(0) + return digits \ No newline at end of file diff --git a/Week_01/G20200343030491/LeetCode_83_491.py b/Week_01/G20200343030491/LeetCode_83_491.py new file mode 100644 index 00000000..c318ca70 --- /dev/null +++ b/Week_01/G20200343030491/LeetCode_83_491.py @@ -0,0 +1,18 @@ +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, x): +# self.val = x +# self.next = None + +class Solution: + def deleteDuplicates(self, head: ListNode) -> ListNode: + cur1, cur2 = head, head + while cur2 and cur2.next: + if cur1.val == cur2.next.val: + cur2 = cur2.next + else: + cur1.next = cur2.next + cur1, cur2 = cur2.next, cur2.next + if cur2 and not cur2.next: + cur1.next = cur2.next + return head \ No newline at end of file diff --git a/Week_01/G20200343030491/LeetCode_88_491.py b/Week_01/G20200343030491/LeetCode_88_491.py new file mode 100644 index 00000000..d59a2496 --- /dev/null +++ b/Week_01/G20200343030491/LeetCode_88_491.py @@ -0,0 +1,29 @@ +def merge_pythonic(nums1,m,nums2,n): + nums1 = nums1[:m] + nums1.extend(nums2) + nums1.sort() + return nums1 + +def merge(nums1,m,nums2,n): + while n > 0: + if m<= 0 or nums1[m-1] <= nums2[n-1]: + nums1[m+n-1] = nums2[n-1] + n -= 1 + else: + nums1[m+n-1] = nums1[m-1] + m -= 1 + return nums1 + +def mergeRec(nums1,m,nums2,n): + if n == 0: + return + if m == 0: + nums1[:n] = nums2[:n] + return + maxVal = max(nums1[m-1],nums2[n-1]) + nums1[m+n-1] = maxVal + if (maxVal == nums1[m-1]): + mergeRec(nums1,m-1,nums2,n) + else: + mergeRec(nums1,m,nums2,n-1) + \ No newline at end of file diff --git a/Week_01/G20200343030493/removeDuplicates.java b/Week_01/G20200343030493/removeDuplicates.java new file mode 100644 index 00000000..2a55b764 --- /dev/null +++ b/Week_01/G20200343030493/removeDuplicates.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) { + if (nums.length == 0 ) return 0; + int i = 0; + for ( int j = 1; j & nums, int k) { + k = k % nums.size(); + int cntRotated = 0; + int length = nums.size(); + + for (int start = 0; cntRotated < length; start++) { + int current = start; + int numToBeRotated = nums[start]; //当前元素 + + do { + int next = (current + k) % length; //元素要放的位置 + int temp = nums[next]; + nums[next] = numToBeRotated; + numToBeRotated = temp; + current = next; + cntRotated++; //统计替换元素额个数 + } while (start != current); // 避免循环复制 + } + } + + // 采用反转法(三次反转) + // 时间复杂度:O(n) + // 空间复杂度:O(1) + void rotate2(vector& nums, int k) { + int length=nums.size(); + k = k % length; // k可能大于n,这里保证k小于n + + reverse(&nums[0],&nums[length]); // 反转所有元素 + reverse(&nums[0],&nums[k]); // 反转前k个元素 + reverse(&nums[k],&nums[length]); // 反转后n-k个元素 + } + + // 暴力法(超出运行时间),每次移动一步 + // 时间复杂度:O(n*k) + // 空间复杂度:O(1) + void rotate1(vector& nums, int k) { + int last, temp; + int length = nums.size(); + for(int i=0; i twoSum(vector& nums, int target) { + vector result; + unordered_map vmap; // 存储<值,建> + int length = nums.size(); + int another; // 存储在字典中,another = target - current + vmap[nums[0]] = 0; + + for(int i=1; i twoSum1(vector& nums, int target) { + vector v; + int length = nums.size(); + for(int i=0; i 0) { + moveToRightByOneStep(nums); + } + } + + private void moveToRightByOneStep(int[] nums) { + int temp = nums[nums.length - 1]; + for (int i = nums.length - 2; i >= 0; i--) { + nums[i + 1] = nums[i]; + } + nums[0] = temp; + } +} +// @lc code=end diff --git a/Week_01/G20200343030499/LeetCode_1_499.java b/Week_01/G20200343030499/LeetCode_1_499.java new file mode 100644 index 00000000..6c6317ac --- /dev/null +++ b/Week_01/G20200343030499/LeetCode_1_499.java @@ -0,0 +1,24 @@ +import java.util.*; +/* + * @lc app=leetcode id=1 lang=java + * + * [1] Two Sum + */ +/** + * 构造一个map。扫描数组时直接查找target - nums[n]是否在map中 + * 时间/空间复杂度:O(n)/O(n) + */ +// @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(nums[i])) { + return new int[] { i, map.get(nums[i]) }; + } + map.put(target - nums[i], i); + } + return null; // Won't execute, according to the question desc. + } +} +// @lc code=end diff --git a/Week_01/G20200343030499/LeetCode_21_499.java b/Week_01/G20200343030499/LeetCode_21_499.java new file mode 100644 index 00000000..d1503d70 --- /dev/null +++ b/Week_01/G20200343030499/LeetCode_21_499.java @@ -0,0 +1,31 @@ +/* + * @lc app=leetcode id=21 lang=java + * + * [21] Merge Two Sorted Lists + */ + +// @lc code=start +/** + * Definition for singly-linked list. public class ListNode { int val; ListNode + * next; ListNode(int x) { val = x; } } + */ +/** + * merge sort类似方法 + * 时间/空间复杂度:O(n)/O(n) + */ +class Solution { + public ListNode mergeTwoLists(ListNode l1, ListNode l2) { + if (l1 != null && l2 != null) { + if (l1.val < l2.val) { + l1.next = mergeTwoLists(l1.next, l2); + return l1; + } else { + l2.next = mergeTwoLists(l1, l2.next); + return l2; + } + } else { + return l1 == null ? l2 : l1; + } + } +} +// @lc code=end diff --git a/Week_01/G20200343030499/LeetCode_26_499.java b/Week_01/G20200343030499/LeetCode_26_499.java new file mode 100644 index 00000000..f1cec649 --- /dev/null +++ b/Week_01/G20200343030499/LeetCode_26_499.java @@ -0,0 +1,36 @@ +/* + * @lc app=leetcode id=26 lang=java + * + * [26] Remove Duplicates from Sorted Array + */ +// 时间复杂度: O(n) +// 空间复杂度: O(1) +// @lc code=start +class Solution { + public int removeDuplicates(int[] nums) { + int length = nums.length; + if (length <= 1) { + return length; + } + + // 从位置1开始插入第一个和currentNum不相等的数字 + int result = 1; + int insertPos = 1; + int currentNum = nums[0]; + for (int i = 1; i < length; i++) { + if (nums[i] != currentNum) { + nums[insertPos] = nums[i]; + result++; + insertPos++; + currentNum = nums[i]; + } + } + + // 剩余位置补0 + for (int i = result; i < length; i++) { + nums[i] = 0; + } + return result; + } +} +// @lc code=end diff --git a/Week_01/G20200343030499/LeetCode_283_499.java b/Week_01/G20200343030499/LeetCode_283_499.java new file mode 100644 index 00000000..fe4b16d5 --- /dev/null +++ b/Week_01/G20200343030499/LeetCode_283_499.java @@ -0,0 +1,45 @@ +/* + * @lc app=leetcode id=283 lang=java + * + * [283] Move Zeroes + */ + +// @lc code=start +/* + * 1. 只有数组有0时才有计算的意义。所以判断第一个0的位置,如果没有则直接返回 + * 2. 如果找到第一个零,则从此处开始处理之后的元素: + * a. 指针pointer始终指向未处理元素中第一个0的位置 + * b. 指针i发现未处理元素中有非零项则插入到pointer位置。pointer同时后移一位 + * c. i == nums.length 时返回 + * + * 时间复杂度:O(n) 数组中每个元素都用常数项时间处理一遍 + * 空间复杂度:O(1) 没有占用额外空间 + */ + +class Solution { + public void moveZeroes(int[] nums) { + int len = nums.length; + if (len <= 1) { + return; + } + + int pointer = 0; + while (pointer < len) { + if (nums[pointer] == 0) { + break; + } + pointer++; + } + if (pointer == len) { + return; + } + for (int i = pointer; i < len; i++) { + if (nums[i] != 0) { + nums[pointer] = nums[i]; + nums[i] = 0; + pointer++; + } + } + } +} +// @lc code=end diff --git a/Week_01/G20200343030499/LeetCode_641_499.java b/Week_01/G20200343030499/LeetCode_641_499.java new file mode 100644 index 00000000..a6a7e9ac --- /dev/null +++ b/Week_01/G20200343030499/LeetCode_641_499.java @@ -0,0 +1,112 @@ +/* + * @lc app=leetcode id=641 lang=java + * + * [641] Design Circular Deque + */ +// @lc code=start +/** + * 用数组实现 + * 循环使用下标避免不必要的数据移动 + * head, tail分别表示头和尾下标 + * head == tail时表示满 + * tail + 1 == head时表示空 + */ +class MyCircularDeque { + private int[] data; + private int head; + private int tail; + + /** Initialize your data structure here. Set the size of the deque to be k. */ + public MyCircularDeque(int k) { + // Can't support k < 1. Assume k >= 1 + data = new int[k + 1]; + head = 1; + tail = 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; + } + data[head] = value; + head = (head + 1) % data.length; + 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 = (data.length + tail - 1) % data.length; + 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 = (data.length + head - 1) % data.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) % data.length; + return true; + } + + /** Get the front item from the deque. */ + public int getFront() { + if (isEmpty()) { + return -1; + } + return data[(data.length + head - 1) % data.length]; + } + + /** Get the last item from the deque. */ + public int getRear() { + if (isEmpty()) { + return -1; + } + return data[(tail + 1) % data.length]; + } + + /** Checks whether the circular deque is empty or not. */ + public boolean isEmpty() { + return (tail + 1) % data.length == head; + } + + /** Checks whether the circular deque is full or not. */ + public boolean isFull() { + return head == tail; + } +} + +/** + * 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/G20200343030499/LeetCode_66_499.java b/Week_01/G20200343030499/LeetCode_66_499.java new file mode 100644 index 00000000..40a31506 --- /dev/null +++ b/Week_01/G20200343030499/LeetCode_66_499.java @@ -0,0 +1,31 @@ +/* + * @lc app=leetcode id=66 lang=java + * + * [66] Plus One + */ + +// 时间复杂度: O(n) +// 空间复杂度: O(1) +// @lc code=start +class Solution { + public int[] plusOne(int[] digits) { + return plusOneAt(digits, digits.length - 1); + } + + private int[] plusOneAt(int[] digits, int at) { + if (at == -1) { + int[] biggerDigits = new int[digits.length + 1]; + biggerDigits[0] = 1; + return biggerDigits; + } + + if (digits[at] == 9) { + digits[at] = 0; + return plusOneAt(digits, at - 1); + } else { + digits[at]++; + return digits; + } + } +} +// @lc code=end diff --git a/Week_01/G20200343030499/LeetCode_88_499.java b/Week_01/G20200343030499/LeetCode_88_499.java new file mode 100644 index 00000000..3d632f7c --- /dev/null +++ b/Week_01/G20200343030499/LeetCode_88_499.java @@ -0,0 +1,21 @@ +/* + * @lc app=leetcode id=88 lang=java + * + * [88] Merge Sorted Array + */ +// 时间复杂度: O(m+n) +// 空间复杂度: O(1) +// @lc code=start +class Solution { + public void merge(int[] nums1, int m, int[] nums2, int n) { + if (m != 0 && n != 0) { + nums1[m + n - 1] = nums1[m - 1] > nums2[n - 1] ? nums1[m-- - 1] : nums2[n-- - 1]; + merge(nums1, m, nums2, n); + } + if (m == 0 && n != 0) { + nums1[n - 1] = nums2[n - 1]; + merge(nums1, 0, nums2, n - 1); + } + } +} +// @lc code=end diff --git a/Week_01/G20200343030501/LeetCode_1_501.go b/Week_01/G20200343030501/LeetCode_1_501.go new file mode 100644 index 00000000..308b892e --- /dev/null +++ b/Week_01/G20200343030501/LeetCode_1_501.go @@ -0,0 +1,20 @@ +package G20200343030501 + +func twoSum(nums []int, target int) []int { + indexMap := make(map[int]int) + for index, value := range nums { + completion := target - value + completionIndex, exist := indexMap[completion] + if exist { + if index > completionIndex { + return []int{completionIndex, index} + } else { + return []int{index, completionIndex} + } + } else { + indexMap[value] = index + continue + } + } + return []int{0, 0} +} \ No newline at end of file diff --git a/Week_01/G20200343030501/LeetCode_66_501.go b/Week_01/G20200343030501/LeetCode_66_501.go new file mode 100644 index 00000000..62779e4b --- /dev/null +++ b/Week_01/G20200343030501/LeetCode_66_501.go @@ -0,0 +1,25 @@ +package G20200343030501 + +func plusOne(digits []int) []int { + len := len(digits) + addEnd := 1 + i := len - 1 + for ; i >= 0; i-- { + currentNum := digits[i] + if currentNum + addEnd == 10 { + addEnd = 1 + digits[i] = 0 + } else { + digits[i] += 1 + addEnd = 0 + break + } + } + var result []int + if i == -1 && addEnd == 1 { + result = append([]int{1}, digits...) + } else { + result = digits + } + return result +} diff --git a/Week_01/G20200343030503/LeetCode_11_503.java b/Week_01/G20200343030503/LeetCode_11_503.java new file mode 100644 index 00000000..2cb2a22b --- /dev/null +++ b/Week_01/G20200343030503/LeetCode_11_503.java @@ -0,0 +1,32 @@ +/** + * 采用双指针向中间移动 + * 1. 遍历数组 并且定义2个指针 rear和head 如果head < rear 就遍历 + * 2. 求面积 s = x * y + * x = (rear - head) + * y = Math.min(nums[rear],nums[head]); + * 3. 取出最大的面积 + * + * 最容易出现问题的就是: 三目运算中++ -- 的使用 + * + */ +class Solution { + public int maxArea(int[] nums) { + int maxArea = 0; + for (int head = 0,rear = nums.length - 1; head < rear; ) { + //int minHeight = nums[head] > nums[rear] ? nums[rear--] : nums[head++] ; + int minHeight = 0; + if (nums[head] > nums[rear]) { + minHeight = nums[rear]; + rear --; + }else { + minHeight = nums[head]; + head ++; + } + + int area = (rear - head + 1) * minHeight; + maxArea = Math.max(maxArea,area); + + } + return maxArea; + } +} \ No newline at end of file diff --git a/Week_01/G20200343030503/LeetCode_15_503.java b/Week_01/G20200343030503/LeetCode_15_503.java new file mode 100644 index 00000000..5b984315 --- /dev/null +++ b/Week_01/G20200343030503/LeetCode_15_503.java @@ -0,0 +1,44 @@ +/** + * + * 三数之和 + * 核心思想 排序 + 双指针 或者 使用哈希表 + * 排序 + 双指针 中 1. 排序是前提(特别注意排序问题) 2. 双指针向内收敛 + * 难以想到的地方: + * sum = 0的时候去完重复 i和j都需要变化 i++ j-- + * + */ + +class Solution { + public List> threeSum(int[] nums) { + //结果保存在list集合中 + List> result = new ArrayList<>(); + //排序 + Arrays.sort(nums); + //遍历集合 + //定义2个指针 i、j + int i; + int j; + for (int k = 0; k < nums.length; k++) { + // 因为已经排好序nums[k],nums[i],nums[j]中nums[k]最小,如果nums[k]大于0那么三数只和就不可能等于0,直接返回 + if (nums[k] > 0) break; + //k对应元素去重 + if (k > 0 && nums[k] == nums[k-1]) continue; + i = k + 1; //i从k的下一个元素开始 + j = nums.length - 1;//j从最后一个元素开始 + while (i < j) { + int sum = nums[k] + nums[i] + nums[j]; + if ( sum == 0) { + result.add(Arrays.asList(nums[k],nums[i],nums[j])); + //i、j元素去重 + while (i < j && nums[i] == nums[i+1]) { i++; } + while (i < j && nums[j] == nums[j-1]) { j--; } + i++; + j--; + } + else if (sum < 0) i ++; + else j --; + } + } + return result; + } +} \ No newline at end of file diff --git a/Week_01/G20200343030503/LeetCode_189_503.java b/Week_01/G20200343030503/LeetCode_189_503.java new file mode 100644 index 00000000..44134e72 --- /dev/null +++ b/Week_01/G20200343030503/LeetCode_189_503.java @@ -0,0 +1,25 @@ +/** + * + * homework + * https://leetcode-cn.com/problems/rotate-array/ + * + * 题目要点: 1. 使用取余的方式判断i+k大于len 则从头开始 arr[(i + k) % nums.length] + * 2. 需要重新开辟一个数组去存放旋转之后的值 用于改变原数组的顺序 + * time complexity O(n) + * space complexity O(n) + * 关于官方题解中的 使用环状和使用反转 现阶段理解比较困难 + * + */ +class Solution { + public void rotate(int[] nums, int k) { + int[] arr = new int[nums.length]; + + for (int i = 0; i < nums.length; i++) { + arr[(i + k) % nums.length] = nums[i]; + } + + for (int i = 0; i < arr.length; i++) { + nums[i] = arr[i]; + } + } +} \ No newline at end of file diff --git a/Week_01/G20200343030503/LeetCode_1_503.java b/Week_01/G20200343030503/LeetCode_1_503.java new file mode 100644 index 00000000..a21bccfe --- /dev/null +++ b/Week_01/G20200343030503/LeetCode_1_503.java @@ -0,0 +1,38 @@ +/* + * homework + * https://leetcode-cn.com/problems/two-sum/ + * 方式一、 暴力求解法 + * 双层for循环 + * time complexity O(n^2) + * space complexity O(1) + * 方式二、 使用哈希表 + * time complexity O(n) 只遍历了一边nums所以时间复杂度是O(n) + * space complexity O(n) 空间复杂度取决于hash表中元素的个数 + * + * + * + * 题目明确: 每种输入只会对应一个答案 + */ +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[i] + nums[j] == target) { + // return new int[] { i, j }; + // } + // } + // } + + // throw new IllegalArgumentException("No two sum 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[]{i,map.get(target - nums[i])}; + } + map.put(nums[i],i); + } + throw new IllegalArgumentException("No two sum solution"); + } +} \ No newline at end of file diff --git a/Week_01/G20200343030503/LeetCode_21_503.java b/Week_01/G20200343030503/LeetCode_21_503.java new file mode 100644 index 00000000..690b64d4 --- /dev/null +++ b/Week_01/G20200343030503/LeetCode_21_503.java @@ -0,0 +1,37 @@ +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode(int x) { val = x; } + * } + * 思路分析: + * 创建一个新的列表,遍历链表1和链表2,分别比较每个节点的大小放入融合列表中 + * + * 注意事项: + * 1. 创建一个新的列表headNode + * 2. curMerge指向头节点且不断的向后遍历指向新的节点 保存链表1和链表2的较小的值 + * 3. 最后的时候l1和l2中正好有一个是非空的将其添加到融合列表中 + * 4. 因为融合列表第一个节点的值是-1,所以返回的时候从-1的下一个节点开始返回 + */ +class Solution { + public ListNode mergeTwoLists(ListNode l1, ListNode l2) { + ListNode headNode = new ListNode(-1); + ListNode cur1 = l1; + ListNode cur2 = l2; + ListNode curMerge = headNode; + while (cur1 != null && cur2 != null) { + if (cur1.val > cur2.val) { + curMerge.next = cur2; + cur2 = cur2.next; + }else { + curMerge.next = cur1; + cur1 = cur1.next; + } + curMerge = curMerge.next; + } + //此时l1和l2中正好有一个是非空的,因此将非空列表连接到合并列表的末尾。 + curMerge.next = cur1 == null ? cur2 : cur1; + return headNode.next; + } +} \ No newline at end of file diff --git a/Week_01/G20200343030503/LeetCode_22_503.java b/Week_01/G20200343030503/LeetCode_22_503.java new file mode 100644 index 00000000..fba1a0e8 --- /dev/null +++ b/Week_01/G20200343030503/LeetCode_22_503.java @@ -0,0 +1,24 @@ +/** + * + * homework + * https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array/ + * + * 题目要点: 1. 有序的数组 2. 双指针法解决相同元素 3. 返回的是新数组的长度 + * 特别注意: 遍历的时候一定要根据返回的数组的新的长度进行遍历,否则会出现 eg. [1,1,2] ==> [1,2,2] + * time complexity O(n) + * space complexity O(1) + * + * + */ + +class Solution { + public int removeDuplicates(int[] nums) { + int j = 0; + for (int i = 1; i < nums.length; i++) { + if (nums[j] != nums[i]) { + nums[++j] = nums[i]; + } + } + return j + 1; + } +} \ No newline at end of file diff --git a/Week_01/G20200343030503/LeetCode_283_503.java b/Week_01/G20200343030503/LeetCode_283_503.java new file mode 100644 index 00000000..1d61fa52 --- /dev/null +++ b/Week_01/G20200343030503/LeetCode_283_503.java @@ -0,0 +1,22 @@ +class Solution { + /** + * + * 1. 遍历数组,如果元素不为0,先用nums[j]记录该值nums[i] + * 2. 判断如果j与i不想等,把nums[i]所对应的值改为0 否则继续遍历 + * 3. j++ + * + * 做这个题目的时候,老师的这段代码思想可以理解,就是最终卡到了赋值 i!=j num[i] = 0 这块,遇到第1个0开始,下一次遍历j和i 就不相同了此时要先使用nums[j]记录nums[i]当前的值,然后把nums[i]修改为0 + **/ + public void moveZeroes(int[] nums) { + 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++; + } + } + } +} \ No newline at end of file diff --git a/Week_01/G20200343030503/LeetCode_66_503.java b/Week_01/G20200343030503/LeetCode_66_503.java new file mode 100644 index 00000000..8c7d07e6 --- /dev/null +++ b/Week_01/G20200343030503/LeetCode_66_503.java @@ -0,0 +1,25 @@ +/** + * + * homework + * https://leetcode-cn.com/problems/plus-one/ + * + * 题目理解: 其实就是多位数加1之后的值 特殊情况就是出现9的时候需要进位,如果999这种数字,加1之后需要进位,需要给数组扩容 + * time complexity O(n) + * space complexity O(1) + * + * + */ +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; + } +} \ No newline at end of file diff --git a/Week_01/G20200343030503/LeetCode_70_503.java b/Week_01/G20200343030503/LeetCode_70_503.java new file mode 100644 index 00000000..80e339b1 --- /dev/null +++ b/Week_01/G20200343030503/LeetCode_70_503.java @@ -0,0 +1,28 @@ +/** + * 爬楼梯 + * 方式一、 使用递归 + * 方式二、 初始化3个值,每次修改前2个值,第三个值等于前两个值只和 + * + */ +class Solution { + public int climbStairs(int n) { + // if (n <= 2) { + // return n; + // } + // return climbStairs(n - 1) + climbStairs(n - 2); + if(n <= 2) { + return n; + } + int step_one = 1; + int step_two = 2; + + int step_three = 0; + for (int i = 3 ; i <= n ;i++) { + step_three = step_two + step_one; + step_one = step_two; + step_two = step_three; + } + return step_three; + } + +} \ No newline at end of file diff --git a/Week_01/G20200343030503/LeetCode_88_503.java b/Week_01/G20200343030503/LeetCode_88_503.java new file mode 100644 index 00000000..2a9805d9 --- /dev/null +++ b/Week_01/G20200343030503/LeetCode_88_503.java @@ -0,0 +1,88 @@ +/** + * + * homework + * https://leetcode-cn.com/problems/merge-sorted-array/ + * + * 方式一、直接将数组二中的元素添加到数组一中然后排序 + * time complexity O(nlogn) Arrays.sort(arr) 内部用的是快排时间复杂度是nlogn > 大于for循环的时间复杂度n所以取大的nlog + * space complexity O(1) + * + * 方式二、将输出数组中的有效值存放到复制数组中nums1_copy, 分别定义2个指针到nums1_copy p1和nums2 p2 然后循环判断p1和p2所对应的值,将其添加到输出数组中 + * time complexity O(n + m) + * space complexity O(m) 使用了一个复制数组,所以空间复杂度为O(m) + * 方式二特别注意一点: 假设 nums1 有足够的空间(空间大小大于或等于 m + n)来保存 nums2 中的元素。 如果没有这个条件那么会出现数组ArrayIndexOutOfBoundsException + * + * 方式三、 + * 核心思想,从后往前将nums2和nums1中有效值中大的一次放到nums1的最后 + * 实现: 定义三个指针分别从指向nums有效数值处p1,nums1的last处p,nums2的last处p2 + * time complexity O(n + m) + * space complexity O(1) 在原数组上进行的操作 + * + * + * 一定要注意: 题干明确表示需要 1. 有序整数数组 2. nums1 有足够的空间(空间大小大于或等于 m + n)来保存 nums2 中的元素 + * + */ + +时间复杂度O(n) 是不是只要是一层循环,就可以理解为时间复杂度就是O(n) +class Solution1 { + + public void merge1(int[] nums1, int m, int[] nums2, int n) { + int j = 0; + for (int i = m; i < m + n; i++) { + nums1[i] = nums2[j]; + j++; + } + Arrays.sort(nums1); + } + + public void merge2(int[] nums1, int m, int[] nums2, int n) { + //复制nums1的数组,保留有效数据位 + int[] nums1_copy = new int[m]; + System.arraycopy(nums1,0,nums1_copy,0,m); + //定义2个指针p1 0~m p2 0~n + int p1 = 0; + int p2 = 0; + int p = 0; + while (p1 < m && p2 < n) { + if (nums1_copy[p1] < nums2[p2]) { + nums1[p++] = nums1_copy[p1++]; + }else { + nums1[p++] = nums2[p2++]; + } + } + 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); + } + } + /** + * 核心思想,因为题干明确 nums1 有足够的空间来保存 nums2 中的元素 + * 所以从nums1的last处开始存储nums1有效值与nums2中的最大值 + * @param nums1 + * @param m + * @param nums2 + * @param n + */ + public void merge3(int[] nums1, int m, int[] nums2, int n) { + //定义三个指针分别从指向nums有效数值处p1,nums1的last处p,nums2的last处p2 + //通常来说,下表总是从0开始,所以需要减1 + 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--]; + }else { + nums1[p--] = nums2[p2--]; + } + } + //因为是在原数组nums1上进行操作,所以如果循环之后,nums1有多出来的不需要动,nums2多出来的需要放到nums1中 + System.arraycopy(nums2,0,nums1,0,p2+1); + } + +} + + diff --git a/Week_01/G20200343030503/NOTE.md b/Week_01/G20200343030503/NOTE.md index 50de3041..29ad703b 100644 --- a/Week_01/G20200343030503/NOTE.md +++ b/Week_01/G20200343030503/NOTE.md @@ -1 +1,70 @@ -学习笔记 \ No newline at end of file +一、 知识笔记 + + 1. 复杂度 常见的复杂度 + + O(1): Constant Complexity 常数复杂度 + O(log n): Logarithmic Complexity 对数复杂度 + + O(n): Linear Complexity 线性时间复杂度 + + O(n^2): N square Complexity 平⽅方 + O(n^3): N square Complexity ⽴立⽅方 + O(2^n): Exponential Growth 指数 + O(n!): Factorial 阶乘
 + + 2. 数据结构与算法 + + a. 程序**=**数据结构**+**算法 + + b. 数据结构: 线性结构和非线性结构。 + + 线性结构: 顺序存储结构(数组)和链式存储结构(链表) + + 1. 顺序存储的线性表称为顺序表,顺序表中的存储元素是连续的 + 2. 链式存储的线性表称为链表,链表中的存储元素不一定是连续的,元素节点中存放数据元素以及相邻元素的地址信息 + 3. 线性结构常见的有:数组、队列、链表和栈 + + 非线性结构: 二维数组,多维数组,广义表,树结构,图结构 + +二、 课后作业 + + 1. 两数之和: 借助hashmap 来求解,时间复杂度数组的大小O(n) ,空间复杂度取决于hashmap中元素的个数O(n) + + 2. 盛水最多的容器: 采用双指针向内收敛法 其实就是就面积 area = x * y ; x= (rear - head) ; y = Math.min(nums[rear],nums[head]); + + 3. 三数只和: 核心思想 排序 + 双指针 或者 使用哈希表 题目重点: 1. 排序, 2 双指针手敛,3. 数组中重复元素问题 + + 4. 删除数组中的重复项: 1. 有序的数组 2. 双指针法解决相同元素 3. 返回的是新数组的长度特别注意返回新数组的长度,遍历的时候一定要根据返回的数组的新的长度进行遍历 + + 5. 加一: 其实就是多位数加1之后的值 特殊情况就是出现9的时候需要进位,如果999这种数字,加1之后需要进位,需要给数组扩容 + + 6. 爬楼梯: 方法一使用递归,效率不高,方法二使用初始化3个值,每次修改前2个值,第三个值等于前两个值只和 + + 7. 合并2个有序数组: + + 方式1 将输出数组中的有效值存放到复制数组中nums1_copy, 分别定义2个指针到nums1_copy p1和nums2 p2 然后循环判断p1和p2所对应的值,将其添加到输出数组中 + + 方式2 从后往前在原数组上进行操作,减少了空间复杂度 + + 需要注意的地方 题干明确表示需要 1. 有序整数数组 2. nums1 有足够的空间来保存 nums2 中的元素如果nums1保存不下nums2那么会报数组下标越界 + + 8. 旋转数组: a. 使用取余的方式判断i+k大于len 则从头开始 arr[(i + k) % nums.length] + + b. 需要重新开辟一个数组去存放旋转之后的值 用于改变原数组的顺序 + + 关于官方题解中的 使用环状和使用反转 现阶段理解比较困难 + + 9. 移动0: 做这个题目的时候,老师的这段代码思想可以理解,就是最终卡到了赋值 i!=j num[i] = 0 这块,遇到第1个0开始,下一次遍历j和i 就不相同了此时要先使用nums[j]记录nums[i]当前的值,然后把nums[i]修改为0 + +三、 总结 + + 1. 基础知识点的复习: 每天复习一遍数据结构与算法的脑图,记住数据结构与算法的脉络 + 2. 代码过数遍: 当敲完一遍的时候,可以理解,第二天需要重新复习一下才能将结果敲出来 + 3. 看题解 + 4. 最重要的还是强迫自己不断的敲代码,训练自己的思维能力 + 5. 感谢助教的帮助 + +四、建议 + +​ 知识点稍微在细一点 ,现阶段对于知识点只能自己在网上搜索总结 + diff --git a/Week_01/G20200343030505/LeetCode_189_G20200343030505.java b/Week_01/G20200343030505/LeetCode_189_G20200343030505.java new file mode 100644 index 00000000..55116916 --- /dev/null +++ b/Week_01/G20200343030505/LeetCode_189_G20200343030505.java @@ -0,0 +1,34 @@ +/** + * + */ + +/** + * @author huangwen05 + * + * @date: 2020年2月16日 下午8:47:10 + */ +public class LeetCode_189_G20200343030505 { + public void rotate(int[] nums, int k) { + if(nums == null || nums.length == 0) { + return; + } + + int lenth = nums.length; + int r = k%lenth; + if(r == 0) return; + int x = lenth - r; + rotate(nums,0, x - 1); + rotate(nums, x, lenth - 1); + rotate(nums, 0, lenth - 1); + } + + public void rotate(int[] nums, int i, int j) { + while (i < j) { + int temp = nums[i]; + nums[i] = nums[j]; + nums[j] = temp; + --j; + ++i; + } + } +} \ No newline at end of file diff --git a/Week_01/G20200343030505/LeetCode_1_G20200343030505.java b/Week_01/G20200343030505/LeetCode_1_G20200343030505.java new file mode 100644 index 00000000..4f67126a --- /dev/null +++ b/Week_01/G20200343030505/LeetCode_1_G20200343030505.java @@ -0,0 +1,32 @@ +/** + * + */ + +/** + * @author huangwen05 + * + * @date: 2020年2月16日 下午8:47:10 + */ +public class LeetCode_1_G20200343030505 { + public int[] twoSum(int[] nums, int target) { + if(nums == null || nums.length < 2) { + return new int[0]; + } + + Map map = new HashMap(); + for(int i=0;i stacks = new Stack(); + int maxArea = 0; + for(int i=0;i height[stacks.peek()]) { + h = height[stacks.pop()]; + + if(!stacks.isEmpty()) { + int area = (Math.min(height[i], height[stacks.peek()]) - h) * (i - stacks.peek() - 1); + maxArea += area; + } + } + + stacks.add(i); + } + + return maxArea; + } + } \ No newline at end of file diff --git a/Week_01/G20200343030505/LeetCode_641_G20200343030505.java b/Week_01/G20200343030505/LeetCode_641_G20200343030505.java new file mode 100644 index 00000000..216e4b06 --- /dev/null +++ b/Week_01/G20200343030505/LeetCode_641_G20200343030505.java @@ -0,0 +1,94 @@ +/** + * + */ + +/** + * @author huangwen05 + * + * @date: 2020年2月16日 下午8:56:10 + */ +public class LeetCode_641_G20200343030505 { + + private int front; + private int rear; + private int capacity; + private int[] arr; + + /** Initialize your data structure here. Set the size of the deque to be k. */ + public MyCircularDeque(int k) { + arr = 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; + front = (front - 1 + capacity)%capacity; + arr[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()) return false; + arr[rear] = value; + rear = (rear + 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; + arr[front] = 0; + front = (front + 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; + rear = (rear - 1 + capacity)%capacity; + arr[rear] = 0; + return true; + } + + /** Get the front item from the deque. */ + public int getFront() { + if(isEmpty()) return -1; + return arr[front]; + } + + /** Get the last item from the deque. */ + public int getRear() { + if(isEmpty()) return -1; + return arr[(rear - 1 + capacity)%capacity]; + } + + /** Checks whether the circular deque is empty or not. */ + public boolean isEmpty() { + if(front == rear) return true; + return false; + } + + /** Checks whether the circular deque is full or not. */ + public boolean isFull() { + if((rear + 1)%capacity == front) { + 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(); + */ \ No newline at end of file diff --git a/Week_01/G20200343030505/LeetCode_66_G20200343030505.java b/Week_01/G20200343030505/LeetCode_66_G20200343030505.java new file mode 100644 index 00000000..0ad39c5d --- /dev/null +++ b/Week_01/G20200343030505/LeetCode_66_G20200343030505.java @@ -0,0 +1,12 @@ +/** + * + */ + +/** + * @author huangwen05 + * + * @date: 2020年2月16日 下午8:50:14 + */ +public class LeetCode_88_G20200343030505 { + +} diff --git a/Week_01/G20200343030505/LeetCode_88_G20200343030505.java b/Week_01/G20200343030505/LeetCode_88_G20200343030505.java new file mode 100644 index 00000000..7f0e4982 --- /dev/null +++ b/Week_01/G20200343030505/LeetCode_88_G20200343030505.java @@ -0,0 +1,30 @@ +/** + * + */ + +/** + * @author huangwen05 + * + * @date: 2020年2月16日 下午8:50:14 + */ +public class LeetCode_66_G20200343030505 { + public int[] plusOne(int[] digits) { + if(digits == null || digits.length == 0) { + return new int[0]; + } + + int i = digits.length - 1; + while (i >= 0) { + digits[i] = digits[i] + 1; + digits[i] = digits[i] % 10; + if(digits[i] != 0) { + return digits; + } + --i; + } + + int[] result = new int[digits.length + 1]; + result[0] = 1; + return result; + } +} \ No newline at end of file diff --git a/Week_01/G20200343030507/507-Week 01/LeetCode_189_507.py b/Week_01/G20200343030507/507-Week 01/LeetCode_189_507.py new file mode 100644 index 00000000..76c1b7e0 --- /dev/null +++ b/Week_01/G20200343030507/507-Week 01/LeetCode_189_507.py @@ -0,0 +1,10 @@ +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 + nums[:] = nums[::-1] + nums[:k] = nums[:k][::-1] + nums[k:] = nums[k:][::-1] \ No newline at end of file diff --git a/Week_01/G20200343030507/507-Week 01/LeetCode_1_507.py b/Week_01/G20200343030507/507-Week 01/LeetCode_1_507.py new file mode 100644 index 00000000..ddd80ac1 --- /dev/null +++ b/Week_01/G20200343030507/507-Week 01/LeetCode_1_507.py @@ -0,0 +1,8 @@ +class Solution: + def twoSum(self, nums: List[int], target: int) -> List[int]: + d = dict() + for index, num in enumerate(nums): + if d.get(num) == None: + d[target - num] = index + else: + return [d.get(num), index] \ No newline at end of file diff --git a/Week_01/G20200343030507/507-Week 01/LeetCode_21_507.py b/Week_01/G20200343030507/507-Week 01/LeetCode_21_507.py new file mode 100644 index 00000000..0f39f232 --- /dev/null +++ b/Week_01/G20200343030507/507-Week 01/LeetCode_21_507.py @@ -0,0 +1,10 @@ +class Solution: + def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode: + if not l1 or not l2: + return l1 or l2 + if l1.val < l2.val: + l1.next = self.mergeTwoLists(l1.next, l2) + return l1 + else: + l2.next = self.mergeTwoLists(l1, l2.next) + return l2 \ No newline at end of file diff --git a/Week_01/G20200343030507/507-Week 01/LeetCode_26_507.py b/Week_01/G20200343030507/507-Week 01/LeetCode_26_507.py new file mode 100644 index 00000000..7efb261a --- /dev/null +++ b/Week_01/G20200343030507/507-Week 01/LeetCode_26_507.py @@ -0,0 +1,10 @@ +class Solution: + def removeDuplicates(self, nums: List[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 \ No newline at end of file diff --git a/Week_01/G20200343030507/507-Week 01/LeetCode_283_507.py b/Week_01/G20200343030507/507-Week 01/LeetCode_283_507.py new file mode 100644 index 00000000..32cd34a7 --- /dev/null +++ b/Week_01/G20200343030507/507-Week 01/LeetCode_283_507.py @@ -0,0 +1,6 @@ +class Solution: + def moveZeroes(self, nums: List[int]) -> None: + count = nums.count(0) + nums[:] = [i for i in nums if i != 0] + nums += [0]*count + return nums \ No newline at end of file diff --git a/Week_01/G20200343030507/507-Week 01/LeetCode_66_507.py b/Week_01/G20200343030507/507-Week 01/LeetCode_66_507.py new file mode 100644 index 00000000..bcf8c362 --- /dev/null +++ b/Week_01/G20200343030507/507-Week 01/LeetCode_66_507.py @@ -0,0 +1,6 @@ +class Solution: + def plusOne(self, digits: List[int]) -> List[int]: + num = 0 + for i in range(len(digits)): + num += digits[i] * pow(10, (len(digits) - i - 1)) + return [int(i) for i in str(num + 1)] \ No newline at end of file diff --git a/Week_01/G20200343030507/507-Week 01/LeetCode_88_507.py b/Week_01/G20200343030507/507-Week 01/LeetCode_88_507.py new file mode 100644 index 00000000..93f93235 --- /dev/null +++ b/Week_01/G20200343030507/507-Week 01/LeetCode_88_507.py @@ -0,0 +1,18 @@ +class Solution: + def merge(self, nums1: List[int], m: int, nums2: List[int], n: int) -> None: + """ + Do not return anything, modify nums1 in-place instead. + """ + p1 = m - 1 + p2 = n - 1 + p = m + n - 1 + while p1 > 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] \ No newline at end of file diff --git a/Week_01/G20200343030507/NOTE.md b/Week_01/G20200343030507/NOTE.md index 50de3041..3b4d0769 100644 --- a/Week_01/G20200343030507/NOTE.md +++ b/Week_01/G20200343030507/NOTE.md @@ -1 +1,17 @@ -学习笔记 \ No newline at end of file +学习笔记 + +【week01】 +解题思想 +1.最大的误区:做题只做一遍 +2.重要思想:升维;空间换时间 +3.懵逼的时候怎么办:想能否暴力解决;基本情况是什么样的(也就是想最简单的情况是怎样的);如何泛化? +4.找最近重复子问题,也就是找重复性 + +动态规划 +将一个问题拆成几个子问题,分别求解这些子问题,即可推断出大问题的解。 + +双指针套路 +关于双指针套路的问题,一开始必须要做的事情就是排序,如果没排序的话是无法实现后面的夹逼的 + +数组和链表的区别 +链表适合插入、删除,时间复杂度 O(1);数组支持随机访问,根据下标随机访问的时间复杂度为 O(1)(对于排好序的数组,用二分查找,时间复杂度也是 O(logn))。 \ No newline at end of file diff --git a/Week_01/G20200343030509/001_509.java b/Week_01/G20200343030509/001_509.java new file mode 100644 index 00000000..90ed3a79 --- /dev/null +++ b/Week_01/G20200343030509/001_509.java @@ -0,0 +1,27 @@ +import java.util.HashMap; +import java.util.Map; + +/* + * @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++) { + //循环到的数字对应的解 + int key = target - nums[i]; + if (map.containsKey(key)) { + //如果解存在于map,返回解的位置和现在的位置 + return new int[]{ map.get(key), i }; + } + //把数字和位置存入哈希表 + map.put( nums[i], i); + } + throw new IllegalArgumentException("No two sum solution"); + } +} \ No newline at end of file diff --git a/Week_01/G20200343030509/015_509.java b/Week_01/G20200343030509/015_509.java new file mode 100644 index 00000000..acc1a819 --- /dev/null +++ b/Week_01/G20200343030509/015_509.java @@ -0,0 +1,67 @@ +import java.util.Arrays; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; + +/* + * @lc app=leetcode.cn id=15 lang=java + * + * [15] 三数之和 + */ + +// @lc code=start +class Solution015 { + + public static void main( String[] args) { + int[] nums = {-1, 0 , 1, 2, -1, -4}; + List> list = threeSum2(nums); + System.out.println(list); + } + + public static List> threeSum(int[] nums) { + List> list = new LinkedList<>(); + Arrays.sort(nums); + for (int i = 0; i < nums.length - 2; i++) { + if (i == 0 || (i > 0 && nums[i - 1] != nums[i])) { + int left = i + 1, right = nums.length - 1; + while (left < right) { + if (nums[i] + nums[left] + nums[right] == 0) { + list.add(Arrays.asList(nums[i], nums[left], nums[right])); + while (left < right && nums[left] == nums[left + 1]) { + left++; + } + while (left < right && nums[right] == nums[right - 1]) { + right--; + } + left++; + right--; + } else if (nums[i] + nums[left] + nums[right] > 0) { + right--; + } else { + left++; + } + } + } + } + return list; + } + + public static List> threeSum2(int[] nums) { + List> list = new LinkedList<>(); + //暴力法,时间没通过 + 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] == 0) { + List temp = Arrays.asList(nums[i], nums[j], nums[k]); + Collections.sort(temp); + if ( !list.contains(temp)) { + list.add(temp); + } + } + } + } + } + return list; + } +} \ No newline at end of file diff --git a/Week_01/G20200343030509/026_509.java b/Week_01/G20200343030509/026_509.java new file mode 100644 index 00000000..ff35b700 --- /dev/null +++ b/Week_01/G20200343030509/026_509.java @@ -0,0 +1,30 @@ +/* + * @lc app=leetcode.cn id=26 lang=java + * + * [26] 删除排序数组中的重复项 + */ + +// @lc code=start +class Solution { + public int removeDuplicates(int[] nums) { + if (nums.length < 2) { + return nums.length; + } + //快慢指针 + int pre = 0, next =1; + while(next < nums.length) { + //如果不相等 + if(nums[pre] != nums[next]) { + //并且快指针不是慢指针的下一个 + if(next - pre > 1) { + //把快指针的值赋给慢指针的下一个 + nums[pre + 1] = nums[next]; + }; + //把慢指针往后移 + pre++; + } + next++; + } + return pre + 1; + } +} \ No newline at end of file diff --git a/Week_01/G20200343030509/189_509.java b/Week_01/G20200343030509/189_509.java new file mode 100644 index 00000000..a11c5959 --- /dev/null +++ b/Week_01/G20200343030509/189_509.java @@ -0,0 +1,40 @@ +/* + * @lc app=leetcode.cn id=189 lang=java + * + * [189] 旋转数组 + */ + +// @lc code=start +class Solution { + + //三次旋转 + public void rotate(int[] nums, int 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; + start++; + end--; + } + } + + //暴力 + public void rotate2(int[] nums, int k) { + int temp, pre; + for (int i = 0; i < k; i++) { + pre = nums[nums.length - 1]; + for ( int j=0; j < nums.length; j++) { + temp = nums[j]; + nums[j] = pre; + pre = temp; + } + } + } +} \ No newline at end of file diff --git a/Week_01/G20200343030509/283_509.java b/Week_01/G20200343030509/283_509.java new file mode 100644 index 00000000..e69de29b diff --git a/Week_01/G20200343030509/deque_509.java b/Week_01/G20200343030509/deque_509.java new file mode 100644 index 00000000..137866f2 --- /dev/null +++ b/Week_01/G20200343030509/deque_509.java @@ -0,0 +1,22 @@ +import java.util.Deque; +import java.util.LinkedList; + +class deque_509 { + public static void main(String[] args) { + Deque deque = new LinkedList(); + + deque.addLast("a"); + deque.addLast("b"); + deque.addLast("c"); + System.out.println(deque); + + final String str = deque.peekLast(); + System.out.println(str); + System.out.println(deque); + + while (deque.size() > 0) { + System.out.println(deque.removeFirst()); + } + System.out.println(deque); + } +} \ No newline at end of file diff --git a/Week_01/G20200343030511/LeetCode_189(1)_511.java b/Week_01/G20200343030511/LeetCode_189(1)_511.java new file mode 100644 index 00000000..563366f1 --- /dev/null +++ b/Week_01/G20200343030511/LeetCode_189(1)_511.java @@ -0,0 +1,21 @@ +class Solution { + public void rotate(int[] nums, int k) { + if(nums==null||nums.length<=1) return; + + reverise(nums,0,nums.length-1); + reverise(nums,0,k%nums.length-1); + reverise(nums,k%nums.length,nums.length-1); + + } + + private void reverise(int[] nums, int start, int end) { + while(start0; j--) { + nums[j]=nums[j-1]; + } + nums[0]=temp; + } + } + +} \ No newline at end of file diff --git a/Week_01/G20200343030511/LeetCode_21(2)_511.java b/Week_01/G20200343030511/LeetCode_21(2)_511.java new file mode 100644 index 00000000..16678086 --- /dev/null +++ b/Week_01/G20200343030511/LeetCode_21(2)_511.java @@ -0,0 +1,28 @@ +/** + * 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 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/G20200343030511/LeetCode_21_511.java b/Week_01/G20200343030511/LeetCode_21_511.java new file mode 100644 index 00000000..15f1008d --- /dev/null +++ b/Week_01/G20200343030511/LeetCode_21_511.java @@ -0,0 +1,22 @@ +/** + * 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(l1, l2.next); + return l2; + } + } +} \ No newline at end of file diff --git a/Week_01/G20200343030511/LeetCode_26_511.java b/Week_01/G20200343030511/LeetCode_26_511.java new file mode 100644 index 00000000..074d2594 --- /dev/null +++ b/Week_01/G20200343030511/LeetCode_26_511.java @@ -0,0 +1,18 @@ +class Solution { + public int removeDuplicates(int[] nums) { + + if(nums ==null||nums.length==0) return 0; + if(nums.length==1)return 1; + + int i=1,j=1; + for (; i < nums.length; i++) { + if(nums[i]!=nums[i-1]){ + nums[j++]=nums[i]; + } + } + + + + return j; + } +} \ No newline at end of file diff --git a/Week_01/G20200343030511/LeetCode_283_511.java b/Week_01/G20200343030511/LeetCode_283_511.java new file mode 100644 index 00000000..384e7b91 --- /dev/null +++ b/Week_01/G20200343030511/LeetCode_283_511.java @@ -0,0 +1,19 @@ +class Solution { + public void moveZeroes(int[] nums) { + int i =0; + for (; i < nums.length; i++) { + if(nums[i]==0) break; + } + int j=i; + for (; j < nums.length; j++) { + if(nums[j]!=0){ + nums[i]=nums[j]; + i++; + } + } + + for (int j2 = i; j2 < nums.length; j2++) { + nums[j2]=0; + } + } +} \ No newline at end of file diff --git a/Week_01/G20200343030511/LeetCode_42(2)_511.java b/Week_01/G20200343030511/LeetCode_42(2)_511.java new file mode 100644 index 00000000..f8f0d05c --- /dev/null +++ b/Week_01/G20200343030511/LeetCode_42(2)_511.java @@ -0,0 +1,21 @@ +class Solution { + public int trap(int[] height) { + if(height==null&&height.length<=1) return 0; + int[] max_left = new int[height.length]; + int[] max_right = new int[height.length]; + for (int i = 1; i < max_left.length-1; i++) { + max_left[i] = Math.max(max_left[i-1], height[i-1]); + } + for (int i = max_right.length-2; i > 0 ; i--) { + max_right[i] = Math.max(max_right[i+1], height[i+1]); + } + int maxArea =0; + for (int i = 1; i < height.length-1; i++) { + if(height[i]>=max_left[i]||height[i]>=max_right[i]){ + continue; + } + maxArea = maxArea+ Math.min(max_left[i], max_right[i])-height[i]; + } + return maxArea; + } +} diff --git a/Week_01/G20200343030511/LeetCode_42(3)_511.java b/Week_01/G20200343030511/LeetCode_42(3)_511.java new file mode 100644 index 00000000..4c811901 --- /dev/null +++ b/Week_01/G20200343030511/LeetCode_42(3)_511.java @@ -0,0 +1,24 @@ +class Solution { + public int trap(int[] height) { + int left =1; + int right =height.length-2; + int sum =0; + int max =0; + int maxRight =0; + for (int i = 1; i < height.length-1; i++) { + if(height[left-1]height[left]){ + sum = sum +max-height[left]; + } + left++; + }else{ + maxRight =Math.max(maxRight, height[right+1]); + if(maxRight>height[right]){ + sum =sum+maxRight-height[right]; + } + right--; + } + } + return sum; + } diff --git a/Week_01/G20200343030511/LeetCode_42(4)_511.java b/Week_01/G20200343030511/LeetCode_42(4)_511.java new file mode 100644 index 00000000..311baac3 --- /dev/null +++ b/Week_01/G20200343030511/LeetCode_42(4)_511.java @@ -0,0 +1,2 @@ +class Solution { +} diff --git a/Week_01/G20200343030511/LeetCode_42_511.java b/Week_01/G20200343030511/LeetCode_42_511.java new file mode 100644 index 00000000..f226bafe --- /dev/null +++ b/Week_01/G20200343030511/LeetCode_42_511.java @@ -0,0 +1,29 @@ +class Solution { + public int trap(int[] height) { + if(height==null&&height.length<=1) return 0; + + int[] h = height; + int maxArea =0; + + for (int i = 1; i < h.length-1; i++) { + + int maxLeft =0; + int maxRight =0; + int area; + + + for (int j = 0; j < i; j++) { + maxLeft = Math.max(h[j], maxLeft); + } + for (int j = i+1; j < h.length; j++) { + maxRight =Math.max(maxRight, h[j]); + } + if(h[i]>=maxLeft||h[i]>=maxRight){ + continue; + } + area = Math.min(maxRight,maxLeft) - h[i]; + maxArea = maxArea + area; + } + return maxArea; + } + } diff --git a/Week_01/G20200343030511/LeetCode_66_511.java b/Week_01/G20200343030511/LeetCode_66_511.java new file mode 100644 index 00000000..c1f8a09a --- /dev/null +++ b/Week_01/G20200343030511/LeetCode_66_511.java @@ -0,0 +1,15 @@ +class Solution { + public int[] plusOne(int[] digits) { + for (int i = digits.length-1; i >= 0; i--) { + if(digits[i]!=9) { + digits[i]++; + return digits; + }else{ + digits[i]=0; + } + } + int[] result = new int[digits.length+1]; + result[0]=1; + return result; + } +} \ No newline at end of file diff --git a/Week_01/G20200343030511/LeetCode_88(2)_511.java b/Week_01/G20200343030511/LeetCode_88(2)_511.java new file mode 100644 index 00000000..e6b106fb --- /dev/null +++ b/Week_01/G20200343030511/LeetCode_88(2)_511.java @@ -0,0 +1,26 @@ +class Solution { + public void merge(int[] nums1, int m, int[] nums2, int n) { + if (nums1.length < nums2.length) + return ; + int[] nums3 = new int[m]; + System.arraycopy(nums1, 0, nums3, 0, m); + + int i = 0, j = 0, k = 0; + while (i < m && j < n) { + if (nums3[i] < nums2[j]) { + nums1[k++] = nums3[i]; + i++; + } else { + nums1[k++] = nums2[j]; + j++; + } + } + // ϲ + if (i < m) { + System.arraycopy(nums3, i, nums1, k, m - i); + } + if (j < n) { + System.arraycopy(nums2, j, nums1, k, n - j); + } + } +} \ No newline at end of file diff --git a/Week_01/G20200343030511/LeetCode_88_511.java b/Week_01/G20200343030511/LeetCode_88_511.java new file mode 100644 index 00000000..f69481d3 --- /dev/null +++ b/Week_01/G20200343030511/LeetCode_88_511.java @@ -0,0 +1,24 @@ +class Solution { + public void merge(int[] nums1, int m, int[] nums2, int n) { + if (nums1.length < nums2.length) + return ; + + int l =m-1; + int k= n-1; + int p =m+n-1; + + while(l>=0&&k>=0){ + if(nums1[l]= 0; i--) { + digits[i]++; + digits[i] = digits[i] % 10; + if (digits[i] !== 0) return digits; + } + digits = new Array(digits.length + 1).fill(0); + digits[0] = 1; + return digits; +}; \ No newline at end of file diff --git a/Week_01/G20200343030519/Week 01/LeetCode_88_519.js b/Week_01/G20200343030519/Week 01/LeetCode_88_519.js new file mode 100644 index 00000000..70ace586 --- /dev/null +++ b/Week_01/G20200343030519/Week 01/LeetCode_88_519.js @@ -0,0 +1,14 @@ +// https://leetcode-cn.com/problems/merge-sorted-array/ + +var merge = function(nums1, m, nums2, n) { + let len1 = m - 1; + let len2 = n - 1; + let len = m + n - 1; + while (len1 >= 0 && len2 >= 0) { + nums1[len--] = nums1[len1] > nums2[len2] ? nums1[len1--] : nums2[len2--]; + } + function arrayCopy(src, srcIndex, dest, destIndex, length) { + dest.splice(destIndex, length, ...src.slice(srcIndex, srcIndex + length)); + } + arrayCopy(nums2, 0, nums1, 0, len2 + 1); +}; \ No newline at end of file diff --git a/Week_01/G20200343030561/NOTE.md b/Week_01/G20200343030519/Week 01/NOTE.md similarity index 100% rename from Week_01/G20200343030561/NOTE.md rename to Week_01/G20200343030519/Week 01/NOTE.md diff --git a/Week_01/G20200343030523/.idea/codeStyles/Project.xml b/Week_01/G20200343030523/.idea/codeStyles/Project.xml new file mode 100644 index 00000000..565c3479 --- /dev/null +++ b/Week_01/G20200343030523/.idea/codeStyles/Project.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Week_01/G20200343030523/id_523/LeetCode_189_523.java b/Week_01/G20200343030523/id_523/LeetCode_189_523.java new file mode 100644 index 00000000..62f55e08 --- /dev/null +++ b/Week_01/G20200343030523/id_523/LeetCode_189_523.java @@ -0,0 +1,37 @@ +package array; + +/** + * https://leetcode-cn.com/problems/rotate-array/ + */ +public class RotateArray { + + public void rotate(int[] nums, int k) { + + if (nums == null || nums.length == 1 || k <= 0) { + return; + } + + k = k % nums.length; + int count = 0; + for (int start = 0; count < nums.length; start++) { + int pre = nums[start]; + int current = start; + do { + int next = (current + k) % nums.length; + int temp = nums[next]; + nums[next] = pre; + pre = temp; + current = next; + count++; + } while (start != current); + } + } + + public static void main(String[] args) { + int[] nums = new int[]{1, 2, 3, 4, 5, 6, 7}; + int k = 3; + RotateArray rotateArray = new RotateArray(); + rotateArray.rotate(nums, k); + } + +} diff --git a/Week_01/G20200343030523/id_523/LeetCode_1_523.java b/Week_01/G20200343030523/id_523/LeetCode_1_523.java new file mode 100644 index 00000000..2d8ca6c6 --- /dev/null +++ b/Week_01/G20200343030523/id_523/LeetCode_1_523.java @@ -0,0 +1,50 @@ +package hashmap; + +import java.util.HashMap; +import java.util.Map; + +/** + * https://leetcode-cn.com/problems/two-sum/ + */ +public class TwoSum { + + public int[] twoSum(int[] nums, int target) { + + if (nums == null) { + return new int[]{}; + } + + HashMap map = new HashMap<>(); + for (int i = 0; i < nums.length; i++) { + Integer existIndex = map.get(nums[i]); + if (existIndex != null) { + if (target == 2 * nums[i]) { + return new int[]{existIndex, i}; + } + } else { + map.put(nums[i], i); + } + } + + for (Map.Entry keyValue : map.entrySet()) { + Integer key = map.get(target - keyValue.getKey()); + if (key != null && !key.equals(keyValue.getValue())) { + return new int[]{keyValue.getValue(), key}; + } + } + return new int[]{}; + + } + + public static void main(String[] args) { +// int[] nums = {2, 7, 11, 15}; + int[] nums = {3, 3}; + int target = 6; + TwoSum twoSum = new TwoSum(); + int[] ret = twoSum.twoSum(nums, target); + for (int i : ret) { + System.out.println(i); + } + } + +} diff --git a/Week_01/G20200343030523/id_523/LeetCode_21_523.java b/Week_01/G20200343030523/id_523/LeetCode_21_523.java new file mode 100644 index 00000000..63213c90 --- /dev/null +++ b/Week_01/G20200343030523/id_523/LeetCode_21_523.java @@ -0,0 +1,62 @@ +package linkedlist; + +/** + * https://leetcode-cn.com/problems/merge-two-sorted-lists/ + */ +public class MergeTwoSortedLists { + + public ListNode mergeTwoLists(ListNode l1, ListNode l2) { + + ListNode head = new ListNode(0); + ListNode pos = head; + + ListNode p1 = l1; + ListNode p2 = l2; + while (p1 != null && p2 != null) { + if (p1.val <= p2.val) { + pos.next = p1; + p1 = p1.next; + } else if (p2.val < p1.val) { + pos.next = p2; + p2 = p2.next; + } + pos = pos.next; + } + + while (p1 != null) { + pos.next = p1; + pos = pos.next; + p1 = p1.next; + } + + while (p2 != null) { + pos.next = p2; + pos = pos.next; + p2 = p2.next; + } + + return head.next; + } + + public static void main(String[] args) { + ListNode node1 = new ListNode(1); + ListNode node2 = new ListNode(2); + ListNode node3 = new ListNode(4); + ListNode l1 = node1; + node1.next = node2; + node2.next = node3; + + ListNode node4 = new ListNode(1); + ListNode node5 = new ListNode(3); + ListNode node6 = new ListNode(4); + ListNode node7 = new ListNode(6); + ListNode l2 = node4; + node4.next = node5; + node5.next = node6; + node6.next = node7; + + MergeTwoSortedLists mergeTwoSortedLists = new MergeTwoSortedLists(); + ListNode l3 = mergeTwoSortedLists.mergeTwoLists(l1, null); + } + +} diff --git a/Week_01/G20200343030523/id_523/LeetCode_26_523.java b/Week_01/G20200343030523/id_523/LeetCode_26_523.java new file mode 100644 index 00000000..ab5c5a9c --- /dev/null +++ b/Week_01/G20200343030523/id_523/LeetCode_26_523.java @@ -0,0 +1,33 @@ +package array; + +/** + * https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array/ + */ +public class RemoveDuplicatesFromSortedArray { + + public int removeDuplicates(int[] nums) { + if (nums == null || 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; + } + + public static void main(String[] args) { + int[] nums = new int[]{0, 0, 1, 1, 1, 2, 2, 3, 3, 4}; + RemoveDuplicatesFromSortedArray array = new RemoveDuplicatesFromSortedArray(); + int length = array.removeDuplicates(nums); + System.out.println("length:" + length); + for (int i = 0; i < length; i++) { + System.out.print(nums[i] + " "); + } + } + +} diff --git a/Week_01/G20200343030523/id_523/LeetCode_283_523.java b/Week_01/G20200343030523/id_523/LeetCode_283_523.java new file mode 100644 index 00000000..5d54700a --- /dev/null +++ b/Week_01/G20200343030523/id_523/LeetCode_283_523.java @@ -0,0 +1,28 @@ +package array; + +/** + * https://leetcode-cn.com/problems/move-zeroes/ + */ +public class MoveZeroes01 { + + public void moveZeroes(int[] nums) { + 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 main(String[] args) { + int[] nums = new int[]{0, 1, 0, 3, 12}; + MoveZeroes01 moveZeroes = new MoveZeroes01(); + moveZeroes.moveZeroes(nums); + System.out.println(nums); + } + +} diff --git a/Week_01/G20200343030523/id_523/LeetCode_641_523_Array.java b/Week_01/G20200343030523/id_523/LeetCode_641_523_Array.java new file mode 100644 index 00000000..0b4d2716 --- /dev/null +++ b/Week_01/G20200343030523/id_523/LeetCode_641_523_Array.java @@ -0,0 +1,119 @@ +package queue; + +/** + * https://leetcode-cn.com/problems/design-circular-deque/ + */ +public class MyCircularDeque01 { + + private int[] data; + private int front; + private int tail; + private int capacity; + + /** + * Initialize your data structure here. Set the size of the deque to be k. + */ + public MyCircularDeque01(int k) { + capacity = k + 1; + data = new int[capacity]; + front = 0; + tail = 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; + } + front = (front - 1 + capacity) % capacity; + data[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()) { + return false; + } + data[tail] = value; + tail = (tail + 1 + data.length) % 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; + } + 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; + } + tail = (tail - 1 + capacity) % capacity; + return true; + } + + /** + * Get the front item from the deque. + */ + public int getFront() { + if (isEmpty()) { + return -1; + } + return data[front]; + } + + /** + * Get the last item from the deque. + */ + public int getRear() { + if (isEmpty()) { + return -1; + } + return data[(tail - 1 + capacity) % capacity]; + } + + /** + * Checks whether the circular deque is empty or not. + */ + public boolean isEmpty() { + return front == tail; + } + + /** + * Checks whether the circular deque is full or not. + */ + public boolean isFull() { + return (tail + 1) % capacity == front; + } + + + public static void main(String[] args) { + MyCircularDeque01 circularDeque = new MyCircularDeque01(3); // 设置容量大小为3 + circularDeque.insertLast(1); // 返回 true + circularDeque.insertLast(2); // 返回 true + circularDeque.insertFront(3); // 返回 true + System.out.println(circularDeque.insertFront(4)); // 已经满了,返回 false + System.out.println(circularDeque.getRear()); // 返回 2 + System.out.println(circularDeque.isFull()); // 返回 true + System.out.println(circularDeque.deleteLast()); // 返回 true + System.out.println(circularDeque.insertFront(4)); // 返回 true + System.out.println(circularDeque.getFront()); // 返回 4 + + int[] arr = new int[1000000000]; + } + +} diff --git a/Week_01/G20200343030523/id_523/LeetCode_641_523_List.java b/Week_01/G20200343030523/id_523/LeetCode_641_523_List.java new file mode 100644 index 00000000..e035bf30 --- /dev/null +++ b/Week_01/G20200343030523/id_523/LeetCode_641_523_List.java @@ -0,0 +1,150 @@ +package queue; + +/** + * https://leetcode-cn.com/problems/design-circular-deque/ + */ +public class MyCircularDeque { + + private Node head; + private Node tail; + private int capacity; + private int size; + + /** + * Initialize your data structure here. Set the size of the deque to be k. + */ + public MyCircularDeque(int k) { + this.capacity = k; + this.size = 0; + head = new Node(0); + tail = new Node(0); + head.next = tail; + tail.pre = 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; + } + size++; + Node node = new Node(value); + Node first = head.next; + node.next = first; + first.pre = node; + head.next = node; + node.pre = 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; + } + size++; + Node node = new Node(value); + Node last = tail.pre; + node.pre = last; + last.next = node; + node.next = tail; + tail.pre = node; + return true; + } + + /** + * Deletes an item from the front of Deque. Return true if the operation is successful. + */ + public boolean deleteFront() { + if (isEmpty()) { + return false; + } + + size--; + Node first = head.next; + head.next = first.next; + first.next.pre = head; + first = null; + return true; + + } + + /** + * Deletes an item from the rear of Deque. Return true if the operation is successful. + */ + public boolean deleteLast() { + if (isEmpty()) { + return false; + } + size--; + Node last = tail.pre; + last.pre.next = tail; + tail.pre = last.pre; + last = null; + 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.pre.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 == capacity; + } + + class Node { + int value; + Node next; + Node pre; + + public Node(int value) { + this.value = value; + this.next = null; + this.pre = null; + } + } + + public static void main(String[] args) { + MyCircularDeque circularDeque = new MyCircularDeque(3); // 设置容量大小为3 + circularDeque.insertLast(1); // 返回 true + circularDeque.insertLast(2); // 返回 true + circularDeque.insertFront(3); // 返回 true + System.out.println(circularDeque.insertFront(4)); // 已经满了,返回 false + System.out.println(circularDeque.getRear()); // 返回 2 + System.out.println(circularDeque.isFull()); // 返回 true + System.out.println(circularDeque.deleteLast()); // 返回 true + System.out.println(circularDeque.insertFront(4)); // 返回 true + System.out.println(circularDeque.getFront()); // 返回 4 + } + +} diff --git a/Week_01/G20200343030523/id_523/LeetCode_66_523.java b/Week_01/G20200343030523/id_523/LeetCode_66_523.java new file mode 100644 index 00000000..9b3f5b25 --- /dev/null +++ b/Week_01/G20200343030523/id_523/LeetCode_66_523.java @@ -0,0 +1,31 @@ +package array; + +/** + * https://leetcode-cn.com/problems/plus-one/ + */ +public class PlusOne01 { + + public int[] plusOne(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) { + digits = new int[digits.length + 1]; + digits[0] = 1; + } + return digits; + } + + public static void main(String[] args) { + int[] digits = new int[]{9, 9, 9}; + PlusOne01 plusOne = new PlusOne01(); + int[] res = plusOne.plusOne(digits); + } + +} diff --git a/Week_01/G20200343030523/id_523/LeetCode_88_523.java b/Week_01/G20200343030523/id_523/LeetCode_88_523.java new file mode 100644 index 00000000..f8565f26 --- /dev/null +++ b/Week_01/G20200343030523/id_523/LeetCode_88_523.java @@ -0,0 +1,40 @@ +package array; + +/** + * https://leetcode-cn.com/problems/merge-sorted-array/ + */ +public class MergeSortedArray { + + public void merge(int[] nums1, int m, int[] nums2, int n) { + + int j = m - 1; + int i = n - 1; + int pos = m + n - 1; + while (i >= 0 && j >= 0) { + if (nums2[i] >= nums1[j]) { + nums1[pos--] = nums2[i--]; + } else { + nums1[pos--] = nums1[j]; + nums1[j] = Integer.MIN_VALUE; + j--; + } + } + + while (i >= 0) { + nums1[i] = nums2[i]; + i--; + } + + } + + public static void main(String[] args) { + int[] num1 = new int[]{1, 2, 3, 0, 0, 0}; + int m = 3; + int[] num2 = new int[]{-1, 1, 2}; + int n = 3; + + MergeSortedArray mergeSortedArray = new MergeSortedArray(); + mergeSortedArray.merge(num1, m, num2, n); + } + +} diff --git a/Week_01/G20200343030527/LeetCode_26_527.java b/Week_01/G20200343030527/LeetCode_26_527.java new file mode 100644 index 00000000..294fc0e7 --- /dev/null +++ b/Week_01/G20200343030527/LeetCode_26_527.java @@ -0,0 +1,18 @@ +class LeetCode_26_527 { + public int removeDuplicates(int[] nums) { + if (nums == null || nums.length == 0) { + return 0; + } + + int i = 0; + int j = 1; + while (j < nums.length) { + if (nums[i] != nums[j]) { + nums[i + 1] = nums[j]; + i++; + } + j++; + } + return i+1; + } +} \ No newline at end of file diff --git a/Week_01/G20200343030527/LeetCode_42_527.java b/Week_01/G20200343030527/LeetCode_42_527.java new file mode 100644 index 00000000..aec78cfe --- /dev/null +++ b/Week_01/G20200343030527/LeetCode_42_527.java @@ -0,0 +1,22 @@ +class LeetCode_42_527 { + public int trap(int[]height){ + if (height == null || height.length <=2 ) { + return 0; + } + + int leftMax = 0; + int rightMax[] = new int[height.length]; + int result = 0; + for (int i = height.length - 2; i > 0; i--) { + rightMax[i] = Math.max(rightMax[i + 1], height[i + 1]); + } + for(int i = 1;i < height.length - 1; i++){ + leftMax = Math.max(leftMax, height[i - 1]); + int min = Math.min(leftMax, rightMax[i]); + if (height[i] < min) { + result += min - height[i]; + } + } + return result; + } +} \ No newline at end of file diff --git a/Week_01/G20200343030527/NOTE.md b/Week_01/G20200343030527/NOTE.md index 50de3041..dc8b8e18 100644 --- a/Week_01/G20200343030527/NOTE.md +++ b/Week_01/G20200343030527/NOTE.md @@ -1 +1,49 @@ -学习笔记 \ No newline at end of file +# 学习笔记 + +## 改写Deque +```java +class Rewrite { + 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.removeFirst); + } + System.out.println(deque); + } +} +``` + +## 学习总结 +### 五步刷题法 + 1. 第一遍 + * 5分钟:读题 思考 + * 直接看解法:多种解法,比较优劣 + * 背诵、默写好的解法 + + 2. 第二遍 + * 自己写,提交 + * 多种解法比较、体会——>优化 + + 3. 第三遍 + * 一天后,重复做题 + * 不同解法的熟练程度——专项刻意练习 + + 4. 第四遍 + * 一周后,反复回来练习相同的题目 + +### 编程思路 +1. 自顶向下编程 +2. 提提取重复部分 +3. 升维思想 + 空间换时间 + + \ No newline at end of file diff --git a/Week_01/G20200343030529/LeetCode_1_529.java b/Week_01/G20200343030529/LeetCode_1_529.java new file mode 100644 index 00000000..3f0bc464 --- /dev/null +++ b/Week_01/G20200343030529/LeetCode_1_529.java @@ -0,0 +1,28 @@ +import java.util.HashMap; + +/* + * @lc app=leetcode.cn id=1 lang=java + * + * [1] 两数之和 + */ + +// @lc code=start +class Solution { + public int[] twoSum(int[] nums, int target) { + int[] result = new int[2]; + HashMap map = new HashMap<>(); + for (int i = 0; i < nums.length; i++) { + int another = target - nums[i]; + if (map.containsKey(another)) { + result[0] = map.get(another); + result[1] = i; + return result; + } else { + map.put(nums[i], i); + } + } + return null; + } +} +// @lc code=end + diff --git a/Week_01/G20200343030529/LeetCode_26_529.java b/Week_01/G20200343030529/LeetCode_26_529.java new file mode 100644 index 00000000..c40143e5 --- /dev/null +++ b/Week_01/G20200343030529/LeetCode_26_529.java @@ -0,0 +1,52 @@ +import java.util.HashSet; + +/* + * @lc app=leetcode.cn id=26 lang=java + * + * [26] 删除排序数组中的重复项 + */ + +// @lc code=start +class Solution { + /* + * 方法一、双指针(快慢指针),新建一个同样大小的数组,找出不一样的数值,填入新数组,最后用新数组的值代替愿数组 + */ + // public int removeDuplicates(int[] nums) { + // int[] temp = new int[nums.length]; + // int size = 0; + // for (int i = 1, j = 0; i < nums.length; i++) { + // if (nums[j] != nums[i]) { + // temp[size++] = nums[j]; + // temp[size++] = nums[i]; + // j = i; + // } + // } + // for (int i = 0; i < size; i++) { + // nums[i] = temp[i]; + // } + // return size; + // } + + /* + * 方法二、双指针(快慢指针),直接在原数组修改 + */ + public int removeDuplicates(int[] nums) { + if (nums.length == 0) { + 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; + } + + public static void main(String[] args) { + Solution solution = new Solution(); + solution.removeDuplicates(new int[]{1,1,2}); + } +} +// @lc code=end + diff --git a/Week_01/G20200343030529/LeetCode_641_529.java b/Week_01/G20200343030529/LeetCode_641_529.java new file mode 100644 index 00000000..37f1d961 --- /dev/null +++ b/Week_01/G20200343030529/LeetCode_641_529.java @@ -0,0 +1,327 @@ +import java.util.LinkedList; + +/* + * @lc app=leetcode.cn id=641 lang=java + * + * [641] 设计循环双端队列 + */ + +// @lc code=start + +/* +* 方法一:采用单链表,缺点在于每次插入新value,都要new一个node。 +*/ +// class MyCircularDeque { + +// private LinkedList linkedList = new LinkedList<>(); +// private int size = 0; +// private int n = 0; + +// public MyCircularDeque(int k) { +// size = k; +// } + +// public boolean insertFront(int value) { +// if (isFull()) { +// return false; +// } +// linkedList.addFirst(value); +// n++; +// return n <= size; +// } + +// public boolean insertLast(int value) { +// if (isFull()) { +// return false; +// } +// linkedList.addLast(value); +// n++; +// return n <= size; +// } + +// public boolean deleteFront() { +// if (isEmpty()) { +// return false; +// } +// linkedList.removeFirst(); +// n--; +// return true; +// } + +// public boolean deleteLast() { +// if (isEmpty()) { +// return false; +// } +// linkedList.removeLast(); +// n--; +// return true; +// } + +// public int getFront() { +// if (isEmpty()) { +// return -1; +// } +// return linkedList.getFirst(); +// } + +// public int getRear() { +// if (isEmpty()) { +// return -1; +// } +// return linkedList.getLast(); +// } + +// public boolean isEmpty() { +// return n == 0; +// } + +// /** Checks whether the circular deque is full or not. */ +// public boolean isFull() { +// return n == size; +// } +// } + +/* +* 方法二:采用数组+双指针,一个指针为head,一个指针为tail +*/ +// class MyCircularDeque { +// private int[] array; +// private int head = 0; +// private int tail = 0; +// //队列中数据大小 +// private int n = 0; + +// public MyCircularDeque(int k) { +// array = new int[k]; +// } + +// /* +// * 向队列头插入元素,需要递增head指针,但需要处理head指针指向数组末尾情况, +// * head到达末尾,需要回到数组0位置 +// */ +// public boolean insertFront(int value) { +// if (isFull()) { +// return false; +// } +// //处理队列为空时,在array数组中0位置插入数据 +// if (n == 0) { +// array[head] = value; +// n++; +// return true; +// } +// if (head + 1 == array.length) { +// head = 0; +// } else { +// head++; +// } +// array[head] = value; +// n++; +// return true; +// } + +// /* +// * 向队列尾插入元素,需要递减tail指针,但需要处理tail指针指向数组0位置的情况, +// * tail到数组0位置,需要回到数组末尾 +// */ +// public boolean insertLast(int value) { +// if (isFull()) { +// return false; +// } +// //处理队列为空时,在array数组中0位置插入数据 +// if (n == 0) { +// array[tail] = value; +// n++; +// return true; +// } +// if (tail == 0) { +// tail = array.length - 1; +// } else { +// tail--; +// } +// array[tail] = value; +// n++; +// return true; +// } + +// /* +// * 删除队列头,head指针递减,但需要处理head指针到达数组0位置后,需要回到数组末尾 +// */ +// public boolean deleteFront() { +// if (isEmpty()) { +// return false; +// } +// n--; +// array[head] = 0; +// if (n == 0) { +// return true; +// } +// if (head == 0) { +// head = array.length - 1; +// } else { +// head--; +// } +// return true; +// } + +// /* +// * 删除队列尾,tail指针递增,但需要处理tail指针到达数组末尾位置后,需要回到数组0位置 +// */ +// public boolean deleteLast() { +// if (isEmpty()) { +// return false; +// } +// n--; +// array[tail] = 0; +// if (n == 0) { +// return true; +// } +// if (tail == array.length - 1) { +// tail = 0; +// } else { +// tail++; +// } +// return true; +// } + +// public int getFront() { +// if (isEmpty()) { +// return -1; +// } +// return array[head]; +// } + +// public int getRear() { +// if (isEmpty()) { +// return -1; +// } +// return array[tail]; +// } + +// public boolean isEmpty() { +// if (n == 0) { +// return true; +// } +// return false; +// } + +// public boolean isFull() { +// if (n == array.length) { +// return true; +// } +// return false; +// } +// } + +/* +* 方法三:采用数组+双指针,一个指针为head,一个指针为tail, +* 但数组大小为输入大小的2n+1倍,且head和tail指向(2n + 1) / 2位置, +* 即数组中间。此做法不用处理head和tail指针分别在数组两端位置的情况,缺点是空间复杂度为O(2n) +*/ +class MyCircularDeque { + private int[] array; + private int head = 0; + private int tail = 0; + private int n = 0; + private int size = 0; + + public MyCircularDeque(int k) { + size = k; + array = new int[2 * size + 1]; + head = array.length / 2; + tail = head; + } + + public boolean insertFront(int value) { + if (isFull()) { + return false; + } + if (n != 0) { + head++; + } + n++; + array[head] = value; + return true; + } + + public boolean insertLast(int value) { + if (isFull()) { + return false; + } + if (n != 0) { + tail--; + } + n++; + array[tail] = value; + return true; + } + + public boolean deleteFront() { + if (isEmpty()) { + return false; + } + array[head] = 0; + n--; + if (n != 0) { + head--; + } + return true; + } + + public boolean deleteLast() { + if (isEmpty()) { + return false; + } + array[tail] = 0; + n--; + if (n != 0) { + tail++; + } + + return true; + } + + public int getFront() { + if (isEmpty()) { + return -1; + } + return array[head]; + } + + public int getRear() { + if (isEmpty()) { + return -1; + } + return array[tail]; + } + + public boolean isEmpty() { + if (n == 0) { + return true; + } + return false; + } + + public boolean isFull() { + if (n == size) { + return true; + } + return false; + } + + public static void main(String[] args) { + MyCircularDeque obj = new MyCircularDeque(3); + boolean param_0 = obj.insertFront(3); + boolean param_1 = obj.insertFront(3); + boolean param_2 = obj.insertLast(1); + boolean param_3 = obj.insertLast(2); + boolean param_4 = obj.insertFront(4); + int param_5 = obj.getRear(); + boolean param_6 = obj.isFull(); + boolean param_7 = obj.deleteLast(); + boolean param_8 = obj.insertFront(4); + int param_9 = obj.getFront(); + + } +} + +// @lc code=end diff --git a/Week_01/G20200343030531/leetcode_189_531.go b/Week_01/G20200343030531/leetcode_189_531.go new file mode 100644 index 00000000..179c93df --- /dev/null +++ b/Week_01/G20200343030531/leetcode_189_531.go @@ -0,0 +1,120 @@ +package main + +import "fmt" + +func main() { + a := []int{1, 2, 3, 4, 5, 6 ,7} + rotate(a, 5) +} +// 暴力法 +// 太复杂了,失败,需要思考为什么这样做 +/* + 反思:1.可以从第一个开始就进行置换处理,获取最后一个进行置换 + 2.到了最后一个的时候实际上已经完成所有的置换了。 + 3.这里有个问题就是从第一个开始直接置换之前的还是等带置换最后的。 +*/ +/* +func rotate(nums []int, k int) { + for i := 0; i < k; i++ { + var temp, previous int + for j := 0; j < len(nums); j++ { + if j+1 < len(nums) { + if j == 0 { + previous = nums[0] + }else { + previous = temp + } + temp = nums[j+1] + nums[j+1] = previous + }else { + nums[0] = temp + } + + } + } +} +*/ +// 经典暴力法 +/* +func rotate(nums []int, k int) { + for i := 0; i < k; i++ { + var temp, previous int + previous = nums[len(nums) - 1] + for j := 0; j < len(nums); j++ { + temp = nums[j] + nums[j] = previous + previous = temp + } + } + fmt.Println(nums) +} +*/ +// 使用反转 +func rotate(nums []int, k int) { + k %= len(nums) + revers(&nums, 0, len(nums)-1) + fmt.Println(nums) + revers(&nums, 0, k-1) + fmt.Println(nums) + revers(&nums, k, len(nums)-1) + fmt.Println(nums) + + /* + // 全部反转 + rotateAll(&nums) + fmt.Println("第二次打印:", nums) + // 前部反转 + rotateFront(&nums, 0, k) + fmt.Println("第四次打印:", nums) + // 后部反转 + rotateBack(&nums, k, len(nums)) + fmt.Println("第六次打印:", nums) + */ +} +// 全部反转 +// 使用双指针夹逼替换 +/* +func rotateAll(nums *[]int) { + for i := 0; i < len(*nums)/2; i++ { + var temp int + temp = (*nums)[i] + (*nums)[i] = (*nums)[len(*nums)-1-i] + (*nums)[len(*nums)-1-i] = temp + } + fmt.Println("第一次打印:", *nums) +} + +// 前部反转 +func rotateFront(nums *[]int, start, end int) { + for i := 0; i < end/2; i++ { + var temp int + temp = (*nums)[i+start] + (*nums)[i+start] = (*nums)[end-i-1] + (*nums)[end-i-1] = temp + } + fmt.Println("第三次打印:", *nums) +} + +// 后部反转 +func rotateBack(nums *[]int, start, end int) { + for i := 0; i < (end-start)/2; i++ { + fmt.Println("i = ", i, "start = ", start, "end = ", end) + var temp int + temp = (*nums)[i+start] + (*nums)[i+start] = (*nums)[end-i-1] + (*nums)[end-i-1] = temp + } + fmt.Println("第五次打印:", *nums) +} +*/ +// 对照leetcode使用反转解法 +func revers(num *[]int, start, end int) { + for start < end { + var temp int + temp = (*num)[start] + (*num)[start] = (*num)[end] + (*num)[end] = temp + start++ + end-- + } +} diff --git a/Week_01/G20200343030531/leetcode_283_531.go b/Week_01/G20200343030531/leetcode_283_531.go new file mode 100644 index 00000000..872b735f --- /dev/null +++ b/Week_01/G20200343030531/leetcode_283_531.go @@ -0,0 +1,53 @@ +package main + +import ( +"fmt" +) + +func main() { + sli := []int{0, 1, 0 , 3, 12, 0, 0, 14, 4} + moveZeroes(sli) +} + +// 双指针法 +// 双指针法,快指针向前移动,慢指针指向当前0值,快指针位置是非零值, +// 则将该值移动到慢指针位置,慢指针前进一位, +// 补零操作, + +// 记录0值操作非常多余,把非零值移动到前面,插入下标以后的都是0值 +func moveZeroes(nums []int) { + var count int + slow := 0 + for quick := 0; quick < len(nums); quick++ { + if nums[quick] == 0 { + count++ + }else { + nums[slow] = nums[quick] + slow++ + } + } + for i := (len(nums) - count); i < len(nums); i++ { + nums[i] = 0 + } + fmt.Println(nums) +} + +// 该方法通过记录0值个数,将非零值前移,然后末端补零的方式实现移动 +/* +func moveZeroes(nums []int) { + + var count int + for i := 0; i < len(nums); i++ { + if nums[i] == 0 { + count++ + }else { + nums[i-count] = nums[i] + } + } + + for i := (len(nums) - count); i < len(nums); i++ { + nums[i] = 0 + } + fmt.Println(nums) +} +*/ \ No newline at end of file diff --git a/Week_01/G20200343030533/LeetCdoe_041_533.c b/Week_01/G20200343030533/LeetCdoe_041_533.c new file mode 100644 index 00000000..9723b049 --- /dev/null +++ b/Week_01/G20200343030533/LeetCdoe_041_533.c @@ -0,0 +1,111 @@ +/*接雨水 + * 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。 + * 例如[0,1,0,2,1,0,1,3,2,1,2,1], 输出6 +*/ + +//暴力法: 通过 224ms +//计算每个位置的左右最高的高度 +//然后选择两者的较小者减去本身的高度 +int trap(int* height, int heightSize){ + + int ans = 0; + + //第0个位置和最后一个位置无法接水 + for ( int i = 1; i < heightSize - 1; i++){ + int max_left = height[i]; + int max_right = height[i]; + for ( int j = i ;j >= 0; j--){ + max_left = (max_left > height[j]) ? max_left : height[j]; + } + for ( int j = i ;j < heightSize; j++){ + max_right = (max_right > height[j]) ? max_right : height[j]; + } + ans += (max_left < max_right ? max_left : max_right) - height[i]; + + } + return ans; + +} + +//空间换时间: 8ms +//两次遍历,存放给定位置的左右最大值 +int trap(int* height, int heightSize){ + if (heightSize == 0) return NULL; //特殊值 + int ans = 0; + int *max_left = malloc(sizeof(int) * heightSize); + int *max_right= malloc(sizeof(int) * heightSize); + //记录每个位置的最大左边界 + max_left[0] = height[0]; + for (int i = 1; i < heightSize; i++){ + max_left[i] = height[i] > max_left[i-1] ? height[i] : max_left[i-1]; + } + //记录每个位置的最大右边界 + max_right[heightSize-1] = height[heightSize-1]; + for (int i = heightSize-2; i >= 0; i--){ + max_right[i] = height[i] > max_right[i+1] ? height[i] : max_right[i+1]; + } + + for (int i = 1; i < heightSize - 1; i++){ + ans += (max_left[i] < max_right[i] ? max_left[i] : max_right[i]) - height[i]; + } + + free(max_left); + free(max_right); + return ans; +} + +//栈: +typedef struct { + int *arr; + int count; +} Stack; + +int peek(Stack *st){ + return st->arr[st->count-1]; +} + +void pop(Stack *st){ + st->count--; + return; +} + +void push(Stack *st, int val){ + + st->arr[st->count] = val; + st->count++; + return ; +} + +bool empty(Stack *st){ + return st->count == 0 ? true : false; +} + +int min(int a, int b){ + return a > b ? b : a; +} + +int trap(int* height, int heightSize){ + if (heightSize == 0) return NULL; + + int ans = 0, current = 0; + Stack * st = malloc(sizeof(Stack)); + st->arr = malloc(sizeof(int) * (heightSize+1)); + st->count = 0; + + while( current < heightSize){ + while( !empty(st) && height[current] > height[peek(st)]){ + int top = peek(st); + pop(st); + if ( empty(st)) break; + int distance = current - peek(st) - 1; + int bounded_height = min(height[current], height[peek(st)]) -height[top]; + ans += distance * bounded_height; + } + push(st, current++); + } + return ans; + + +} + + diff --git a/Week_01/G20200343030533/LeetCode_001_533.c b/Week_01/G20200343030533/LeetCode_001_533.c new file mode 100644 index 00000000..9deba1c0 --- /dev/null +++ b/Week_01/G20200343030533/LeetCode_001_533.c @@ -0,0 +1,51 @@ +/** + * Note: The returned array must be malloced, assume caller calls free(). + */ +/** + * Note: The returned array must be malloced, assume caller calls free(). + */ + +struct hashtable { + int key; /* key */ + int value; + UT_hash_handle hh; /* makes this structure hashable */ +}; + +void add(struct hashtable **table, int num, int idx) { + //申请一个结构存放数据 + struct hashtable *s; + s = malloc(sizeof(struct hashtable)); + s->key = num; + s->value = idx; + HASH_ADD_INT((*table), key, s ); /* id: name of key field */ +} + + +//一遍哈希法 +// 从头往后遍历,检查target - nums[i] 是否在hash表中 +// 如果不在, 以值为key,下标为value进行存放 +int* twoSum(int* nums, int numsSize, int target, int* returnSize){ + + struct hashtable *table = NULL; //新建哈希表 + struct hashtable *tmp; //用于存放找到中间结果 + *returnSize = 2; + int *res = (int*)malloc(sizeof(int) * *returnSize); + + int remain; + for(int i = 0; i < numsSize; i++){ + remain = target - nums[i]; //剩余值 + // 在表table中查找remin, 如果有结果,返回tmp + HASH_FIND_INT(table, &remain, tmp); + if ( tmp == NULL ){ + add(&table, nums[i], i); + } else { + res[1] = i; + res[0] = tmp->value; + break; + } + + } + + return res; + +} diff --git a/Week_01/G20200343030533/LeetCode_001_533.java b/Week_01/G20200343030533/LeetCode_001_533.java new file mode 100644 index 00000000..8cb14eb5 --- /dev/null +++ b/Week_01/G20200343030533/LeetCode_001_533.java @@ -0,0 +1,19 @@ +//照搬官方的解释,主要是在学习Java的map的使用 +class Solution { + publit[] twoSum(int[] nums, int target) { + // Map构建方法为Map<键类型, 值类型> 变量名 = new HashMap<>(); + Map map = new HashMap<>(); + for (int i = 0; i < nums.length; i++) { + int complement = target - nums[i]; + //查询操作, .containsKey + if (map.containsKey(complement)) { + //取值操作.get + return new int[] { map.get(complement), i }; + } + //插入操作 .put(key, value) + map.put(nums[i], i); + } + // 丢错报错throw + throw new IllegalArgumentException("No two sum solution"); + } +} diff --git a/Week_01/G20200343030533/LeetCode_001_533.py b/Week_01/G20200343030533/LeetCode_001_533.py new file mode 100644 index 00000000..47976f51 --- /dev/null +++ b/Week_01/G20200343030533/LeetCode_001_533.py @@ -0,0 +1,16 @@ +""" +Python果然简洁了很多,自带字典就是好 +""" +class Solution(object): + def twoSum(self, nums, target): + """ + :type nums: List[int] + :type target: int + :rtype: List[int] + """ + d = dict(); + for idx, val in enumerate(nums): + if (target - val ) in d: + return [idx, d[target - val]] + else: + d[ val ] = idx; diff --git a/Week_01/G20200343030533/LeetCode_021_533.c b/Week_01/G20200343030533/LeetCode_021_533.c new file mode 100644 index 00000000..064b438e --- /dev/null +++ b/Week_01/G20200343030533/LeetCode_021_533.c @@ -0,0 +1,71 @@ +/* 题目描述 + *将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 +*/ + +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * struct ListNode *next; + * }; + */ + +//第二版代码, 速度0ms, 击败100% +struct ListNode* mergeTwoLists(struct ListNode* l1, struct ListNode* l2){ + //考虑输入为NULL + if ( l1 == NULL && l2 == NULL) return NULL; + if ( l1 == NULL && l2 != NULL) return l2; + if ( l2 == NULL && l1 != NULL) return l1; + //哑节点 + struct ListNode *dummy = (struct ListNode*)malloc(sizeof(struct ListNode)); + struct ListNode *cur = dummy; + while( l1 != NULL && l2 != NULL){ + if ( l1->val > l2->val){ + cur->next = l2; + l2 = l2->next; + } else{ + cur->next = l1; + l1 = l1->next; + } + cur = cur->next; + } + cur->next = ( l1 == NULL) ? l2 : l1; + return dummy->next; + +} + + + +//第一版代码 +struct ListNode* mergeTwoLists(struct ListNode* l1, struct ListNode* l2){ + + struct ListNode *new_node, *new_head; + + if ( l1 == NULL && l2 != NULL ) return l2; + if ( l1 != NULL && l2 == NULL ) return l1; + if ( l1 == NULL && l2 == NULL ) return NULL; + + //获取第一个节点 + if ( l1->val < l2->val ){ + new_node = l1; + l1 = l1->next; + } else{ + new_node = l2; + l2 = l2->next; + } + new_head = new_node; + + while ( l1 != NULL && l2 != NULL){ + if ( l1->val < l2->val ){ + new_node->next = l1; + l1 = l1->next; + } else{ + new_node->next = l2; + l2 = l2->next; + } + new_node = new_node->next; + } + new_node->next = l1 == NULL ? l2 : l1; + return new_head; + +} diff --git a/Week_01/G20200343030533/LeetCode_026_533.c b/Week_01/G20200343030533/LeetCode_026_533.c new file mode 100644 index 00000000..8006e4b5 --- /dev/null +++ b/Week_01/G20200343030533/LeetCode_026_533.c @@ -0,0 +1,20 @@ +/* + * 解题思路,双指针法 + * 慢指针记录不重复元素的位置。 快指针遍历数组,同时和慢指针比较。如果两者不相同,就将该元素赋值到慢指针的下一个元素。 +*/ + +int removeDuplicates(int* nums, int numsSize){ + if (numsSize == 0 ) return 0; + int i = 0; + int j = 0; + for ( int i = 0; i < numsSize ; i++){ + if (nums[i] != nums[j]){ + j++; + nums[j] = nums[i]; + } + } + j++; + return j; + +} + diff --git a/Week_01/G20200343030533/LeetCode_026_533.cpp b/Week_01/G20200343030533/LeetCode_026_533.cpp new file mode 100644 index 00000000..0691d7f5 --- /dev/null +++ b/Week_01/G20200343030533/LeetCode_026_533.cpp @@ -0,0 +1,18 @@ +//思路同C, 用C++写一遍 +class Solution { +public: + int removeDuplicates(vector& nums) { + if (nums.size() == 0 ) return 0; + + int fast = 0, slow = 0; + for (; fast < nums.size(); fast++){ + if ( nums[fast] != nums[slow]){ + slow++; + nums[slow] = nums[fast]; + } + } + slow++; + return slow; + + } +}; diff --git a/Week_01/G20200343030533/LeetCode_026_533.java b/Week_01/G20200343030533/LeetCode_026_533.java new file mode 100644 index 00000000..61dc18a5 --- /dev/null +++ b/Week_01/G20200343030533/LeetCode_026_533.java @@ -0,0 +1,15 @@ +//思路同C,只不过用java写 +class Solution { + public int removeDuplicates(int[] nums) { + int j = 0; + for (int i = 0; i < nums.length; i++){ + if (nums[i] != nums[j]){ + j++; + nums[j] = nums[i]; + } + } + j++; + return j; + + } +} diff --git a/Week_01/G20200343030533/LeetCode_026_533.py b/Week_01/G20200343030533/LeetCode_026_533.py new file mode 100644 index 00000000..c22a7cfb --- /dev/null +++ b/Week_01/G20200343030533/LeetCode_026_533.py @@ -0,0 +1,20 @@ +""" +思路同C,只不过用Python写 +""" +class Solution(object): + def removeDuplicates(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + if len(nums) == 0: + return 0 + slow = 0 + fast = 0 + while fast < len(nums) : + if nums[slow] != nums[fast]: + slow += 1 + nums[slow] = nums[fast] + fast += 1 + slow += 1 + return slow diff --git a/Week_01/G20200343030533/LeetCode_066_533.c b/Week_01/G20200343030533/LeetCode_066_533.c new file mode 100644 index 00000000..4417199d --- /dev/null +++ b/Week_01/G20200343030533/LeetCode_066_533.c @@ -0,0 +1,122 @@ +// 第四次 +// 想清楚了逻辑,简化了代码 +int* plusOne(int* digits, int digitsSize, int* returnSize){ + + if (digitsSize == 0) return ; + + for ( int i = digitsSize - 1; i >= 0; i-- ){ + digits[i]++; + digits[i] = digits[i] % 10; + if (digits[i] != 0 ) { + *returnSize = digitsSize; + return digits; + } + } + + int *res = (int *)malloc(sizeof(int) * (digitsSize+1)); + res[0] = 1; + memcpy(res+1, digits, sizeof(int) * digitsSize); + *returnSize =( digitsSize + 1); + return res; + +} + +// 第三次 +// 在第二次的代码上进行优化,中间只要不进位,就可以退出 + +int* plusOne(int* digits, int digitsSize, int* returnSize){ + + if ( digitsSize == 0) return ; + + // 从后往前 + // 先算最后一位 + int sum = digits[digitsSize - 1] + 1; + digits[digitsSize-1] = sum % 10; + int carry = sum / 10; + for ( int i = digitsSize - 2; i >= 0; i--){ + sum = digits[i] + carry; + digits[i] = sum % 10; + carry = sum / 10; + if ( carry == 0 ) { + *returnSize = digitsSize ; + return digits; + } + } + + if (carry != 0 ){ + int *res = (int *)malloc(sizeof(int) * (digitsSize+1)); + res[0] = carry; + memcpy(res+1, digits, sizeof(int) * digitsSize); + *returnSize =( digitsSize + 1); + return res; + } + *returnSize = digitsSize; + return digits ; + + +} + + + +//第二次写的代码 +int* plusOne(int* digits, int digitsSize, int* returnSize){ + + if ( digitsSize == 0) return ; + + // 从后往前 + // 先算最后一位 + int sum = digits[digitsSize - 1] + 1; + digits[digitsSize-1] = sum % 10; + int carry = sum / 10; + for ( int i = digitsSize - 2; i >= 0; i--){ + sum = digits[i] + carry; + digits[i] = sum % 10; + carry = sum / 10; + } + if (carry > 0 ){ + int *res = (int *)malloc(sizeof(int) * (digitsSize+1)); + res[0] = carry; + memcpy(res+1, digits, sizeof(int) * digitsSize); + *returnSize =( digitsSize + 1); + return res; + + } + + *returnSize = digitsSize ; + return digits; + +} + +//第一次写的代码 + +int* plusOne(int* digits, int digitsSize, int* returnSize){ + + // 如果末尾小于9 + if (digits[digitsSize - 1] < 9){ + *returnSize = digitsSize; + digits[digitsSize-1]+=1; + return digits; + } + //否则要从后往前计算 + //进位 + int carry = 1; + for ( int i = digitsSize - 1; i >= 0; i--){ + if (carry){ + digits[i] += 1; + carry = 0; + } + if ( digits[i] > 9){ + digits[i] = digits[i] -10; + carry = 1; + } + } + if ( carry == 0) { + *returnSize =digitsSize; + return digits; + } + *returnSize = digitsSize + 1; + int *res = (int*)malloc( sizeof(int) * *returnSize); + res[0] = 1; + memcpy(res+1, digits, sizeof(int) * digitsSize); + return res; +} diff --git a/Week_01/G20200343030533/LeetCode_088_533.c b/Week_01/G20200343030533/LeetCode_088_533.c new file mode 100644 index 00000000..186a07b6 --- /dev/null +++ b/Week_01/G20200343030533/LeetCode_088_533.c @@ -0,0 +1,36 @@ +//方法2: 参考讨论写的代码 +//从尾往前 + +void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n){ + int len = m + n ; + for (int i = len - 1; i >= 0; i--){ + //下面这个条件语句是精髓 + //或语句前:在两个数组都没有到头时, 谁最大谁到最后 + //或语句后: 如果第二个数组结束了,那么后续只用处理第一个数组 + if ( ( m > 0 && n > 0 && nums1[m-1] > nums2[n-1] ) \ + || n == 0) { + nums1[i] = nums1[--m]; + } else{ + nums1[i] = nums2[--n]; + } + } +} + +//方法1: 先把元素加入到最后,然后排序 +//时间复杂度O(nlog n), 空间复杂度O(n) +int cmp(const void *a, const void *b){ + return *(int*)a - *(int*)b; +} + +void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n){ + + int i = m; + int j = 0; + while ( j < nums2Size){ + nums1[i] = nums2[j]; + i++; + j++; + } + qsort(nums1, m+n, sizeof(int), cmp); + return nums1; +} diff --git a/Week_01/G20200343030533/LeetCode_155_533.c b/Week_01/G20200343030533/LeetCode_155_533.c new file mode 100644 index 00000000..6f014b70 --- /dev/null +++ b/Week_01/G20200343030533/LeetCode_155_533.c @@ -0,0 +1,102 @@ +#define STACKSZIE 100 +typedef struct { + int *arr; + int count; + int size; +} Stack; + +typedef struct { + Stack *data; + Stack *helper; + +} MinStack; + +/** initialize your data structure here. */ + +MinStack* minStackCreate() { + + MinStack *obj = (MinStack *)malloc(sizeof(MinStack)); + // 使用数组作为栈, 大小固定 + obj->data = (Stack *)malloc(sizeof(Stack)); + obj->data->arr = (int *)malloc(sizeof(int) * STACKSZIE); + obj->data->size = STACKSZIE; + obj->data->count = 0; + + obj->helper = (Stack *)malloc(sizeof(Stack)); + obj->helper->arr = (int *)malloc(sizeof(int) * STACKSZIE); + obj->helper->size = STACKSZIE; + obj->helper->count = 0; + + return obj; + +} + +void minStackPush(MinStack* obj, int x) { + + //辅助栈为空 + if ( obj->helper->count == 0 ){ + obj->helper->arr[obj->helper->count] = x; + obj->helper->count++; + } else { + //判断新增的元素是否小于等于辅助栈的顶部元素 + if ( x <= obj->helper->arr[obj->helper->count-1] ){ + obj->helper->arr[obj->helper->count] = x; + obj->helper->count++; + } + } + + obj->data->arr[obj->data->count] = x; + obj->data->count++; + +} + +void minStackPop(MinStack* obj) { + //检查是否为空 + if ( obj->data->count == 0 ) return ; + + //检查数据栈和辅助栈是否相同 + int x = obj->data->arr[obj->data->count-1]; + int y = obj->helper->arr[obj->helper->count-1]; + + if ( x == y) { + obj->helper->count--; + } + + obj->data->count--; + +} + +int minStackTop(MinStack* obj) { + + return obj->data->arr[obj->data->count-1]; + +} + +int minStackGetMin(MinStack* obj) { + + return obj->helper->arr[obj->helper->count-1]; + +} + +void minStackFree(MinStack* obj) { + + free(obj->data->arr); + free(obj->data); + free(obj->helper->arr); + free(obj->helper); + free(obj); +} + +/** + * Your MinStack struct will be instantiated and called as such: + * MinStack* obj = minStackCreate(); + * minStackPush(obj, x); + + * minStackPop(obj); + + * int param_3 = minStackTop(obj); + + * int param_4 = minStackGetMin(obj); + + * minStackFree(obj); +*/ diff --git a/Week_01/G20200343030533/LeetCode_189_533.c b/Week_01/G20200343030533/LeetCode_189_533.c new file mode 100644 index 00000000..963d9305 --- /dev/null +++ b/Week_01/G20200343030533/LeetCode_189_533.c @@ -0,0 +1,39 @@ +//方法2: 3次反转 +void rotate(int* nums, int numsSize, int k){ + k = k % numsSize; + // 第一次反转 + int tmp; + for (int i = 0 ; i < numsSize / 2; i++){ + tmp = nums[i]; + nums[i] = nums[numsSize-i-1]; + nums[numsSize-i-1] = tmp; + } + //第二次反转 + for (int i = 0 ; i < k / 2; i++){ + tmp = nums[i]; + nums[i] = nums[k-i-1]; + nums[k-i-1] = tmp; + } + //第三次反转 + for (int i = k ; i < (numsSize + k ) >> 1; i++){ + tmp = nums[i]; + nums[i] = nums[numsSize-i+k-1]; + nums[numsSize-i+k-1] = tmp; + } +} +//方法1: 非原地算法 +void rotate(int* nums, int numsSize, int k){ + + k = k % numsSize; + + int *arr = (int *)malloc( sizeof(int) * numsSize); + + //移动后k个元素 + memcpy(arr, nums+(numsSize-k), sizeof(int) * k); + //移动前numsSize-k个元素 + memcpy(arr+k, nums, sizeof(int) * (numsSize -k)); + + memcpy(nums, arr, sizeof(int) * numsSize); + free(arr); + +} diff --git a/Week_01/G20200343030533/LeetCode_283_533.c b/Week_01/G20200343030533/LeetCode_283_533.c new file mode 100644 index 00000000..930a5940 --- /dev/null +++ b/Week_01/G20200343030533/LeetCode_283_533.c @@ -0,0 +1,13 @@ +void moveZeroes(int* nums, int numsSize){ + if (numsSize == 0 ) return; + int i, j = 0; + for ( i = 0 ; i < numsSize; i++){ + if (nums[i] != 0){ + if (i != j){ + nums[j] = nums[i]; + nums[i] = 0; + } + j++; + } + } +} diff --git a/Week_01/G20200343030533/LeetCode_283_533.java b/Week_01/G20200343030533/LeetCode_283_533.java new file mode 100644 index 00000000..a02fdbfc --- /dev/null +++ b/Week_01/G20200343030533/LeetCode_283_533.java @@ -0,0 +1,15 @@ +class Solution { + public void moveZeroes(int[] nums) { + 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/G20200343030533/LeetCode_641_533.c b/Week_01/G20200343030533/LeetCode_641_533.c new file mode 100644 index 00000000..8963529c --- /dev/null +++ b/Week_01/G20200343030533/LeetCode_641_533.c @@ -0,0 +1,140 @@ +/* https://leetcode-cn.com/problems/design-circular-deque +设计实现双端队列。你的实现需要支持以下操作: + + - MyCircularDeque(k):构造函数,双端队列的大小为k。 + - insertFront():将一个元素添加到双端队列头部。 如果操作成功返回 true。 + - insertLast():将一个元素添加到双端队列尾部。如果操作成功返回 true。 + - deleteFront():从双端队列头部删除一个元素。 如果操作成功返回 true。 + - deleteLast():从双端队列尾部删除一个元素。如果操作成功返回 true。 + - getFront():从双端队列头部获得一个元素。如果双端队列为空,返回 -1。 + - getRear():获得双端队列的最后一个元素。 如果双端队列为空,返回 -1。 + - isEmpty():检查双端队列是否为空。 + - isFull():检查双端队列是否满了。 +*/ + +//代码思路参考了 https://leetcode-cn.com/problems/design-circular-deque/solution/shu-zu-shi-xian-de-xun-huan-shuang-duan-dui-lie-by/ + +typedef struct { + int *arr; + int head; + int tail; + int size; + +} MyCircularDeque; + +/** Initialize your data structure here. Set the size of the deque to be k. */ +bool myCircularDequeIsFull(MyCircularDeque* obj); +bool myCircularDequeIsEmpty(MyCircularDeque* obj); +MyCircularDeque* myCircularDequeCreate(int k) { + + MyCircularDeque *obj = malloc(sizeof(MyCircularDeque) * (k+1)); + obj->arr = malloc(sizeof(int) * (k+1)); + obj->head = 0; + obj->tail = 0; + obj->size = k + 1; + return obj; + +} + +/** Adds an item at the front of Deque. Return true if the operation is successful. */ +bool myCircularDequeInsertFront(MyCircularDeque* obj, int value) { + + if ( myCircularDequeIsFull(obj)) return false; + + int pos = (obj->head+obj->size-1) % obj->size; + obj->arr[pos] = value; + obj->head = pos; + return true; + + +} + +/** Adds an item at the rear of Deque. Return true if the operation is successful. */ +bool myCircularDequeInsertLast(MyCircularDeque* obj, int value) { + if ( myCircularDequeIsFull(obj)) return false; + + obj->arr[obj->tail] = value; + obj->tail = (obj->tail+1) % obj->size; + + return true; + +} + +/** Deletes an item from the front of Deque. Return true if the operation is successful. */ +bool myCircularDequeDeleteFront(MyCircularDeque* obj) { + if ( myCircularDequeIsEmpty(obj)) return false; + + obj->head = (obj->head+1) % obj->size; + return true; + +} + +/** Deletes an item from the rear of Deque. Return true if the operation is successful. */ +bool myCircularDequeDeleteLast(MyCircularDeque* obj) { + if ( myCircularDequeIsEmpty(obj)) return false; + + obj->tail = (obj->tail-1+obj->size) % obj->size; + return true; +} + +/** Get the front item from the deque. */ +int myCircularDequeGetFront(MyCircularDeque* obj) { + if ( myCircularDequeIsEmpty(obj) ) return -1; + + return obj->arr[obj->head]; + +} + +/** Get the last item from the deque. */ +int myCircularDequeGetRear(MyCircularDeque* obj) { + if ( myCircularDequeIsEmpty(obj) ) return -1; + + int pos = (obj->tail+obj->size-1) % obj->size; + + return obj->arr[pos]; + + +} + +/** Checks whether the circular deque is empty or not. */ +bool myCircularDequeIsEmpty(MyCircularDeque* obj) { + + return (obj->head == obj->tail) ? true : false; + +} + +/** Checks whether the circular deque is full or not. */ +bool myCircularDequeIsFull(MyCircularDeque* obj) { + + return (obj->head == (obj->tail+1) % obj->size) ? true : false; + +} + +void myCircularDequeFree(MyCircularDeque* obj) { + free(obj->arr); + free(obj); + return ; + +} + +/** + * Your MyCircularDeque struct will be instantiated and called as such: + * MyCircularDeque* obj = myCircularDequeCreate(k); + * bool param_1 = myCircularDequeInsertFront(obj, value); + + * bool param_2 = myCircularDequeInsertLast(obj, value); + + * bool param_3 = myCircularDequeDeleteFront(obj); + + * bool param_4 = myCircularDequeDeleteLast(obj); + + * int param_5 = myCircularDequeGetFront(obj); + + * int param_6 = myCircularDequeGetRear(obj); + + * bool param_7 = myCircularDequeIsEmpty(obj); + + * bool param_8 = myCircularDequeIsFull(obj); + + * myCircularDequeFree(obj); +*/ diff --git a/Week_01/G20200343030535/LeetCode_11_535.java b/Week_01/G20200343030535/LeetCode_11_535.java new file mode 100644 index 00000000..e7c5497d --- /dev/null +++ b/Week_01/G20200343030535/LeetCode_11_535.java @@ -0,0 +1,58 @@ +package leetcode.Week01; + +public class LeetCode_11_535 { + + /*** + *给定 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 + * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + */ + /** + * 思路1:暴力法 time : o(n^2) + * 思路2:双指针法 time : o(n) + */ + + public static int maxArea1(int[] height) { + /**1.排除掉i * i*/ + int maxAreas = 0; + for (int i = 0; i < height.length - 1; i++) { + for (int j = i + 1; j < height.length; j++) { + int area = (j - i) * Math.min(height[i],height[j]); + maxAreas = Math.max(area,maxAreas); + } + } + return maxAreas; + } + + public static int maxArea2(int[] height) { + int maxAreas = 0; + int p1 = 0; /**p1表示头指针*/ + int p2 = height.length - 1; /**p2表示尾指针*/ + while (p1 < p2){ + int minHeight = height[p1] <= height[p2] ? height[p1++] : height[p2--]; + int area = (p2 - p1 + 1) * minHeight; /**为何加1:数组下标从0开始,坐标从1开始*/ + maxAreas = Math.max(maxAreas,area); + } + return maxAreas; + } + + public static void main(String[] args) { + int[] A = {1,8,6,2,5,4,8,3,7}; + System.out.println("最大的面积为:" + maxArea2(A)); + } +} diff --git a/Week_01/G20200343030535/LeetCode_141_535.java b/Week_01/G20200343030535/LeetCode_141_535.java new file mode 100644 index 00000000..6b8d67d3 --- /dev/null +++ b/Week_01/G20200343030535/LeetCode_141_535.java @@ -0,0 +1,73 @@ +package leetcode.Week01; + +import java.util.HashSet; +import java.util.Set; + +public class LeetCode_141_535 { + + /** + * 给定一个链表,判断链表中是否有环。 + * + * 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。 + * + *   + * + * 来源:力扣(LeetCode) + * 链接:https://leetcode-cn.com/problems/linked-list-cycle + * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + */ + + class ListNode { + int val; + ListNode next; + ListNode(int x) { + val = x; + next = null; + } + } + + /** + * 思路1:暴力法 时间复杂度o(n),空间复杂度o(n) + * 记录下来你访问过的所有节点,把它记录到set/hash里面 + * 那么,再新访问的元素有没有之前出现在set/hash里面, + * 表示我又走回到了原来的老节点去了, + * 那就说明有环了 + * 思路2:快慢指针 时间复杂度o(n),空间复杂度o(1) + * + */ + public boolean hasCycle1(ListNode head) { + Set nodesSeen = new HashSet<>(); + while (head != null){ + if (nodesSeen.contains(head)){ + return true; + }else { + nodesSeen.add(head); + } + head = head.next; + } + return false; + } + + public boolean hasCycle2(ListNode head) { + if (head == null || head.next == null){ + return false; + } + ListNode slow = head; + ListNode fast = head.next; + while (slow != fast){ + /**分成2种情况: + * 1.快指针是尾节点的情况,则判断fast.next=null + * 2.快指针走2步就是空指针的情况,则判断fast=null + * */ + if (fast == null || fast.next == null){ + return false; + } + slow = slow.next; + /**快指针每次走2步*/ + fast = fast.next.next; + } + return true; + } + + +} diff --git a/Week_01/G20200343030535/LeetCode_155_535.java b/Week_01/G20200343030535/LeetCode_155_535.java new file mode 100644 index 00000000..8adef07d --- /dev/null +++ b/Week_01/G20200343030535/LeetCode_155_535.java @@ -0,0 +1,32 @@ +package leetcode.Week01; + +public class LeetCode_155_535 { + + /** + * 最小栈: + * 设计一个支持 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. + * + * 来源:力扣(LeetCode) + * 链接:https://leetcode-cn.com/problems/min-stack + * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + */ + + + /** initialize your data structure here. */ + +} diff --git a/Week_01/G20200343030535/LeetCode_15_535.java b/Week_01/G20200343030535/LeetCode_15_535.java new file mode 100644 index 00000000..deedec19 --- /dev/null +++ b/Week_01/G20200343030535/LeetCode_15_535.java @@ -0,0 +1,104 @@ +package leetcode.Week01; + +import java.util.*; +import java.util.stream.Collectors; + +public class LeetCode_15_535 { + + /** + * 给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组。 + * + * 注意:答案中不可以包含重复的三元组。 + * + *   + * + * 示例: + * + * 给定数组 nums = [-1, 0, 1, 2, -1, -4], + * + * 满足要求的三元组集合为: + * [ + * [-1, 0, 1], + * [-1, -1, 2] + * ] + * + * 来源:力扣(LeetCode) + * 链接:https://leetcode-cn.com/problems/3sum + * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + */ + + /** + * 思路1:暴力法 + * 思路2:哈希法 a+b+c=0,转换成 a+b = -c + * 思路3:双指针(左右下标往中间推进): + * 双指针法铺垫: 先将给定 nums 排序,复杂度为O(NlogN) + * 双指针法思路: 固定3 个指针中最左(最小)数字的指针 k,双指针 i,j 分设在数组索引(k,len(nums)) + * (k,len(nums)) 两端,通过双指针交替向中间移动,记录对于每个固定指针 k 的所有满足 nums[k] + nums[i] + nums[j] == 0 的 i,j 组合: + * 当 nums[k] > 0 时直接break跳出:因为 nums[j] >= nums[i] >= nums[k] > 0,即3 个数字都大于0 ,在此固定指针 k 之后不可能再找到结果了。 + * 当 k > 0且nums[k] == nums[k - 1]时即跳过此元素nums[k]:因为已经将 nums[k - 1] 的所有组合加入到结果中,本次双指针搜索只会得到重复组合。 + * i,j 分设在数组索引(k,len(nums)) + * (k,len(nums)) 两端,当i < j时循环计算s = nums[k] + nums[i] + nums[j],并按照以下规则执行双指针移动: + * 当s < 0时,i += 1并跳过所有重复的nums[i]; + * 当s > 0时,j -= 1并跳过所有重复的nums[j]; + * 当s == 0时,记录组合[k, i, j]至res,执行i += 1和j -= 1并跳过所有重复的nums[i]和nums[j],防止记录到重复组合。 + */ + /** + * 遇到这个题目的话:将暴力法和哈希法和双指针法都概述一次,并且能写出如下的方法,那么的话基本ok了 + */ + + /**暴力法:*/ + public static List> threeSum1(int[] nums) { + /**先排序*/ + Arrays.sort(nums); + List> dataList = new ArrayList<>(); + for (int i = 0; i < nums.length; i++) { + for (int j = i + 1; j < nums.length; j++) { + for (int k = j + 1; k < nums.length; k++) { + if (nums[i] + nums[j] + nums[k] == 0){ + dataList.add(new ArrayList<>(Arrays.asList(nums[i],nums[j],nums[k]))); + } + } + } + } + return dataList.stream().distinct().collect(Collectors.toList()); + } + + /**双指针(左右下标往中间推进):*/ + public static List> threeSum3(int[] nums) { + List> result = new ArrayList<>(); + /**这里的前置++(--)和后置++(--)的效果是一样的,前置*/ + /**先排序*/ + Arrays.sort(nums); + for (int k = 0; k <= nums.length - 3; k++) { /**k表示:-c的下标的位置*/ + if (nums[k] > 0) { break; } + if (k > 0 && nums[k] == nums[k - 1]) { continue; } + int i = k + 1; /**除了k的下标的位置开始的头指针*/ + int j = nums.length - 1; /**尾指针*/ + while (i < j) { + int sum = nums[i] + nums[j] + nums[k]; + if (sum < 0) { + while (i < j && nums[i] == nums[++i]); /**移动下标*/ + } else if (sum > 0) { + while (i < j && nums[j] == nums[--j]); + } else { + result.add(new ArrayList<>(Arrays.asList(nums[k],nums[i],nums[j]))); + while (i < j && nums[i] == nums[++i]) ; + while (i < j && nums[j] == nums[--j]) ; + } + } + } + return result; + } + + public static void main(String[] args) { + int[] A = {-1, 0, 1, 2, -1, -4}; + List> dataList = threeSum1(A); + for (List integers : dataList) { + for (Integer integer : integers) { + System.out.print(integer + ","); + } + System.out.println(); + } + + } +} diff --git a/Week_01/G20200343030535/LeetCode_1_535.java b/Week_01/G20200343030535/LeetCode_1_535.java new file mode 100644 index 00000000..116b2391 --- /dev/null +++ b/Week_01/G20200343030535/LeetCode_1_535.java @@ -0,0 +1,68 @@ +package leetcode.Week01; + +import java.util.HashMap; +import java.util.Map; + +public class LeetCode_1_535 { + /** + * 给定一个整数数组 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 + * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + */ + /** + * 思路1: 暴力法 time : o(n^2) + * 思路2: 哈希法 time : o(n) + */ + + public static int[] twoSum1(int[] nums, int target) { + int[] indexValue = new int[2]; + for (int i = 0; i < nums.length; i++) { + for (int j = i + 1; j < nums.length; j++) { + if (nums[i] + nums[j] == target){ + indexValue[0] = i; + indexValue[1] = j; + break; + } + } + } + return indexValue; + } + + public static int[] twoSum2(int[] nums, int target) { + Map map = new HashMap<>(); + for (int i = 0; i < nums.length; i++) { + /**原因是题目的限定条件:你不能重复利用这个数组中同样的元素。 + * 利用map的key是唯一的,将数组进行去重 + * */ + int value = target - nums[i]; + if (map.containsKey(value)){ + return new int[]{i,map.get(value)}; + } + map.put(nums[i],i); + } + return null; + } + + + public static void main(String[] args) { + int[] A = {2, 7, 11, 15}; + int target = 9; + int[] result = twoSum2(A,target); + System.out.println("符合条件的的下标是:"); + for (int i = 0; i < result.length; i++) { + System.out.print(i + ","); + } + } + +} diff --git a/Week_01/G20200343030535/LeetCode_206_535.java b/Week_01/G20200343030535/LeetCode_206_535.java new file mode 100644 index 00000000..6dd215b9 --- /dev/null +++ b/Week_01/G20200343030535/LeetCode_206_535.java @@ -0,0 +1,50 @@ +package leetcode.Week01; + +import java.util.List; + +public class LeetCode_206_535 { + + /** + * 反转一个单链表。 + * + * 示例: + * + * 输入: 1->2->3->4->5->NULL + * 输出: 5->4->3->2->1->NULL + */ + class ListNode { + int val; + ListNode next; + ListNode(int x) { val = x; } + } + + /** + * 多new了一个节点 + */ + public ListNode reverseList1(ListNode head) { + ListNode pre = new ListNode(-1); + while (head != null){ + /**保存pre后面的指针*/ + ListNode temNode = pre.next; + pre.next = new ListNode(head.val); + pre.next.next = temNode; + head = head.next; + } + return pre.next; + } + + /** + * 操作都是指针操作 + */ + public ListNode reverseList2(ListNode head) { + ListNode prev = null; + ListNode curr = head; + while (curr != null){ + ListNode tempNode = curr.next; + curr.next = prev; + prev = curr; + curr = tempNode; + } + return prev; + } +} diff --git a/Week_01/G20200343030535/LeetCode_20_535.java b/Week_01/G20200343030535/LeetCode_20_535.java new file mode 100644 index 00000000..62b4ccb2 --- /dev/null +++ b/Week_01/G20200343030535/LeetCode_20_535.java @@ -0,0 +1,106 @@ +package leetcode.Week01; + +import java.util.HashMap; +import java.util.Stack; + +public class LeetCode_20_535 { + /** + * 题目: 有效的括号问题 + *给定一个只包括 '(',')','{','}','[',']' 的字符串,判断字符串是否有效。 + * + * 有效字符串需满足: + * + * 左括号必须用相同类型的右括号闭合。 + * 左括号必须以正确的顺序闭合。 + * 注意空字符串可被认为是有效字符串。 + * + * 示例 1: + * + * 输入: "()" + * 输出: true + * 示例 2: + * + * 输入: "()[]{}" + * 输出: true + * 示例 3: + * + * 输入: "(]" + * 输出: false + * 示例 4: + * + * 输入: "([)]" + * 输出: false + * 示例 5: + * + * 输入: "{[]}" + * 输出: true + * + * 来源:力扣(LeetCode) + * 链接:https://leetcode-cn.com/problems/valid-parentheses + * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + */ + + /** + * 思路1:暴力法 不断地replace匹配的括号->"" + * //a.()[]{} 只需要扫一次 + * //b.(({[]}))) 最多要扫n^2 + * 时间复杂度为 o(n^2) + * 思路2:栈 + * 什么样的问题可以使用栈来解决呢?洋葱型 + * 具有所谓的最近相关性的问题 + * (从外到内,从内到外,逐渐扩散,而且最外层和最内层是一对) + */ + + /** + * 技巧性 + */ + public boolean isValid1(String s) { + Stack stack = new Stack<>(); + for (char c : s.toCharArray()){ + /**遇到左括号的处理*/ + if (c == '{'){ + stack.push('}'); + }else if (c == '('){ + stack.push(')'); + }else if (c == '['){ + stack.push(']'); + }else if (stack.empty() || stack.pop() != c){ + /**遇到右括号的处理**/ + /**如果存储右括号栈为空:说明没有右括号和c进行匹配了 + * 如果存储右括号栈顶元素没有和c能够匹配的,说明是无效的括号 + * */ + return false; + } + } + /** + * 如果字符串中的元素已经遍历完成,存储右括号的栈为空,则是有效的字符串。 + * 如果栈不为空,则是无效的字符串 + */ + return stack.empty(); + } + + private HashMap mappings; + + public LeetCode_20_535(){ + this.mappings = new HashMap<>(); + this.mappings.put(')','('); + this.mappings.put('}','{'); + this.mappings.put(']','['); + } + + public boolean isValid2(String s) { + Stack stack = new Stack<>(); + for (int i = 0; i < s.length(); i++) { + char c = s.charAt(i); + if (this.mappings.containsKey(c)){ + char topElement = stack.empty() ? '#' : stack.pop(); + if (topElement != this.mappings.get(c));{ + return false; + } + }else { + stack.push(c); + } + } + return stack.isEmpty(); + } +} diff --git a/Week_01/G20200343030535/LeetCode_24_535.java b/Week_01/G20200343030535/LeetCode_24_535.java new file mode 100644 index 00000000..3cb70786 --- /dev/null +++ b/Week_01/G20200343030535/LeetCode_24_535.java @@ -0,0 +1,32 @@ +package leetcode.Week01; + +public class LeetCode_24_535 { + + /** + * 题目:两两交换链表中的节点 + * 给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。 + * + * 你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。 + * + *   + * + * 示例: + * + * 给定 1->2->3->4, 你应该返回 2->1->4->3. + * + * 来源:力扣(LeetCode) + * 链接:https://leetcode-cn.com/problems/swap-nodes-in-pairs + * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + */ + + class ListNode { + int val; + ListNode next; + ListNode(int x) { val = x; } + } + + public ListNode swapPairs(ListNode head) { + + return null; + } +} diff --git a/Week_01/G20200343030535/LeetCode_283_535.java b/Week_01/G20200343030535/LeetCode_283_535.java new file mode 100644 index 00000000..b182a030 --- /dev/null +++ b/Week_01/G20200343030535/LeetCode_283_535.java @@ -0,0 +1,94 @@ +package leetcode.Week01; + +public class LeetCode_283_535 { + + /** + * + * 给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。 + * + * 示例: + * + * 输入: [0,1,0,3,12] + * 输出: [1,3,12,0,0] + * 说明: + * + * 必须在原数组上操作,不能拷贝额外的数组。 + * 尽量减少操作次数。 + * + * 来源:力扣(LeetCode) + * 链接:https://leetcode-cn.com/problems/move-zeroes + * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + */ + + /** + * 思路1:暴力法 o(n^2) + * 思路2:双指针法 o(n) + */ + + + public static void moveZeroes(int[] nums) { + int p1 = 0; /**用来表示移动的下标的位置*/ + int p2 = 0; /**用来表示要添加的下标的位置*/ + while (p1 < nums.length){ + if (nums[p1] != 0){ + /**当p1和p2相同的时候,就算本身和本身替换了,也没有关系,但是问题在于是否赋值为0的情况,当值不为0的时候,如果把值替换成0的话,就出问题了*/ + nums[p2] = nums[p1]; + if (p1 != p2) { + nums[p1] = 0; + } + p2++; + } + p1++; + } + } + + + public static void moveZeroes3(int[] nums) { + int[] A = new int[nums.length]; + int maxIndex = nums.length - 1; + int minIndex = 0; + for (int i = 0; i < nums.length; i++) { + if (nums[i] == 0){ + A[maxIndex] = nums[i]; + maxIndex--; + }else { + A[minIndex] = nums[i]; + minIndex++; + } + } + } + + public static void moveZeroes2(int[] nums) { + int snowBallSize = 0; + for (int i = 0; i < nums.length; i++) { + if (nums[i] == 0){ + snowBallSize++; + }else if (snowBallSize > 0){ + int t = nums[i]; + nums[i] = 0; + nums[i - snowBallSize] = t; + } + } + } + + public static void moveZeroes1(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++; + } + } + } + + public static void main(String[] args) { + int[] A = {0,1,0,3,12}; + moveZeroes(A); + for (int i = 0; i < A.length; i++) { + System.out.print(A[i] + ","); + } + } + +} diff --git a/Week_01/G20200343030535/LeetCode_70_535.java b/Week_01/G20200343030535/LeetCode_70_535.java new file mode 100644 index 00000000..1d32ded6 --- /dev/null +++ b/Week_01/G20200343030535/LeetCode_70_535.java @@ -0,0 +1,83 @@ +package leetcode.Week01; + +public class LeetCode_70_535 { + /** + * 假设你正在爬楼梯。需要 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 阶 + * + * 来源:力扣(LeetCode) + * 链接:https://leetcode-cn.com/problems/climbing-stairs + * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + */ + + /*** + * 是否能暴力 + * 具体情况 + * 找重复性 + */ + + public static int climbStairs1(int n) { + /**递归方法:*/ + if (n == 1 || n == 0) {return 1;} + else { + return climbStairs1(n - 1) + climbStairs1(n - 2); + } + } + + /** + * 思路:斐波那契数 + */ + + public static int climbStairs2(int n) { + if (n == 1){return 1;} + if (n == 2){return 2;} + int fn = 0; + int f1 = 1; + int f2 = 2; + for (int i = 3; i <= n; i++) { + fn = f1 + f2; + f1 = f2; + f2 = fn; + } + return fn; + } + public static int climbStairs3(int N) { + if(N == 0){ return 0;} + if(N == 1){return 1;} + int fn = 0; + int f0 = 0; + int f1 = 1; + for(int i = 2; i <= N; i++){ + fn = f0 + f1; + f0 = f1; + f1 = fn; + } + return fn; + } + + + + public static void main(String[] args) { + int n = 3; + System.out.println("有多少种爬楼梯:" + climbStairs3(n)); + } +} diff --git a/Week_01/G20200343030535/LeetCode_84_535.java b/Week_01/G20200343030535/LeetCode_84_535.java new file mode 100644 index 00000000..2e4a439c --- /dev/null +++ b/Week_01/G20200343030535/LeetCode_84_535.java @@ -0,0 +1,5 @@ +package leetcode.Week01; + +public class LeetCode_84_535 { + +} diff --git "a/Week_01/G20200343030537/1.\344\270\244\346\225\260\344\271\213\345\222\214.py" "b/Week_01/G20200343030537/1.\344\270\244\346\225\260\344\271\213\345\222\214.py" new file mode 100644 index 00000000..67fae69a --- /dev/null +++ "b/Week_01/G20200343030537/1.\344\270\244\346\225\260\344\271\213\345\222\214.py" @@ -0,0 +1,19 @@ +# +# @lc app=leetcode id=1 lang=python3 +# +# [1] Two Sum +# +from typing import List +# @lc code=start +class Solution: + def twoSum(self, nums: List[int], target: int) -> List[int]: + if len(nums) <= 1: + return False + hashmap = {} + for i, num in enumerate(nums): + if num in hashmap: + return [hashmap[num], i] + else: + hashmap[target - num] = i +# @lc code=end + diff --git "a/Week_01/G20200343030537/283.\347\247\273\345\212\250\351\233\266.py" "b/Week_01/G20200343030537/283.\347\247\273\345\212\250\351\233\266.py" new file mode 100644 index 00000000..c1c703dc --- /dev/null +++ "b/Week_01/G20200343030537/283.\347\247\273\345\212\250\351\233\266.py" @@ -0,0 +1,20 @@ +# +# @lc app=leetcode.cn id=283 lang=python3 +# +# [283] 移动零 +# +from typing import List +# @lc code=start +class Solution: + def moveZeroes(self, nums: List[int]) -> None: + """ + Do not return anything, modify nums in-place instead. + """ + lastNonZeroFoundAt = 0 + for i in range(len(nums)): + if nums[i] != 0 : + nums[lastNonZeroFoundAt], nums[i] = nums[i] , nums[lastNonZeroFoundAt] + lastNonZeroFoundAt=lastNonZeroFoundAt+1 + +# @lc code=end + diff --git a/Week_01/G20200343030541/LeetCode_1_541.java b/Week_01/G20200343030541/LeetCode_1_541.java new file mode 100644 index 00000000..f95bbafa --- /dev/null +++ b/Week_01/G20200343030541/LeetCode_1_541.java @@ -0,0 +1,37 @@ +import java.util.HashMap; +import java.util.Map; + +public class LeetCode_1_541 { + public int[] twoSumSolution1(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}; + } + } + } + throw new IllegalArgumentException("No two sum solution"); + } + + public int[] twoSumSolution2(int[] nums, int target) { + Map map = new HashMap<>(); + for(int i=0; i < nums.length; i++) { + int remaining = target - nums[i]; + if (map.containsKey(remaining)) { + return new int[] {map.get(remaining), i}; + } + map.put(nums[i], i); + } + throw new IllegalArgumentException("No two sum solution"); + } + + public static void main(String[] args) { + LeetCode_1_541 test = new LeetCode_1_541(); + int[] nums = {1,2,3,4,5,6}; + int target = 3; + int[] result = test.twoSumSolution2(nums, target); + for (int aResult : result) { + System.out.println(aResult); + } + } +} diff --git a/Week_01/G20200343030541/LeetCode_283_089.java b/Week_01/G20200343030541/LeetCode_283_089.java new file mode 100644 index 00000000..c2ee4633 --- /dev/null +++ b/Week_01/G20200343030541/LeetCode_283_089.java @@ -0,0 +1,29 @@ +public class LeetCode_283_089 { + // 两次遍历解法 + public void solution1(int[] nums) { + int visited = 0; + // 移动非零元素 + for (int i =0; i < nums.length; ++i) { + if(nums[i] != 0) { + nums[visited++] = nums[i]; + } + } + // 将剩余空间填充为0 + for (int i=visited; i < nums.length; ++i) { + nums[i] = 0; + } + } + + // 一次遍历 + public void solution2(int[] nums) { + int pivot = 0; + for (int i=0; i < nums.length; i++) { + if (nums[i] != 0) { + int temp = nums[i]; + nums[i] = nums[pivot]; + nums[pivot++] = temp; + } + } + } + +} diff --git a/Week_01/G20200343030543/LeetCode_283_543.java b/Week_01/G20200343030543/LeetCode_283_543.java new file mode 100644 index 00000000..5fac0596 --- /dev/null +++ b/Week_01/G20200343030543/LeetCode_283_543.java @@ -0,0 +1,16 @@ +class Solution { + public void moveZeroes(int[] nums) { + if(nums == null || nums.length == 0){ + return; + } + int index = 0; + for(int num : nums){ + if(num != 0){ + nums[index++] = num; + } + } + while(index < nums.length){ + nums[index++] = 0; + } + } +} \ No newline at end of file diff --git a/Week_01/G20200343030543/LeetCode_641_543.java b/Week_01/G20200343030543/LeetCode_641_543.java new file mode 100644 index 00000000..544312af --- /dev/null +++ b/Week_01/G20200343030543/LeetCode_641_543.java @@ -0,0 +1,78 @@ +class MyCircularDeque { + private int capacity; + private int[] array; + private int front; + private int rear; + + /** Initialize your data structure here. Set the size of the deque to be k. */ + public MyCircularDeque(int k) { + capacity = k + 1; + array = new int[capacity]; + front = 0; + rear = 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; + } + front = (front - 1 + capacity) % capacity; + array[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()){ + return false; + } + array[rear] = value; + rear = (rear + 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; + } + front = (front + 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; + } + rear = (rear - 1 + capacity) % capacity; + return true; + } + + /** Get the front item from the deque. */ + public int getFront() { + if(isEmpty()){ + return -1; + } + return array[front]; + } + + /** Get the last item from the deque. */ + public int getRear() { + if(isEmpty()){ + return -1; + } + return array[(rear - 1 + capacity) % capacity]; + } + + /** Checks whether the circular deque is empty or not. */ + public boolean isEmpty() { + return rear == front; + } + + /** Checks whether the circular deque is full or not. */ + public boolean isFull() { + return (rear + 1) % capacity == front; + } +} diff --git a/Week_01/G20200343030543/MyDeque.java b/Week_01/G20200343030543/MyDeque.java new file mode 100644 index 00000000..d30c9267 --- /dev/null +++ b/Week_01/G20200343030543/MyDeque.java @@ -0,0 +1,14 @@ + Deque deque = new LinkedList<>(); + deque.addFirst("a"); + deque.addLast("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.pollFirst()); + } + System.out.println(deque); diff --git a/Week_01/G20200343030543/NOTE.md b/Week_01/G20200343030543/NOTE.md index 50de3041..bf374d60 100644 --- a/Week_01/G20200343030543/NOTE.md +++ b/Week_01/G20200343030543/NOTE.md @@ -1 +1,2 @@ -学习笔记 \ No newline at end of file +学习笔记 +进度有点跟不上 \ No newline at end of file diff --git "a/Week_01/G20200343030543/\345\210\206\346\236\220 Queue \345\222\214 Priority Queue \347\232\204\346\272\220\347\240\201" "b/Week_01/G20200343030543/\345\210\206\346\236\220 Queue \345\222\214 Priority Queue \347\232\204\346\272\220\347\240\201" new file mode 100644 index 00000000..0fff625e --- /dev/null +++ "b/Week_01/G20200343030543/\345\210\206\346\236\220 Queue \345\222\214 Priority Queue \347\232\204\346\272\220\347\240\201" @@ -0,0 +1,2 @@ +java中的Queue是个接口,Priority实现了Queue接口。 +Priority优先队列底层实现是堆,插入需要维护元素的权值 \ No newline at end of file diff --git a/Week_01/G20200343030545/LeetCode_01_545.py b/Week_01/G20200343030545/LeetCode_01_545.py new file mode 100644 index 00000000..006479e9 --- /dev/null +++ b/Week_01/G20200343030545/LeetCode_01_545.py @@ -0,0 +1,47 @@ +""" + 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。 + 你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。 + + 示例: + 给定 nums = [2, 7, 11, 15], target = 9 + 因为 nums[0] + nums[1] = 2 + 7 = 9 + 所以返回 [0, 1] +""" +from typing import List + + +class Solution: + def twoSum(self, nums: List[int], target: int) -> List[int]: + return self.use_hash(nums, target) + + @classmethod + def directly(cls, nums: List[int], target: int) -> List[int]: + """ + 暴力求解法 + 两层循环嵌套,外层循环从0到n,内层循环从1到n + 时间复杂度O(n^2),空间复杂度O(1) + """ + for i in range(len(nums)): + for j in range(1, len(nums)): + if nums[i] + nums[j] == target and i != j: + return [i, j] + + @classmethod + def use_hash(cls, nums: List[int], target: int) -> List[int]: + """ + 使用一个字典关系存储元素和下标的对应关系。 + 从头开始遍历数组,每次遍历时,以当前遍历的元素为num1,通过target计算num2。 + 判断num2是否在字典中,如果在返回当前遍历的index,以及nums2的index,不在就将当前元素的值和下标存入字典中。 + 时间复杂度是O(n),空间复杂度是O(n) + """ + hash_map = dict() + for index, row in enumerate(nums): + other_row = target - row + + if other_row in hash_map: + return [hash_map[other_row], index] + hash_map[row] = index + + +if __name__ == '__main__': + pass diff --git a/Week_01/G20200343030545/LeetCode_11_545.py b/Week_01/G20200343030545/LeetCode_11_545.py new file mode 100644 index 00000000..11401ce7 --- /dev/null +++ b/Week_01/G20200343030545/LeetCode_11_545.py @@ -0,0 +1,62 @@ +""" + 给定 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 +""" + +from typing import List + + +class Solution: + def maxArea(self, height: List[int]) -> int: + pass + + @classmethod + def directly(cls, height: List[int]) -> int: + """ + 暴力求解法 + 两层循环 + 第一层循环从0开始到n-1 + 第二层循环从第一层循环的下标+1开始到n + 时间负载度O(n^2),空间复杂度是O(1) + """ + res = 0 + for i in range(len(height) - 1): + for j in range(i + 1, len(height)): + width = min(height[i], height[j]) + + length = j - i + res = max(res, (width * length)) + return res + + @classmethod + def double_pointer(cls, height: List[int]) -> int: + """ + 双指针解法: + 一个指针从头,一个指针从尾,每次循环计算之间的面积,然后比较双指针所在下标的值的大小。 + 哪个小哪个移动。头指针小 头指针+1 尾指针小 尾指针-1 + 时间复杂度O(n),空间复杂度是O(1) + """ + res = 0 + + i = 0 + j = len(height) - 1 + + while i < j: + length = j - i + width = min(height[j], height[i]) + + res = max(res, length * width) + + if height[j] > height[i]: + i += 1 + else: + j -= 1 + + return res diff --git a/Week_01/G20200343030545/LeetCode_141_545.py b/Week_01/G20200343030545/LeetCode_141_545.py new file mode 100644 index 00000000..0d030878 --- /dev/null +++ b/Week_01/G20200343030545/LeetCode_141_545.py @@ -0,0 +1,67 @@ +""" + 给定一个链表,判断链表中是否有环。 + 为了表示给定链表中的环,我们使用整数 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 + 解释:链表中没有环。 +""" + + +class ListNode: + def __init__(self, x): + self.val = x + self.next = None + + +class Solution: + def hasCycle(self, head: ListNode) -> bool: + return self.double_pointer(head) + + @classmethod + def use_hash(cls, head: ListNode) -> bool: + """ + 依次遍历链表,每次遍历的时候判断该节点是否存在于hash表中。 + 如果存在则证明链表有环,反之将节点存入到hash表中。 + 时间复杂度O(n),空间复杂度O(n) + """ + hash_map = {} + while head and head.next: + if head in hash_map: + return True + hash_map[head] = 0 + head = head.next + return False + + @classmethod + def double_pointer(cls, head: ListNode) -> bool: + """ + 快慢指针循环遍历,当快指针等于慢指针的时候,则说明有环。 + 时间复杂度O(n),空间复杂度O(1) + """ + if not (head and head.next): + return False + + slow_node = head.next + fast_node = head.next.next + + while fast_node and fast_node.next: + if slow_node == fast_node: + return True + + slow_node = slow_node.next + fast_node = fast_node.next.next + + return False diff --git a/Week_01/G20200343030545/LeetCode_142_545.py b/Week_01/G20200343030545/LeetCode_142_545.py new file mode 100644 index 00000000..57b08bb0 --- /dev/null +++ b/Week_01/G20200343030545/LeetCode_142_545.py @@ -0,0 +1,79 @@ +""" + 给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。 + 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 + 如果 pos 是 -1,则在该链表中没有环。 + 说明:不允许修改给定的链表。 + + 示例 1: + 输入:head = [3,2,0,-4], pos = 1 + 输出:tail connects to node index 1 + 解释:链表中有一个环,其尾部连接到第二个节点。 + + 示例 2: + 输入:head = [1,2], pos = 0 + 输出:tail connects to node index 0 + 解释:链表中有一个环,其尾部连接到第一个节点。 + + 示例 3: + 输入:head = [1], pos = -1 + 输出:no cycle + 解释:链表中没有环。 +""" + + +class ListNode: + def __init__(self, x): + self.val = x + self.next = None + + +class Solution: + def detectCycle(self, head: ListNode) -> ListNode: + return self.use_hash(head) + + @classmethod + def use_hash(cls, head: ListNode) -> ListNode: + """ + 使用hash表保存每个节点的值,在保存之前判断一下如果该节点已经存在则说明已经有环,返回该节点即可。 + 时间复杂度O(n),空间复杂度O(n) + """ + if not (head and head.next): + return head + + res = None + hash_map = {} + while head and head.next: + if head in hash_map: + return head + hash_map[head] = 0 + head = head.next + + return res + + @classmethod + def floyd(cls, head: ListNode) -> ListNode: + res = None + + if not (head and head.next): + return res + + fast_node = head.next.next + slow_node = head.next + check_node = None + + # 找出快慢节点交汇的节点 + while fast_node and fast_node.next: + if slow_node == fast_node: + check_node = fast_node + break + fast_node = fast_node.next.next + slow_node = slow_node.next + + # 如果check_code,则说明链表有环。 + if check_node: + root_node = head + while check_node != root_node: + check_node = check_node.next + root_node = root_node.next + res = check_node + return res diff --git a/Week_01/G20200343030545/LeetCode_155_545.py b/Week_01/G20200343030545/LeetCode_155_545.py new file mode 100644 index 00000000..f604a3ef --- /dev/null +++ b/Week_01/G20200343030545/LeetCode_155_545.py @@ -0,0 +1,66 @@ +""" + 设计一个支持 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. +""" + + +class MinStack: + + def __init__(self): + """ + initialize your data structure here. + """ + self.__ori_stack = [] + self.__min_stack = [] + + def empty(self) -> bool: + return not bool(self.__ori_stack) + + def push(self, x: int) -> None: + self.__ori_stack.append(x) + if self.__min_stack: + + # 这个if else是重点。 + if self.__min_stack[-1] > x: + # 如果最小栈的站定元素比新值大, 压栈 + self.__min_stack.append(x) + else: + # 反之 将最小栈的栈顶元素再压到最小栈,这样做的好吃时,出栈时不用考虑那么多,直接出就行 + self.__min_stack.append(self.__min_stack[-1]) + else: + self.__min_stack.append(x) + + def pop(self) -> None: + if not self.empty(): + self.__ori_stack.pop() + self.__min_stack.pop() + + def top(self) -> int: + if not self.empty(): + return self.__ori_stack[-1] + raise + + def getMin(self) -> int: + if not self.empty(): + return self.__min_stack[-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() diff --git a/Week_01/G20200343030545/LeetCode_15_545.py b/Week_01/G20200343030545/LeetCode_15_545.py new file mode 100644 index 00000000..65f6faa7 --- /dev/null +++ b/Week_01/G20200343030545/LeetCode_15_545.py @@ -0,0 +1,74 @@ +""" + 给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c , + 使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组。 + + 注意:答案中不可以包含重复的三元组。 + + 示例: + 给定数组 nums = [-1, 0, 1, 2, -1, -4], + 满足要求的三元组集合为: + [ + [-1, 0, 1], + [-1, -1, 2] + ] +""" + +from typing import List + + +class Solution: + def threeSum(self, nums: List[int]) -> List[List[int]]: + return self.three_pointer_loop(nums) + + @classmethod + def three_pointer_loop(cls, nums: List[int]) -> List[List[int]]: + """ + 先将列表进行排序,用python自带的sort就行。 + 用三个指针处理。两层循环,外层循环的遍历列表,内层循环是对第二个和第三个指针进行移位比较操作。 + + 第一个指针从头开始遍历列表。 + 第二个指针每次的初始位置都是第一个指针的下标+1 + 第三个指针每次的初始位置都是列表的最后一个元素。 + 跳出循环的条件是: + 1、循环遍历完成 + 2、有下标对应的值大于0。 + 时间复杂度是O(n^2),空间复杂度是O(1) + """ + + res = [] + + nums.sort() + + for index in range(len(nums)): + start_index = index + 1 + end_index = len(nums) - 1 + + if nums[index] > 0: + return res + + if index > 0 and nums[index] == nums[index - 1]: + continue + + while end_index > start_index: + check_sum = nums[index] + nums[start_index] + nums[end_index] + + if check_sum == 0: + res.append([nums[index], nums[start_index], nums[end_index]]) + + while end_index > start_index and nums[start_index] == nums[start_index + 1]: + start_index += 1 + + while end_index > start_index and nums[end_index] == nums[end_index - 1]: + end_index -= 1 + + start_index += 1 + end_index -= 1 + elif nums[end_index] > check_sum: + end_index -= 1 + else: + start_index += 1 + return res + + +if __name__ == '__main__': + print(Solution.directly([-1, 0, 1, 2, -1, -4])) diff --git a/Week_01/G20200343030545/LeetCode_189_545.py b/Week_01/G20200343030545/LeetCode_189_545.py new file mode 100644 index 00000000..bae55b8c --- /dev/null +++ b/Week_01/G20200343030545/LeetCode_189_545.py @@ -0,0 +1,114 @@ +""" + 给定一个数组,将数组中的元素向右移动 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) 的 原地 算法。 +""" +from typing import List + + +class Solution: + def rotate(self, nums: List[int], k: int) -> None: + """ + Do not return anything, modify nums in-place instead. + """ + return self.ring(nums, k) + + @classmethod + def directly(cls, nums: List[int], k: int) -> None: + """ + 暴力求解法 + 外层循环k次,内存循环从头到尾依此交换数据 + 时间复杂度是O(n*k),空间复杂度是O(1) + """ + for i in range(k): + value = nums[-1] + for j in range(len(nums)): + nums[j], value = value, nums[j] + + @classmethod + def reverse(cls, nums: List[int], k: int) -> None: + """ + 三次反转 + 根据 split_point = k%len(nums) 将数组分成两段。 + 第一段: 反转列表下标在这个[0, nums_len - split_point - 1]区间内的值。 + 第二段: 反转列表下标在这个[nums_len-split, nums-1]区间内的值。 + 第一次反转 反转第一段数据。 + 第二次反转 反转第二段数据。 + 然后整体再反转一次。 + + 例如 [1, 2, 3, 4, 5, 6, 7] k =3 + 第一段 列表下标区间在[0,3],即是nums[0],nums[1],nums[2],nums[3]的值。反转后是[4, 3, 2, 1, 5, 6, 7] + 第二段 列表下标区间在[4,6],即是nums[4],nums[5],nums[6]的值。反转后是[4, 3, 2, 1, 7, 6, 5] + 然后整体反转[5, 6, 7, 1, 2, 3, 4] + 时间复杂度是O(n),空间复杂度是O(1)。 + """ + nums_len = len(nums) + split_point = k % nums_len + + def swap(left, right): + while left < right: + nums[left], nums[right] = nums[right], nums[left] + left += 1 + right -= 1 + + swap(0, nums_len - split_point - 1) + swap(nums_len - split_point, nums_len - 1) + swap(0, nums_len - 1) + + @classmethod + def ring(cls, nums: List[int], k: int) -> None: + """ + 环状替换 + 从0开始循环,当0大于等于数组长度的时候或者移动次数等于整个数组长度的时候终止循环 + """ + + # FIXME 看了官方的题解后研究了两个小时,Zzz~ + nums_len = len(nums) + k = k % nums_len + + move_times = i = 0 # 定义初始的指针位置 以及循环次数 + while i < len(nums): + new_i = (i + k) % nums_len # 计算出当前下标的新位置 + v = nums[i] # 存储当前位置的值 + + while True: + old_v = nums[new_i] # 存储当前下标的新位置的原始值 + nums[new_i] = v # 更新新位置的值 + v = old_v + new_i = (new_i + k) % nums_len # 计算新位置原始值的插入下标 + move_times += 1 # 移动次数加1 + if new_i == i: # 当新位置的下标等于外层循环指针的值的时候说明这次更新后,外层循环指针的值要移动了 + nums[new_i] = v # 但是移动前要把外层循环下标的值更新 + move_times += 1 + break + i += 1 + + if move_times == nums_len: + break + + +if __name__ == '__main__': + params_1 = [1, 2, 3, 4, 5, 6] + params_2 = [1, 2, 3, 4, 5, 6] + Solution.reverse(params_1, 21) + Solution.ring(params_2, 21) + + print(params_1) + print(params_2) diff --git a/Week_01/G20200343030545/LeetCode_206_545.py b/Week_01/G20200343030545/LeetCode_206_545.py new file mode 100644 index 00000000..fd5f2de7 --- /dev/null +++ b/Week_01/G20200343030545/LeetCode_206_545.py @@ -0,0 +1,60 @@ +""" + 反转一个单链表。 + + 示例: + 输入: 1->2->3->4->5->NULL + 输出: 5->4->3->2->1->NULL +""" + + +class ListNode(object): + def __init__(self, x): + self.val = x + self.next = None + + +class Solution(object): + def reverseList(self, head): + pass + + @classmethod + def recursive(cls, head): + """ + 递归的方法: + 找到最后一个节点,然后依此往回归纳更新。 + 时间复杂度:O(n),空间复杂度O(n) + """ + if head is None or head.next is None: + return head + + new_head = cls.recursive(head.next) + head.next.next = head + head.next = None + return new_head + + @classmethod + def loop(cls, head): + """ + 循环判断: + 5->4->3-2-1 + + loop1: 5->4->3->2->1 4->3->2->1 5 + loop2: 4->3->2->1 3->2->1 4->5 + loop3: 3->2->1 2->1 3->4->5 + loop4: 2->1 1 2->3->4->5 + loop5: 1 None 1->2->3->4->5 + + 时间复杂度O(n),空间复杂度O(1) + + """ + if not head or head.next is None: + return head + + prev = None + while head: + tmp_node = head.next + + head.next = prev + + prev, head = head, tmp_node + return prev diff --git a/Week_01/G20200343030545/LeetCode_20_545.py b/Week_01/G20200343030545/LeetCode_20_545.py new file mode 100644 index 00000000..52866973 --- /dev/null +++ b/Week_01/G20200343030545/LeetCode_20_545.py @@ -0,0 +1,82 @@ +""" + 给定一个只包括 '(',')','{','}','[',']' 的字符串,判断字符串是否有效。 + + 有效字符串需满足: + 左括号必须用相同类型的右括号闭合。 + 左括号必须以正确的顺序闭合。 + 注意空字符串可被认为是有效字符串。 + + 示例 1: + 输入: "()" + 输出: true + + 示例 2: + 输入: "()[]{}" + 输出: true + + 示例 3: + 输入: "(]" + 输出: false + + 示例 4: + 输入: "([)]" + 输出: false + + 示例 5: + 输入: "{[]}" + 输出: true +""" + + +class Solution: + def isValid(self, s: str) -> bool: + return self.use_stack(s) + + @classmethod + def use_stack(cls, s: str) -> bool: + """ + 运用栈这种数据结构 + 依次遍历字符串入栈。 + 当字符属于右括号时,弹出站定元素,比较弹出的内容和此时遍历的内容。如果有效循环这个操作,如果无效则直接返回非False + 当字符属于左括号时,压栈。 + 循环结束判断栈里是否还有元素,如果有则返回False, 无返回True + + 有一个小技巧:就是可以先判断字符串的长度,如果长度是奇数,则肯定不是有效的。 + 时间复杂度O(n),空间复杂度O(n) + """ + + s_len = len(s) + + if s_len % 2 != 0: # 奇数为肯定不符合要求 + return False + + stack = [] + for info in s: + if info in ("]", "}", ")"): + if not stack: + return False + ori_info = stack.pop() + if cls.check_valid(ori_info, info): + continue + else: + return False + else: + stack.append(info) + return True if not stack else False + + @classmethod + def check_valid(cls, info: str, check_info: str) -> bool: + if info == "[" and check_info == "]": + res = True + elif info == "{" and check_info == "}": + res = True + elif info == "(" and check_info == ")": + res = True + else: + res = False + + return res + + +if __name__ == '__main__': + print(Solution.use_stack("(]")) diff --git a/Week_01/G20200343030545/LeetCode_21_545.py b/Week_01/G20200343030545/LeetCode_21_545.py new file mode 100644 index 00000000..a83ee306 --- /dev/null +++ b/Week_01/G20200343030545/LeetCode_21_545.py @@ -0,0 +1,73 @@ +""" + 将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。  + + 示例: + 输入:1->2->4, 1->3->4 + 输出:1->1->2->3->4->4 +""" + + +class ListNode: + def __init__(self, x): + self.val = x + self.next = None + + +class Solution: + def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode: + return self.loop(l1, l2) + + @classmethod + def recursive(cls, l1: ListNode, l2: ListNode) -> ListNode: + """ + 递归处理 + l1.val > l2.val merge(l2.next, l1) + l1.val < l2.val merge(l1.next, l2) + + 引用网友R.D的一段话: + "每次都把最小值压入栈,最后出栈的时候,将所有数连在一起就可以了。 + 说白了,就是用一个栈维护了顺序。最后的连接,当然是小的连小的,所以l1 小, + 就连到 l1,l2 小就连到 l2,最后先返回的,就是最小的头结点。 + + 时间复杂度O(m+n),空间复杂度O(m+n) + """ + + if not (l1 and l2): + return l1 or l2 + elif l1.val < l2.val: + l1.next = cls.recursive(l1.next, l2) + return l1 + else: + l2.next = cls.recursive(l1, l2.next) + return l2 + + @classmethod + def loop(cls, l1: ListNode, l2: ListNode) -> ListNode: + """ + 迭代遍历:当两个链表都有值的时候,比较对应的val,更新节点信息。 + 迭代结束后,判断两个链表是否有剩余的节点,然后添加进去 + 时间复杂度是O(n+m),空间复杂度是O(1) + """ + root = ListNode(-1) + + prev = root + + while l1 and l2: + if l1.val > l2.val: + prev.next = l2 + l2 = l2.next + else: + prev.next = l1 + l1 = l1.next + + prev = prev.next + + prev.next = l1 or l2 + + return root.next + + +if __name__ == '__main__': + node1 = ListNode(1) + node2 = None + Solution.loop(node1, node2) diff --git a/Week_01/G20200343030545/LeetCode_239_545.py b/Week_01/G20200343030545/LeetCode_239_545.py new file mode 100644 index 00000000..84fcb66f --- /dev/null +++ b/Week_01/G20200343030545/LeetCode_239_545.py @@ -0,0 +1,53 @@ +""" + 给定一个数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。 + 你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。 + 返回滑动窗口中的最大值。 + + 示例: + 输入: nums = [1,3,-1,-3,5,3,6,7], 和 k = 3 + 输出: [3,3,5,5,6,7] + + 解释: + 滑动窗口的位置 最大值 + --------------- ----- + [1 3 -1] -3 5 3 6 7 3 + 1 [3 -1 -3] 5 3 6 7 3 + 1 3 [-1 -3 5] 3 6 7 5 + 1 3 -1 [-3 5 3] 6 7 5 + 1 3 -1 -3 [5 3 6] 7 6 + 1 3 -1 -3 5 [3 6 7] 7 + + 提示: + 你可以假设 k 总是有效的,在输入数组不为空的情况下,1 ≤ k ≤ 输入数组的大小。 +""" +from typing import List + + +class Solution: + def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]: + return self.directly(nums, k) + + @classmethod + def directly(cls, nums: List[int], k: int) -> List[int]: + """ + 暴力求解法 + 外层循环控制列表元素的遍历 + 内层循环控制 k个数的循环 + 时间复杂度O(n*k),空间复杂度O(n-k+1) + """ + res = [] + for i in range(len(nums)): + max_value = float("-inf") + for j in range(i, k + i): + max_value = max(nums[j], max_value) + res.append(max_value) + if i == len(nums) - k: + break + return res + + +if __name__ == '__main__': + params = [1, 3, -1, -3, 5, 3, 6, 7] + num = 3 + + print(Solution.directly(params, num)) diff --git a/Week_01/G20200343030545/LeetCode_24_545.py b/Week_01/G20200343030545/LeetCode_24_545.py new file mode 100644 index 00000000..b44efd12 --- /dev/null +++ b/Week_01/G20200343030545/LeetCode_24_545.py @@ -0,0 +1,58 @@ +""" + 给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。 + 你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。 + + 示例: + 给定 1->2->3->4, 你应该返回 2->1->4->3. +""" + + +class ListNode: + def __init__(self, x): + self.val = x + self.next = None + + +class Solution: + def swapPairs(self, head: ListNode) -> ListNode: + return self.loop(head) + + @classmethod + def recursive(cls, head: ListNode) -> ListNode: + """ + 递归更新每两个点的链表形态。 + 时间复杂度:O(N),N 指的是链表的节点数量。 + 空间复杂度:O(N),递归过程使用的堆栈空间。 + """ + if not (head and head.next): + return head + + next_node = head.next + head.next = cls.recursive(head.next.next) + next_node.next = head + return next_node + + @classmethod + def loop(cls, head: ListNode) -> ListNode: + """ + 循环遍历 + 单独设置一个前驱节点,方便 + 时间复杂度是O(n),空间复杂度是O(1) + """ + root = ListNode(-1) + root.next = head + + prev = root + + while head and head.next: + first_node = head + second_node = head.next + + prev.next = second_node + first_node.next = second_node.next + second_node.next = first_node + + head = first_node.next + prev = first_node + + return root.next diff --git a/Week_01/G20200343030545/LeetCode_25_545.py b/Week_01/G20200343030545/LeetCode_25_545.py new file mode 100644 index 00000000..4a2d0567 --- /dev/null +++ b/Week_01/G20200343030545/LeetCode_25_545.py @@ -0,0 +1,69 @@ +""" + 给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表。 + k 是一个正整数,它的值小于或等于链表的长度。 + 如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。 + + 示例: + 给定这个链表:1->2->3->4->5 + 当 k = 2 时,应当返回: 2->1->4->3->5 + 当 k = 3 时,应当返回: 3->2->1->4->5 + 说明: + 你的算法只能使用常数的额外空间。 + 你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。 +""" + + +class ListNode: + def __init__(self, x): + self.val = x + self.next = None + + +class Solution: + def reverseKGroup(self, head: ListNode, k: int) -> ListNode: + return self.loop(head, k) + + @classmethod + def loop(cls, head: ListNode, k: int) -> ListNode: + + # FIXME 还没做完 + total_count = cls.find_node_count(head) + stop_times = total_count - (total_count % k) + + prev_node = head + total_loop_times = 0 + + while True: + tmp_k = k + + next_node = None + while prev_node: + + prev_node = prev_node.next + tmp_k -= 1 + + if tmp_k == 0: + # 说明在这个节点停止 + prev_node = prev_node.next + + if total_loop_times == stop_times: + break + + @classmethod + def find_node_count(cls, head: ListNode) -> int: + res = 0 + while head: + head = head.next + res += 1 + return res + + @classmethod + def reverse_node(cls, head: ListNode) -> ListNode: + prev_node = None + while head: + next_node = head.next + head.next = prev_node + prev_node = head + head = next_node + + return prev_node diff --git a/Week_01/G20200343030545/LeetCode_26_545.py b/Week_01/G20200343030545/LeetCode_26_545.py new file mode 100644 index 00000000..2eedf073 --- /dev/null +++ b/Week_01/G20200343030545/LeetCode_26_545.py @@ -0,0 +1,49 @@ +""" + 给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。 + 不要使用额外的数组空间,你必须在原地修改输入数组并在使用 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。 + + 不需要考虑数组中超出新长度后面的元素。 +""" +from typing import List + + +class Solution: + def removeDuplicates(self, nums: List[int]) -> int: + return self.double_pointer(nums) + + @classmethod + def double_pointer(cls, nums: List[int]) -> int: + """ + 双指针(快慢指针)方法 + + i 代表慢指针 初始从0开始。 + j 代表快指针 初始从1开始。 + 从j开始依此遍历列表,快指针和慢指针上的数据做比较。如果相等则慢指针不动,反之慢指针加1,然后将快指针所在位置的值赋给慢指针的所在位置上。 + + 例如:[1, 1, 2, 2, 3, 3] i=0, j=1 + loop1 nums[1]==nums[0] i不动 + loop2 nums[2]!=nums[0] 先将i+=1,i变为1。再将j的值赋给i,即nums[1]=nums[2],列表中的元素变为[1,2,2,2,3,3] + loop3 nums[3]==nums[1] i不动 + loop4 nums[4]!=nums[1] 先将i+=1,i变为2。再将j的值赋给i,即nums[2]=nums[4],列表中的元素变为[1,2,2,2,3,3] + loop5 nums[5]==nums[0] i不动 + 循环结束,但是i是从0开始的,所以计算列表长度的时候需要返回i+1。 + 整体的时间复杂度是O(n),空间复杂度是O(1)。 + """ + i = 0 + for index in range(1, len(nums)): + if nums[index] != nums[i]: + i += 1 + nums[i] = nums[index] + return i + 1 + + +if __name__ == '__main__': + print(Solution.double_pointer([1, 2, 3, 4, 5, 5, 5, 5])) diff --git a/Week_01/G20200343030545/LeetCode_283_545.py b/Week_01/G20200343030545/LeetCode_283_545.py new file mode 100644 index 00000000..8b5de664 --- /dev/null +++ b/Week_01/G20200343030545/LeetCode_283_545.py @@ -0,0 +1,40 @@ +""" + 给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。 + + 示例: + 输入: [0,1,0,3,12] + 输出: [1,3,12,0,0] + 说明: + 必须在原数组上操作,不能拷贝额外的数组。 + 尽量减少操作次数。 +""" +from typing import List + + +class Solution: + + def moveZeroes(self, nums: List[int]) -> None: + """ + Do not return anything, modify nums in-place instead. + """ + return self.double_pointer_and_swap(nums) + + @classmethod + def double_pointer_and_swap(cls, nums) -> None: + """ + 双指针并且交换数据: + 初始化一个变量j,从头开始循环nums,如果对应的值不是0,则交换i和j的值,并且j+=1。 + + 例如: [1, 2, 0 ,0 , 2] + loop1: [1, 2, 0, 0, 2] j=0 循环完后j=1 + loop2: [1, 2, 0, 0, 2] j=1 循环完后j=2 + loop3: [1, 2, 2, 0, 0] j=2 循环完后j=3 + loop4: [1, 2, 2, 0, 0] j=0 循环完后j=1 + loop5: [1, 2, 2, 0, 0] j=0 循环完后j=1 + 时间复杂度 O(n),空间负载度O(1) + """ + j = 0 + for i in range(len(nums)): + if nums[i]: + nums[i], nums[j] = nums[j], nums[i] + j += 1 diff --git a/Week_01/G20200343030545/LeetCode_42_545.py b/Week_01/G20200343030545/LeetCode_42_545.py new file mode 100644 index 00000000..3e3cc862 --- /dev/null +++ b/Week_01/G20200343030545/LeetCode_42_545.py @@ -0,0 +1,167 @@ +""" + 给定 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 +""" +from typing import List + + +class Stack: + def __init__(self): + self.__list = list() + + def peek(self): + if not self.empty(): + return self.__list[-1] + + def empty(self) -> bool: + return not bool(self.__list) + + def pop(self) -> bool: + if self.empty(): + return False + self.__list.pop() + return True + + def push(self, v: object) -> bool: + self.__list.append(v) + return True + + def __str__(self): + return "Stack[" + ",".join([str(self.__list[i]) for i in range(len(self.__list) - 1, -1, -1)]) + "]" + + +class Solution: + def trap(self, height: List[int]) -> int: + return self.dp_2(height) + + @classmethod + def stack_hand(cls, height: List[int]) -> int: + """ + 使用栈处理 + 依次入栈: + 1) 当栈为空时,继续入栈 + 2) 当栈顶元素小于当前元素时,说明会产生积水,继续入栈 + 3) 当栈顶元素大于当前元素时,说明积水停止了。 + 时间复杂度:O(n),空间复杂度:O(n) + """ + + current = 0 + height_len = len(height) + res = 0 + stack = Stack() + + while current < height_len: + while not stack.empty() and height[current] > height[stack.peek()]: + print(current,'ff') + v = height[stack.peek()] + stack.pop() + if stack.empty(): + break + + distance = current - stack.peek() - 1 + min_v = min(height[stack.peek()], height[current]) + res += (distance * (min_v - v)) + + stack.push(current) + current += 1 + + return res + + @classmethod + def directly(cls, height: List[int]) -> int: + """ + 暴力求解法。计算每一个下标能存储的最大雨滴然后累加。 + 详细: + 计算每一列中左边最高的和右边最高的,取两者最小值V和当前列比较。 + 1)如果V大雨当前列的值,则可以存放的雨水是当前列和V的差值 + 2)如果V等于或者小于当前列,则该列存放的雨水为0。 + 时间复杂度:O(n^2),空间复杂度O(1) + """ + res = 0 + + for i in range(len(height)): + max_left = max_right = 0 + for j in range(0, i): + max_left = max(max_left, height[j]) + + for k in range(i, len(height)): + max_right = max(max_right, height[k]) + + v = height[i] + + check_v = min(max_left, max_right) + + if check_v > v: + res += check_v - v + return res + + @classmethod + def dp_1(cls, height: List[int]) -> int: + """ + 动态规划求解 + 用两个列表存储 左边最大列 右边做大列 + 总共3次循环。 + + 时间复杂度O(n),空间复杂度O(n) + """ + res = 0 + height_length = len(height) + max_left_info = [0] * height_length + max_right_info = [0] * height_length + + for i in range(1, height_length): + max_left_info[i] = max(max_left_info[i - 1], height[i - 1]) + + for j in range(height_length - 2, -1, -1): + max_right_info[j] = max(max_right_info[j + 1], height[j + 1]) + + for k in range(height_length): + max_left = max_left_info[k] + max_right = max_right_info[k] + + v = height[k] + check_v = min(max_left, max_right) + if check_v > v: + res += (check_v - v) + return res + + @classmethod + def dp_2(cls, height: List[int]) -> int: + """ + 动态规划求解。 + 思路和dp_1 一样,只不过是用两个临时变量保存max_left, max_right + 时间复杂度O(n),空间复杂度O(1) + """ + height_len = len(height) + max_left = max_right = 0 + left = 1 + right = height_len - 2 + + res = 0 + + for i in range(1, height_len - 1): + if height[left - 1] < height[right + 1]: + # 左柱子比右柱子小 + max_left = max(max_left, height[left - 1]) + + if max_left > height[left]: + res += (max_left - height[left]) + + left += 1 + else: + # 右柱子比左柱子小 + max_right = max(max_right, height[right + 1]) + + if max_right > height[right]: + res += (max_right - height[right]) + right -= 1 + + return res + + +if __name__ == '__main__': + print(Solution.stack_hand([2, 1, 2])) diff --git a/Week_01/G20200343030545/LeetCode_641_545.py b/Week_01/G20200343030545/LeetCode_641_545.py new file mode 100644 index 00000000..6fc9c820 --- /dev/null +++ b/Week_01/G20200343030545/LeetCode_641_545.py @@ -0,0 +1,129 @@ +""" + 设计实现双端队列。 + 你的实现需要支持以下操作: + 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: + + def __init__(self, k: int): + """ + Initialize your data structure here. Set the size of the deque to be k. + """ + self.__k = k + self.__front = 0 # 指向队列头部第 1 个有效数据的位置。 + self.__rear = 0 # 指向队列尾部的下一个位置,即下一个从队尾入队元素的位置。 + self.__capacity = self.__k + 1 + self.__array = [0] * self.__capacity # 多存储一个空间用于 区分 队列满还是空 + + 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 + + self.__front = (self.__front - 1 + self.__capacity) % self.__capacity + self.__array[self.__front] = 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 + self.__array[self.__rear] = value + self.__rear = (self.__rear + 1) % self.__capacity + 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 + + self.__front = (self.__front + 1) % self.__capacity + 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 + self.__rear = (self.__rear - 1 + self.__capacity) % self.__capacity + return True + + def getFront(self) -> int: + """ + Get the front item from the deque. + """ + if self.isEmpty(): + return -1 + return self.__array[self.__front] + + def getRear(self) -> int: + """ + Get the last item from the deque. + """ + if self.isEmpty(): + return -1 + return self.__array[(self.__rear - 1 + self.__capacity) % self.__capacity] + + def isEmpty(self) -> bool: + """ + Checks whether the circular deque is empty or not. + """ + return self.__front == self.__rear + + def isFull(self) -> bool: + """ + Checks whether the circular deque is full or not. + """ + return (self.__rear + 1) % self.__capacity == self.__front + + +if __name__ == '__main__': + myci = MyCircularDeque(7) + myci.insertFront(10) + myci.insertFront(11) + myci.insertFront(12) + myci.insertFront(13) + myci.insertFront(14) + myci.insertFront(15) + myci.insertLast(16) + myci.insertLast(17) + myci.deleteFront() + myci.insertLast(17) + myci.insertLast(142) + + print(myci._MyCircularDeque__array) diff --git a/Week_01/G20200343030545/LeetCode_66_545.py b/Week_01/G20200343030545/LeetCode_66_545.py new file mode 100644 index 00000000..9eff4980 --- /dev/null +++ b/Week_01/G20200343030545/LeetCode_66_545.py @@ -0,0 +1,42 @@ +""" + 给定一个由整数组成的非空数组所表示的非负整数,在该数的基础上加一。 + 最高位数字存放在数组的首位, 数组中每个元素只存储单个数字。 + 你可以假设除了整数 0 之外,这个整数不会以零开头。 + + 示例 1: + 输入: [1,2,3] + 输出: [1,2,4] + 解释: 输入数组表示数字 123。 + + 示例 2: + 输入: [4,3,2,1] + 输出: [4,3,2,2] + 解释: 输入数组表示数字 4321。 +""" + +from typing import List + + +class Solution: + def plusOne(self, digits: List[int]) -> List[int]: + return self.tail_loop(digits) + + @classmethod + def tail_loop(cls, digits: List[int]) -> List[int]: + """ + 从尾部开始循环遍历。 + 对应下标元素的值加1,然后对10取模得到一个一个新值。 + 如果这个新值不等于0,则说明不用往后循环了,直接返回就行。否则持续这个循环。 + TODO: 如果循环结束函数依然没有返回,则是99, 999, 9999...这种的值,所以要在最前面的一位加1。 + 时间复杂度:O(n), 空间复杂度:O(1) + """ + for index in range(len(digits) - 1, -1, -1): + digits[index] = (digits[index] + 1) % 10 + if digits[index]: + return digits + digits.insert(0, 1) + return digits + + @classmethod + def python_trick(cls, digits: List[int]) -> List[int]: + return [int(i) for i in str(int(''.join(map(str, digits))) + 1)] diff --git a/Week_01/G20200343030545/LeetCode_70_545.py b/Week_01/G20200343030545/LeetCode_70_545.py new file mode 100644 index 00000000..dfb2ae5d --- /dev/null +++ b/Week_01/G20200343030545/LeetCode_70_545.py @@ -0,0 +1,71 @@ +""" + 假设你正在爬楼梯。需要 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 阶 +""" + + +class Solution: + def climbStairs(self, n: int) -> int: + pass + + @classmethod + def recursive(cls, n: int) -> int: + """ + 递归解决: + f(n) = f(n-1) + f(n) + 终止条件 n小于3时,返回对应n。 + 时间复杂度O(2^n),空间复杂度O(n) + """ + if n < 3: + return n + return cls.recursive(n - 1) + cls.recursive(n - 2) + + @classmethod + def recursive_use_hash(cls, n: int) -> int: + """ + 和递归方法一样,只是用一个hash表记录一下每个数的值,防止重复计算。 + 时间复杂度O(n),空间复杂度是O(n) + """ + + def recursive(_n: int, mapping: dict = None) -> int: + mapping = mapping or {} + if _n < 3: + return 2 + if _n in mapping: + return mapping[_n] + else: + result = recursive(_n - 1) + recursive(_n - 2) + mapping[_n] = result + return result + + return recursive(n) + + @classmethod + def loop_compute(cls, n: int) -> int: + """ + 自低向上计算 + 时间复杂度O(n),空间复杂度O(1) + """ + if n < 3: + return n + + a, b = 1, 2 + for i in range(3, n + 1): + a, b = b, a + b + return b diff --git a/Week_01/G20200343030545/LeetCode_84_545.py b/Week_01/G20200343030545/LeetCode_84_545.py new file mode 100644 index 00000000..7856780a --- /dev/null +++ b/Week_01/G20200343030545/LeetCode_84_545.py @@ -0,0 +1,115 @@ +""" + 给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。 + 求在该柱状图中,能够勾勒出来的矩形的最大面积。 + + 示例: + 输入: [2,1,5,6,2,3] + 输出: 10 +""" +from typing import List + + +class Solution: + def largestRectangleArea(self, heights: List[int]) -> int: + pass + + @classmethod + def directly_2(cls, heights: List[int]) -> int: + """ + 暴力求解法,三层循环嵌套。 + 第一层控制柱子的遍历。 + 第二层控制柱子往由遍历 + 第三层控制第一层循环的所在的柱子和第二层循环所在的柱子中间的最小值获取。 + 然后依次更新外层公用的面积 + + 时间复杂度:O(n^3), 空间复杂度O(1) + """ + res = 0 + height_len = len(heights) + + for i in range(height_len): # 第一层循环用于遍历每个柱子 + for j in range(i, height_len): + min_height = float("inf") + for k in range(i, j + 1): + print(k) + min_height = min(heights[k], min_height) + res = max(res, min_height * (j - i + 1)) + return res + + @classmethod + def directly_1(cls, heights: List[int]) -> int: + """ + 暴力求解法 + 两层循环 + 第一层循环控制柱子的遍历, + 第二层循环依次往右边遍历,并且计算出每次遍历时的最大面积。 + 和暴力求解法1不同的时,不用去找两根柱子之间的最小柱子,用一个变量保存这次循环时,最小柱子的高度。 + 时间复杂度O(n^2),空间复杂度O(1) + """ + heights_len = len(heights) + res = 0 + for index in range(heights_len): + min_height = float("inf") + for tmp_index in range(index, heights_len): + min_height = min(min_height, heights[tmp_index]) + res = max(res, min_height * (tmp_index - index + 1)) + return res + + @classmethod + def divide(cls, heights: List[int]) -> int: + """ + 分治法 + 确定了最矮柱子以后,矩形的宽尽可能往两边延伸。 + 在最矮柱子左边的最大面积矩形(子问题)。 + 在最矮柱子右边的最大面积矩形(子问题)。 + + 时间复杂度 平均开销:O(nlogn) 最坏O(n^2) + 空间复杂度 O(n) + FIXME: 还是不太理解,先敲一遍 + """ + + def _divide(nums: List[int], start: int, end: int) -> int: + if start > end: + return 0 + + min_index = start + for i in range(start, end + 1): + if nums[min_index] > nums[i]: + min_index = i + + check_value = max(_divide(nums, start, min_index - 1), _divide(nums, min_index + 1, end)) + return max(check_value, nums[min_index] * (end - start + 1)) + + return _divide(heights, 0, len(heights) - 1) + + @classmethod + def use_stack(cls, heights: List[int]) -> int: + """ + 使用栈的数据结构(单调递增栈) + 1. 先判断栈是否为空 + 2. + """ + stack = [] + + res = 0 + for index in range(len(heights)): + if not stack: + stack.append(index) + else: + if heights[index] < heights[stack[-1]]: + # 说明已经找到了右边界,然后依次弹出栈顶元素 并且计算该元素的最大面积 + while True: + tmp_index = stack.pop() + print(tmp_index, "ffff", heights[tmp_index], index - tmp_index + 1) + + res = max(res, heights[tmp_index] * (index - tmp_index + 1)) + if not stack: + break + stack.append(index) + else: + stack.append(index) + return res + + +if __name__ == '__main__': + print(Solution.use_stack([2, 1, 5, 6, 2, 3])) diff --git a/Week_01/G20200343030545/LeetCode_88_545.py b/Week_01/G20200343030545/LeetCode_88_545.py new file mode 100644 index 00000000..958286e4 --- /dev/null +++ b/Week_01/G20200343030545/LeetCode_88_545.py @@ -0,0 +1,81 @@ +""" + 给定两个有序整数数组 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] +""" + +from typing import List + + +class Solution: + def merge(self, nums1: List[int], m: int, nums2: List[int], n: int) -> None: + """ + Do not return anything, modify nums1 in-place instead. + """ + + @classmethod + def double_pointer_v1(cls, nums1: List[int], m: int, nums2: List[int], n: int) -> None: + """ + 定义两个指针,分别都从0开始 循环遍历,判断对应的值,添加到新列表中。 + 循环结束后,新列表需要更新nums1或者nums2剩余的元素。 + 最后将新列表赋值给nums1。 + 时间复杂度:O(m+n),空间复杂度O(m+n) + """ + i = j = 0 + res = [] + + while i < m and j < n: + if nums1[i] < nums2[j]: + res.append(nums1[i]) + i += 1 + else: + res.append(nums2[j]) + j += 1 + res += (nums1[i:m] + nums2[j:n]) + + nums1[:] = res + + @classmethod + def double_pointer_v2(cls, nums1: List[int], m: int, nums2: List[int], n: int) -> None: + """ + 双指针解法2,从后往前。 + 首先计算出合并后数组的最大下标。 + 从两个数组的指定位置的后面开始遍历。比较结果,然后插入到后面的位置并且对应的下标减1。循环判断 + 最后需要处理一下nums2遗留的数据 + 时间复杂度:O(m+n),空间复杂度O(1) + """ + p = m + n - 1 # 表示是新的nums1的最后一个下标地址 + + p1 = m - 1 + p2 = 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 + nums1[0:p2 + 1] = nums2[0:p2 + 1] + + +if __name__ == '__main__': + a = [1, 2, 3, 0, 0, 0] + b = [1, 5, 6] + Solution.double_pointer_v1(a, 3, b, 3) + # print(a) + + a1 = [2, 4, 5, 0, 0, 0, 0, 0, 0] + b1 = [1, 2, 3] + Solution.double_pointer_v2(a1, 3, b1, 3) + print(a1) diff --git a/Week_01/G20200343030553/LeetCode_21_G20200343030553.java b/Week_01/G20200343030553/LeetCode_21_G20200343030553.java new file mode 100644 index 00000000..3bd1aba6 --- /dev/null +++ b/Week_01/G20200343030553/LeetCode_21_G20200343030553.java @@ -0,0 +1,46 @@ +class Solution { + // public ListNode mergeTwoLists(ListNode l1, ListNode l2) { + // // 复杂度 time O(n) space O(1) + // ListNode dummy = new ListNode(-1); + // ListNode head = dummy; + // ListNode a1 = l1; + // ListNode a2 = l2; + // while(a1!=null && a2!=null){ + // if(a1.val <= a2.val){ + // dummy.next = a1; + // a1 = a1.next; + // }else{ + // dummy.next = a2; + // a2 = a2.next; + // } + // dummy = dummy.next; + // } + + // // while(a1!=null){ + // // dummy.next = a1; + // // a1 = a1.next; + // // dummy = dummy.next; + // // } + // // while(a2!=null){ + // // dummy.next = a2; + // // a2 = a2.next; + // // dummy = dummy.next; + // // } + // // dummy.next = null; + // //优化 + // dummy.next = (a1 !=null) ? a1:a2; + // return head.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; + } + } +} \ No newline at end of file diff --git a/Week_01/G20200343030553/LeetCode_42_G20200343030553.java b/Week_01/G20200343030553/LeetCode_42_G20200343030553.java new file mode 100644 index 00000000..9217feb2 --- /dev/null +++ b/Week_01/G20200343030553/LeetCode_42_G20200343030553.java @@ -0,0 +1,20 @@ +class Solution { + public int trap(int[] height) { + int sum = 0; + + for(int i=1;i=0;j--){ + maxl = Math.max(maxl, height[j]); + } + for(int j=i;j map = new HashMap<>(); + for(int i=0;i 0) { + nums[i - count] = nums[i]; + nums[i] = 0; + } + + } + } +} diff --git a/Week_01/G20200343030561/Leetcode_042_561.java b/Week_01/G20200343030561/Leetcode_042_561.java new file mode 100644 index 00000000..33dfe555 --- /dev/null +++ b/Week_01/G20200343030561/Leetcode_042_561.java @@ -0,0 +1,29 @@ +/* + * @lc app=leetcode.cn id=42 lang=java + * + * [42] 接雨水 + */ + +// @lc code=start +class Solution { + public int trap(final int[] height) { + if (height.length < 2) return 0; + + int ret = 0; + int len = height.length; + int[] left = new int[len]; + int[] right = new int[len]; + left[0] = height[0]; + for(var i = 1; i < len; ++ i) + left[i] = Math.max(height[i], left[i - 1]); + right[len - 1] = height[len - 1]; + for(var i = len - 2; i >= 0; --i ) + right[i] = Math.max(height[i], right[i + 1]); + for(var i = 1; i < len - 1 ; ++i) { + ret += Math.min(left[i], right[i]) - height[i]; + } + return ret; + } +} +// @lc code=end + diff --git a/Week_01/G20200343030561/Leetcode_066_561.java b/Week_01/G20200343030561/Leetcode_066_561.java new file mode 100644 index 00000000..44ec539d --- /dev/null +++ b/Week_01/G20200343030561/Leetcode_066_561.java @@ -0,0 +1,29 @@ +/* + * @lc app=leetcode.cn id=66 lang=java + * + * [66] 加一 + */ + +// @lc code=start +class Solution { + public int[] plusOne(int[] digits) { + for(var i = digits.length - 1; i >= 0; i--) { + + if (digits[i] == 9) { + digits[i] = 0; + } else { + digits[i] ++; + return digits; + } + + } + int[] ret = new int[digits.length + 1]; + for (var i = 0; i < ret.length; i++) { + ret[i] = 0; + } + ret[0] = 1; + return ret; + } +} +// @lc code=end + diff --git a/Week_01/G20200343030561/Leetcode_088_561.java b/Week_01/G20200343030561/Leetcode_088_561.java new file mode 100644 index 00000000..878a9636 --- /dev/null +++ b/Week_01/G20200343030561/Leetcode_088_561.java @@ -0,0 +1,20 @@ +/* + * @lc app=leetcode.cn id=88 lang=java + * + * [88] 合并两个有序数组 + */ + +// @lc code=start +class Solution { + public void merge(int[] nums1, int m, int[] nums2, int n) { + int p = m-- + n-- - 1; + while (m >= 0 && n >= 0) + nums1[p--] = nums1[m] > nums2[n] ? nums1[m--] : nums2[n--]; + + + while (n >= 0) + nums1[p--] = nums2[n--]; + } +} +// @lc code=end + diff --git a/Week_01/G20200343030561/Leetcode_641_561.java b/Week_01/G20200343030561/Leetcode_641_561.java new file mode 100644 index 00000000..ef19d7ff --- /dev/null +++ b/Week_01/G20200343030561/Leetcode_641_561.java @@ -0,0 +1,88 @@ +/* + * @lc app=leetcode.cn id=641 lang=java + * + * [641] 设计循环双端队列 + */ + +// @lc code=start +class MyCircularDeque { + int[] arr; + int front; + int rear; // + int maxLength; + /** Initialize your data structure here. Set the size of the deque to be k. */ + public MyCircularDeque(int k) { + maxLength = k + 1; + front = 0; + rear = 0; + arr = new int[maxLength]; + } + + /** 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 + maxLength) % maxLength; // change pointer before assign value + arr[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()) return false; + arr[rear] = value; + rear = (rear + 1) % maxLength;// change pointer after assign value; whatever iF or iL, one of them should assign value before; + 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) % maxLength; + 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 + maxLength) % maxLength; + return true; + } + + /** Get the front item from the deque. */ + public int getFront() { + if (isEmpty()) return -1; + return arr[front]; + } + + /** Get the last item from the deque. */ + public int getRear() { + if (isEmpty()) return -1; + //as pointer plus one after assign value + return arr[(rear - 1 + maxLength) % maxLength]; + } + + /** 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 (rear + 1) % maxLength == front; + } +} + +/** + * 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/G20200343030561/NOTE.org b/Week_01/G20200343030561/NOTE.org new file mode 100644 index 00000000..5a441c9c --- /dev/null +++ b/Week_01/G20200343030561/NOTE.org @@ -0,0 +1,72 @@ +* 学习总结 +** Java 的基本功有些差,比如for(data_type variable:array)这样的遍历方式之前都没用过。还需要多看别人的解法多熟悉一下。 +** 看到新题 想到暴力解法也要写出来,不要不屑于暴力法,很考验基本功。 +** 看到旧题 想到怎么解了也要再解一遍,就像数学题,总是自以为会了,实则还是会犯马虎。 +** 基本功最考验两点,解题在这浪费好多时间 +*** 下标i 是否 +1 or -1 +*** 判断条件 > or < 还是 >= or <= + +* 源码分析 +** Queue 源码 +*** Queue +Java中Queue为Interface,继承Collection,说明是集合家族的一员 +**** 包含如下方法: +- add +- offer +- remove +- poll +- element +- peek +*** AbstractQueue +AbstractQueue为Queue的一个实现类 +**** 封装3个方法 +- add +- clear +- element +分别调用 +- offer +- poll +- peek +并加以判断,抛出异常。 +**** 2个批量方法 +- clear +- addAll +分别调用 +- poll +- add +*** LinkedList +Queue较为常用的实现方式之一 +**** 与 Queue 相关的方法 +***** offer +offer 调用 add, add 调用 linkLast 并返回真,linkLast修改last.next、替换last、判断之前的last是否为空 为空则将新节点设为first +***** poll +poll 判断是否为空 不为空则调用 ulinkFirst,ulinkFirst 修改指针,将参数的item返回。 +***** peek +判断是否为空,返回first的item。 +** Priority Queue 源码 +Java 中的 Priority Queue 使用二叉堆维护队列 +*** 入队 +add 别名 offer,offer 判断大小、调用 siftUp, siftUp 根据是否有比较器 使用不同的方法,siftUpComparable 循环比较父节点与参数的大小 并交换位置 直到出现父节点比参数小为止。 +*** 扩容 +*** 出队 +remove 调用 poll,poll 取出队首、将队尾元素设为 null --size仍大于0 将末元素做为参数调用siftDown,siftDown 根据是否有比较器调用不同的方法,siftDownComparable 循环判断 (左右子节点较小者 与 参数)的大小 若参数大则交换位置 +*** 取首 +element 调用 peek, peek 返回队首queue[0] +* 改写示例代码-Deque +#+begin_src java + Deque deque = new LinkedList(); + + deque.addLast("a"); + deque.addLast("b"); + deque.addLast("c"); + System.out.println(deque); + + String str = deque.getFirst(); + System.out.println(str); + System.out.println(deque); + + while(deque.size() > 0) { + System.out.println(deque.pollFirst()); + } + System.out.println(); +#+end_src diff --git a/Week_01/G20200343030569/LeetCode_189_569.java b/Week_01/G20200343030569/LeetCode_189_569.java new file mode 100644 index 00000000..1ff14292 --- /dev/null +++ b/Week_01/G20200343030569/LeetCode_189_569.java @@ -0,0 +1,35 @@ + +/* + * 189.Rotate Array + * 旋转数组 + */ +public class LeetCode_189_569 { + + public static void main(String[] args) { + int[] nums = { 1,2,3,4,5,6,7 }; + int k = 4; + (new LeetCode_189_569()).new Solution().rotate(nums,k); + for( int i = 0; i < nums.length; i++ ){ + System.out.println(nums[i]); + } + } + + class Solution { + public void rotate(int[] nums, int k) { + k = k % nums.length; + for (int i = 0, count = 0; count < nums.length; i++) { + int source = i; + int sourceValue = nums[source]; + do { + int dest = (source + k) % nums.length; + int temp = nums[dest]; + nums[dest] = sourceValue; + source = dest; + sourceValue = temp; + count++; + } while (source != i); + } + } + } +} + diff --git a/Week_01/G20200343030569/LeetCode_1_569.java b/Week_01/G20200343030569/LeetCode_1_569.java new file mode 100644 index 00000000..a6759fb7 --- /dev/null +++ b/Week_01/G20200343030569/LeetCode_1_569.java @@ -0,0 +1,33 @@ +import java.util.HashMap; +import java.util.Map; + +/* + * 1. Two Sum + * 两数之和 + */ +public class LeetCode_1_569 { + + public static void main(String[] args) { + // TODO Auto-generated method stub + int[] nums = { 12,2,7,11,15 }; + int target = 9; + int[] n = (new LeetCode_1_569()).new Solution().twoSum(nums, target); + for( int i = 0; i < n.length; i++ ){ + System.out.println(n[i]); + } + } + + class Solution { + public int[] twoSum(int[] nums, int target) { + Map map = new HashMap(); + for (int i = 0; i < nums.length; i++) { + int want = target - nums[i]; + if( map.containsKey(want) ) { + return new int[] { map.get(want), i }; + } + map.put(nums[i], i); + } + return null; + } + } +} diff --git a/Week_01/G20200343030569/LeetCode_21_569.java b/Week_01/G20200343030569/LeetCode_21_569.java new file mode 100644 index 00000000..5e98222f --- /dev/null +++ b/Week_01/G20200343030569/LeetCode_21_569.java @@ -0,0 +1,52 @@ +/* + * 21. Merge Two Sorted Lists + * 合并两个有序链表 + */ +public class LeetCode_21_569 { + + public static void main(String[] args) { + LeetCode_21_569 lc = new LeetCode_21_569(); + ListNode ln13 = lc.createNewNode(4, null); + ListNode ln12 = lc.createNewNode(2, ln13); + ListNode ln11 = lc.createNewNode(1, ln12); + + ListNode ln23 = lc.createNewNode(4, null); + ListNode ln22 = lc.createNewNode(3, ln23); + ListNode ln21 = lc.createNewNode(1, ln22); + + ListNode node = lc.new Solution().mergeTwoLists(ln11,ln21); + while (node != null) { + System.out.println(node.val); + node = node.next; + } + + } + + public ListNode createNewNode( int i, ListNode next ) { + ListNode node = new ListNode(i); + node.next = next; + return node; + } + + + public class ListNode { + int val; + ListNode next; + ListNode(int x) { val = x; } + } + + class Solution { + public ListNode mergeTwoLists(ListNode l1, ListNode l2) { + ListNode tempNode = new ListNode(0); + ListNode currentNode = tempNode; + while (l1 != null && l2 != null) { + currentNode.next = (l1.val < l2.val) ? l1 : l2; + ListNode n = (l1.val < l2.val) ? (l1 = l1.next) : (l2 = l2.next); + currentNode = currentNode.next; + } + ListNode nonEmpty = (l1 != null) ? l1 : l2; + currentNode.next = nonEmpty; + return tempNode.next; + } + } +} diff --git a/Week_01/G20200343030569/LeetCode_26_569.java b/Week_01/G20200343030569/LeetCode_26_569.java new file mode 100644 index 00000000..f708d3f9 --- /dev/null +++ b/Week_01/G20200343030569/LeetCode_26_569.java @@ -0,0 +1,31 @@ +/* + * 26. Remove Duplicates from Sorted Array + * 删除排序数组中的重复项 + */ +public class LeetCode_26_569 { + public static void main( String[] argv) { + int[] nums = { 0,0,1,1,1,2,2,3,3,4,4 }; + int n = (new LeetCode_26_569()).new Solution().removeDuplicates(nums); + for( int i = 0; i < n; i++ ){ + System.out.println(nums[i]); + } + } + + class Solution { + public int removeDuplicates(int[] nums) { + if (nums.length <= 1) + return nums.length; + + int validIndex = 1; + int lastNum = nums[0]; + for (int i = 1; i < nums.length; i++) { + if (nums[i] != lastNum) { + nums[validIndex++] = nums[i]; + lastNum = nums[i]; + } + } + return validIndex; + } + } +} + diff --git a/Week_01/G20200343030569/LeetCode_283_569.java b/Week_01/G20200343030569/LeetCode_283_569.java new file mode 100644 index 00000000..9b0cedac --- /dev/null +++ b/Week_01/G20200343030569/LeetCode_283_569.java @@ -0,0 +1,28 @@ + +/* + * 283. Move Zeroes + * 移动零 + */ +public class LeetCode_283_569 { + + public static void main(String[] args) { + int[] nums = { 0,1,0,3,12,0 }; + int target = 9; + (new LeetCode_283_569()).new Solution().moveZeroes(nums); + for( int i = 0; i < nums.length; i++ ){ + System.out.println(nums[i]); + } + } + + class Solution { + public void moveZeroes(int[] nums) { + int validIndex = 0; + for ( int i = 0; i < nums.length; i++ ) { + if ( nums[i] != 0 ) { + nums[validIndex++] = nums[i]; + nums[i] = 0; + } + } + } + } +} diff --git a/Week_01/G20200343030569/LeetCode_42_569.java b/Week_01/G20200343030569/LeetCode_42_569.java new file mode 100644 index 00000000..fed72188 --- /dev/null +++ b/Week_01/G20200343030569/LeetCode_42_569.java @@ -0,0 +1,50 @@ +/* + * 42. Trapping Rain Water + * 接雨水 + */ +public class LeetCode_42_569 { + + public static void main(String[] args) { + // TODO Auto-generated method stub + int[] nums = { 2,0,2 }; + int n = (new LeetCode_42_569()).new Solution().trap(nums); + System.out.println(n); + } + + class Solution { + /* + * 按行算水量,行数等于高度数组的最大值,但这个算法对于高度高的数组超时,比较垃圾 + */ + public int trap(int[] height) { + int water = 0; + int rows = 0; + for (int i:height) { + rows = Math.max(rows, i); + } + //遍历每行 + for ( int i = 1; i <= rows; i++ ) { + int rowWater = 0; + int left = -1; + int right = -1; + for ( int j = 0; j < height.length; j++ ) { + if ( height[j] >= i ) { + if ( left < 0 ) { //第一个left + left = j; + }else { + if ( j == left + 1 ) { + left = j; + }else { + right = j; + rowWater = rowWater + (right - left - 1); + left = right; + right = -1; + } + } + } + } + water += rowWater; + } + return water; + } + } +} diff --git a/Week_01/G20200343030569/LeetCode_641_569.java b/Week_01/G20200343030569/LeetCode_641_569.java new file mode 100644 index 00000000..9c9f5e0c --- /dev/null +++ b/Week_01/G20200343030569/LeetCode_641_569.java @@ -0,0 +1,150 @@ +/* + * 641. Design Circular Deque + * 设计循环双端队列 + */ +public class LeetCode_641_569 { + + public static void main(String[] args) { + + MyCircularDeque circularDeque = new MyCircularDeque(8); + circularDeque.insertFront(5); + circularDeque.getFront(); + circularDeque.isEmpty(); + circularDeque.deleteFront(); + circularDeque.insertLast(3); + circularDeque.getRear(); + circularDeque.insertLast(7); + circularDeque.insertFront(7); + circularDeque.deleteLast(); + circularDeque.insertLast(4); + circularDeque.isEmpty(); + + + + + + + + /*circularDeque.insertFront(1); + circularDeque.insertLast(2); + circularDeque.getFront(); + circularDeque.insertLast(3); + circularDeque.getFront(); + circularDeque.insertFront(5); + circularDeque.getRear(); + circularDeque.getFront(); + circularDeque.getFront(); + circularDeque.deleteLast(); + circularDeque.getRear();*/ + + + /* 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 +*/ + } + + +} + +class MyCircularDeque { + + class Node { + Node prev; + int value; + Node next; + + Node( Node prev, int value, Node next) { + this.prev = prev; + this.value = value; + this.next = next; + } + } + + int maxSize; + int size; + Node head; + Node tail; + + public MyCircularDeque(int k) { + this.maxSize = k; + } + + public boolean insertFront(int value) { + if ( size == maxSize ) + return false; + Node n = new Node( null, value, head ); + if ( head == null ) + tail = n; + else + head.prev = n; + head = n; + size++; + return true; + } + + public boolean insertLast(int value) { + if ( size == maxSize ) + return false; + Node n = new Node( tail, value, null ); + if ( tail == null ) + head = n; + else + tail.next = n; + tail = n; + size++; + return true; + } + + public boolean deleteFront() { + if ( head == null ) + return false; + Node n = head; + Node next = head.next; + n.next = null; + head = next; + if ( head != null ) + head.prev = null; + else + tail = null; + size--; + return true; + } + + public boolean deleteLast() { + if ( tail == null ) + return false; + Node n = tail; + Node prev = tail.prev; + n.prev = null; + tail = prev; + if ( tail != null ) + tail.next = null; + else + head = null; + size--; + return true; + } + + public int getFront() { + return (size==0) ? -1 : head.value; + } + + public int getRear() { + return (size==0) ? -1 : tail.value; + } + + public boolean isEmpty() { + return (size == 0); + } + + public boolean isFull() { + return (size == maxSize); + } +} \ No newline at end of file diff --git a/Week_01/G20200343030569/LeetCode_66_569.java b/Week_01/G20200343030569/LeetCode_66_569.java new file mode 100644 index 00000000..5ff5ebe5 --- /dev/null +++ b/Week_01/G20200343030569/LeetCode_66_569.java @@ -0,0 +1,30 @@ +/* + * 66. Plus One + * 加一 + */ +public class LeetCode_66_569 { + + public static void main(String[] args) { + int[] nums = { 4,3,8,9 }; + (new LeetCode_66_569()).new Solution().plusOne(nums); + for( int i = 0; i < nums.length; i++ ){ + System.out.println(nums[i]); + } + } + + class Solution { + public int[] plusOne(int[] digits) { + int carry = 0; + for ( int i = digits.length - 1; i >= 0; i-- ) { + int j = digits[i] + (i == digits.length-1 ? 1 : 0 ) + carry--; + carry = (j / 10 > 0) ? 1 : 0; + digits[i] = j % 10; + } + if ( carry > 0 ) { + digits = new int[digits.length+1]; + digits[0] = 1; + } + return digits; + } + } +} diff --git a/Week_01/G20200343030569/LeetCode_88_569.java b/Week_01/G20200343030569/LeetCode_88_569.java new file mode 100644 index 00000000..0002ebab --- /dev/null +++ b/Week_01/G20200343030569/LeetCode_88_569.java @@ -0,0 +1,24 @@ +import java.util.Arrays; + +/* + * 88. Merge Sorted Array + * 合并两个有序数组 + */ +public class LeetCode_88_569 { + + public static void main(String[] args) { + int[] nums1 = { 1,2,3,0,0,0 }; + int[] nums2 = { 2,5,6 }; + (new LeetCode_88_569()).new Solution().merge(nums1, 3, nums2, 3); + for( int i = 0; i < nums1.length; i++ ){ + System.out.println(nums1[i]); + } + } + + 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/G20200343030571/NOTE.md b/Week_01/G20200343030571/NOTE.md index 50de3041..4f6b8afb 100644 --- a/Week_01/G20200343030571/NOTE.md +++ b/Week_01/G20200343030571/NOTE.md @@ -1 +1 @@ -学习笔记 \ No newline at end of file +学习笔记 diff --git a/Week_01/G20200343030571/main/merge-sorted-array.go b/Week_01/G20200343030571/main/merge-sorted-array.go new file mode 100644 index 00000000..0134b336 --- /dev/null +++ b/Week_01/G20200343030571/main/merge-sorted-array.go @@ -0,0 +1,53 @@ +package main +/* +合并两个有序数组: + 给定两个有序整数数组 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] +*/ +/* + 暴力法:用nums2从头到尾依次跟nums1比较,小于等于则插入。 + O(m*n) + + 排序法:直接插到尾部然后排序 + O((n+m)log(n+m)) + +*/ + +/* + 去看了一眼题解,发现原来只要从后往前插入数据,就可以省去了暴力法多次在元素中间 + 插入元素的开销,妙啊 + +*/ +func merge(nums1 []int, m int, nums2 []int, n int) { + len1 := m - 1 + len2 := n - 1 + len := m + n - 1 + + for { + if len1 < 0 || len2 < 0 { + break + } + if nums2[len2] >= nums1[len1] { + nums1[len] = nums2[len2] + len2-- + } else { + nums1[len] = nums1[len1] + len1-- + } + len-- + } + if len2 >= 0 { + copy(nums1[0:len2+1], nums2[0:len2+1]) + } + +} diff --git a/Week_01/G20200343030571/main/remove-duplicates-from-sorted-array.go b/Week_01/G20200343030571/main/remove-duplicates-from-sorted-array.go new file mode 100644 index 00000000..3db37f3f --- /dev/null +++ b/Week_01/G20200343030571/main/remove-duplicates-from-sorted-array.go @@ -0,0 +1,81 @@ +package main +/* +删除排序数组中的重复项: + +给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。 +不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O (1) 额外空间的条件下完成。 +*/ + + +/* + 一开始自己能想出个大概思路,应该也算是属于“用空间换时间”范围里的。 + 就是在一次遍历中,用两个指针,一个指针负责遍历,一个指针负责记录“遇到下一个非重复项的时候应该插入的地方” + 然后用一个变量temp来存储应该与遍历指针进行比对来看是否重复的数,也就是遇到的最新的非重复的数。 +*/ + +/* + 以下是自己按照思路,并修改直到通过的代码。 + 由于思路不够清晰,一开始写的代码错误百出,甚至把判断是否重复后分别的操作给搞混了。 +*/ +func removeDuplicates1(nums []int) int { + if len(nums) == 0 { + return 0 + } + temp := nums[0] + + i,j := int(1),int(1) + for ; i < len(nums); i++ { + if nums[i] == temp { + } else { + nums[j] = nums[i] + temp = nums[i] + j++ + } + } + return j +} + +/* + 通过查看别人的题解,发现自己代码中的temp变量是不必要的,因为其实那个慢指针前面位置的元素 + 就等于是temp. + 然后自己写了removeDuplicates2. + 然后照着这个思路写完之后,发现自己的代码才打败30%左右,觉得不对劲。 + + 再比对,发现这是由于自己有个定势思维,就是那个慢指针一定是要指向下一个被插入的位置,然后他的 + 上一个位置来替换temp.这就导致了我每次if判断中都要执行一次j-1的计算操作。 +*/ + +func removeDuplicates2(nums []int) int { + len := int(len(nums)) + if len == 0 {return 0} + + i,j := int(1),int(1) + for ; i < len; i++ { + if (nums[i] != nums[j-1]) { + nums[j] = nums[i] + j++ + } + } + return j +} + +/* + 最终版本如下: + 通过调换赋值与自增的顺序。慢指针在对比前直接指向应该比对的元素。 + 比对发现不相等后,再自增正好指向了这次应该赋值的位置与下一次比对的位置。 + 击败了93.93% +*/ +func removeDuplicates3(nums []int) int { + len := int(len(nums)) + if len == 0 {return 0} + + i,j := int(1),int(0) + for ; i < len; i++ { + if (nums[i] != nums[j]) { + j++ + nums[j] = nums[i] + + } + } + return j + 1 +} \ No newline at end of file diff --git a/Week_01/G20200343030571/main/rotate-array.go b/Week_01/G20200343030571/main/rotate-array.go new file mode 100644 index 00000000..1864074c --- /dev/null +++ b/Week_01/G20200343030571/main/rotate-array.go @@ -0,0 +1,69 @@ +package main +/* +旋转数组 + 给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数。 + + 示例 1: + 输入: [1,2,3,4,5,6,7,8] 和 k = 3 + 输出: [6,7,8,1,2,3,4,5] + 解释: + 向右旋转 1 步: [7,1,2,3,4,5,6] + 向右旋转 2 步: [6,7,1,2,3,4,5] + 向右旋转 3 步: [5,6,7,1,2,3,4] + +/* + 一开始看了题之后毫无头绪,暴力法都没想出来,然后去看了题解发现原来那么暴力。。。 + 感觉那种暴力法我也能想出来,就是没往那么暴力上想。然后通过暴力法也没想到啥好的优化解法。 + 再看官方题解的三次反转,一开始没看懂时以为是用了啥比较高级的数学原理,后来再一看,才发现原来这个原理就是基于常识的。 + 然后有了思路就自己动手写了下, + 自己一开始没想到len == 1和k == 0的情况,只想到了len == 0的情况。 + 修改后通过,才击败36.92% +*/ +func rotate1(nums []int, k int) { + len := int(len(nums)) + if len <= 1 {return} + k = k % len + if k == 0 {return} + reverse1(nums, 0, len-1) + reverse1(nums, 0, k-1) + reverse1(nums, k, len-1) +} + +func reverse1(nums []int, i int, j int) { + for { + nums[i], nums[j] = nums[j], nums[i] + i++ + j-- + if i >= j { + break + } + } +} +/* + 全看了下题解,发现是因为这题应该用while-do的逻辑而不是do-while. + 用while-do的好处不仅可以省去一开始对k == 0的判断。 + 并且当 k == 1|| k == len-1时,可以少在一次反转中做一个不必要的反转操作(即:我 转 我 自 己)。 + 修改代码如下,击败95.48% + +*/ +func rotate2(nums []int, k int) { + len := int(len(nums)) + if len <= 1 {return} + k = k % len + //if k == 0 {return} + reverse2(nums, 0, len-1) + reverse2(nums, 0, k-1) + reverse2(nums, k, len-1) +} + +func reverse2(nums []int, i int, j int) { + for { + if i >= j { + break + } + nums[i], nums[j] = nums[j], nums[i] + i++ + j-- + + } +} \ No newline at end of file diff --git a/Week_01/G20200343030573/LeetCode_189_573.py b/Week_01/G20200343030573/LeetCode_189_573.py new file mode 100644 index 00000000..33de89a9 --- /dev/null +++ b/Week_01/G20200343030573/LeetCode_189_573.py @@ -0,0 +1,5 @@ +class Solution: + def rotate(self, nums, k): + n = len(nums) + k = k % n + nums[:] = nums[n-k:] + nums[:n-k] \ No newline at end of file diff --git a/Week_01/G20200343030573/LeetCode_1_573.py b/Week_01/G20200343030573/LeetCode_1_573.py new file mode 100644 index 00000000..38a449ca --- /dev/null +++ b/Week_01/G20200343030573/LeetCode_1_573.py @@ -0,0 +1,10 @@ +class Solution(object): + def twoSum(self, nums, target): + if len(nums) <= 1: + return False + buff_dict = {} + for i in range(len(nums)): + if nums[i] in buff_dict: + return [buff_dict[nums[i]], i] + else: + buff_dict[target - nums[i]] = i \ No newline at end of file diff --git a/Week_01/G20200343030573/LeetCode_21_573.py b/Week_01/G20200343030573/LeetCode_21_573.py new file mode 100644 index 00000000..50561bc6 --- /dev/null +++ b/Week_01/G20200343030573/LeetCode_21_573.py @@ -0,0 +1,7 @@ +class Solution: + def mergeTwoLists(self, a, b): + if a and b: + if a.val > b.val: + a, b = b, a + a.next = self.mergeTwoLists(a.next, b) + return a or b \ No newline at end of file diff --git a/Week_01/G20200343030573/LeetCode_26_573.py b/Week_01/G20200343030573/LeetCode_26_573.py new file mode 100644 index 00000000..057b9599 --- /dev/null +++ b/Week_01/G20200343030573/LeetCode_26_573.py @@ -0,0 +1,8 @@ +class Solution(object): + def removeDuplicates(self, nums): + x = 1 + for i in range(len(nums) - 1): + if (nums[i] != nums[i + 1]): + nums[x] = nums[i + 1] + x += 1 + return (x) diff --git a/Week_01/G20200343030573/LeetCode_283_573.py b/Week_01/G20200343030573/LeetCode_283_573.py new file mode 100644 index 00000000..2b08658d --- /dev/null +++ b/Week_01/G20200343030573/LeetCode_283_573.py @@ -0,0 +1,7 @@ +class Solution(object): + def moveZeroes(self, nums): + zero = 0 + for i in xrange(len(nums)): + if nums[i] != 0: + nums[i], nums[zero] = nums[zero], nums[i] + zero += 1 diff --git a/Week_01/G20200343030573/LeetCode_42_573.py b/Week_01/G20200343030573/LeetCode_42_573.py new file mode 100644 index 00000000..d5f7ac3c --- /dev/null +++ b/Week_01/G20200343030573/LeetCode_42_573.py @@ -0,0 +1,13 @@ +class Solution: + def trap(self, arr): + left = right = water = 0 + i, j = 0, len(arr) - 1 + while i <= j: + left, right = max(left, arr[i]), max(right, arr[j]) + while i <= j and arr[i] <= left <= right: + water += left - arr[i] + i += 1 + while i <= j and arr[j] <= right <= left: + water += right - arr[j] + j -= 1 + return water diff --git a/Week_01/G20200343030573/LeetCode_641_573.py b/Week_01/G20200343030573/LeetCode_641_573.py new file mode 100644 index 00000000..3bb698ae --- /dev/null +++ b/Week_01/G20200343030573/LeetCode_641_573.py @@ -0,0 +1,61 @@ +class MyCircularDeque: + + def __init__(self, k): + self._size = 0 + self._front, self._rear = 0, 0 + self._capacity = k + self._data = [-1] * k + + def getFront(self): + return self._data[self._front] + + def getRear(self): + return self._data[self._rear] + + def isEmpty(self): + return self._size == 0 + + def isFull(self): + return self._size == self._capacity + + def insertFront(self, value): + 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): + 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): + 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): + 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 diff --git a/Week_01/G20200343030573/LeetCode_66_573.py b/Week_01/G20200343030573/LeetCode_66_573.py new file mode 100644 index 00000000..9416d042 --- /dev/null +++ b/Week_01/G20200343030573/LeetCode_66_573.py @@ -0,0 +1,11 @@ +class Solution(object): + def plusOne(self, digits): + length = len(digits) - 1 + while digits[length] == 9: + digits[length] = 0 + length -= 1 + if (length < 0): + digits = [1] + digits + else: + digits[length] += 1 + return digits diff --git a/Week_01/G20200343030573/LeetCode_88_573.py b/Week_01/G20200343030573/LeetCode_88_573.py new file mode 100644 index 00000000..06adaca3 --- /dev/null +++ b/Week_01/G20200343030573/LeetCode_88_573.py @@ -0,0 +1,4 @@ +class Solution(object): + def merge(self, nums1, m, nums2, n): + nums1[m:] = nums2[:n] + nums1.sort() \ No newline at end of file diff --git a/Week_01/G20200343030575/LeetCode_11_575.swift b/Week_01/G20200343030575/LeetCode_11_575.swift new file mode 100644 index 00000000..0ba628f0 --- /dev/null +++ b/Week_01/G20200343030575/LeetCode_11_575.swift @@ -0,0 +1,22 @@ +/* + * @lc app=leetcode.cn id=11 lang=swift + * + * [11] 盛最多水的容器 + */ + +// @lc code=start +class Solution { + func maxArea(_ heights: [Int]) -> Int { + var areas = [Int]() + for i in 0.. [[Int]] { + var map = Dictionary>() + for i in 0..() + } + + map[nums[i]]!.insert(i) + } + var result = Set<[Int]>() + for i in 0.. 2 || (set.contains(i) == false && set.contains(j) == false) { + result.insert(sortThreeNum([nums[i], nums[j], opsiteSum])) + } + } + } + return Array(result) + } + + func sortThreeNum(_ nums: [Int]) -> [Int]{ + assert(nums.count == 3) + if nums[0] <= nums[1] { + if nums[1] <= nums[2] { + return [nums[0], nums[1], nums[2]] + }else if nums[0] <= nums[2] { + return [nums[0], nums[2], nums[1]] + }else{ + return [nums[2], nums[0], nums[1]] + } + }else{ + if nums[0] <= nums[2] { + return [nums[1], nums[0], nums[2]] + }else if nums[1] <= nums[2] { + return [nums[1], nums[2], nums[0]] + }else{ + return [nums[2], nums[1], nums[0]] + } + } + } +} + +// @lc code=end + diff --git a/Week_01/G20200343030575/LeetCode_167_575.swift b/Week_01/G20200343030575/LeetCode_167_575.swift new file mode 100644 index 00000000..f1466b90 --- /dev/null +++ b/Week_01/G20200343030575/LeetCode_167_575.swift @@ -0,0 +1,23 @@ +/* + * @lc app=leetcode.cn id=167 lang=swift + * + * [167] 两数之和 II - 输入有序数组 + */ + +// @lc code=start +class Solution { + func twoSum(_ numbers: [Int], _ target: Int) -> [Int] { + var left = 0, right = numbers.count - 1 + while(numbers[left] + numbers[right] != target){ + if numbers[left] + numbers[right] < target { + left += 1 + }else{ + right -= 1 + } + } + + return [left+1, right+1] + } +} +// @lc code=end + diff --git a/Week_01/G20200343030575/LeetCode_189_575.swift b/Week_01/G20200343030575/LeetCode_189_575.swift new file mode 100644 index 00000000..869f2bcf --- /dev/null +++ b/Week_01/G20200343030575/LeetCode_189_575.swift @@ -0,0 +1,38 @@ +/* + * @lc app=leetcode.cn id=189 lang=swift + * + * [189] 旋转数组 + */ + +// @lc code=start +class Solution { + func rotate(_ nums: inout [Int], _ k: Int) { + guard nums.count > 1, k > 0 else { + return + } + + let interval = k % nums.count + reverse(&nums, start: 0, end: nums.count) + reverse(&nums, start: 0, end: interval) + reverse(&nums, start: interval, end: nums.count) + } + + func reverse(_ nums: inout[Int], start: Int, end: Int){ + guard nums.count > 0, end > start, nums.count >= end else { + return + } + + var left = start; + var right = end - 1 + while(left < right){ + var temp = nums[left] + nums[left] = nums[right] + nums[right] = temp + + left += 1 + right -= 1 + } + } +} +// @lc code=end + diff --git a/Week_01/G20200343030575/LeetCode_1_575.swift b/Week_01/G20200343030575/LeetCode_1_575.swift new file mode 100644 index 00000000..805ba4d4 --- /dev/null +++ b/Week_01/G20200343030575/LeetCode_1_575.swift @@ -0,0 +1,21 @@ +/* + * @lc app=leetcode.cn id=1 lang=swift + * + * [1] 两数之和 + */ + +// @lc code=start +class Solution { + func twoSum(_ nums: [Int], _ target: Int) -> [Int] { + for i in 0.. ListNode? { + if l1 == nil { + return l2 + } + + if l2 == nil { + return l1 + } + + + let result: ListNode? + var current : ListNode? + + var left = l1, right = l2 + if l1!.val <= l2!.val { + result = l1 + current = l1 + left = l1?.next + }else{ + result = l2 + current = l2 + right = l2?.next + } + + while left != nil || right != nil { + + if left == nil { + current!.next = right + break + }else if right == nil { + current!.next = left + break + }else{ + if left!.val < right!.val { + current!.next = left + left = left?.next + }else{ + current!.next = right + right = right?.next + } + current = current!.next + } + } + + + return result + + } +} +// @lc code=end + diff --git a/Week_01/G20200343030575/LeetCode_26_575.swift b/Week_01/G20200343030575/LeetCode_26_575.swift new file mode 100644 index 00000000..a5af0f19 --- /dev/null +++ b/Week_01/G20200343030575/LeetCode_26_575.swift @@ -0,0 +1,30 @@ +/* + * @lc app=leetcode.cn id=26 lang=swift + * + * [26] 删除排序数组中的重复项 + */ + +// @lc code=start +class Solution { + func removeDuplicates(_ nums: inout [Int]) -> Int { + guard nums.count > 1 else{ + return nums.count + } + + var result = 0 + for i in 1.. 0 else { + return + } + + var notZeroIndex = 0 + for index in 0.. [Int] { + var result = digits + for i in (0.. Int { + guard n != 1 else { + return 1 + } + guard n != 2 else { + return 2 + } + + var results = Array.init(repeating: 1, count: n+1) + results[1] = 1 + results[2] = 2 + for i in 2...n { + results[i] = results[i-1] + results[i-2] + } + return results[n] + } +} +// @lc code=end + diff --git a/Week_01/G20200343030575/LeetCode_88_575.swift b/Week_01/G20200343030575/LeetCode_88_575.swift new file mode 100644 index 00000000..5b2c6449 --- /dev/null +++ b/Week_01/G20200343030575/LeetCode_88_575.swift @@ -0,0 +1,34 @@ +/* + * @lc app=leetcode.cn id=88 lang=swift + * + * [88] 合并两个有序数组 + */ + +// @lc code=start +class Solution { + func merge(_ nums1: inout [Int], _ m: Int, _ nums2: [Int], _ n: Int) { + var firstIndex = m - 1, secondIndex = n - 1 + var index = m + n - 1 + while firstIndex >= 0 && secondIndex >= 0 { + if nums1[firstIndex] >= nums2[secondIndex] { + nums1[index] = nums1[firstIndex] + firstIndex -= 1 + }else{ + nums1[index] = nums2[secondIndex] + secondIndex -= 1 + } + index -= 1 + } + + while secondIndex >= 0 { + nums1[index] = nums2[secondIndex] + secondIndex -= 1 + index -= 1 + + } + } +} + + +// @lc code=end + diff --git a/Week_01/G20200343030577/LeetCode_26_577.go b/Week_01/G20200343030577/LeetCode_26_577.go new file mode 100644 index 00000000..5fefb198 --- /dev/null +++ b/Week_01/G20200343030577/LeetCode_26_577.go @@ -0,0 +1,74 @@ +/* + * @lc app=leetcode.cn id=26 lang=golang + * + * [26] 删除排序数组中的重复项 + * + * https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array/description/ + * + * algorithms + * Easy (48.38%) + * Likes: 1328 + * Dislikes: 0 + * Total Accepted: 246K + * Total Submissions: 507K + * 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 +func removeDuplicates(nums []int) int { + // 处理空集或者只有一个元素的集合 + if len(nums) <=1 { + return len(nums) + } + + k := 0 + for i:= 1;i< len(nums);i++{ + if nums[i] != nums[k] { + k++ + nums[k] = nums[i] + } + } + return k+1 +} +// @lc code=end + diff --git a/Week_01/G20200343030577/LeetCode_283_577.go b/Week_01/G20200343030577/LeetCode_283_577.go new file mode 100644 index 00000000..602a1a8d --- /dev/null +++ b/Week_01/G20200343030577/LeetCode_283_577.go @@ -0,0 +1,48 @@ +/* + * @lc app=leetcode.cn id=283 lang=golang + * + * [283] 移动零 + * + * https://leetcode-cn.com/problems/move-zeroes/description/ + * + * algorithms + * Easy (59.14%) + * Likes: 496 + * Dislikes: 0 + * Total Accepted: 107.1K + * Total Submissions: 180.4K + * Testcase Example: '[0,1,0,3,12]' + * + * 给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。 + * + * 示例: + * + * 输入: [0,1,0,3,12] + * 输出: [1,3,12,0,0] + * + * 说明: + * + * + * 必须在原数组上操作,不能拷贝额外的数组。 + * 尽量减少操作次数。 + * + * + */ + +// @lc code=start +func moveZeroes(nums []int) { + k := 0 + for i := 0;i= 0; --j) +// nums[j + 1] = nums[j]; +// nums[0] = tmp; +// } +// }; + +// 2.新建临时数据存储结果。时间复杂度:O(n) 空间复杂度:O(n) +// var rotate = function(nums, k) { +// let arr = []; +// let len = nums.length; +// for (let i = 0; i < len; ++i) { +// arr[(i + k) % len] = nums[i]; +// } +// +// for (let i = 0; i < len; ++i) { +// nums[i] = arr[i]; +// } +// } + +// 3.翻转数组,然后分别翻转前k个元素和后面len - k个元素。时间复杂度:0(n) 空间复杂度:0(1) +var rotate = function (nums, k) { + k = k % nums.length; + reverse(nums, 0, nums.length); + reverse(nums, 0, k); + reverse(nums, k, nums.length); +} + +var reverse = function(nums, start, end) { + let L = start, R = end - 1; + while (L < R) { + let tmp = nums[L]; + nums[L] = nums[R]; + nums[R] = tmp; + + L++; R--; + } +} diff --git a/Week_01/G20200343030581/LeetCode_1_581.js b/Week_01/G20200343030581/LeetCode_1_581.js new file mode 100644 index 00000000..0989e299 --- /dev/null +++ b/Week_01/G20200343030581/LeetCode_1_581.js @@ -0,0 +1,25 @@ +/** + * @param {number[]} nums + * @param {number} target + * @return {number[]} + */ +// 1. 暴力 O(n^2) +// var twoSum = function(nums, target) { +// for (let i = 0; i < nums.length - 1; i++) { +// for (let j = i + 1; j < nums.length; j++) { +// if (nums[i] + nums[j] == target) +// return [i, j]; +// } +// } +// }; + +// 2.Hash O(n) +var twoSum = function (nums, target) { + let dic = {}; + for (let i = 0; i < nums.length; i++) { + if (dic[nums[i]] != undefined) { + return [dic[nums[i]], i]; + } + dic[target - nums[i]] = i; + } +} diff --git a/Week_01/G20200343030581/LeetCode_21_581.js b/Week_01/G20200343030581/LeetCode_21_581.js new file mode 100644 index 00000000..ad6af375 --- /dev/null +++ b/Week_01/G20200343030581/LeetCode_21_581.js @@ -0,0 +1,17 @@ +var mergeTwoLists = function(l1, l2) { + let dummy = new ListNode(0); + let p = dummy; + let p1 = l1, p2 = l2; + while (p1 && p2) { + if (p1.val < p2.val) { + p.next = p1; + p1 = p1.next; + } else { + p.next = p2; + p2 = p2.next; + } + p = p.next; + } + p.next = p1 ? p1 : p2 ? p2 : null; + return dummy.next; +} diff --git a/Week_01/G20200343030581/LeetCode_26_581.js b/Week_01/G20200343030581/LeetCode_26_581.js new file mode 100644 index 00000000..f22c3093 --- /dev/null +++ b/Week_01/G20200343030581/LeetCode_26_581.js @@ -0,0 +1,13 @@ +/** + * @param {number[]} nums + * @return {number} + */ +var removeDuplicates = function(nums) { + let j = 0; + for (let i = 0; i < nums.length; ++i) { + if (nums[i] == nums[i - 1]) continue; + nums[j++] = nums[i]; + } + + return j; +} diff --git a/Week_01/G20200343030581/LeetCode_283_581.js b/Week_01/G20200343030581/LeetCode_283_581.js new file mode 100644 index 00000000..1ce6af99 --- /dev/null +++ b/Week_01/G20200343030581/LeetCode_283_581.js @@ -0,0 +1,14 @@ +/** + * @param {number[]} nums + * @return {void} Do not return anything, modify nums in-place instead. + */ +// 1.左->右 +var moveZeroes = function(nums) { + let j = 0; + for (let i = 0; i < nums.length; ++i) { + if (nums[i]) + nums[j++] = nums[i]; + } + for (; j < nums.length; ++j) + nums[j] = 0; +} diff --git a/Week_01/G20200343030581/LeetCode_42_581.js b/Week_01/G20200343030581/LeetCode_42_581.js new file mode 100644 index 00000000..ac56e149 --- /dev/null +++ b/Week_01/G20200343030581/LeetCode_42_581.js @@ -0,0 +1,38 @@ +/** + * @param {number[]} height + * @return {number} + */ +// 1.暴力 +// var trap = function(height) { +// let res = 0; +// for(let k = 0; k < height.length; k++) { +// let maxLeftHeight = 0, maxRightHeight = 0; +// for (let i = 0; i <= k; ++i) +// maxLeftHeight = Math.max(maxLeftHeight, height[i]); +// for (let j = k; j < height.length; ++j) +// maxRightHeight = Math.max(maxRightHeight, height[j]); +// +// res += Math.min(maxLeftHeight, maxRightHeight) - height[k]; +// } +// +// return res; +// }; +// 2. 单调栈 +var trap = function (height) { + let res = 0; + let stack = []; + const peek = () => stack[stack.length - 1]; + for (let i = 0; i < height.length; i++) { + while (stack.length > 0 && height[i] > height[peek()]) { + let top = stack.pop(); + if (!stack.length) break; + let w = i - peek() - 1; + let h = Math.min(height[peek()], height[i]) - height[top]; + res += w * h; + } + + stack.push(i); + } + + return res; +} diff --git a/Week_01/G20200343030581/LeetCode_641_581.js b/Week_01/G20200343030581/LeetCode_641_581.js new file mode 100644 index 00000000..774ad80b --- /dev/null +++ b/Week_01/G20200343030581/LeetCode_641_581.js @@ -0,0 +1,111 @@ +/** + * Initialize your data structure here. Set the size of the deque to be k. + * @param {number} k + */ +var MyCircularDeque = function(k) { + this.capacity = k; + this.arr = []; +}; + +/** + * Adds an item at the front of Deque. Return true if the operation is successful. + * @param {number} value + * @return {boolean} + */ +MyCircularDeque.prototype.insertFront = function(value) { + if (this.arr.length < this.capacity) { + this.arr.unshift(value); + return true; + } + + return false; +}; + +/** + * Adds an item at the rear of Deque. Return true if the operation is successful. + * @param {number} value + * @return {boolean} + */ +MyCircularDeque.prototype.insertLast = function(value) { + if (this.arr.length < this.capacity) { + this.arr.push(value); + return true; + } + + return false; +}; + +/** + * Deletes an item from the front of Deque. Return true if the operation is successful. + * @return {boolean} + */ +MyCircularDeque.prototype.deleteFront = function() { + if (this.arr.length > 0) { + this.arr.shift(); + return true; + } + + return false; +}; + +/** + * Deletes an item from the rear of Deque. Return true if the operation is successful. + * @return {boolean} + */ +MyCircularDeque.prototype.deleteLast = function() { + if (this.arr.length > 0) { + this.arr.pop(); + return true; + } + + return false; +}; + +/** + * Get the front item from the deque. + * @return {number} + */ +MyCircularDeque.prototype.getFront = function() { + if (this.arr.length > 0) + return this.arr[0]; + return -1; +}; + +/** + * Get the last item from the deque. + * @return {number} + */ +MyCircularDeque.prototype.getRear = function() { + if (this.arr.length > 0) + return this.arr[this.arr.length - 1]; + return -1; +}; + +/** + * Checks whether the circular deque is empty or not. + * @return {boolean} + */ +MyCircularDeque.prototype.isEmpty = function() { + return this.arr.length == 0; +}; + +/** + * Checks whether the circular deque is full or not. + * @return {boolean} + */ +MyCircularDeque.prototype.isFull = function() { + return this.arr.length == this.capacity; +}; + +/** + * Your MyCircularDeque object will be instantiated and called as such: + * var obj = new MyCircularDeque(k) + * var param_1 = obj.insertFront(value) + * var param_2 = obj.insertLast(value) + * var param_3 = obj.deleteFront() + * var param_4 = obj.deleteLast() + * var param_5 = obj.getFront() + * var param_6 = obj.getRear() + * var param_7 = obj.isEmpty() + * var param_8 = obj.isFull() + */ diff --git a/Week_01/G20200343030581/LeetCode_66_581.js b/Week_01/G20200343030581/LeetCode_66_581.js new file mode 100644 index 00000000..227deaf0 --- /dev/null +++ b/Week_01/G20200343030581/LeetCode_66_581.js @@ -0,0 +1,17 @@ +/** + * @param {number[]} digits + * @return {number[]} + */ +var plusOne = function(digits) { + for (let i = digits.length - 1; i >= 0; --i) { + if (digits[i] == 9) + digits[i] = 0; + else { + digits[i]++; + return digits; + } + } + digits.unshift(1); + + return digits; +} diff --git a/Week_01/G20200343030581/LeetCode_88_581.js b/Week_01/G20200343030581/LeetCode_88_581.js new file mode 100644 index 00000000..0d7d35a5 --- /dev/null +++ b/Week_01/G20200343030581/LeetCode_88_581.js @@ -0,0 +1,18 @@ +/** + * @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) { + let k = m + n - 1; + for (var i = m - 1, j = n - 1; 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--]; +} diff --git a/Week_01/G20200343030583/LeetCode_189_583.py b/Week_01/G20200343030583/LeetCode_189_583.py new file mode 100644 index 00000000..04f520b4 --- /dev/null +++ b/Week_01/G20200343030583/LeetCode_189_583.py @@ -0,0 +1,73 @@ +# +# @lc app=leetcode id=189 lang=python3 +# +# [189] Rotate Array +# 1. pop the last one, insert into first position which is very slow with O(k*n) +# 2. cyclic replacement in the list (https://leetcode.com/problems/rotate-array/discuss/269948/4-solutions-in-python-(From-easy-to-hard)) +# 3. use reverse (call 3 times): reverse the whole list, reverse first k elements, reverse the rest elements. (same url) +# 4. use deque (collection.deque(nums)), but O(n) extra memory (https://leetcode.com/problems/rotate-array/discuss/54564/Python-easy-to-understand-solutions.) +# The last solution is not provided in this code file. +# @lc code=start + +# first +# class Solution: +# def rotate(self, nums: List[int], k: int) -> None: +# """ +# Do not return anything, modify nums in-place instead. +# """ +# for i in range(k): +# e = nums.pop() +# nums.insert(0,e) + +# second +# class Solution: +# def rotate(self, nums: List[int], k: int) -> None: +# """ +# Do not return anything, modify nums in-place instead. +# """ +### Note that there would be case that the list just contain one elements but k > 1, +### i.e. reverse itself twice +# k = k % len(nums) +# start = 0 +# count = 0 +# while count < len(nums) +# current = start +# prev = nums[current] + +# while True: +# next = (current + k) % len(nums) +# temp = nums[next] +# nums[next] = prev +# prev = temp +# current = next +# count += 1 + +# if start == current: +# break + +# start += 1 + +# third +class Solution: + def rotate(self, nums: List[int], k: int) -> None: + """ + Do not return anything, modify nums in-place instead. + """ +### Note that there would be case that the list just contain one elements but k > 1, +### i.e. reverse itself twice + k = k % len(nums) + # Note that you need to use self._function + self.reverse(0, len(nums) - 1, nums) + self.reverse(0, k - 1, nums) + self.reverse(k, len(nums) - 1, nums) + + # Note that you need to add self as a param in a class + def reverse(self, start, end, nums) -> None: + while start < end: + nums[start],nums[end] = nums[end], nums[start] + start += 1 + end -= 1 + + +# @lc code=end + diff --git a/Week_01/G20200343030583/LeetCode_1_583.py b/Week_01/G20200343030583/LeetCode_1_583.py new file mode 100644 index 00000000..dfa58943 --- /dev/null +++ b/Week_01/G20200343030583/LeetCode_1_583.py @@ -0,0 +1,48 @@ +# +# @lc app=leetcode id=1 lang=python +# +# [1] Two Sum +# 1. brute force, O(n*n) +# 2. hash table mapping, O(n) +# 3. two pointer, O(n) + +# @lc code=start +# Second +# class Solution(object): +# def twoSum(self, nums, target): +# """ +# :type nums: List[int] +# :type target: int +# :rtype: List[int] +# """ +# map = dict() +# for i in range(len(nums)): +# if nums[i] not in map: +# # because there is exactly one solution +# map[target - nums[i]] = i +# else: +# return map[nums[i]],i +# return -1, -1 + +# Third +class Solution(object): + def twoSum(self, nums, target): + """ + :type nums: List[int] + :type target: int + :rtype: List[int] + """ + nums = enumerate(nums) + nums = sorted(nums, key = lambda x:x[1]) + i,j = 0, len(nums) - 1 + while i < j: + if nums[i][1] + nums[j][1] < target: + i += 1 + elif nums[i][1] + nums[j][1] > target: + j -= 1 + else: + return sorted([nums[i][0],nums[j][0]]) + + return -1, -1 +# @lc code=end + diff --git a/Week_01/G20200343030583/LeetCode_21_583.py b/Week_01/G20200343030583/LeetCode_21_583.py new file mode 100644 index 00000000..02fe8d36 --- /dev/null +++ b/Week_01/G20200343030583/LeetCode_21_583.py @@ -0,0 +1,66 @@ +# +# @lc app=leetcode id=21 lang=python +# +# [21] Merge Two Sorted Lists +# 1. iteratively +# 2. recursively + +# @lc code=start +# Definition for singly-linked list. +# class ListNode(object): +# def __init__(self, x): +# self.val = x +# self.next = None + +# First +# class Solution(object): +# def mergeTwoLists(self, l1, l2): +# """ +# :type l1: ListNode +# :type l2: ListNode +# :rtype: ListNode +# """ +# # No head point +# # because it may not go into the first loop +# current = l = ListNode(0) +# p = l1 +# q = l2 + +# while p and q: +# if p.val < q.val: +# current.next = p +# p = p.next +# else: +# current.next = q +# q = q.next +# current = current.next +# if q: +# current.next = q +# if p: +# current.next = p +# return l.next + +# Second +def mergeTwoLists(self, l1, l2): + """ + :type l1: ListNode + :type l2: ListNode + :rtype: ListNode + """ + if not l1: + return l2 + if not l2: + return l1 + + start = None + if l1.val < l2.val: + start = l1 + start.next = self.mergeTwoLists(l1.next,l2) + else: + start = l2 + start.next = self.mergeTwoLists(l1, l2.next) + + return start + +# @lc code=end + diff --git a/Week_01/G20200343030583/LeetCode_26_583.py b/Week_01/G20200343030583/LeetCode_26_583.py new file mode 100644 index 00000000..9a69980f --- /dev/null +++ b/Week_01/G20200343030583/LeetCode_26_583.py @@ -0,0 +1,20 @@ +# +# @lc app=leetcode id=26 lang=python3 +# +# [26] Remove Duplicates from Sorted Array +# 1. brute force, count distinct elements, O(n) +# 2. directly s = set(nums), return len(s), list(s), but not satisfy the needs for this case + +# @lc code=start +class Solution: + def removeDuplicates(self, nums: List[int]) -> int: + x = 1 + for i in range(len(nums) - 1): + if nums[i] != nums[i+1]: + nums[x] = nums[i+1] + x += 1 + return x + + +# @lc code=end + diff --git a/Week_01/G20200343030583/LeetCode_283_583.py b/Week_01/G20200343030583/LeetCode_283_583.py new file mode 100644 index 00000000..f29bffc6 --- /dev/null +++ b/Week_01/G20200343030583/LeetCode_283_583.py @@ -0,0 +1,45 @@ +# +# @lc app=leetcode id=283 lang=python +# +# [283] Move Zeroes +# + +# @lc code=start +# class Solution(object): +# def moveZeroes(self, nums): +# """ +# :type nums: List[int] +# :rtype: None Do not return anything, modify nums in-place instead. +# """ +# zero_pointer = self.find_first_zero(nums) +# for i in range(len(nums)): +# if nums[i] != 0 and i > zero_pointer: +# nums[zero_pointer],nums[i] = nums[i],0 +# zero_pointer = self.find_first_zero(nums[zero_pointer + 1:]) + +# def find_first_zero(self, nums): +# i = 0 +# while nums[i] != 0: +# i += 1 +# return i + +class Solution(object): + def moveZeroes(self, nums): + """ + :type nums: List[int] + :rtype: None Do not return anything, modify nums in-place instead. + """ + count = 0 + for i in range (len(nums)): + if nums[i] != 0: + nums[count] = nums[i] + count += 1 + while count < len(nums): + nums[count] = 0 + count += 1 + + + + +# @lc code=end + diff --git a/Week_01/G20200343030583/LeetCode_42_583.py b/Week_01/G20200343030583/LeetCode_42_583.py new file mode 100644 index 00000000..1ac999e5 --- /dev/null +++ b/Week_01/G20200343030583/LeetCode_42_583.py @@ -0,0 +1,83 @@ +# +# @lc app=leetcode id=42 lang=python +# +# [42] Trapping Rain Water +# 1. brute force O(n^2), for each bar, find left max and right max height +# 2. dynamic programming to store left max height and right max height O(n) +# 3. stack O(n) +# 4. two pointer O(n) https://leetcode.com/problems/trapping-rain-water/discuss/17554/Share-my-one-pass-Python-solution-with-explaination + +# @lc code=start +# second +# class Solution(object): +# def trap(self, height): +# """ +# :type height: List[int] +# :rtype: int +# """ +# if len(height) <= 1: +# return 0 +# left_max = [0 for i in range(len(height))] +# right_max = [0 for j in range(len(height))] +# left_max[0], right_max[-1] = height[0], height[len(height) - 1] +# for i in range(1,len(height)): +# left_max[i] = max(left_max[i - 1], height[i]) +# for j in range(len(height) - 2, -1, -1): +# right_max[j] = max(right_max[j+1], height[j]) +# ans = 0 +# for i in range(len(height)): +# ans += min(left_max[i],right_max[i]) - height[i] +# return ans + +# Third +# class Solution(object): +# def trap(self, height): +# """ +# :type height: List[int] +# :rtype: int +# """ +# if len(height) <= 1: +# return 0 +# stack = [] +# ans = 0 +# for current in range(len(height)): +# while(len(stack) != 0 and height[current] > height[stack[-1]]): +# h = height[stack[-1]] +# stack.pop() +# if len(stack) == 0: +# break +# stack_top = stack[-1] +# distance = current - stack_top - 1 +# boundary_height = min(height[stack_top],height[current]) - h +# ans += distance * boundary_height + +# stack.append(current) + +# return ans + +# Fourth +class Solution(object): + def trap(self, height): + """ + :type height: List[int] + :rtype: int + """ + if len(height) <= 1: + return 0 + ans = 0 + left = 0 + right = len(height) - 1 + left_max = height[left] + right_max = height[right] + while left < right: + left_max, right_max = max(left_max,height[left]),max(right_max,height[right]) + if left_max <= right_max: + ans += left_max - height[left] + left += 1 + else: + ans += right_max - height[right] + right -= 1 + + return ans +# @lc code=end + diff --git a/Week_01/G20200343030583/LeetCode_641_583.py b/Week_01/G20200343030583/LeetCode_641_583.py new file mode 100644 index 00000000..fce0b81a --- /dev/null +++ b/Week_01/G20200343030583/LeetCode_641_583.py @@ -0,0 +1,127 @@ +# +# @lc app=leetcode id=641 lang=python +# +# [641] Design Circular Deque +# 1. use list +# 2. use collection.deque,use appendleft() for insertFront() and popleft() for deleteFront() + +# @lc code=start +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.Deque = [] + # self.Deque = collection.deque([]) + + 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.Deque) < self.size: + self.Deque = [value] + self.Deque + # self.Deque.appendleft(value) + return True + else: + 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.Deque) < self.size: + self.Deque.append(value) + return True + else: + return False + + + def deleteFront(self): + """ + Deletes an item from the front of Deque. Return true if the operation is successful. + :rtype: bool + """ + if len(self.Deque) == 0: + return False + else: + self.Deque = self.Deque[1:] + # self.Deque.popleft() + return True + + def deleteLast(self): + """ + Deletes an item from the rear of Deque. Return true if the operation is successful. + :rtype: bool + """ + if len(self.Deque) == 0: + return False + else: + self.Deque.pop() + return True + + + + def getFront(self): + """ + Get the front item from the deque. + :rtype: int + """ + if len(self.Deque) == 0: + return -1 + else: + return self.Deque[0] + + + def getRear(self): + """ + Get the last item from the deque. + :rtype: int + """ + if len(self.Deque) == 0: + return -1 + else: + return self.Deque[-1] + + + def isEmpty(self): + """ + Checks whether the circular deque is empty or not. + :rtype: bool + """ + if len(self.Deque) == 0: + return True + else: + return False + + def isFull(self): + """ + Checks whether the circular deque is full or not. + :rtype: bool + """ + if len(self.Deque) < self.size: + return False + else: + return True + + +# 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() +# @lc code=end + diff --git a/Week_01/G20200343030583/LeetCode_66_583.py b/Week_01/G20200343030583/LeetCode_66_583.py new file mode 100644 index 00000000..56d9d39f --- /dev/null +++ b/Week_01/G20200343030583/LeetCode_66_583.py @@ -0,0 +1,62 @@ +# +# @lc app=leetcode id=66 lang=python +# +# [66] Plus One +# 1. Check the final digit firstly, then process x99 case by converting into string +# 2. Convert into string -> integer value + 1-> string -> integer value +# 3. Check every digits + +# @lc code=start + +# First +# class Solution(object): +# def plusOne(self, digits): +# """ +# :type digits: List[int] +# :rtype: List[int] +# """ +# # most simple case +# if digits[-1] < 9: +# digits[-1] += 1 +# return digits +# else: +# num_digits = len(digits) +# sum = 0 +# i = num_digits - 1 +# j = 0 +# while i >= 0: +# sum += digits[j] * pow(10,i) +# i -= 1 +# j += 1 +# sum += 1 +# new_digits = [int(e) for e in list(str(sum))] +# return new_digits + +# Second +# class Solution(object): +# def plusOne(self, digits): +# """ +# :type digits: List[int] +# :rtype: List[int] +# """ +# return [int(j) for j in list(str(int(''.join([str(i) for i in digits])) + 1))] + +# Third +class Solution(object): + def plusOne(self, digits): + """ + :type digits: List[int] + :rtype: List[int] + """ + digits[-1] += 1 + for i in range(len(digits)-1,0,-1): + if digits[i] != 10: + break + else: + digits[i-1], digits[i] = digits[i-1] + 1, 0 + if digits[0] == 10: + digits[0] = 0 + digits = [1] + digits + return digits +# @lc code=end + diff --git a/Week_01/G20200343030583/LeetCode_88_583.py b/Week_01/G20200343030583/LeetCode_88_583.py new file mode 100644 index 00000000..acbf66c2 --- /dev/null +++ b/Week_01/G20200343030583/LeetCode_88_583.py @@ -0,0 +1,76 @@ +# +# @lc app=leetcode id=88 lang=python +# +# [88] Merge Sorted Array +# 1. use extra list to store +# and then change the value in nums1 (from small to large), O(n) +# 2. Directly change nums1, from large to small, O(n) +# 3. Direcly use sorted function and renew value in nums1 +# @lc code=start + +# First +# 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. +# """ + +# # extreme case need to be considered first +# if n == 0: +# return +# if m == 0 and n != 0 : +# # for i in range (n): +# # nums1[i] = nums2[i] +# nums1[:] = nums2[:] +# return + +# nums = [] +# p = 0 +# q = 0 +# while p < m and q < n: +# if nums1[p] < nums2[q]: +# nums.append(nums1[p]) +# p += 1 +# else: +# nums.append(nums2[q]) +# q += 1 + +# if q < n: +# nums = nums + nums2[q:] +# if p < m: +# nums = nums + nums1[p:] +# # Note that nums + nums1[p:] may exceed m + n because there +# # are some 0s in nums 1 +# for i in range(m + n): +# nums1[i] = nums[i] + +# Second +# class Solution: +# def merge(self, nums1: List[int], m: int, nums2: List[int], n: int) -> None: +# """ +# Do not return anything, modify nums1 in-place instead. +# """ +# while m > 0 and n > 0: +# if nums1[m - 1] > nums2[n - 1]: +# nums1[m + n - 1] = nums1[m - 1] +# m -= 1 +# else: +# nums1[m + n - 1] = nums2[n - 1] +# n -= 1 + +# nums1[:n] = nums2[:n] + +# Third +class Solution: + def merge(self, nums1: List[int], m: int, nums2: List[int], n: int) -> None: + """ + Do not return anything, modify nums1 in-place instead. + """ + nums1[:] = sorted(nums1[:m] + nums2[:n]) + +# @lc code=end + diff --git a/Week_01/G20200343030583/NOTE.md b/Week_01/G20200343030583/NOTE.md index 50de3041..2caebbac 100644 --- a/Week_01/G20200343030583/NOTE.md +++ b/Week_01/G20200343030583/NOTE.md @@ -1 +1,52 @@ -学习笔记 \ No newline at end of file +## 学习笔记 week01 Summary +### Array: +- Prepend: O(1) [*] +- Append: O(1) +- Lookup: O(1) +- Insert: O(n) +- Delete: O(n) + +### LinkList: +- Prepend: O(1) +- Append: O(1) +- Lookup: O(n) +- Insert: O(1) +- Delete: O(1) + +### Skip List: +升维 + 空间换时间
+Add index for some node: 一级索引,二级索引(more coarse),……,多级索引
+时间复杂度 O(log n)
+维护成本较高。添加和删除都要重新对索引进行修改
+空间复杂度 O(n)
+ +Q70
+!找最近 重复子问题
+第三级台阶走法:第一级台阶 + 2步; 第二级台阶 + 1步
+f(3) = f(1) + f(2)
+f(4) = f(2) + f(3)
+->fibonacci
+ +懵逼时候: +1. 能不能暴力解?基本情况
+2. 找最近重复子问题 (重复性) + +#### 双指针方法 +1.可能要排序?
+2.向中缩进 (根据题目条件判断缩进策略)
+E.g, 3 sums and 两柱中间面积
+\* 快慢指针 (检测链表有环) + +### deque 双端队列 + +### Priority queue +Push: O(1)
+Pop: O(log n) 按照元素优先级取出
+底层具体实现的数据结构较为多样和复杂:heap, bst, treap
+ +#### 最近相关性 -> 用栈来解决 +E.g. 括号字符串的有效性 Q20 + +#### 先来后到 -> queue +E.g. Sliding window -> queue Q239 + diff --git a/Week_01/G20200343030585/Deque.java b/Week_01/G20200343030585/Deque.java new file mode 100644 index 00000000..f711aacf --- /dev/null +++ b/Week_01/G20200343030585/Deque.java @@ -0,0 +1,18 @@ +import java.util.ArrayDeque; + +public class Deque { + public static void main(final String[] args) { + final ArrayDeque deque = new ArrayDeque(); + deque.addFirst("a"); + deque.addFirst("b"); + deque.addFirst("c"); + System.out.println(deque); + final 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); + } +} // class定义结束 \ No newline at end of file diff --git a/Week_01/G20200343030585/LeetCode_189_585.py b/Week_01/G20200343030585/LeetCode_189_585.py new file mode 100644 index 00000000..60a1716d --- /dev/null +++ b/Week_01/G20200343030585/LeetCode_189_585.py @@ -0,0 +1,40 @@ +# -*- coding:utf-8 -*- + +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. 将需要移动到头部的元素取出,将其他元素后移,将移动的元素放到前面 + 2. 使用反转来实现 + 1.想整体反转,这样所有数据就倒了 + 2.再把0-k部分反转 + 3.把k-end部分反转 + 4.对于旋转的次数比数组元素大的情况,可以理解为把所有元素旋转1遍到多遍后(也就是不改变元素原来的位置),最后执行一遍k - length的操作 + + """ + if k > len(nums): + return False + nums.reverse() + nums = self.reverse(nums, 0, k - 1) + nums = self.reverse(nums, k, len(nums) - 1) + return nums + + + def reverse(self, nums, start, end): + while True: + if start >= end: + break + + temp = nums[start] + nums[start] = nums[end] + nums[end] = temp + start += 1 + end -= 1 + return nums + +if __name__ == "__main__": + obj = Solution() + print(obj.rotate([1,2,3,4,5,6,7,8,9,0], 3)) \ No newline at end of file diff --git a/Week_01/G20200343030585/LeetCode_1_585.py b/Week_01/G20200343030585/LeetCode_1_585.py new file mode 100644 index 00000000..4087eb3c --- /dev/null +++ b/Week_01/G20200343030585/LeetCode_1_585.py @@ -0,0 +1,33 @@ +# -*- coding:utf-8 -*- +class Solution(object): + def twoSum(self, nums, target): + """ + :type nums: List[int] + :type target: int + :rtype: List[int] + """ + #需要从一个整数数组里面任意找出两个整数他们的和与指定的值相同 + # 1.迭代找出每个两位数,顺序取一个元素为主元素,然后依次再去一个剩下的元素, + # 两个一起匹配结果,如果每个子元素都匹配完依然没有结果就使用下一个主元素, + # 依次使用完所有元素,如果没有就不能满足 + # 2. 然后匹配指定目标值 + i = 0 + j = 0 + length = len(nums) + while True: + if j >= length: + return False + + master = nums[j] + for i in range(j+1, length): + iterm = nums[i] + if master + iterm == target: + return [j, i] + j = j + 1 + +if __name__ == "__main__": + obj = Solution() + print(obj.twoSum([11, 15, 2, 7], 9)) + + + \ No newline at end of file diff --git a/Week_01/G20200343030585/LeetCode_21_585.py b/Week_01/G20200343030585/LeetCode_21_585.py new file mode 100644 index 00000000..e50c0baf --- /dev/null +++ b/Week_01/G20200343030585/LeetCode_21_585.py @@ -0,0 +1,36 @@ +# -*- coding:utf-8 -*- + +# 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 + 解题思路: + 1.使用一个新list保存合并后的数据 + 2. 由于两个链表都有序,一次循环两个链表,使用两个指针分别指向两个链表表头 + 3. 依次比较两个链表的元素,元素小的添加到新list,然后将指针后移,再进行比较 + 4. 如果指针已经大于当前list,直接添加另一个list的所有值 + """ + + l3 = ListNode("") + ret = l3 + + while l1 and l2: + if l1.val > l2.val: + l3.next = l2 + l2 = l2.next + else: + l3.next = l1 + l1 = l1.next + l3 = l3.next + + l3.next = l1 if l1 is not None else l2 + return ret.next + \ No newline at end of file diff --git a/Week_01/G20200343030585/LeetCode_283_585.py b/Week_01/G20200343030585/LeetCode_283_585.py new file mode 100644 index 00000000..c61e7878 --- /dev/null +++ b/Week_01/G20200343030585/LeetCode_283_585.py @@ -0,0 +1,25 @@ +# -*- coding:utf-8 -*- +class Solution(object): + def moveZeroes(self, nums): + """ + :type nums: List[int] + :rtype: None Do not return anything, modify nums in-place instead. + """ + length = len(nums) + if length <= 0: + return + cnt = 0 + for i in range(length): + if nums[i] != 0: + nums[cnt] = nums[i] + if i > cnt: + nums[i] = 0 + cnt += 1 + + print(nums) + + +if __name__ == "__main__": + obj = Solution() + obj.moveZeroes([-959151711, 623836953, 209446690, -1950418142, 1339915067, -733626417, 481171539, -2125997010, -1225423476, 1462109565, 147434687, -1800073781, -1431212205, -450443973, 50097298, 753533734, -747189404, -2070885638, 0, -1484353894, -340296594, -2133744570, 619639811, -1626162038, 669689561, 0, 112220218, 502447212, -787793179, 0, -726846372, -1611013491, 204107194, 1605165582, -566891128, 2082852116, 0, 532995238, -1502590712, 0, 2136989777, -2031153343, 371398938, -1907397429, 342796391, 609166045, -2007448660, -1096076344, -323570318, 0, - + 2082980371, 2129956379, -243553361, -1549960929, 1502383415, 0, -1394618779, 694799815, 78595689, -1439173023, -1416578800, 685225786, -333502212, -1181308536, -380569313, 772035354, 0, -915266376, 663709718, 1443496021, -777017729, -883300731, -387828385, 1907473488, -725483724, -972961871, -1255712537, 383120918, 1383877998, 1722751914, 0, -1156050682, 1952527902, -560244497, 1304305692, 1173974542, -1313227247, -201476579, -298899493, -1828496581, -1724396350, 1933643204, 1531804925, 1728655262, -955565449, 0, -69843702, -461760848, 268336768, 1446130876]) diff --git a/Week_01/G20200343030585/LeetCode_42_585.py b/Week_01/G20200343030585/LeetCode_42_585.py new file mode 100644 index 00000000..158ba342 --- /dev/null +++ b/Week_01/G20200343030585/LeetCode_42_585.py @@ -0,0 +1,49 @@ +# -*- coding:utf-8 -*- +# 解题思路: +# 1 什么是能接水的空间,是一个柱子后有个下降的空间,等于是后面柱子的高度小于当前柱子的高度,同时后面还要有个上升空间 +# 2 知道了接水的空间后再计算接水的大小,1宽度*1高度为一个单位,下降的空间会有占用空间的柱子,要把这个删除 +# 3 使用一个栈和两个指针,第一个指针指向第一个元素,第二个指针依次指向第一个指针后面的元素 +# 4 发现一个柱子比栈顶小就入栈,比栈顶高栈顶元素出栈,出栈后再计算与新的栈顶之间的水, +# min(height[current], height[st[top]]) * (current - st[top] - 1) +# 可以将两边中一边最高的元素作为水池的高,减去中间任意大于0的柱子 heights[i], +# + + +class Solution(object): + def trap(self, height): + """ + :type height: List[int] + :rtype: int + """ + if len(height) < 3: + return 0 + + sum = 0 # 总蓄水量 + current = 0 # 当前指针 + st = [] # stack + + + for current in range(0, len(height)): + # 如果栈不空并且当前指向的高度大于栈顶高度就一直循环 + while len(st) > 0 and height[current] > height[st[0]]: + h = height[st[0]]; # 取出要出栈的元素 + st.pop(0); #出栈 + if (len(st) == 0): # 栈空就出去 + break; + + distance = current - st[0] - 1 #两堵墙之前的距离。 + minVal = min(height[st[0]], height[current]) + sum = sum + distance * (minVal - h) + + st.insert(0, current) # 当前指向的墙入栈 + current += 1 # 指针后移 + + return sum + +if __name__ == "__main__": + obj = Solution() + # print(obj.trap([0,1,0,2,0,1,0,1,3,2,1,2,1])) + # print(obj.trap([1,2,3,4,0,5])) + # print(obj.trap([2,0,2])) + print(obj.trap([9,2,9,3,2,2,1,4,8])) + \ No newline at end of file diff --git a/Week_01/G20200343030585/LeetCode_641_585.py b/Week_01/G20200343030585/LeetCode_641_585.py new file mode 100644 index 00000000..8ef2c2c1 --- /dev/null +++ b/Week_01/G20200343030585/LeetCode_641_585.py @@ -0,0 +1,141 @@ +# -*- coding:utf-8 -*- + +# 解题思路 +# 循环双端队列可以理解一个两端都可以插入删除的队列,同时队列的指针可以从存储结构的尾部走到头部 +# 队列会有两个指针一个指向头部元素,一个指向尾部元素的后一位 +# 判断队列为空需要将判断两个指针是否指向同一个位置,为避免队列为满的时候也出现这种情况,队列中多增加一个占位元素 +# 插入一个元素,从前端插入需要计算指针的位置,就是从队头部增加,考虑存在循环的情况,所以要模上存储的大小 +# 队尾指针始终未最后一个元素+1的位置 +# 获取队头元素和队尾元素并不影响指针的位置,只返回值就可以 + +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.front = 0 # front始终指向第一个元素的位置 + self.rear = 0 + self.capacity = k + 1 # 多出来一个是为了保证空和满的判断不冲突 + self.a = [0 for _ in range(self.capacity)] + + 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.a[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.a[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.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 + return True + + + def getFront(self): + """ + Get the front item from the deque. + :rtype: int + """ + if self.isEmpty(): + return -1 + return self.a[self.front] + + + def getRear(self): + """ + Get the last item from the deque. + :rtype: int + """ + if self.isEmpty(): + return -1 + return self.a[(self.rear - 1 + self.capacity) % self.capacity] + + + def isEmpty(self): + """ + Checks whether the circular deque is empty or not. + :rtype: bool + """ + return self.rear == self.front + + + def isFull(self): + """ + Checks whether the circular deque is full or not. + :rtype: bool + """ + return (self.rear + 1) % self.capacity == self.front + + def __str__(self): + return " ".join([str(x) for x in self.a]) + + + + +if __name__ == "__main__": + obj = MyCircularDeque(3) + param_1 = obj.insertFront(1) + param_2 = obj.insertLast(2) + param_2 = obj.insertLast(3) + param_2 = obj.insertLast(4) + + param_6 = obj.getRear() + + param_3 = obj.isFull() + print(param_3) + + param_4 = obj.deleteLast() + + param_5 = obj.getFront() + param_7 = obj.isEmpty() + + param_8 = obj.isFull() + print(param_8) + + +# 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/G20200343030585/LeetCode_66_585.py b/Week_01/G20200343030585/LeetCode_66_585.py new file mode 100644 index 00000000..639727ba --- /dev/null +++ b/Week_01/G20200343030585/LeetCode_66_585.py @@ -0,0 +1,31 @@ +# -*- coding:utf-8 -*- + +# 解题思路 +# 1.输入是非负整数组成的数组,每个元素为一个数字 +# 2.要求在这个数字上+1,然后再按大小输出到数组,保证在数组里面的顺序是从大到小 +# 3.由于只是加一,只需要考虑最后一位+1的情况 +# 1. 最后一位非9,+1后直接写入最后一位的值就行 +# 2. 最后一位为9,+1后结果为0,需要判断然后进一位+1,这个步骤可以循环 +# 3.最后排除数字全是9的情况 + +class Solution(object): + def plusOne(self, digits): + """ + :type digits: List[int] + :rtype: List[int] + """ + length = len(digits) + for i in range(length - 1, -1, -1): + digits[i] += 1 + digits[i] = digits[i] % 10 + if digits[i] != 0: + return digits + + digits.insert(0, 1) + return digits + + + +if __name__ == "__main__": + obj = Solution() + print(obj.plusOne([9,9,9])) \ No newline at end of file diff --git a/Week_01/G20200343030587/src/main/java/com/work/LeetCode_1_587.java b/Week_01/G20200343030587/src/main/java/com/work/LeetCode_1_587.java new file mode 100644 index 00000000..038d3d11 --- /dev/null +++ b/Week_01/G20200343030587/src/main/java/com/work/LeetCode_1_587.java @@ -0,0 +1,59 @@ +package com.work; + +import java.util.HashMap; +import java.util.Map; + +/** + * 两数之和 + * + * 给定一个整数数组 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 + * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + */ + +public class LeetCode_1_587 { + 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[i] + nums[j] == target) { + // return new int[]{i,j}; + // } + // } + // } + //hashmap 二次循环 + // 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++) { + // Integer num = map.get(target - nums[i]); + // if(num != null && num != i) { + // return new int[]{i,num}; + // } + //} + + //hashmap 一次循环 + Map map = new HashMap<>(); + for(int i = 0; i < nums.length; i++) { + Integer val = map.get(target - nums[i]); + if(val != null && val.intValue() != i){ + return new int[]{i,val}; + } + map.put(nums[i], i); + } + + throw new IllegalArgumentException("No two sum solution"); + } +} diff --git a/Week_01/G20200343030587/src/main/java/com/work/LeetCode_26_587.java b/Week_01/G20200343030587/src/main/java/com/work/LeetCode_26_587.java new file mode 100644 index 00000000..89af71c5 --- /dev/null +++ b/Week_01/G20200343030587/src/main/java/com/work/LeetCode_26_587.java @@ -0,0 +1,40 @@ +package com.work; + +/** + * + * 删除排序数组中的重复项 + * + * 给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。 + * + * 不要使用额外的数组空间,你必须在原地修改输入数组并在使用 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。 + * + * 你不需要考虑数组中超出新长度后面的元素。 + * + * 来源:力扣(LeetCode) + * 链接:https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array + * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + */ +public class LeetCode_26_587 { + public int removeDuplicates(int[] nums) { + int j = 0; + for (int i = 1; i < nums.length; i++) { + if (nums[j] != nums[i]){ + if (++j != i) nums[j] = nums[i]; + } + } + return j + 1; + } +} diff --git a/Week_01/G20200343030587/src/main/java/com/work/LeetCode_283_587.java b/Week_01/G20200343030587/src/main/java/com/work/LeetCode_283_587.java new file mode 100644 index 00000000..bc4a46c6 --- /dev/null +++ b/Week_01/G20200343030587/src/main/java/com/work/LeetCode_283_587.java @@ -0,0 +1,49 @@ +package com.work; + +/** + * 移动零 + * + * 给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。 + * + * 示例: + * + * 输入: [0,1,0,3,12] + * 输出: [1,3,12,0,0] + * 说明: + * + * 必须在原数组上操作,不能拷贝额外的数组。 + * 尽量减少操作次数。 + * + * 来源:力扣(LeetCode) + * 链接:https://leetcode-cn.com/problems/move-zeroes + * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + */ + +public class LeetCode_283_587 { + //一次循环 + public void moveZeroes(int[] nums) { + for (int i = 0,j=0 ; i < nums.length; i++) { + if(nums[i] != 0){ + nums[j] = nums[i]; + if(i != j) { + nums[i] = 0; + } + j++; + } + } + } + + //二次循环 + public void moveZeroes2(int[] nums) { + int j = 0; + for (int i = 0; i < nums.length; i++) { + if(nums[i] != 0){ + nums[j++] = nums[i]; + } + } + + for (int i = j; i < nums.length; i++) { + nums[i] = 0; + } + } +} diff --git a/Week_01/G20200343030589/LeetCode_1_589.go b/Week_01/G20200343030589/LeetCode_1_589.go new file mode 100644 index 00000000..e0c82740 --- /dev/null +++ b/Week_01/G20200343030589/LeetCode_1_589.go @@ -0,0 +1,26 @@ +/* + * @lc app=leetcode.cn id=1 lang=golang + * + * [1] 两数之和 + */ + +// @lc code=start +func twoSum(nums []int, target int) []int { + result := []int{0,0} + for i := 0; i < len(nums); i++ { + isResult := false + temp := target - nums[i] + for j := 0; j < len(nums); j++ { + if (temp == nums[j] && i != j){ + result[0]=i + result[1]=j + isResult = true + break + } + } + if isResult{ + break + } + } + return result +} \ No newline at end of file diff --git a/Week_01/G20200343030589/LeetCode_283_589.go b/Week_01/G20200343030589/LeetCode_283_589.go new file mode 100644 index 00000000..019f53cf --- /dev/null +++ b/Week_01/G20200343030589/LeetCode_283_589.go @@ -0,0 +1,20 @@ +/* + * @lc app=leetcode.cn id=283 lang=golang + * + * [283] 移动零 + */ + +// @lc code=start +func moveZeroes(nums []int) { + j := 0 + for i := 0; i < len(nums); i++ { + if nums[i]!=0 { + if i != j{ + noZero := nums[i] + nums[i] = nums[j] + nums[j] = noZero + } + j++ + } + } +} \ No newline at end of file diff --git a/Week_01/G20200343030589/NOTE.md b/Week_01/G20200343030589/NOTE.md index 50de3041..95200073 100644 --- a/Week_01/G20200343030589/NOTE.md +++ b/Week_01/G20200343030589/NOTE.md @@ -1 +1,3 @@ -学习笔记 \ No newline at end of file +学习笔记 +第一周的学习笔记总结为脑图如下: +![](week01.jpg) \ No newline at end of file diff --git a/Week_01/G20200343030589/week01.jpg b/Week_01/G20200343030589/week01.jpg new file mode 100644 index 00000000..398d7263 Binary files /dev/null and b/Week_01/G20200343030589/week01.jpg differ diff --git a/Week_01/G20200343030591/LeetCode_155_591.java b/Week_01/G20200343030591/LeetCode_155_591.java new file mode 100644 index 00000000..03780c5a --- /dev/null +++ b/Week_01/G20200343030591/LeetCode_155_591.java @@ -0,0 +1,40 @@ +class MinStack { + + + /** + * 用两个栈实现,普通栈和只放最小栈的栈 (永远保证栈顶是最小的值可以O(1)的获取) + * 入栈:只有栈顶元素大于当前要入栈的元素 最小栈才能放值 + * 出栈:只有最小栈与普通栈值一样 才能出栈 + * 获取栈顶元素:用的是普通栈的值 + * 获取最小值:用的是最小栈 + */ + + Stack stack; + Stack minStack; + + /** initialize your data structure here. */ + public MinStack() { + stack = new Stack<>(); + minStack = new Stack<>(); + } + + public void push(int x) { + stack.push(x); + if (minStack.isEmpty() || minStack.peek() >= x) { + minStack.push(x); + } + } + + public void pop() { + if (stack.pop().equals(minStack.peek())) + minStack.pop(); + } + + public int top() { + return stack.peek(); + } + + public int getMin() { + return minStack.peek(); + } +} \ No newline at end of file diff --git a/Week_01/G20200343030591/LeetCode_189_591.java b/Week_01/G20200343030591/LeetCode_189_591.java new file mode 100644 index 00000000..b64141a0 --- /dev/null +++ b/Week_01/G20200343030591/LeetCode_189_591.java @@ -0,0 +1,33 @@ +/** + * 题目名称:旋转数组 + */ +class Solution { + + // 暴力法一轮旋转一次 旋转K轮 + 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; + } + } + } + + // hash取模 1构建一个新数组;2用取模的方式把原数组中的元素定位到指定位置;3.最后把新数组中的元素复制给原数组 + public void rotate(int[] nums, int k) { + int[] a = new int[nums.length]; + int len = nums.length; + for (int i = 0; i < len; i++) { + a[ (i + k) % len ] = nums[i]; + } + for (int j = 0; j < len; j++) { + nums[j] = a[j]; + } + } +} + + + diff --git a/Week_01/G20200343030591/LeetCode_1_591.java b/Week_01/G20200343030591/LeetCode_1_591.java new file mode 100644 index 00000000..c0db119e --- /dev/null +++ b/Week_01/G20200343030591/LeetCode_1_591.java @@ -0,0 +1,29 @@ + +class Solution { + + + /** + * 题目名称:两数之和 + * 思路解析: + * + * 易错点,老是想让i从1开始,他俩从同一个位置开始走 + * @param nums + * @return + */ + public int[] twoSum(int[] nums, int target) { + Map cache = new HashMap<>(); + int len = nums.length; + + for (int i = 0; i < len; i++) { + int result = target - nums[i]; + if (cache.get(result)!=null) { + return new int[]{i, cache.get(result)}; + } + cache.put(nums[i], i); + } + + return new int[]{}; + } + + + diff --git a/Week_01/G20200343030591/LeetCode_20_591.java b/Week_01/G20200343030591/LeetCode_20_591.java new file mode 100644 index 00000000..37625514 --- /dev/null +++ b/Week_01/G20200343030591/LeetCode_20_591.java @@ -0,0 +1,60 @@ + +class Solution { + + private static final Integer CACHE_NUMBER = 3; + + public static Map cache = new HashMap<>(CACHE_NUMBER); + + /** + * 题目名称:有效的括号 + * 思路解析: + * 1、先把所有右括号当做key放入 哈希表中 + * 2、判断是否是左括号 是则入栈,不是则表示是不合法的括号 + * 3、判断是否为右括号,如果是右括号,则与栈顶元素匹配出栈,不是则为非法括号 + * 4、最后如果循环完成,栈为空则表示所有扩好都匹配上了 + * + * @param nums + * @return + */ + public boolean isValid(String s) { + cache.put('}', '{'); + cache.put(')', '('); + cache.put(']', '['); + Stack stack = new Stack(); + for (Character item : s.toCharArray()) { + // 先判断左括号 如果加入的是左括号 则可以加入 是右括号 则是不正确的 + if (!cache.containsKey(item)) { + stack.push(item); + // 判断是否栈为空或者栈顶元素与当前存放的元素无法匹配 则为不和发括号组合 + } else if (stack.isEmpty() || stack.pop() != cache.get(item)) { + return false; + } + } + return stack.isEmpty(); + } + + /** + * 国际站java解法 + * @return + */ + public boolean isValid(String s) { + + Stack stack = new Stack(); + for (Character item : s.toCharArray()) { + if (item=='(') { + stack.push(")"); + } else if (item=='[') { + stack.push("]"); + } else if (item=='{') { + stack.push("}"); + } else if (stack.isEmpty() || stack.pop() != item) { + return false; + } + } + return stack.isEmpty(); + } + +} + + + diff --git a/Week_01/G20200343030591/LeetCode_21_591.java b/Week_01/G20200343030591/LeetCode_21_591.java new file mode 100644 index 00000000..7285e040 --- /dev/null +++ b/Week_01/G20200343030591/LeetCode_21_591.java @@ -0,0 +1,30 @@ + +class Solution { + + public ListNode mergeTwoLists(ListNode l1, ListNode l2) { + ListNode pHead = new ListNode(0); + ListNode p = pHead; + + while (l1!=null && l2!=null) { + if (l1.val < l2.val) { + p.next = l1; + l1 = l1.next; + } else { + p.next = l2; + l2 = l2.next; + } + p = p.next; + } + + p.next = (l1==null) ? l2 : l1; + + return pHead.next; + + } + + + +} + + + diff --git a/Week_01/G20200343030591/LeetCode_239_591.java b/Week_01/G20200343030591/LeetCode_239_591.java new file mode 100644 index 00000000..b39170df --- /dev/null +++ b/Week_01/G20200343030591/LeetCode_239_591.java @@ -0,0 +1,42 @@ +class Solution { + +// 输入: nums = [1,3,-1,-3,5,3,6,7], 和 k = 3 +// 输出: [3,3,5,5,6,7] +// +// 解释过程中队列中都是具体的值,方便理解,具体见代码。 +// 初始状态:L=R=0,队列:{} +// i=0,nums[0]=1。队列为空,直接加入。队列:{1} +// i=1,nums[1]=3。队尾值为1,3>1,弹出队尾值,加入3。队列:{3} +// i=2,nums[2]=-1。队尾值为3,-1<3,直接加入。队列:{3,-1}。此时窗口已经形成,L=0,R=2,result=[3] +// i=3,nums[3]=-3。队尾值为-1,-3<-1,直接加入。队列:{3,-1,-3}。队首3对应的下标为1,L=1,R=3,有效。result=[3,3] +// i=4,nums[4]=5。队尾值为-3,5>-3,依次弹出后加入。队列:{5}。此时L=2,R=4,有效。result=[3,3,5] +// i=5,nums[5]=3。队尾值为5,3<5,直接加入。队列:{5,3}。此时L=3,R=5,有效。result=[3,3,5,5] +// i=6,nums[6]=6。队尾值为3,6>3,依次弹出后加入。队列:{6}。此时L=4,R=6,有效。result=[3,3,5,5,6] +// i=7,nums[7]=7。队尾值为6,7>6,弹出队尾值后加入。队列:{7}。此时L=5,R=7,有效。result=[3,3,5,5,6,7] + + public int[] maxSlidingWindow(int[] nums, int k) { + if(nums == null || nums.length < 2) return nums; + // 双向队列 保存当前窗口最大值的数组位置 保证队列中数组位置的数值按从大到小排序 + LinkedList queue = new LinkedList(); + // 结果数组 + int[] result = new int[nums.length-k+1]; + // 遍历nums数组 + for(int i = 0;i < nums.length;i++){ + // 保证从大到小 如果前面数小则需要依次弹出,直至满足要求 + while(!queue.isEmpty() && nums[queue.peekLast()] <= nums[i]){ + queue.pollLast(); + } + // 添加当前值对应的数组下标 + queue.addLast(i); + // 判断当前队列中队首的值是否有效 + if(queue.peek() <= i-k){ + queue.poll(); + } + // 当窗口长度为k时 保存当前窗口中最大值 + if(i+1 >= k){ + result[i+1-k] = nums[queue.peek()]; + } + } + return result; + } +} \ No newline at end of file diff --git a/Week_01/G20200343030591/LeetCode_26_591.java b/Week_01/G20200343030591/LeetCode_26_591.java new file mode 100644 index 00000000..52323be9 --- /dev/null +++ b/Week_01/G20200343030591/LeetCode_26_591.java @@ -0,0 +1,30 @@ + +class Solution { + + + /** + * 思路解析: + * 1.创建两个指针 快指针和慢指针 + * 2、当两个指针值 相等,慢指针不动,快指针继续向前移动 + * 3、两个指针值 不相等,将快指针所在位置的值赋给 慢指针+1的位置,并且慢指针向前移动一位 + * 4、重复2~3 知道fast等于数组长度 + * @param nums + * @return + */ + public int removeDuplicates(int[] nums) { + int len = nums.length; + if (len == 0) return 0; + + int slow = 0; + for (int fast=1; fast < len; fast++) { + if (nums[fast]!=nums[slow]) { + nums[++slow] = nums[fast]; + } + } + return ++slow; + } + +} + + + diff --git a/Week_01/G20200343030591/LeetCode_283_591.java b/Week_01/G20200343030591/LeetCode_283_591.java new file mode 100644 index 00000000..eca74f82 --- /dev/null +++ b/Week_01/G20200343030591/LeetCode_283_591.java @@ -0,0 +1,40 @@ + +class Solution { + + + /** + * 题目名称:移动0 + * 思路解析: + * 1、定义一个j指针,用于指向下一个不为0的位置 + * 2、定义一个i指针,遍历数组查找不为0的数 + * 3、i和j一起向前走,j遇到为0的数就停下来,i则继续向前走 + * 4、i只要不为0,就与j交换位置,交换完成后,j向前走一步 + * 5、重复3~4,直到遍历完数组 + * + * 易错点,老是想让i从1开始,他俩从同一个位置开始走 + * @param nums + * @return + */ + public void moveZeroes(int[] nums) { + int len = nums.length; + if (len == 0) return; + + int j = 0; + for (int i = 0; i < len; i++) { + if (nums[i]!=0) { + swap(nums, i, j); + j++; + } + } + } + + void swap(int[] nums, int i, int j) { + int temp = nums[i]; + nums[i] = nums[j]; + nums[j] = temp; + } + +} + + + diff --git a/Week_01/G20200343030591/LeetCode_42_591.java b/Week_01/G20200343030591/LeetCode_42_591.java new file mode 100644 index 00000000..052888ed --- /dev/null +++ b/Week_01/G20200343030591/LeetCode_42_591.java @@ -0,0 +1,65 @@ + +class Solution { + + /** + * 暴力法 + * 每轮遍历找到 最大左右边界 计算并累加面积 + * 直到都遍历完 + * @param height + * @return + */ + public int trap(int[] height) { + int n = height.length; + int area = 0; + for (int i=1; i < n - 1;i++) { + int maxLeft = 0, maxRight = 0; + // 找到左边界 + for (int j=i; j >= 0; j--) { + maxLeft = Math.max(maxLeft, height[j]); + } + // 找到右边界 + for (int j=i; j < n; j++) { + maxRight = Math.max(maxRight, height[j]); + } + + area += Math.min(maxLeft, maxRight) - height[i]; + } + return area; + } + + /** + * 双指针法 + * 1、定义两个指针 一个指向最左边,一个指向最右边 + * 2、如果左边的值比右边的值小,则更新左边的数据 + * 3、反之,则更新右边数据 + * 4、左边和右边相遇则结束 + * @param height + * @return + */ + public int trap(int[] height) { + int n = height.length; + int left = 0, right = height.length - 1; + int max_left = 0, max_right = 0; + int trapArea = 0; + while(left < right) { + // 左边小 则更新左边 + if (height[left] < height[right]) { + if (height[left] > max_left) { + max_left = height[left]; + } else { + trapArea += max_left - height[left]; + } + left++; + // 右边小,则更新右边 + } else { + if (height[right] > max_right) { + max_right = height[right]; + } else { + trapArea += max_right - height[right]; + } + right--; + } + } + return trapArea; + } +} \ No newline at end of file diff --git a/Week_01/G20200343030591/LeetCode_641_591.java b/Week_01/G20200343030591/LeetCode_641_591.java new file mode 100644 index 00000000..5304b98a --- /dev/null +++ b/Week_01/G20200343030591/LeetCode_641_591.java @@ -0,0 +1,114 @@ +class Solution { + + // 1、不用设计成动态数组,使用静态数组即可 + // 2、设计 head 和 tail 指针变量 + // 3、head == tail 成立的时候表示队列为空 + // 4、tail + 1 == head + + private int capacity; + private int[] arr; + private int front; + private int rear; + + /** + * Initialize your data structure here. Set the size of the deque to be k. + */ + public MyCircularDeque(int k) { + capacity = k + 1; + arr = new int[capacity]; + + // 头部指向第 1 个存放元素的位置 + // 插入时,先减,再赋值 + // 删除时,索引 +1(注意取模) + front = 0; + // 尾部指向下一个插入元素的位置 + // 插入时,先赋值,再加 + // 删除时,索引 -1(注意取模) + rear = 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; + } + front = (front - 1 + capacity) % capacity; + arr[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()) { + return false; + } + arr[rear] = value; + rear = (rear + 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; + } + // front 被设计在数组的开头,所以是 +1 + front = (front + 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; + } + // rear 被设计在数组的末尾,所以是 -1 + rear = (rear - 1 + capacity) % capacity; + return true; + } + + /** + * Get the front item from the deque. + */ + public int getFront() { + if (isEmpty()) { + return -1; + } + return arr[front]; + } + + /** + * Get the last item from the deque. + */ + public int getRear() { + if (isEmpty()) { + return -1; + } + // 当 rear 为 0 时防止数组越界 + return arr[(rear - 1 + capacity) % capacity]; + } + + /** + * 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 (rear + 1) % capacity == front; + } + +} \ No newline at end of file diff --git a/Week_01/G20200343030591/LeetCode_66_591.java b/Week_01/G20200343030591/LeetCode_66_591.java new file mode 100644 index 00000000..9534c09a --- /dev/null +++ b/Week_01/G20200343030591/LeetCode_66_591.java @@ -0,0 +1,26 @@ +class Solution { + /** + * 加1 + * 思路解析: + * 1、通过从后往前的循环,给个位数+1 + * 2、加1后,分两种情况: + * 3、不需要进位直接返回就可以了 + * 4、需要进位 则进入下一轮循环,继续给前一位+1 + * 5、边界 如果循环都遍历完了 还是没有返回结果 那么说明数组的最高位也需要进位 + * 此时需要 扩容数组1位 然后给最高位补1 + * @param digits + * @return + */ + public int[] plusOne(int[] digits) { + int len = digits.length; + for (int i = len - 1; i >= 0; i--) { + digits[i]++; + // 判断是否有进位 不为0 则无需进位,为0则需要进位 + digits[i] = digits[i] % 10; + if (digits[i]!=0) return digits; + } + digits = new int[len+1]; + digits[0] = 1; + return digits; + } +} \ No newline at end of file diff --git a/Week_01/G20200343030593/LeetCode_189_593.java b/Week_01/G20200343030593/LeetCode_189_593.java new file mode 100644 index 00000000..e9cada82 --- /dev/null +++ b/Week_01/G20200343030593/LeetCode_189_593.java @@ -0,0 +1,58 @@ +class Solution { + /*暴力求解*/ + public void rotate(int[] nums, int k) { + /*声明一个变量,获取替换当前值的元素*/ + int pre; + /*声明一个变量,用于交换时的中间值*/ + int temp; + for(int i=0;i= 0; i-- { + rightMax[i] = max(height[i], rightMax[i+1]) + } + + ans := 0 + for i := 0; i < len(height); i++ { + ans += min(leftMax[i], rightMax[i]) - height[i] + } + return ans +} + +func max(a, b int) int { + if a > b { + return a + } + return b +} + +func min(a, b int) int { + if a < b { + return a + } + return b +} diff --git a/Week_01/G20200343030595/LeetCode_641_595.go b/Week_01/G20200343030595/LeetCode_641_595.go new file mode 100644 index 00000000..7ecd7d04 --- /dev/null +++ b/Week_01/G20200343030595/LeetCode_641_595.go @@ -0,0 +1,88 @@ +type MyCircularDeque struct { + vals []int + length int +} + +/** Initialize your data structure here. Set the size of the deque to be k. */ +func Constructor(k int) MyCircularDeque { + return MyCircularDeque{ + length: k, + vals: make([]int, 0), + } +} + +/** Adds an item at the front of Deque. Return true if the operation is successful. */ +func (this *MyCircularDeque) InsertFront(value int) bool { + if len(this.vals) == this.length { + return false + } + this.vals = append([]int{value}, this.vals...) + 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 len(this.vals) == this.length { + return false + } + this.vals = append(this.vals, value) + return true +} + +/** Deletes an item from the front of Deque. Return true if the operation is successful. */ +func (this *MyCircularDeque) DeleteFront() bool { + if len(this.vals) == 0 { + return false + } + this.vals = this.vals[1:] + return true +} + +/** Deletes an item from the rear of Deque. Return true if the operation is successful. */ +func (this *MyCircularDeque) DeleteLast() bool { + l := len(this.vals) + if l == 0 { + return false + } + this.vals = this.vals[:l-1] + return true +} + +/** Get the front item from the deque. */ +func (this *MyCircularDeque) GetFront() int { + if len(this.vals) == 0 { + return -1 + } + return this.vals[0] +} + +/** Get the last item from the deque. */ +func (this *MyCircularDeque) GetRear() int { + if len(this.vals) == 0 { + return -1 + } + return this.vals[len(this.vals)-1] +} + +/** Checks whether the circular deque is empty or not. */ +func (this *MyCircularDeque) IsEmpty() bool { + return len(this.vals) == 0 +} + +/** Checks whether the circular deque is full or not. */ +func (this *MyCircularDeque) IsFull() bool { + return len(this.vals) == this.length +} + +/** + * 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/G20200343030595/LeetCode_66_595.go b/Week_01/G20200343030595/LeetCode_66_595.go new file mode 100644 index 00000000..d9ce2cc8 --- /dev/null +++ b/Week_01/G20200343030595/LeetCode_66_595.go @@ -0,0 +1,14 @@ +func plusOne(digits []int) []int { + extra := 1 + for i := len(digits) - 1; i >= 0; i-- { + remain := (digits[i] + extra) % 10 + extra = (digits[i] + extra) / 10 + digits[i] = remain + } + + if extra != 0 { + return append([]int{extra}, digits...) + } + + return digits +} diff --git a/Week_01/G20200343030595/LeetCode_88_595.go b/Week_01/G20200343030595/LeetCode_88_595.go new file mode 100644 index 00000000..7e558f70 --- /dev/null +++ b/Week_01/G20200343030595/LeetCode_88_595.go @@ -0,0 +1,25 @@ +func merge(nums1 []int, m int, nums2 []int, n int) { + cur := m + n - 1 + i, j := m-1, n-1 + for i >= 0 || j >= 0 { + switch { + case i < 0: + nums1[cur] = nums2[j] + j-- + + case j < 0: + nums1[cur] = nums1[i] + i-- + + default: + if nums1[i] > nums2[j] { + nums1[cur] = nums1[i] + i-- + } else { + nums1[cur] = nums2[j] + j-- + } + } + cur-- + } +} diff --git a/Week_01/G20200343030597/Solution.java b/Week_01/G20200343030597/Solution.java new file mode 100644 index 00000000..96840a33 --- /dev/null +++ b/Week_01/G20200343030597/Solution.java @@ -0,0 +1,30 @@ +package Week_01.G20200343030597; + +public class Solution { + public int[] plusOne(int[] digits) { + for (int i = digits.length-1; i >= 0; i-- ) { + digits[i]++; + digits[i] = digits[i] % 10; + System.out.println(digits[i]); + if(digits[i] != 0){ + return digits; + } + } + digits = new int[digits.length + 1]; + digits[0] = 1; + return digits; + } + public void moveZeroes(int[] nums) { + int j = 0; + int temp = 0; + for (int i = 0; i < nums.length; i++) { + if (nums[i] != 0){ + temp = nums[j]; + nums[j] = nums[i]; + nums[i] = temp; + j++; + } + } + } + +} diff --git a/Week_01/G20200343030599/LeetCode_01_599.js b/Week_01/G20200343030599/LeetCode_01_599.js new file mode 100644 index 00000000..1bccc44b --- /dev/null +++ b/Week_01/G20200343030599/LeetCode_01_599.js @@ -0,0 +1,34 @@ +/* + * @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) { + //方法一:两重暴力循环 + /* + for (let i = 0; i < nums.length - 1; i++) { + for (let j = i + 1; j < nums.length; j++) { + if (nums[j] === target - nums[i]) return [i, j]; + } + } + */ + + //方法二:Hash表 + let temp = []; + + for (let i = 0; i < nums.length; i++) { + if (temp[nums[i]] !== undefined) { + return [temp[nums[i]], i] + } + temp[target - nums[i]] = i; + } + +}; +// @lc code=end \ No newline at end of file diff --git a/Week_01/G20200343030599/LeetCode_189_599.js b/Week_01/G20200343030599/LeetCode_189_599.js new file mode 100644 index 00000000..98242063 --- /dev/null +++ b/Week_01/G20200343030599/LeetCode_189_599.js @@ -0,0 +1,38 @@ +/* + * @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) { + let len = nums.length + + //方法一:暴力求解 + /* + for (let i = 0; i < k; i++) { + let current = nums[len - 1]; + for (let j = 0; j < len; j++) { + [nums[j], current] = [current, nums[j]]; + } + } + */ + + //方法二:把数组尾部的元素删除后添加在数组头部 + /* + for (let i = 0; i < k; i++) { + nums.unshift(nums.pop()) + } + */ + + //方法三:找到数组旋转的索引位置 len - k % n + let reversePoint = len - k % len; + reversePoint !== 0 && (nums.splice(0, 0, ...nums.splice(reversePoint, k))) + +}; +// @lc code=end \ No newline at end of file diff --git a/Week_01/G20200343030599/LeetCode_21_599.js b/Week_01/G20200343030599/LeetCode_21_599.js new file mode 100644 index 00000000..0403d2eb --- /dev/null +++ b/Week_01/G20200343030599/LeetCode_21_599.js @@ -0,0 +1,33 @@ +/* + * @lc app=leetcode.cn id=21 lang=javascript + * + * [21] 合并两个有序链表 + */ + +// @lc code=start +/** + * Definition for singly-linked list. + * function ListNode(val) { + * this.val = val; + * this.next = null; + * } + */ +/** + * @param {ListNode} l1 + * @param {ListNode} l2 + * @return {ListNode} + */ +var mergeTwoLists = function (l1, l2) { + //使用递归 + if (!l1) return l2; + if (!l2) return l1; + + if (l1.val < l2.val) { + l1.next = mergeTwoLists(l1.next, l2); + return l1; + } else { + l2.next = mergeTwoLists(l1, l2.next); + return l2; + } +}; +// @lc code=end \ No newline at end of file diff --git a/Week_01/G20200343030599/LeetCode_26_599.js b/Week_01/G20200343030599/LeetCode_26_599.js new file mode 100644 index 00000000..c3a460c1 --- /dev/null +++ b/Week_01/G20200343030599/LeetCode_26_599.js @@ -0,0 +1,29 @@ +/* + * @lc app=leetcode.cn id=26 lang=javascript + * + * [26] 删除排序数组中的重复项 + */ + +// @lc code=start +/** + * @param {number[]} nums + * @return {number} + */ +var removeDuplicates = function (nums) { + + if (nums.length === 0) return 0; + + //双指针法:i指针用来遍历数组,j指针用来指向当前不重复数组的最后一项 + //注意审题:数组是已经排好序的数组,所以如果有重复元素,那么它们一定连续出现的 + //且不需要考虑数组中超出新长度后面的元素 + let j = 0; + for (let i = 1; i < nums.length; i++) { + if (nums[i] !== nums[j]) { + j++; + nums[j] = nums[i]; + } + } + + return j + 1; +}; +// @lc code=end \ No newline at end of file diff --git a/Week_01/G20200343030599/LeetCode_283_599.js b/Week_01/G20200343030599/LeetCode_283_599.js new file mode 100644 index 00000000..12076fdd --- /dev/null +++ b/Week_01/G20200343030599/LeetCode_283_599.js @@ -0,0 +1,45 @@ +/* + * @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 len = nums.length; + // let end = len - 1; + + // for (let i = 0; i < len; i++) { + + // if (i >= end) break; + + // if (nums[i] === 0) { + // nums.splice(i, 1); + // i--; + // nums.push(0); + // end--; + // } + // } + + //解法二: + let j = 0; + let len = nums.length; + + for (let i = 0; i < len; i++) { + if (nums[i] !== 0) { + nums[j] = nums[i]; + + if (i !== j) { + nums[i] = 0; + } + + j++; + } + } +}; +// @lc code=end \ No newline at end of file diff --git a/Week_01/G20200343030599/LeetCode_66.599.js b/Week_01/G20200343030599/LeetCode_66.599.js new file mode 100644 index 00000000..21a1fd07 --- /dev/null +++ b/Week_01/G20200343030599/LeetCode_66.599.js @@ -0,0 +1,31 @@ +/* + * @lc app=leetcode.cn id=66 lang=javascript + * + * [66] 加一 + */ + +// @lc code=start +/** + * @param {number[]} digits + * @return {number[]} + */ +var plusOne = function (digits) { + const len = digits.length; + + //从末位开始 + for (let i = len - 1; i >= 0; i--) { + //数组的值 + 1 (末位 + 1) + digits[i]++; + + //末位和10取模,如果结果为0,则说明有进位,如果结果不为0,则说明没有进位可直接返回+1之后的数组 + digits[i] %= 10; + + if (digits[i] !== 0) return digits; + } + + //如果原数组+1后所有位都需要进位,则数组的长度需要扩充一位 + digits = [...Array(len + 1)].map(_ => 0); //声明一个长度为len+1的所有值为0的数组 + digits[0] = 1; + return digits; +}; +// @lc code=end \ No newline at end of file diff --git a/Week_01/G20200343030599/LeetCode_88_599.js b/Week_01/G20200343030599/LeetCode_88_599.js new file mode 100644 index 00000000..c2c852a3 --- /dev/null +++ b/Week_01/G20200343030599/LeetCode_88_599.js @@ -0,0 +1,28 @@ +/* + * @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) { + // 双指针 + 从后往前 + let p1 = m - 1; + let p2 = n - 1; + let p = m + n - 1; + + while (p1 >= 0 && p2 >= 0) { + nums1[p--] = nums1[p1] > nums2[p2] ? nums1[p1--] : nums2[p2--]; + } + + //如果nums的m = 0 , 则把nums2中的所有值放到nums1中 + nums1.splice(0, p2 + 1, ...nums2.slice(0, p2 + 1)) +}; +// @lc code=end \ No newline at end of file diff --git "a/Week_01/G20200343030601/189.\346\227\213\350\275\254\346\225\260\347\273\204.java" "b/Week_01/G20200343030601/189.\346\227\213\350\275\254\346\225\260\347\273\204.java" new file mode 100644 index 00000000..66065feb --- /dev/null +++ "b/Week_01/G20200343030601/189.\346\227\213\350\275\254\346\225\260\347\273\204.java" @@ -0,0 +1,81 @@ +/* + * @lc app=leetcode.cn id=189 lang=java + * + * [189] 旋转数组 + * + * https://leetcode-cn.com/problems/rotate-array/description/ + * + * algorithms + * Easy (40.41%) + * Likes: 487 + * Dislikes: 0 + * Total Accepted: 97.4K + * Total Submissions: 240.9K + * 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 { + public void rotate(int[] nums, int k) { + k = k % nums.length; + if (0 == nums.length || 0 == k) { + return; + } + + // int currentPos = nums.length - 1; + // int origialLastValue = nums[currentPos]; + // int nextPos = currentPos; + // do { + // currentPos = nextPos; + // nextPos = (nextPos - k) < 0 ? nextPos - k + nums.length : nextPos - k; + // nums[currentPos] = nums[nextPos]; + // } while (nextPos != nums.length - 1); + + // nums[currentPos] = origialLastValue; + + + int count = 0; + for (int startPos = 0; count < nums.length; startPos++) { + int currentPos = startPos; + int preValue = nums[startPos]; + do { + int nextPos = (currentPos + k) % nums.length; + int temp = nums[nextPos]; + nums[nextPos] = preValue; + preValue = temp; + currentPos = nextPos; + count++; + } while(currentPos != startPos); + } + } +} +// @lc code=end + diff --git "a/Week_01/G20200343030601/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/G20200343030601/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 00000000..426d6797 --- /dev/null +++ "b/Week_01/G20200343030601/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,95 @@ +import java.util.Deque; + +import javax.sound.sampled.SourceDataLine; + +/* + * @lc app=leetcode.cn id=26 lang=java + * + * [26] 删除排序数组中的重复项 + * + * https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array/description/ + * + * algorithms + * Easy (48.50%) + * Likes: 1328 + * Dislikes: 0 + * Total Accepted: 245.9K + * Total Submissions: 506.8K + * 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 lastValue = nums[0]; + int lastPos = 0; + for (int i = 1; i < nums.length; ++i) { + if (nums[i] != lastValue) { + lastValue = nums[i]; + nums[++lastPos] = lastValue; + } + } + return lastPos + 1; + + Deque deque = new LinkedList(); + deque.addFirst("a"); + deque.addLast("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); + } +} +// @lc code=end + diff --git a/Week_01/G20200343030601/NOTE.md b/Week_01/G20200343030601/NOTE.md index 50de3041..e1f6be78 100644 --- a/Week_01/G20200343030601/NOTE.md +++ b/Week_01/G20200343030601/NOTE.md @@ -1 +1,80 @@ -学习笔记 \ No newline at end of file +# 学习笔记(第一周) + +**学号:** G20200343030601 + +**姓名:** 冯学智 + +**微信:** SDMrFeng + +## 1. 用add first或add last这套新的API改写Deque的代码 + + Deque deque = new LinkedList(); + deque.addFirst("a"); + deque.addLast("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); + +## 2. 分析Queue源码 + +java中Queue是实现了Collection的接口,包括以下接口函数: + +- boolean add(E e) + + 向队列中添加一个元素。一些队列有大小限制,因此如果想在一个满的队列中加入一个新项,调用 add() 方法就会抛出一个 unchecked 异常。 + +- boolean offer(E e) + 向队列中添加一个元素。一些队列有大小限制,因此如果想在一个满的队列中加入一个新项,调用 offer() 方法会返回 false。 + +- E remove() + + 从队列中删除第一个元素。如果队列元素为空,调用remove() 的行为与 Collection 接口的版本相似会抛出异常。 + +- E poll() + + 从队列中删除第一个元素。如果队列元素为空,调用poll() 方法时只是返回 null。因此新的方法更适合容易出现异常条件的情况。 + +- E element() + + element()用于在队列的头部查询元素。与 remove() 方法类似,在队列为空时, element() 抛出一个异常。 + +- E peek() + + peek() 用于在队列的头部查询元素。与 poll() 方法类似,在队列为空时,peek() 返回 null。 + +## 3. 分析Priority Queue源码 + +PriorityQueue实现了AbstractQueue,PriorityQueue内部由最小堆实现,也就是说每次执行add或是remove之后,总是让最小的元素移动到根,但是,使用迭代器进行访问时,不会保证一个递增的顺序。为了维持最小堆,队列的元素类型必须实现Comparable接口,或者是在构造队列的时候提供一个元素类型的比较器(Comparator),所以元素不能为空。队列的访问操作poll, remove, peek, and element访问的是队头元素,在这里也就是根元素,也就是最小的元素。实现的主要函数包括以下: + +- 构造函数 + + PriorityQueue的构造函数大致分为两类,一种是确定数组初始化大小和Comparator,另一种是由Collection对象构造 + +- add/offer + + add通过offer实现。这个函数干了这几件事情:检查为空,增加修改次数,需要的情况下扩展,增加大小,赋值,向上调整堆,返回真。 + 这里的关键是SiftUp函数:将要插入的节点与父节点进行比较,如果更小,就将父节点往下,然后继续向上比较,如果大于等于,就放在当前的位置。 + +- remove()/poll() + + 删除并返回最小的队头元素后,将数组末位的元素放到队头,然后SiftDown,基本于上面相反。删除并返回最小的队头元素后,将数组末位的元素放到队头,然后SiftDown,基本于上面相反。 + +## 4. 个人第一周学习总结 + +- 对数据结构掌握没有形成体系,这一周下来,感觉之前自己脑袋里的知识混乱不堪;可以想象接下来几周学习复杂数据结构时,不堪一击的样子。 + +- 刷Leetcode题没有套路,以前做过几道Leetcode题目,稍微用时快一些就沾沾自喜,根本没有get到刷题的精髓。没有形成做题的思考套路、不知道看别人的题解、submit通过即结束,没有复盘和反思总结。 + +- 没有阅读源码的习惯,也不知道从哪里开始阅读如何阅读。以及Review别人代码或让高手review自己代码的习惯,正是覃超老师预习周给讲到的feedback。 + +- 将课程中涉及到的题目整理到excel中,按照五遍刷题法进行复习提炼。 + +- 来训练营的目的掌握课上内容不是目的,做完作业也不是目的,最重要的是掌握思维模式、把知识形成体系、提炼学习套路。 \ No newline at end of file diff --git a/Week_01/G20200343030603/LeetCode_1_603.java b/Week_01/G20200343030603/LeetCode_1_603.java new file mode 100644 index 00000000..ecc0af43 --- /dev/null +++ b/Week_01/G20200343030603/LeetCode_1_603.java @@ -0,0 +1,19 @@ +class Solution { + //双指针解法 + public int removeDuplicates(int[] nums) { + if (nums == null || nums.length == 0){ + return 0; + } + + int p = 0; + for (int q = 1; q < nums.length; q++){ + if (nums[p] != nums[q]){ + if (q - p > 1){ + nums[p + 1] = nums[q]; + } + p++; + } + } + return p+1; + } +} \ No newline at end of file diff --git a/Week_01/G20200343030603/LeetCode_2_603.java b/Week_01/G20200343030603/LeetCode_2_603.java new file mode 100644 index 00000000..b348d330 --- /dev/null +++ b/Week_01/G20200343030603/LeetCode_2_603.java @@ -0,0 +1,58 @@ +class Solution { + public void rotate(int[] nums, int k) { + // //1、暴力法 时间复杂度O(n) 空间复杂度O(1) 执行用时95ms 内存消耗47.1MB + // 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; + // } + // } + + + // //2、使用额外数组 时间复杂度O(n) 空间复杂度O(n) 执行用时1ms 内存消耗47.1MB + // int[] a = new int[nums.length]; + // for (int i = 0; i < nums.length; i++){ + // a[(i + k) % nums.length] = nums[i]; + // } + + // for (int i = 0; i < nums.length; i++){ + // nums[i] = a[i]; + // } + + + //3、环状替换 时间复杂度O(n) 空间复杂度O(1) 执行用时0ms 内存消耗47.3MB + k = k % nums.length; + int count = 0; + for (int start = 0; count < nums.length; start++){ + int current = start; + int prev = nums[start]; + do { + int next = (current + k) % nums.length; + int temp = nums[next]; + nums[next] = prev; + prev = temp; + current = next; + count++; + } while (start != current); + } + + // //4、反转 时间复杂度O(n) 空间复杂度O(1) 执行用时0ms 内存消耗47.3MB + // k %= nums.length; + // reverse(nums, 0, nums.length - 1); + // reverse(nums, 0, k - 1); + // reverse(nums, k, nums.length - 1); + } + + private 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/G20200343030603/LeetCode_3_603.java b/Week_01/G20200343030603/LeetCode_3_603.java new file mode 100644 index 00000000..183678bd --- /dev/null +++ b/Week_01/G20200343030603/LeetCode_3_603.java @@ -0,0 +1,51 @@ +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode(int x) { val = x; } + * } + */ + +public class ListNode { + int val; + ListNode next; + ListNode(int x){ + val = x; + } +} + +class Solution { + public ListNode mergeTwoLists(ListNode l1, ListNode l2) { +// //1、递归 时间复杂度O(n+m) 空间复杂度O(n+m) +// 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; +// } + + //2、迭代 时间复杂度O(n+m) 空间复杂度O(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/G20200343030603/LeetCode_8_603.md b/Week_01/G20200343030603/LeetCode_8_603.md new file mode 100644 index 00000000..e7d92196 --- /dev/null +++ b/Week_01/G20200343030603/LeetCode_8_603.md @@ -0,0 +1,18 @@ +用 add first 或 add last 这套新的 API 改写 Deque 的代码 +```java +Deque deque = new LinkedList(); + +deque.addFirst("a"); +deque.addFirst("b"); +deque.addFirst("c"); +System.out.prinln(deque); + +String str = deque.peekFirst(); +System.out.println(str); +System.out.println(deque); + +while(deque.size() > 0){ + System.out.println(deque.popFirst()); +} +System.out.println(deque); +``` \ No newline at end of file diff --git a/Week_01/G20200343030603/LeetCode_9_603.md b/Week_01/G20200343030603/LeetCode_9_603.md new file mode 100644 index 00000000..7be73016 --- /dev/null +++ b/Week_01/G20200343030603/LeetCode_9_603.md @@ -0,0 +1,604 @@ +一、 Queue源码分析 + +Queue和List一样都是Collection的子接口 +```java +public interface Queue extends Collection { + + // 向队列中添加一个元素 + // 如果添加成功则返回true + // 如果队列容量已满则抛出异常 + boolean add(E e); + + // 向队列中添加一个元素 + // 如果添加成功则返回true + // 如果添加失败则返回false + boolean offer(E e); + + // 移除对头元素 + // 返回对头元素,如果没有对头元素则抛出异常 + // throws NoSuchElementException + E remove(); + + // 移除对头元素 + // 返回对头元素,如果没有对头元素则返回null + E poll(); + + // 返回对头元素,不会删除对头元素 + // 如果没有对头元素则抛出异常 + // throws NoSuchElementException + E element(); + + // 返回对头元素,不会删除对头元素 + // 如果队列为空,则返回null + E peek(); + } +``` + + 二、 Priority Queue源码分析 + +总结 +1. 普通队列都是先进先出的,但是优先级队列是根据优先级进行确定的,优先级最高的先出队列; +2. 优先级队列类似于一颗完全二叉树,其内部实现使用的是数组 +3. 优先级队列在数组中其元素不一定是完全有序的,但是在出队列时,其元素是有序的 +4. 优先级队列插入和删除元素时,都需要对队列中的元素进行调整,其中remove()和add()方法的时间复杂度为O(log n) +而remove(Object obj)和contaions()方法需要O(n)时间复杂度,取对头元素只需要O(1)时间 +5. 优先级队列是非同步的,队列中不允许使用null元素 +```java + +public class PriorityQueue extends AbstractQueue + implements java.io.Serializable { + + private static final long serialVersionUID = -7720805057305804111L; + + //------------------------------初始化定义--------------------------------------------- + // 默认容量为11 + private static final int DEFAULT_INITIAL_CAPACITY = 11; + // 元素的存储方式是数组 + transient Object[] queue; // non-private to simplify nested class access + // 队列中元素的个数 + int size; + // 比较器 + private final Comparator comparator; + // 队列修改的次数 + transient int modCount; // non-private to simplify nested class access + + //-------------------------- 构造函数------------------------------------- + // 创建一个默认容量(11)和自然顺序的优先级队列 + public PriorityQueue() { + this(DEFAULT_INITIAL_CAPACITY, null); + } + // 创建一个指定容量和自然顺序的优先级队列 + public PriorityQueue(int initialCapacity) { + this(initialCapacity, null); + } + // 创建一个默认容量和指定比较器的优先级队列 + public PriorityQueue(Comparator comparator) { + this(DEFAULT_INITIAL_CAPACITY, comparator); + } + // 创建一个指定容量和包含指定集合元素的优先级队列,它分为三种情况: + // 第一种:如果是一个已经排好序的集合,首先根据集合获取到他的比较器方法,然后将集合中的元素添加到队列中; + // 第二种:如果是一个优先级队列,首先获取比较器方法,然后将指定优先级队列中的元素赋值到该队列中; + // 第三种:其他情况默认使用自然比较器,将集合中的元素添加到队列中; + public PriorityQueue(int initialCapacity, + Comparator comparator) { + // Note: This restriction of at least one is not actually needed, + // but continues for 1.5 compatibility + if (initialCapacity < 1) + throw new IllegalArgumentException(); + this.queue = new Object[initialCapacity]; + this.comparator = comparator; + } + + //创建一个包含指定优先级队列的队列,他的实现逻辑与(4)中的第二种情况相同; + @SuppressWarnings("unchecked") + public PriorityQueue(Collection c) { + if (c instanceof SortedSet) { + SortedSet ss = (SortedSet) c; + this.comparator = (Comparator) ss.comparator(); + initElementsFromCollection(ss); + } + else if (c instanceof PriorityQueue) { + PriorityQueue pq = (PriorityQueue) c; + this.comparator = (Comparator) pq.comparator(); + initFromPriorityQueue(pq); + } + else { + this.comparator = null; + initFromCollection(c); + } + } + + //创建一个指定优先级的集合中的元素的队列 + @SuppressWarnings("unchecked") + public PriorityQueue(PriorityQueue c) { + this.comparator = (Comparator) c.comparator(); + initFromPriorityQueue(c); + } + + @SuppressWarnings("unchecked") + public PriorityQueue(SortedSet c) { + this.comparator = (Comparator) c.comparator(); + initElementsFromCollection(c); + } + + // 初始化一个队列 + private void initFromPriorityQueue(PriorityQueue c) { + if (c.getClass() == PriorityQueue.class) { + this.queue = c.toArray(); + this.size = c.size(); + } else { + initFromCollection(c); + } + } + + // 从集合中初始化数据到队列中 + private void initElementsFromCollection(Collection c) { + // 将集合转成数组 + Object[] a = c.toArray(); + // 如果数组不是Object类型,转成Object类型 + if (a.getClass() != Object[].class) + a = Arrays.copyOf(a, a.length, Object[].class); + int len = a.length; + + if (len == 1 || this.comparator != null) + for (Object e : a) + if (e == null) + throw new NullPointerException(); + this.queue = a; + this.size = a.length; + } + + private void initFromCollection(Collection c) { + initElementsFromCollection(c); + heapify(); + } + + 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% 扩容的大小是翻倍或者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; + } + + //向队列中插入了一个元素 + public boolean add(E e) { + return offer(e); + } + + //向队列中插入了一个元素 + public boolean offer(E e) { + //如果元素为null,就抛出异常 + if (e == null) + throw new NullPointerException(); + modCount++; + int i = size; + // 如果队列中的元素个数大于或等于队列的长度,执行grow,对数组的容量进行扩容 + if (i >= queue.length) + grow(i + 1); + size = i + 1; + // 如果队列中的元素为空,那么新加入的元素为第一个元素,直接赋值到0的位置,否则插入元素向上进程调整 + if (i == 0) + queue[0] = e; + else + siftUp(i, e); + return true; + } + + @SuppressWarnings("unchecked") + 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; + } + + // 删除某一个元素 + public boolean remove(Object o) { + int i = indexOf(o); + if (i == -1) + return false; + else { + removeAt(i); + return true; + } + } + + boolean removeEq(Object o) { + for (int i = 0; i < size; i++) { + if (o == queue[i]) { + removeAt(i); + return true; + } + } + return false; + } + + public boolean contains(Object o) { + return indexOf(o) >= 0; + } + + public Object[] toArray() { + return Arrays.copyOf(queue, size); + } + + @SuppressWarnings("unchecked") + public T[] toArray(T[] a) { + final int size = this.size; + if (a.length < size) + // Make a new array of a's runtime type, but my contents: + return (T[]) Arrays.copyOf(queue, size, a.getClass()); + System.arraycopy(queue, 0, a, 0, size); + if (a.length > size) + a[size] = null; + return a; + } + + public Iterator iterator() { + return new Itr(); + } + + private final class Itr implements Iterator { + + private int cursor; + + private int lastRet = -1; + + private ArrayDeque forgetMeNot; + + private E lastRetElt; + + private int expectedModCount = modCount; + + public boolean hasNext() { + return cursor < size || + (forgetMeNot != null && !forgetMeNot.isEmpty()); + } + + @SuppressWarnings("unchecked") + public E next() { + if (expectedModCount != modCount) + throw new ConcurrentModificationException(); + if (cursor < size) + return (E) queue[lastRet = cursor++]; + if (forgetMeNot != null) { + lastRet = -1; + lastRetElt = forgetMeNot.poll(); + if (lastRetElt != null) + return lastRetElt; + } + throw new NoSuchElementException(); + } + + public void remove() { + if (expectedModCount != modCount) + throw new ConcurrentModificationException(); + if (lastRet != -1) { + E moved = PriorityQueue.this.removeAt(lastRet); + lastRet = -1; + if (moved == null) + cursor--; + else { + if (forgetMeNot == null) + forgetMeNot = new ArrayDeque<>(); + forgetMeNot.add(moved); + } + } else if (lastRetElt != null) { + PriorityQueue.this.removeEq(lastRetElt); + lastRetElt = null; + } else { + throw new IllegalStateException(); + } + expectedModCount = modCount; + } + } + + public int size() { + return size; + } + + public void clear() { + modCount++; + for (int i = 0; i < size; i++) + queue[i] = null; + size = 0; + } + + @SuppressWarnings("unchecked") + 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; + } + + //删除某个位置的元素 + @SuppressWarnings("unchecked") + E removeAt(int i) { + // assert i >= 0 && i < size; + modCount++; + //s为数组中的最后一个元素的位置 + 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 siftUp(int k, E x) { + if (comparator != null) + siftUpUsingComparator(k, x); + else + siftUpComparable(k, x); + } + + /** + * 如果是默认比较器,插入元素时的调整方式 + * @param k + * @param x + */ + @SuppressWarnings("unchecked") + private void siftUpComparable(int k, E x) { + Comparable key = (Comparable) x; + // k大于0时,循环遍历K + while (k > 0) { + // 获取K的父节点 + int parent = (k - 1) >>> 1; + // 获取父节点的元素e + Object e = queue[parent]; + // 如果key的值大于等于其父节点的元素,那么不需要进行调整,结束操作 + if (key.compareTo((E) e) >= 0) + break; + // 否则的话将两个值进行对换,同时将k赋值为其父节点的位置 + queue[k] = e; + k = parent; + } + queue[k] = key; + } + + //如果有指定的比较器,插入元素之后的调整方法 + @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 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; + //half为队列的中间一半位置 + int half = size >>> 1; // loop while a non-leaf + //循环调整k,k小于中间位置索引值时循环 + while (k < half) { + //获取k的左孩子索引值 + int child = (k << 1) + 1; // assume left child is least + //获取左孩子的值 + Object c = queue[child]; + //获取k的右孩子索引值 + int right = child + 1; + //如果存在右孩子,并且右孩子的值小于左孩子的值,那么将c值赋值为右孩子的值,也就是取左右孩子中值较小的那位 + if (right < size && + ((Comparable) c).compareTo((E) queue[right]) > 0) + c = queue[child = right]; + //如果key值小于等于孩子结点中的值,不需要调整,结束循环 + if (key.compareTo((E) c) <= 0) + break; + queue[k] = c; + k = child; + } + queue[k] = key; + } + + @SuppressWarnings("unchecked") + private void siftDownUsingComparator(int k, E x) { + int half = size >>> 1; + while (k < half) { + int child = (k << 1) + 1; + Object c = queue[child]; + int right = child + 1; + if (right < size && + comparator.compare((E) c, (E) queue[right]) > 0) + c = queue[child = right]; + if (comparator.compare(x, (E) c) <= 0) + break; + queue[k] = c; + k = child; + } + queue[k] = x; + } + + @SuppressWarnings("unchecked") + private void heapify() { + for (int i = (size >>> 1) - 1; i >= 0; i--) + siftDown(i, (E) queue[i]); + } + + public Comparator comparator() { + return comparator; + } + + private void writeObject(java.io.ObjectOutputStream s) + throws java.io.IOException { + // Write out element count, and any hidden stuff + s.defaultWriteObject(); + + // Write out array length, for compatibility with 1.5 version + s.writeInt(Math.max(2, size + 1)); + + // Write out all elements in the "proper order". + for (int i = 0; i < size; i++) + s.writeObject(queue[i]); + } + + private void readObject(java.io.ObjectInputStream s) + throws java.io.IOException, ClassNotFoundException { + // Read in size, and any hidden stuff + s.defaultReadObject(); + + // Read in (and discard) array length + s.readInt(); + + queue = new Object[size]; + + // Read in all elements. + for (int i = 0; i < size; i++) + queue[i] = s.readObject(); + + // Elements are guaranteed to be in "proper order", but the + // spec has never explained what that might be. + heapify(); + } + + public final Spliterator spliterator() { + return new PriorityQueueSpliterator<>(this, 0, -1, 0); + } + + static final class PriorityQueueSpliterator implements Spliterator { + /* + * This is very similar to ArrayList Spliterator, except for + * extra null checks. + */ + private final PriorityQueue pq; + private int index; // current index, modified on advance/split + private int fence; // -1 until first use + private int expectedModCount; // initialized when fence set + + /** Creates new spliterator covering the given range. */ + PriorityQueueSpliterator(PriorityQueue pq, int origin, int fence, + int expectedModCount) { + this.pq = pq; + this.index = origin; + this.fence = fence; + this.expectedModCount = expectedModCount; + } + + private int getFence() { // initialize fence to size on first use + int hi; + if ((hi = fence) < 0) { + expectedModCount = pq.modCount; + hi = fence = pq.size; + } + return hi; + } + + public PriorityQueueSpliterator trySplit() { + int hi = getFence(), lo = index, mid = (lo + hi) >>> 1; + return (lo >= mid) ? null : + new PriorityQueueSpliterator<>(pq, lo, index = mid, + expectedModCount); + } + + @SuppressWarnings("unchecked") + public void forEachRemaining(Consumer action) { + int i, hi, mc; // hoist accesses and checks from loop + PriorityQueue q; Object[] a; + if (action == null) + throw new NullPointerException(); + if ((q = pq) != null && (a = q.queue) != null) { + if ((hi = fence) < 0) { + mc = q.modCount; + hi = q.size; + } + else + mc = expectedModCount; + if ((i = index) >= 0 && (index = hi) <= a.length) { + for (E e;; ++i) { + if (i < hi) { + if ((e = (E) a[i]) == null) // must be CME + break; + action.accept(e); + } + else if (q.modCount != mc) + break; + else + return; + } + } + } + throw new ConcurrentModificationException(); + } + + public boolean tryAdvance(Consumer action) { + if (action == null) + throw new NullPointerException(); + int hi = getFence(), lo = index; + if (lo >= 0 && lo < hi) { + index = lo + 1; + @SuppressWarnings("unchecked") E e = (E)pq.queue[lo]; + if (e == null) + throw new ConcurrentModificationException(); + action.accept(e); + if (pq.modCount != expectedModCount) + throw new ConcurrentModificationException(); + return true; + } + return false; + } + + public long estimateSize() { + return (long) (getFence() - index); + } + + public int characteristics() { + return Spliterator.SIZED | Spliterator.SUBSIZED | Spliterator.NONNULL; + } + } +} +``` + diff --git a/Week_01/G20200343030605/SolutionPlusOne.php b/Week_01/G20200343030605/SolutionPlusOne.php new file mode 100644 index 00000000..3134eed2 --- /dev/null +++ b/Week_01/G20200343030605/SolutionPlusOne.php @@ -0,0 +1,36 @@ += 0; $i--) { + // +1为10则进一位,否则末位+1 + if (($digits[$i] + 1) >= $scale10) { + $digits[$i] = 0; + } else { + $digits[$i]++; + break; + } + } + + return $digits; + } +} \ No newline at end of file diff --git a/Week_01/G20200343030605/SolutionRemoveDuplicates.php b/Week_01/G20200343030605/SolutionRemoveDuplicates.php new file mode 100644 index 00000000..ad192310 --- /dev/null +++ b/Week_01/G20200343030605/SolutionRemoveDuplicates.php @@ -0,0 +1,29 @@ + + * 你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。 + * + * @param nums + * @param target + * @return + */ + public int[] twoSum(int[] nums, int target) { + Map map = new HashMap<>(); + for (int i = 0; i < nums.length; i++) { + int ele = target - nums[i]; + if (map.containsKey(ele)) { + return new int[]{map.get(ele), i}; + } + map.put(nums[i], i); + } + return new int[2]; + } +} diff --git a/Week_01/G20200343030611/LeetCode_21_611.java b/Week_01/G20200343030611/LeetCode_21_611.java new file mode 100644 index 00000000..48e9fe52 --- /dev/null +++ b/Week_01/G20200343030611/LeetCode_21_611.java @@ -0,0 +1,37 @@ +package datast.array; + +public class LeetCode_21_611 { + + /** + * 将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 + * + * @param l1 + * @param l2 + * @return + */ + 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 = l1; + l1 = l1.next; + } else { + prev.next = l2; + l2 = l2.next; + } + prev = prev.next; + } + prev.next = l1 == null ? l2 : l1; + return head.next; + } + + public class ListNode { + int val; + ListNode next; + + ListNode(int x) { + val = x; + } + } +} diff --git a/Week_01/G20200343030611/LeetCode_26_611.java b/Week_01/G20200343030611/LeetCode_26_611.java new file mode 100644 index 00000000..96ed5cb7 --- /dev/null +++ b/Week_01/G20200343030611/LeetCode_26_611.java @@ -0,0 +1,23 @@ +package datast.array; + +public class LeetCode_26_611 { + + /** + * 给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。 + *

+ * 不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。 + * + * @param nums + * @return + */ + 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; + } +} diff --git a/Week_01/G20200343030611/LeetCode_283_611.java b/Week_01/G20200343030611/LeetCode_283_611.java new file mode 100644 index 00000000..960b1745 --- /dev/null +++ b/Week_01/G20200343030611/LeetCode_283_611.java @@ -0,0 +1,22 @@ +package datast.array; + +public class LeetCode_283_611 { + + /** + * 给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。 + * + * @param nums + */ + public void moveZeroes(int[] nums) { + 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/G20200343030611/LeetCode_66_611.java b/Week_01/G20200343030611/LeetCode_66_611.java new file mode 100644 index 00000000..294aa3eb --- /dev/null +++ b/Week_01/G20200343030611/LeetCode_66_611.java @@ -0,0 +1,28 @@ +package datast.array; + +public class LeetCode_66_611 { + + + /** + * 给定一个由整数组成的非空数组所表示的非负整数,在该数的基础上加一。 + *

+ * 最高位数字存放在数组的首位, 数组中每个元素只存储单个数字。 + *

+ * 你可以假设除了整数 0 之外,这个整数不会以零开头。 + * + * @param digits + * @return + */ + 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/G20200343030611/LeetCode_88_611.java b/Week_01/G20200343030611/LeetCode_88_611.java new file mode 100644 index 00000000..bda6cd78 --- /dev/null +++ b/Week_01/G20200343030611/LeetCode_88_611.java @@ -0,0 +1,24 @@ +package datast.array; + +public class LeetCode_88_611 { + + /** + * 给定两个有序整数数组 nums1 和 nums2,将 nums2 合并到 nums1 中,使得 num1 成为一个有序数组。 + * 初始化 nums1 和 nums2 的元素数量分别为 m 和 n。 + * 你可以假设 nums1 有足够的空间(空间大小大于或等于 m + n)来保存 nums2 中的元素。 + * + * @param nums1 + * @param m + * @param nums2 + * @param n + */ + public void merge(int[] nums1, int m, int[] nums2, int n) { + int p = m - 1; + int q = n - 1; + int f = m + n - 1; + while ((p >= 0) && (q >= 0)) { + nums1[f--] = nums1[p] > nums2[q] ? nums1[p--] : nums2[q--]; + } + System.arraycopy(nums2, 0, nums1, 0, q + 1); + } +} diff --git a/Week_01/G20200343030617/LeetCode_10_617.go b/Week_01/G20200343030617/LeetCode_10_617.go new file mode 100644 index 00000000..2ad406b6 --- /dev/null +++ b/Week_01/G20200343030617/LeetCode_10_617.go @@ -0,0 +1,137 @@ +//设计实现双端队列。 +//你的实现需要支持以下操作: +// +//MyCircularDeque(k):构造函数,双端队列的大小为k。 +//insertFront():将一个元素添加到双端队列头部。 如果操作成功返回 true。 +//insertLast():将一个元素添加到双端队列尾部。如果操作成功返回 true。 +//deleteFront():从双端队列头部删除一个元素。 如果操作成功返回 true。 +//deleteLast():从双端队列尾部删除一个元素。如果操作成功返回 true。 +//getFront():从双端队列头部获得一个元素。如果双端队列为空,返回 -1。 +//getRear():获得双端队列的最后一个元素。 如果双端队列为空,返回 -1。 +//isEmpty():检查双端队列是否为空。 +//isFull():检查双端队列是否满了。 + +package main + +//结点 +type Node struct { + Data int + Pre *Node + Next *Node +} + +type MyCircularDeque struct { + First *Node + Last *Node + Size int + Cap int +} + +/** Initialize your data structure here. Set the size of the deque to be k. */ +func Constructor(k int) MyCircularDeque { + s := new(Node) + s.Pre, s.Next = s, s + return MyCircularDeque{s, s, 0, 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.Cap == this.Size { + return false + } + s := new(Node) + s.Data = value + s.Next = this.First.Next + this.First.Next.Pre = s + + this.First.Next = s + s.Pre = this.First + if this.Size == 0 { + this.Last = s + } + this.Size++ + 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.Cap == this.Size { + return false + } + s := new(Node) + s.Data = value + this.Last.Next = s + s.Pre = this.Last + + this.Last = s + this.Last.Next = this.First + this.First.Pre = this.Last + this.Size++ + 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 + } + s := this.First.Next //找到第一个节点 + this.First.Next = s.Next + s.Next.Pre = this.First + if this.Size == 1 { + this.Last = this.First + } + this.Size-- + 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 + } + s := this.Last.Pre //找到最后一个节点的前驱 + s.Next = this.First + this.Last = s + this.Size-- + return true +} + +/** Get the front item from the deque. */ +func (this *MyCircularDeque) GetFront() int { + if this.IsEmpty() { + return -1 + } + return this.First.Next.Data +} + +/** Get the last item from the deque. */ +func (this *MyCircularDeque) GetRear() int { + if this.IsEmpty() { + return -1 + } + return this.Last.Data +} + +/** Checks whether the circular deque is empty or not. */ +func (this *MyCircularDeque) IsEmpty() bool { + return this.Size == 0 +} + +/** Checks whether the circular deque is full or not. */ +func (this *MyCircularDeque) IsFull() bool { + return this.Cap == this.Size +} + +/** + * 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/G20200343030617/LeetCode_1_617.go b/Week_01/G20200343030617/LeetCode_1_617.go new file mode 100644 index 00000000..adb8106a --- /dev/null +++ b/Week_01/G20200343030617/LeetCode_1_617.go @@ -0,0 +1,19 @@ +//给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。 +//不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。 + +package main + +func removeDuplicates(nums []int) int { + length := len(nums) + if length == 0 { + return 0 + } + p := 1 + for i := 1; i < length; i++ { + if nums[i] != nums[p-1] { + nums[p] = nums[i] + p++ + } + } + return p +} diff --git a/Week_01/G20200343030621/NOTE.md b/Week_01/G20200343030621/NOTE.md index 50de3041..a656511b 100644 --- a/Week_01/G20200343030621/NOTE.md +++ b/Week_01/G20200343030621/NOTE.md @@ -1 +1,100 @@ -学习笔记 \ No newline at end of file +学习笔记 + +# 算法 + +## 算法本质 + +寻找重复性 + +## 优化操作 + +空间换时间 + +# 数据结构 + +### 数组 Array + +优点: + +1. 方便读取数据 (读取数据时间复杂度都是 O(1)) +2. 操作起来方便(直接用下标修改即可) + +缺点: + +1. 除开首尾添加,需要增加数据的话时间复杂度比较高(O(n)) + +时间复杂度 + +- 首尾添加:O(1) +- 读取数据:O(1) +- 插入数据:O(n) +- 删除数据:O(n) + +### 链表 Linked List + +优点: + +1. 可以动态添加 + +缺点: + +1. 只能通过顺次指针访问,查询效率低(所以有了跳表) + +时间复杂度 + +- 首尾添加:O(1) +- 读取数据:O(n) +- 插入数据:O(1) +- 删除数据:O(1) + +### 跳表 + +暂时还不太理解,就是给链表增加维度,优化查找时间 + +### 栈 Stack + +> 特点:先入后出 类似于装羽毛球的圆筒 +> 以及洗碗时候的一堆碗 + +时间复杂度 + +- 插入数据:O(1) +- 删除数据:O(1) + +### 队列 Queue + +> 特点:先入后出 类似于排队 + +时间复杂度 + +- 插入数据:O(1) +- 删除数据:O(1) + +### 双端队列: Deque:Double-end Queue + +> 队列跟栈的结合,实战用的比较多 + +时间复杂度 + +- 插入数据:O(1) +- 删除数据:O(1) +- 查询数据:O(n) + +### 优先队列:Priority Queue + +> 按照元素的优先级取出 例如最大值最小值 +> 实现的数据结构比较多样 + +时间复杂度 + +- 插入数据:O(1) +- 删除数据:O(1) +- 取出数据:O(logN) + +## 本周总结 + +重点是练习遍历,双指针,快慢指针 + +## 自我评价 + +对时间复杂度的理解还不够,还需要多锻炼双指针这种之前用得少的写法,对于链表、栈、队列、优先队列、双端队列这些基本没有接触过 diff --git a/Week_01/G20200343030621/move-zero.js b/Week_01/G20200343030621/move-zero.js new file mode 100644 index 00000000..644c7b52 --- /dev/null +++ b/Week_01/G20200343030621/move-zero.js @@ -0,0 +1,17 @@ +/** + * @param {number[]} nums + * @return {void} Do not return anything, modify nums in-place instead. + */ +// 双指针解法 +var moveZeroes = function(nums) { + let zeroAtIndex = 0; + for (let i = 0; i < nums.length; i++) { + if (nums[i] != 0) { + if (i != zeroAtIndex) { + nums[zeroAtIndex] = nums[i]; + nums[i] = 0; + } + zeroAtIndex++; + } + } +}; diff --git a/Week_01/G20200343030621/remove-duplicates-from-sorted-array.js b/Week_01/G20200343030621/remove-duplicates-from-sorted-array.js new file mode 100644 index 00000000..64365580 --- /dev/null +++ b/Week_01/G20200343030621/remove-duplicates-from-sorted-array.js @@ -0,0 +1,24 @@ +/* +给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。 + +不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。 + +来源:力扣(LeetCode) +链接:https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array +*/ + +// 双指针解法,由于是排序好的数组,就看他左右两边 + +/** + * @param {number[]} nums + * @return {number} + */ +var removeDuplicates = function(nums) { + let p = 0; + for (let q = 1; q < nums.length; q++) { + if (nums[q] !== nums[p]) { + nums[++p] = nums[q]; + } + } + return p + 1; +}; diff --git a/Week_01/G20200343030621/two-sum.js b/Week_01/G20200343030621/two-sum.js new file mode 100644 index 00000000..07ec5ad5 --- /dev/null +++ b/Week_01/G20200343030621/two-sum.js @@ -0,0 +1,37 @@ +// 1.暴力解法 +// 时间复杂度O(n^2) +/** + * @param {number[]} nums + * @param {number} target + * @return {number[]} + */ +var twoSum = function(nums, target) { + let res = []; + for (let i = 0; i < nums.length - 1; i++) { + for (let j = i + 1; j < nums.length; j++) { + if (nums[i] + nums[j] == target) { + res.push(i, j); + } + } + } + return res; +}; + +// 2.哈希解法 +// 时间复杂度O(n) +/** + * @param {number[]} nums + * @param {number} target + * @return {number[]} + */ + +twoSum = function(nums, target) { + var hashObj = {}; + for (let i = 0; i < nums.length; i++) { + var diff = target - nums[i]; + if (hashObj[diff] != undefined) { + return [hashObj[diff], i]; + } + hashObj[nums[i]] = i; + } +}; diff --git a/Week_01/G20200343030623/LeetCode_189_623.php b/Week_01/G20200343030623/LeetCode_189_623.php new file mode 100644 index 00000000..f09cc106 --- /dev/null +++ b/Week_01/G20200343030623/LeetCode_189_623.php @@ -0,0 +1,33 @@ + $len) { + $k = $k % $len; + } + $nums = $this->reverse($nums, 0, $len - 1); + $nums = $this->reverse($nums, 0, $k - 1); + $nums = $this->reverse($nums, $k, $len - 1); + return $nums; + } + + private function reverse($nums, $left, $right) + { + while ($left <= $right) { + $temp = $nums[$left]; + $nums[$left] = $nums[$right]; + $nums[$right] = $temp; + $left++; + $right--; + } + + return $nums; + } +} diff --git a/Week_01/G20200343030623/LeetCode_1_623.php b/Week_01/G20200343030623/LeetCode_1_623.php new file mode 100644 index 00000000..c7d1ddc6 --- /dev/null +++ b/Week_01/G20200343030623/LeetCode_1_623.php @@ -0,0 +1,19 @@ + $num) { + $difference = $target - $num; + if(isset($hashArr[$difference]) && $hashArr[$difference]!== $i) { + return [$i,$hashArr[$difference]]; + } + } + } +} diff --git a/Week_01/G20200343030623/LeetCode_21_623.php b/Week_01/G20200343030623/LeetCode_21_623.php new file mode 100644 index 00000000..6f7954fc --- /dev/null +++ b/Week_01/G20200343030623/LeetCode_21_623.php @@ -0,0 +1,30 @@ +val = $val; } + * } + */ +class Solution { + + /** + * @param ListNode $l1 + * @param ListNode $l2 + * @return ListNode + */ + function mergeTwoLists($l1, $l2) { + if ($l1 == null) return $l2; + if ($l2 == null) return $l1; + + if ($l1->val < $l2->val) { + $l1->next = $this->mergeTwoLists($l1->next, $l2); + return $l1; + } else { + $l2->next = $this->mergeTwoLists($l2->next, $l1); + return $l2; + } + } +} diff --git a/Week_01/G20200343030625/LeetCode_1_625.java b/Week_01/G20200343030625/LeetCode_1_625.java new file mode 100644 index 00000000..932cd0cf --- /dev/null +++ b/Week_01/G20200343030625/LeetCode_1_625.java @@ -0,0 +1,16 @@ +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) }; + } + } + throw new IllegalArgumentException("No two sum solution"); + } +} diff --git a/Week_01/G20200343030625/LeetCode_283_625.java b/Week_01/G20200343030625/LeetCode_283_625.java new file mode 100644 index 00000000..72cb57eb --- /dev/null +++ b/Week_01/G20200343030625/LeetCode_283_625.java @@ -0,0 +1,14 @@ +class Solution { + public void moveZeroes(int[] nums) { + int zeroIdx = 0; + for (int i = 0; i < nums.length; i++){ + if (nums[i] != 0){ + nums[zeroIdx] = nums [i]; + if(zeroIdx != i){ + nums[i] = 0; + } + zeroIdx ++; + } + } + } +} diff --git a/Week_01/G20200343030625/LeetCode_66_625.java b/Week_01/G20200343030625/LeetCode_66_625.java new file mode 100644 index 00000000..c6adcb37 --- /dev/null +++ b/Week_01/G20200343030625/LeetCode_66_625.java @@ -0,0 +1,30 @@ +class Solution { + public int[] plusOne(int[] digits) { + int[] arr = digits; + int idx = arr.length - 1; + int carry = 1; + + while (idx >= 0) { + int sum = arr[idx] + carry; + carry = sum / 10; + arr[idx] = sum % 10; + if (carry == 0) { + break; + } + idx--; + } + + if (carry == 1) { + int[] result = new int[arr.length + 1]; + result[0] = 1; + for (int i = 1; i < result.length; i++) { + result[i] = arr[i - 1]; + } + + return result; + } + + return arr; + + } +} diff --git a/Week_01/G20200343030625/LeetCode_88_625.java b/Week_01/G20200343030625/LeetCode_88_625.java new file mode 100644 index 00000000..bce96d78 --- /dev/null +++ b/Week_01/G20200343030625/LeetCode_88_625.java @@ -0,0 +1,23 @@ +class Solution { + public void merge(int[] nums1, int m, int[] nums2, int n) { + int[] tmp = new int[m]; + System.arraycopy(nums1, 0, tmp, 0, m); + + int p1 = 0; + int p2 = 0; + int p = 0; + while ((p1 < m) && (p2 < n)) { + if(tmp[p1] < nums2[p2]){ + nums1[p++] = tmp[p1++]; + }else{ + nums1[p++] = nums2[p2++]; + } + } + if(p1 < m){ + System.arraycopy(tmp, p1, nums1, p, m - p1); + } + if(p2 < n){ + System.arraycopy(nums2,p2,nums1,p,n - p2); + } + } +} diff --git a/Week_01/G20200343030627/LeetCode_1_627.js b/Week_01/G20200343030627/LeetCode_1_627.js new file mode 100644 index 00000000..95e899af --- /dev/null +++ b/Week_01/G20200343030627/LeetCode_1_627.js @@ -0,0 +1,13 @@ +// remove-duplicates-from-sorted-array + +var removeDuplicates = function(nums) { + var slowIdx = 0; + for (var i = 1; i < nums.length; i++) { + if (nums[slowIdx] != nums[i]) { + nums[slowIdx + 1] = nums[i]; + slowIdx += 1; + } + } + // nums.splice(slowIdx + 1, nums.length); + return slowIdx + 1; +}; \ No newline at end of file diff --git a/Week_01/G20200343030627/LeetCode_2_627.js b/Week_01/G20200343030627/LeetCode_2_627.js new file mode 100644 index 00000000..54e0c9b3 --- /dev/null +++ b/Week_01/G20200343030627/LeetCode_2_627.js @@ -0,0 +1,19 @@ +// rotate-array + +var rotate = function(nums, k) { + k = k % nums.length; + var length = nums.length; + if (length === 1 || k === 0) return; + + nums.reverse(); + reverseAny(nums, 0 ,k - 1); + reverseAny(nums, k, nums.length - 1) +}; + +function reverseAny(arr, startIdx, endIdx) { + for (var i=0; i < Math.floor((endIdx - startIdx + 1)/2); i++) { + var temp = arr[startIdx + i]; + arr[startIdx + i] = arr[endIdx - i]; + arr[endIdx - i] = temp; + } +} \ No newline at end of file diff --git a/Week_01/G20200343030627/LeetCode_6_627.js b/Week_01/G20200343030627/LeetCode_6_627.js new file mode 100644 index 00000000..89a51966 --- /dev/null +++ b/Week_01/G20200343030627/LeetCode_6_627.js @@ -0,0 +1,15 @@ +// move-zeroes +var moveZeroes = function(nums) { + if (nums.length <= 0) return; + + var numberPointer = 0; + for (var i = 0; i < nums.length; i++) { + if (nums[i] !== 0) { + nums[numberPointer] = nums[i]; + numberPointer+=1; + } + } + for (;numberPointer < nums.length; numberPointer++) { + nums[numberPointer] = 0; + } +}; \ No newline at end of file diff --git a/Week_01/G20200343030631/LeetCode_189_631.java b/Week_01/G20200343030631/LeetCode_189_631.java new file mode 100644 index 00000000..da799999 --- /dev/null +++ b/Week_01/G20200343030631/LeetCode_189_631.java @@ -0,0 +1,83 @@ +// Version1 +public static void rotate(int[] nums, int k) { + if (null == nums || nums.length == 0){ + return; + } + // 每次右移1个,循环多次 + for (int i = 0; i < k; i++) { + rotateOneStep(nums); + } + } + +private static void rotateOneStep(int[] nums) { + int previous = nums[nums.length - 1]; + for (int i = 0; i < nums.length; i++) { + int temp = nums[i]; + nums[i] = previous; + previous = temp; + } + } +// Version2 +private static void rotate(int[] nums, int k) { + if (null == nums || nums.length == 0){ + return; + } + // 需多次使用数组长度,避免每次获取; + int length = nums.length; + int[] tmp = new int[length]; + for (int j = 0; j < length; j++) { + int newLoc = (j + k) % length; + tmp[newLoc] = nums[j]; + } + for (int j = 0; j < length; j++) { + nums[j] = tmp[j]; + } + } +// Version3 +private static void rotate(int[] nums, int k) { + if (null == nums || nums.length == 0){ + return; + } + int length = nums.length; + // 当K大于数据长度时,没必要多次执行旋转 + k %= length; + // 翻转整个数组 + reverse(nums, 0, (length - 1)); + // 翻转前K个 + reverse(nums, 0, (k - 1)); + // 翻转剩余n-k个 + reverse(nums, k, (length - 1)); + } + +private static void reverse(int[] nums, int start, int end) { + while (start < end) { + // 两两交换 + int tmp = nums[start]; + nums[start] = nums[end]; + nums[end] = tmp; + start++; + end--; + } + } +// Version4 +private static void rotate(int[] nums, int k) { + if (null == nums || nums.length == 0) { + return; + } + int length = nums.length; + // 当K大于数据长度时,没必要多次执行旋转 + k %= length; + int num = 0; + for (int start = 0; num < length; start++) { + int current = start; + int previous = nums[start]; + do { + int next = (current + k) % length; + int tmp = nums[next]; + nums[next] = previous; + previous = tmp; + current = next; + num++; + } while (start != current); + } + } \ No newline at end of file diff --git a/Week_01/G20200343030631/LeetCode_1_631.java b/Week_01/G20200343030631/LeetCode_1_631.java new file mode 100644 index 00000000..c5f6a01f --- /dev/null +++ b/Week_01/G20200343030631/LeetCode_1_631.java @@ -0,0 +1,63 @@ +public class Solution { + public static void main(String[] args) { + int[] nums = new int[]{2, 7, 11, 15}; + int target = 9; + System.out.println(twoSum(nums, target)); + } + + /** + * 解题思路: 暴力枚举计算,匹配结果 + * 时间复杂度: O(n^2) + * 空间复杂度: O(1) + * 执行用时 :50 ms, 在所有 Java 提交中击败了41.96%的用户 + * 内存消耗 :38.9 MB, 在所有 Java 提交中击败了51.69%的用户 + * @Author: loe881@163.com + * @Date: 2020/2/21 + */ + public static int[] twoSumV1(int[] nums, int target) { + // 边界条件 + if (null == nums || nums.length == 0){ + throw new UnsupportedOperationException("No Solution"); + } + int[] results = new int[2]; + for (int i = 0; i < nums.length - 1; i++) { + int expectNum = target - nums[i]; + for (int j = i + 1; j < nums.length; j++) { + if (expectNum == nums[j]) { + results[0] = j; + results[1] = i; + } + } + } + return results; + } + + /** + * 解题思路: 利用哈希表查找快思想,所有元素放入哈希表,同时为提升效率,将放入元素和查找过程结合,还可以避免一次全部放入,查找时查找到自身的情况 + * 时间复杂度: O(n) + * 空间复杂度: O(n) + * 执行用时: 3 ms, 在所有 Java 提交中击败了95.62%的用户 + * 内存消耗: 41.5 MB, 在所有 Java 提交中击败了5.08%的用户 + * @Author: loe881@163.com + * @Date: 2020/2/21 + */ + public static int[] twoSumV2(int[] nums, int target) { + // 边界条件 + if (null == nums || nums.length == 0){ + throw new UnsupportedOperationException("No Solution"); + } + int[] results = new int[2]; + // 将数组元素存放再hashmap内,快速查找 + Map numMap = new HashMap<>(); + for (int i = 0; i < nums.length; i++) { + int tmp = target - nums[i]; + // 判断目标值与当前值之差是否在map中,在说明有解 + if (numMap.containsKey(tmp)){ + return new int[]{numMap.get(tmp), i}; + } + // 不管是否有解,都要把当前值放在map中,用于后续处理 + numMap.put(nums[i], i); + } + return results; + } +} \ No newline at end of file diff --git a/Week_01/G20200343030631/LeetCode_21_631.java b/Week_01/G20200343030631/LeetCode_21_631.java new file mode 100644 index 00000000..396addca --- /dev/null +++ b/Week_01/G20200343030631/LeetCode_21_631.java @@ -0,0 +1,72 @@ + +public class Solution { + public static void main(String[] args) { + + } + + /** + * 递归思想,对两个链表元素挨个处理 + * 时间复杂度:O(n+m) + * 空间复杂度:O(n+m) + * 执行用时 :0 ms, 在所有 Java 提交中击败了100.00%的用户 + * 内存消耗 :41 MB, 在所有 Java 提交中击败了5.02%的用户 + */ + public ListNode mergeTwoListsV1(ListNode l1, ListNode l2) { + // 边界判断及递归终止条件,如果l1 l2任何一个为空,直接返回另一个即可; + if (null == l1){ + return l2; + } + if (null == l2){ + return l1; + } + // 递归处理,如果当前l1节点值小于l2,则l1为当前节点,继续合并l1.next与l2,对l2也是一样 + if (l1.val < l2.val){ + l1.next = mergeTwoLists(l1.next, l2); + return l1; + }else { + l2.next = mergeTwoLists(l1, l2.next); + return l2; + } + } + + /** + * 解题思路: 迭代方式,新建空链表,比较两个链表元素后放入新链表,两个链表指针逐步后移 + * 时间复杂度: O(n+m) + * 空间复杂度: O(1) + * 执行用时: 1 ms, 在所有 Java 提交中击败了87.80%的用户 + * 内存消耗: 41 MB, 在所有 Java 提交中击败了5.02%的用户 + * + * @Author: loe881@163.com + * @Date: 2020/2/18 + */ + public ListNode mergeTwoListsV2(ListNode l1, ListNode l2) { + // 新建两个节点,一个作为head,一个作为游标 + 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; + } + + // Definition for singly-linked list. + public class ListNode { + int val; + ListNode next; + + ListNode(int x) { + val = x; + } + } + +} \ No newline at end of file diff --git a/Week_01/G20200343030631/LeetCode_26_631.java b/Week_01/G20200343030631/LeetCode_26_631.java new file mode 100644 index 00000000..edebb8a0 --- /dev/null +++ b/Week_01/G20200343030631/LeetCode_26_631.java @@ -0,0 +1,25 @@ +// Version1 +public static int removeDuplicates(int[] nums) { + int result = nums.length; + for (int i = 0; i < nums.length; i++) { + int tmp = nums[i]; + for (int j = i + 1; j < nums.length; j++) { + if (nums[j] == tmp) { + result = result - 1; + break; + } + } + } + return result; + } +// Version2 +public static int removeDuplicates(int[] nums) { + int result = 0; + for (int i = 0; i < nums.length; i++) { + if (nums[i] != nums[result]) { + result++; + nums[result] = nums[i]; + } + } + return result + 1; + } \ No newline at end of file diff --git a/Week_01/G20200343030631/LeetCode_283_631.java b/Week_01/G20200343030631/LeetCode_283_631.java new file mode 100644 index 00000000..1af691d6 --- /dev/null +++ b/Week_01/G20200343030631/LeetCode_283_631.java @@ -0,0 +1,91 @@ +public class Solution { + public static void main(String[] args) { + int[] nums = new int[]{0,1,0,3,12}; + moveZeroes(nums); + System.out.println(Arrays.toString(nums)); + } + + /** + * 解题思路: 不考虑限定条件,复制一个数组作为结果数组 + * 时间复杂度: O(n) + * 空间复杂度: O(n) + * 执行用时: 0 ms, 在所有 Java 提交中击败了100.00%的用户 + * 内存消耗: 41.9 MB, 在所有 Java 提交中击败了5.01%的用户 + * @Author: loe881@163.com + * @Date: 2020/2/25 + */ + public static void moveZeroesV1(int[] nums) { + // 边界条件 + if (null == nums || nums.length == 0){ + return; + } + // 新建一个数组存放结果 + int[] result = new int[nums.length]; + // 默认全部填充为0 + Arrays.fill(result, 0); + for (int i = 0, j = 0; i < nums.length; i++) { + // 碰到非0元素,放在新数组中 + if (nums[i] != 0){ + result[j++] = nums[i]; + } + } + // 将新数组每个元素值复制给nums + for (int i = 0; i < nums.length; i++) { + nums[i] = result[i]; + } + } + + /** + * 解题思路: 优化复制方式,不复制,改为用一个标记位记录指向非0元素最后的位置, + * 碰到0不动,碰到非零则复制到最后一个非零位置之后,最后形成非零数组,再从数组末尾开始赋值为记录个数个0 + * 时间复杂度: O(n) + * 空间复杂度: O(1) + * 执行用时: 0 ms, 在所有 Java 提交中击败了100.00%的用户 + * 内存消耗: 41.9 MB, 在所有 Java 提交中击败了5.01%的用户 + * @Author: loe881@163.com + * @Date: 2020/2/25 + */ + public static void moveZeroesV2(int[] nums) { + // 边界条件 + if (null == nums || nums.length == 0){ + return; + } + int lastNoneZero = 0; + int length = nums.length; + // 满足需求1,数组非零元素有序 + for (int i = 0; i < length; i++) { + // 非0,则同步移动,遇到0则lastNoneZero不更新,lastNoneZero指向最新一个0元素位置 + if (nums[i] != 0){ + nums[lastNoneZero++] = nums[i]; + } + } + // 满足需求2,0元素均在末尾 + for (int i = lastNoneZero; i < length; i++) { + nums[i] = 0; + } + } + + /** + * 解题思路: 继续优化标记位置算法,标记同时移动0,交换元素,减少后续循环操作 + * 时间复杂度: O(n) + * 空间复杂度: O(1) + * 执行用时: 0 ms, 在所有 Java 提交中击败了100.00%的用户 + * 内存消耗: 41.9 MB, 在所有 Java 提交中击败了5.01%的用户 + * @Author: loe881@163.com + * @Date: 2020/2/25 + */ + public static void moveZeroesV3(int[] nums) { + // 边界条件 + if (null == nums || nums.length == 0){ + return; + } + int lastZeroPoint = 0; + for (int i = 0; i < nums.length; i++) { + if (nums[i] != 0){ + int tmp = nums[i]; + nums[i] = nums[lastZeroPoint]; + nums[lastZeroPoint++] = tmp; + } + } + } +} \ No newline at end of file diff --git a/Week_01/G20200343030631/LeetCode_42_631.java b/Week_01/G20200343030631/LeetCode_42_631.java new file mode 100644 index 00000000..3ff8ff15 --- /dev/null +++ b/Week_01/G20200343030631/LeetCode_42_631.java @@ -0,0 +1,6 @@ + +public class Solution { + public static void main(String[] args) { + + } +} diff --git a/Week_01/G20200343030631/LeetCode_641_631.java b/Week_01/G20200343030631/LeetCode_641_631.java new file mode 100644 index 00000000..a191a97d --- /dev/null +++ b/Week_01/G20200343030631/LeetCode_641_631.java @@ -0,0 +1,115 @@ +/** + * 解题思路: 用数组存放实际数据,用headpos指示头部位置,tailPos指示尾部下一个元素要插入的位置,capacity指示数组大小,size指示当前大小,头部插入后挪移数据 + * V2:不再挪移数据,采用解题区推荐思路,使用虚拟环的思路,每次插入不再插入数据头部,而是计算插入位置,判别满或者空使用一个额外空间进行 + * 时间复杂度: + * 空间复杂度: + * 执行用时: 9 ms, 在所有 Java 提交中击败了33.90%的用户 + * 内存消耗: 40.8 MB, 在所有 Java 提交中击败了9.12%的用户 + * + * @Author: loe881@163.com + * @Date: 2020/3/2 + */ +public class Solution { + public static void main(String[] args) { + 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 + } + + + private static class MyCircularDeque { + private int[] datas; + private int headPos; + private int tailPos; + private int capacity; + /** Initialize your data structure here. Set the size of the deque to be k. */ + public MyCircularDeque(int k) { + capacity = k + 1; + datas = new int[capacity]; + headPos = 0; + tailPos = 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; + } + headPos = (headPos - 1 + capacity) % capacity; + datas[headPos] = 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; + } + datas[tailPos] = value; + tailPos = (tailPos + 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; + } + headPos = (headPos + 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; + } + tailPos = (tailPos - 1 + capacity) % capacity; + return true; + } + + + /** Get the front item from the deque. */ + public int getFront() { + if (isEmpty()) { + // 抛异常无法通过leetcode,改为返回-1 +// throw new UnsupportedOperationException("Empty Deque"); + return -1; + } + return datas[headPos]; + } + + /** Get the last item from the deque. */ + public int getRear() { + if (isEmpty()){ + // 抛异常无法通过leetcode,改为返回-1 +// throw new UnsupportedOperationException("Empty Deque"); + return -1; + } + + return datas[(tailPos - 1 + capacity) % capacity]; + } + + /** Checks whether the circular deque is empty or not. */ + public boolean isEmpty() { + return headPos == tailPos; + } + + /** Checks whether the circular deque is full or not. */ + public boolean isFull() { + return (tailPos + 1) % capacity == headPos; + } + + @Override + public String toString() { + return "MyCircularDeque{}"; + } + } +} diff --git a/Week_01/G20200343030631/LeetCode_66_631.java b/Week_01/G20200343030631/LeetCode_66_631.java new file mode 100644 index 00000000..62ffdbd1 --- /dev/null +++ b/Week_01/G20200343030631/LeetCode_66_631.java @@ -0,0 +1,39 @@ +public class Solution { + public static void main(String[] args) { + int[] test1 = new int[]{9, 9, 9, 9}; + int[] test2 = new int[]{4, 3, 2, 1}; + int[] test3 = new int[]{4, 3, 2, 9}; + int[] test4 = new int[]{9,8,7,6,5,4,3,2,1,0}; + List ints = new ArrayList<>(); + ints.add(test1); + ints.add(test2); + ints.add(test3); + ints.add(test4); + for (int[] anInt : ints) { + System.out.println(Arrays.toString(plusOne(anInt))); + } + } + + /** + * 解题思路:从数组最后一位倒序处理,0-8直接+1返回,9+1后向前逐步判断,极限情况下如果加至初始位置,则数组长度扩展1 + * 时间复杂度: O(n) + * 空间复杂度: O(1) + * 执行用时 :1 ms, 在所有 Java 提交中击败了96.78%的用户 + * 内存消耗 :36.2 MB, 在所有 Java 提交中击败了36.51%的用户 + */ + public static int[] plusOne(int[] digits) { + int length = digits.length; + for (int i = length - 1; i >= 0; i--) { + digits[i]++; + digits[i] %= 10; + // 如果当前位不为0,说明无进位,直接返回结果即可 + if (digits[i] != 0){ + return digits; + } + } + // 循环内未返回,说明一直有进位,则复制一个比原数组大1长度的数组 + digits = new int[length + 1]; + digits[0] = 1; + return digits; + } +} \ No newline at end of file diff --git a/Week_01/G20200343030631/LeetCode_88_631.java b/Week_01/G20200343030631/LeetCode_88_631.java new file mode 100644 index 00000000..fcb9f828 --- /dev/null +++ b/Week_01/G20200343030631/LeetCode_88_631.java @@ -0,0 +1,48 @@ +public class Solution { + 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); + System.out.println(Arrays.toString(nums1)); + } + + /** + * 解题思路: 直接合并数组,合并后排序,缺陷是浪费了有序的条件 + * 时间复杂度: O((n+m)log(n+m)) + * 空间复杂度: O(1) + * 执行用时: 1 ms, 在所有 Java 提交中击败了30.75%的用户 + * 内存消耗: 38.3 MB, 在所有 Java 提交中击败了5.02%的用户 + * @Author: loe881@163.com + * @Date: 2020/3/2 + */ + public static void mergeV1(int[] nums1, int m, int[] nums2, int n) { + // 合并nums2至nums1中 + System.arraycopy(nums2, 0, nums1, m, n); + // 排序数组 + Arrays.sort(nums1); + } + + /** + * 解题思路: 利用有序条件+nums1空间足够条件,双指针从两个数组末端比较 + * 时间复杂度: O(n+m) + * 空间复杂度: O(1) + * 执行用时: 0 ms, 在所有 Java 提交中击败了100.00%的用户 + * 内存消耗: 38.3 MB, 在所有 Java 提交中击败了5.20%的用户 + * @Author: loe881@163.com + * @Date: 2020/3/2 + */ + public static void mergeV2(int[] nums1, int m, int[] nums2, int n) { + // nums1数组元素位置 + int nums1Pos = m - 1; + // nums2数组元素位置 + int nums2Pos = n - 1; + // 合并后数组元素位置 + int numsPos = m + n - 1; + while (nums1Pos >= 0 && nums2Pos >= 0){ + // 如果nums1当前位置元素大于nums当前位置元素,则取nums1当前位置元素放在合并数组中,同时nums1数组元素位置减一 + nums1[numsPos--] = (nums1[nums1Pos] > nums2[nums2Pos]) ? nums1[nums1Pos--] : nums2[nums2Pos--]; + } + // 处理nums1的首个值大于nums2内值得情况 + System.arraycopy(nums2, 0, nums1, 0, nums2Pos + 1); + } +} \ No newline at end of file diff --git a/Week_01/G20200343030631/NOTE.md b/Week_01/G20200343030631/NOTE.md index 50de3041..c369c363 100644 --- a/Week_01/G20200343030631/NOTE.md +++ b/Week_01/G20200343030631/NOTE.md @@ -1 +1,5 @@ -学习笔记 \ No newline at end of file +学习笔记 +- keep it simple,keep it stupid!源码中感受到真理; +- 看几遍、读几遍,还得多写几遍; +- 仔细读题,潜藏线索、潜藏坑; +- 先不考虑限定条件下的思路,容易有误导性,虽然解出来了,但是会一直重复整个思路去优化,不能跳开; diff --git a/Week_01/G20200343030633/leetcode_189.py b/Week_01/G20200343030633/leetcode_189.py new file mode 100644 index 00000000..4c7dd9cc --- /dev/null +++ b/Week_01/G20200343030633/leetcode_189.py @@ -0,0 +1,43 @@ +# 暴力 loop K ,每次把末尾换到头位 +#不知道为啥leetcode 执行的时候可以,提交后就超出限制 +def baolirotate(nums, k): + length = len(nums) + for _ in range(k): + previous = nums[length - 1] + for j in range(length): + temp = nums[j] + nums[j] = previous + previous = temp + + +# 环状替换 +def rotate(nums, n): + length = len(nums) + k = n % length + count = 0 + start = 0 + while count < length: + current = start + prev = nums[start] + print('count:', count) + while True: + next = (current + k) % length + temp = nums[next] + nums[next] = prev + prev = temp + current = next + count += 1 + if start == current: + break + start += 1 + + + +a = [1, 2, 3, 4, 5, 6] +k = 2 +print('原始:', a) + +# rotate(a, k) +baolirotate(a, k) + +print('移动', k, '位后:', a) diff --git a/Week_01/G20200343030633/leetcode_21.py b/Week_01/G20200343030633/leetcode_21.py new file mode 100644 index 00000000..a0504978 --- /dev/null +++ b/Week_01/G20200343030633/leetcode_21.py @@ -0,0 +1,86 @@ +# 数组暴力算法: + +# def mergeTwoLists(l1, l2): +# k = 0 +# for i in range(len(l1)): +# for j in range(k, len(l2)): +# if l2[j] > l1[i]: +# l2.insert(j, l1[i]) +# k += 1 +# break +# if j == (len(l2) - 1): +# l2.append(l1[i]) +# return l2 +# +# +# l1 = [1, 2, 3, 4] +# l2 = [1, 3, 4, 5] +# +# l3 = mergeTwoLists(l1, l2) +# +# print('reuslt:', l3) + + +# 链表暴力:递归 +class ListNode(object): + def __init__(self, x): + self.val = x + self.next = None + + def deepcopy(self): + nl = ListNode(self.val) + nl.next = self.next + return nl + + +list1 = ListNode(1) +list1.next = ListNode(2) +list1.next.next = ListNode(4) + +list2 = ListNode(1) +list2.next = ListNode(3) +list2.next.next = ListNode(4) + + +class Solution: + # 递归 + def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode: + if l1 is None: + return l2 + elif l2 is None: + return l1 + elif l1.val < l2.val: + l1.next = self.mergeTwoLists(l1.next, l2) + return l1 + else: + l2.next = self.mergeTwoLists(l1, l2.next) + return l2 + + # 迭代 + def mergeTwoLists2(self, l1: ListNode, l2: ListNode) -> ListNode: + prehead = ListNode(-1) + + prev = prehead + while l1 and l2: + if l1.val <= l2.val: + prev.next = l1 + l1 = l1.next + else: + prev.next = l2 + l2 = l2.next + prev = prev.next + + # exactly one of l1 and l2 can be non-null at this point, so connect + # the non-null list to the end of the merged list. + prev.next = l1 if l1 is not None else l2 + + return prehead.next + + +s = Solution() +l = s.mergeTwoLists2(list1, list2) + +while l.next is not None: + print(l.val) + l = l.next +print(l.val) diff --git a/Week_01/G20200343030635/id635/1.cpp b/Week_01/G20200343030635/id635/1.cpp new file mode 100644 index 00000000..bb19e15d --- /dev/null +++ b/Week_01/G20200343030635/id635/1.cpp @@ -0,0 +1,19 @@ +class Solution { +public: + vector twoSum(vector& nums, int target) { + map a_map; + vector b_vec(2,-1); + for(int i=0;i0) + { + b_vec[0]=a_map[target-nums[i]]; + b_vec[1]=i; + break; + } + a_map[nums[i]]=i; + } + return b_vec; + } +}; diff --git a/Week_01/G20200343030635/id635/283.cpp b/Week_01/G20200343030635/id635/283.cpp new file mode 100644 index 00000000..78ad62ce --- /dev/null +++ b/Week_01/G20200343030635/id635/283.cpp @@ -0,0 +1,17 @@ +class Solution { +public: + void moveZeroes(vector& nums) { + int count=0; + for(auto it=nums.begin();it!=nums.end();) + { + if((*it)==0) + { + it=nums.erase(it); + count++; + } + else + ++it; + } + nums.insert(nums.end(),count,0); + } +}; diff --git a/Week_01/G20200343030643/01-two-sum.py b/Week_01/G20200343030643/01-two-sum.py new file mode 100644 index 00000000..1b3c2037 --- /dev/null +++ b/Week_01/G20200343030643/01-two-sum.py @@ -0,0 +1,11 @@ +class Solution(object): + def twoSum(self, nums, target): + """ + :type nums: List[int] + :type target: int + :rtype: List[int] + """ + for i in range(len(nums)) : + for j in range(i+1, len(nums)) : + if (nums[i] + nums[j] == target): + return [i,j] diff --git a/Week_01/G20200343030643/283-move-zeroes.py b/Week_01/G20200343030643/283-move-zeroes.py new file mode 100644 index 00000000..3ce4e17b --- /dev/null +++ b/Week_01/G20200343030643/283-move-zeroes.py @@ -0,0 +1,12 @@ +class Solution(object): + def moveZeroes (self, nums): + if not nums: + return 0 + + j = 0 + for i in xrange(len(nums)): + if nums[i] : + nums[j] = nums[i] + j += 1 + for i in xrange(j,len(nums)): + nums[i] = 0 diff --git a/Week_02/G20190282010007/NOTE.md b/Week_02/G20190282010007/NOTE.md index 50de3041..ede0f28b 100644 --- a/Week_02/G20190282010007/NOTE.md +++ b/Week_02/G20190282010007/NOTE.md @@ -1 +1,52 @@ -学习笔记 \ No newline at end of file +学习笔记 + +本周的学习继续懵圈中,到了这周,感觉用JavaScript的有点跟不上,需要上网找很多相关的资料来看,然后再对应老师视频里所说的内容,进行理解,感觉还是挺吃力的,不过呢。。真的很有趣啊有木有,左右是树的左右啊,不是图放左一点,不不不,再放右一点,字往左一点,不不不,还是往右一点好看。。。鉴于以上情况,下周需要投入更多的时间进行学习,不然要跟不上了。 +简单的总结 + 关于哈希表 + 通过一个哈希函数(有现成,也可以自己写),将一个key值,转化为真实数据所存储的数组中对应的下标值,以实现将数据分散存储却又能快速查找的方式 + + 关于二叉树 + 树就是一种特殊的链表 + 关于树的遍历 + 前序(根左右) + def preorder(self, root) + if root: + self.traverse_path append(root.val) + self.preorder(root.left) + self.preorder(root.right) + 中序(左根右) + def inorder(self, root) + if root: + self.inorder(root.left) + self.traverse_path append(root.val) + self.inorder(root.right) + 后序(左右根) + def psostorder(self, root) + if root: + self.psostorder(root.left) + self.psostorder(root.right) + self.traverse_path append(root.val) + + 关于递归 + 简单的理解,就是自己调用自己 + 递归事例代码 + 来自Python的示例 + def recursion (level, param1, param2) { + # recursion terminator 递归终结条件 + if level > MAX_LEVEL + process_result + return + + # process logic in current level 处理当前层逻辑 + process(level, data...) + + # drill down 下探到下一层 + self.recursion(level+1,p1,...) + + #reverse the current level status if needed 如有必要的话,清理当前层 + } + + 注意事项: + 抵制人肉递归 + 找最近重复子问题(重复性) + 数学归纳法 \ No newline at end of file diff --git a/Week_02/G20190282010007/leetcode_589_007.js b/Week_02/G20190282010007/leetcode_589_007.js new file mode 100644 index 00000000..f9f02ff7 --- /dev/null +++ b/Week_02/G20190282010007/leetcode_589_007.js @@ -0,0 +1,42 @@ +// 题目: N叉树的前序遍历 +/** + * 题目描述: + * 给定一个 N 叉树,返回其节点值的前序遍历。 + */ + + // 解题语言: javaScript + + // 解题 + +/** + * // Definition for a Node. + * function Node(val, children) { + * this.val = val; + * this.children = children; + * }; + */ +/** + * @param {Node} root + * @return {number[]} + */ +var preorder = function(root) { + // 如果一开始就是空,那就直接返回空 + if (!root) {return []} + + // 数据逻辑处理 + let res = [] + recusion(root) + return res + + // 递归的方法 + function recusion(root) { + // 终止条件 + if (!root) return + // 处理操作 + res.push(root.val) + // 进行下一层的递归 + for (let i = 0; i < root.children.length; i++) { + recusion(root.children[i]) + } + } +}; \ No newline at end of file diff --git a/Week_02/G20190282010007/leetcode_590_007.js b/Week_02/G20190282010007/leetcode_590_007.js new file mode 100644 index 00000000..9a553d8e --- /dev/null +++ b/Week_02/G20190282010007/leetcode_590_007.js @@ -0,0 +1,43 @@ +// 题目: N叉树的后序遍历 +/** + * 题目描述: + * 给定一个 N 叉树,返回其节点值的后序遍历。 + */ + + // 解题语言: javaScript + + // 解题 + +/** + * // Definition for a Node. + * function Node(val, children) { + * this.val = val; + * this.children = children; + * }; + */ +/** + * @param {Node} root + * @return {number[]} + */ +var preorder = function(root) { + // 如果一开始就是空,那就直接返回空 + if (!root) {return []} + + // 数据逻辑处理 + let res = [] + recusion(root) + return res + + // 递归的方法 + function recusion(root) { + // 终止条件 + if (!root) return + // 进行下一层的递归 + for (let i = 0; i < root.children.length; i++) { + recusion(root.children[i]) + } + + // 处理操作----与前序相比,将放入操作放在循环后面 + res.push(root.val) + } +}; \ No newline at end of file diff --git a/Week_02/G20190343010191/LeetCode_144_191.py b/Week_02/G20190343010191/LeetCode_144_191.py new file mode 100644 index 00000000..08716fba --- /dev/null +++ b/Week_02/G20190343010191/LeetCode_144_191.py @@ -0,0 +1,44 @@ +""" +给定一个二叉树,返回它的 前序 遍历。 + + 示例: + +输入: [1,null,2,3] + 1 + \ + 2 + / + 3 + +输出: [1,2,3] + +""" + +""" +思路: + 这周主要练习递归,所以迭代的方法后续再补上 + 对于N 叉树, 不仅有左子树与右子树 + 而且是 child1,child2,child3,....childN + 于后序而言 + 先走访 (由左至右) 所有的儿子 + 最后访问根结点 +""" + +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution: + def preorderTraversal(self, root: TreeNode) -> List[int]: + if root: + res = [] + res.append(root.val) + res.extend(self.preorderTraversal(root.left)) + res.extend(self.preorderTraversal(root.right)) + + else: + res = [] + return res diff --git a/Week_02/G20190343010191/LeetCode_429_191.py b/Week_02/G20190343010191/LeetCode_429_191.py new file mode 100644 index 00000000..76ad36b4 --- /dev/null +++ b/Week_02/G20190343010191/LeetCode_429_191.py @@ -0,0 +1,72 @@ +""" +给定一个 N 叉树,返回其节点值的层序遍历。 (即从左到右,逐层遍历)。 + +例如,给定一个 3叉树 : + +  + + + +  + +返回其层序遍历: + +[ + [1], + [3,2,4], + [5,6] +] +  + +说明: + +树的深度不会超过 1000。 +树的节点总数不会超过 5000。 + +""" + +""" +思路: + 一样先练习递归 + 与前几题相同 + 主要加上层数处理 +""" + +""" +# Definition for a Node. +class Node: + def __init__(self, val=None, children=None): + self.val = val + self.children = children +""" + +""" +# Definition for a Node. +class Node: + def __init__(self, val=None, children=None): + self.val = val + self.children = children +""" + + +class Solution: + def levelOrder(self, root: 'Node') -> list[list[int]]: + + def recur_deph(root: 'Node', depth, res_list): + + if depth + 1 > len(res_list): + res_list.append([]) + res_list[depth].append(root.val) + + for child in root.children: + if child: + recur_deph(child, depth + 1, res_list) + return res_list + + if root: + res = [] + res = recur_deph(root, 0, res) + + else: + res = [] + return res diff --git a/Week_02/G20190343010191/LeetCode_589_191.py b/Week_02/G20190343010191/LeetCode_589_191.py new file mode 100644 index 00000000..42bd1366 --- /dev/null +++ b/Week_02/G20190343010191/LeetCode_589_191.py @@ -0,0 +1,38 @@ +""" +给定一个 N 叉树,返回其节点值的前序遍历。 + +例如,给定一个 3叉树 : + +返回其前序遍历: [1,3,5,6,2,4]。 +""" + +""" +思路: + + 对于N 叉树, 不仅有左子树与右子树 + 而且是 child1,child2,child3,....childN + 于后序而言 + 先访问根结点 + 最后走访 (由左至右) 所有的儿子 +""" + +""" +# Definition for a Node. +class Node: + def __init__(self, val=None, children=None): + self.val = val + self.children = children +""" + + +class Solution: + def preorder(self, root: 'Node') -> list[int]: + if root: + res = [] + res.append(root.val) + for child in root.children: + res.extend(self.preorder(child)) + + else: + res = [] + return res diff --git a/Week_02/G20190343010191/LeetCode_590_191.py b/Week_02/G20190343010191/LeetCode_590_191.py new file mode 100644 index 00000000..3cf719fd --- /dev/null +++ b/Week_02/G20190343010191/LeetCode_590_191.py @@ -0,0 +1,37 @@ +""" +给定一个 N 叉树,返回其节点值的后序遍历。 + +例如,给定一个 3叉树 : + +返回其后序遍历: [5,6,3,2,4,1]. +""" + +""" +思路: + 这周主要练习递归,所以迭代的方法后续再补上 + 对于N 叉树, 不仅有左子树与右子树 + 而且是 child1,child2,child3,....childN + 于后序而言 + 先走访 (由左至右) 所有的儿子 + 最后访问根结点 +""" + +""" +# Definition for a Node. +class Node: + def __init__(self, val=None, children=None): + self.val = val + self.children = children +""" + + +class Solution: + def postorder(self, root: 'Node') -> list[int]: + if root: + res = [] + for child in root.children: + res.extend(self.postorder(child)) + res.append(root.val) + else: + res = [] + return res diff --git a/Week_02/G20190343010191/NOTE.md b/Week_02/G20190343010191/NOTE.md index 50de3041..3e3a94b4 100644 --- a/Week_02/G20190343010191/NOTE.md +++ b/Week_02/G20190343010191/NOTE.md @@ -1 +1,43 @@ -学习笔记 \ No newline at end of file +### 学习笔记 +这次主要练习递归 + +树的走访的前中后序 + +#### 树走访代码模版: + + + def preorder(self,root): + if root: + self.traverse_path.append(root.val) + self.preorder(root.left) + self.preorder(root.right) + + def inorder(self,root): + if root: + self.preorder(root.left) + self.traverse_path.append(root.val) + self.preorder(root.right) + + def postorder(self,root): + if root: + self.preorder(root.left) + self.preorder(root.right) + self.traverse_path.append(root.val) + +递归代码模版 + + def recursion(level,param1,param2,...) + #terminator + #先写终止条件 + + if level > MAX_LEVEL: + #process result + return + #逻辑处理 + process(level,data) + + #drill down + self.recursion(level+1,p1,p2,...) + + # 清理当前层状态( 如果需要) + diff --git a/Week_02/G20190379010083/LeetCode_042_083.swift b/Week_02/G20190379010083/LeetCode_042_083.swift new file mode 100644 index 00000000..c13d2a9d --- /dev/null +++ b/Week_02/G20190379010083/LeetCode_042_083.swift @@ -0,0 +1,111 @@ +// +// 0042_TrappingRainWater.swift +// AlgorithmPractice +// +// https://leetcode-cn.com/problems/trapping-rain-water/ +// Created by Ryeagler on 2020/2/15. +// Copyright © 2020 Ryeagle. All rights reserved. +// + +import Foundation + +class TrappingRainWater { + /// 左右指针 + func trap(_ height: [Int]) -> Int { + var result = 0 + var left = 0, right = height.count - 1 + var leftMax = 0, rightMax = 0 + while left < right { + if height[left] < height[right] { + if height[left] >= leftMax { + leftMax = height[left] + } else { + result += leftMax - height[left] + } + left += 1 + } else { + if height[right] >= rightMax { + rightMax = height[right] + } else { + result += rightMax - height[right] + } + right -= 1 + } + } + return result + } + + /// 栈法 + func trapStack(_ height: [Int]) -> Int { + var result = 0 + var stack = Stack() + var i = 0 + while i < height.count { + if stack.isEmpty || height[i] <= height[stack.peek()!] { + stack.push(i) + i += 1 + } else { + // + let pre = stack.pop()! + if stack.isEmpty == false { + let minHeight = min(height[stack.peek()!], height[i]) + result += (minHeight - height[pre]) * (i - stack.peek()! - 1) + } + } + } + return result + } + + /// 动态法 + func trapDanamic(_ height: [Int]) -> Int { + var result = 0 + var leftMaxArr = [Int]() + var rightMaxArr = [Int]() + + var leftMax = 0 + for i in 0.. 0 { + result += target + } + } + + return result + } + + /// 暴力法 + func trapBruteForce(_ height: [Int]) -> Int { + var result = 0 + + for i in 0.. 0 { + result += target + } + } + + return result + } +} diff --git a/Week_02/G20190379010083/LeetCode_046_083.swift b/Week_02/G20190379010083/LeetCode_046_083.swift new file mode 100644 index 00000000..4f04d188 --- /dev/null +++ b/Week_02/G20190379010083/LeetCode_046_083.swift @@ -0,0 +1,31 @@ +// +// 0046_ Permutations.swift +// AlgorithmPractice +// +// Created by Ryeagler on 2020/2/23. +// Copyright © 2020 Ryeagle. All rights reserved. +// + +import Foundation + +class Permutations { + func permute(_ nums: [Int]) -> [[Int]] { + var result = [[Int]]() + var tempArr = [Int]() + backtrace(&result, &tempArr, nums) + return result + } + + func backtrace(_ result: inout [[Int]], _ tempArr: inout [Int], _ nums: [Int]) { + if tempArr.count == nums.count { + result.append(tempArr) + } else { + for i in 0..?) -> Int { + guard let node = root else { + return 0 + } + + var queue = Queue>() + queue.enqueue(node) + var level = 0 + // 如果队列不为空,则进入循 + while queue.isEmpty == false { + let size = queue.count + for _ in 0..?) -> Int { + if root == nil { + return 0 + } + + let leftDepth = maxDepth_Recursively(root?.left) + let rightDepth = maxDepth_Recursively(root?.right) + return max(leftDepth, rightDepth) + 1 + } +} diff --git a/Week_02/G20190379010083/LeetCode_226_083.swift b/Week_02/G20190379010083/LeetCode_226_083.swift new file mode 100644 index 00000000..c63bd323 --- /dev/null +++ b/Week_02/G20190379010083/LeetCode_226_083.swift @@ -0,0 +1,45 @@ +// +// 0226_InvertBinaryTree.swift +// AlgorithmPractice +// +// Created by Ryeagler on 2020/2/23. +// Copyright © 2020 Ryeagle. All rights reserved. +// + +import Foundation + +class InvertBinaryTree { + func invertTree(_ root: TreeNode?) -> TreeNode? { + guard let node = root else { + return nil + } + + var queue = Queue>() + queue.enqueue(node) + while queue.isEmpty == false { + let count = queue.count + for _ in 0..?) -> TreeNode? { + guard let node = root else { + return nil + } + node.left = invertTree_Recursively(node.left) + node.right = invertTree_Recursively(node.right) + return node + } +} diff --git a/Week_02/G20200343030001/Leetcode_049_001.java b/Week_02/G20200343030001/Leetcode_049_001.java new file mode 100644 index 00000000..63c1a5bd --- /dev/null +++ b/Week_02/G20200343030001/Leetcode_049_001.java @@ -0,0 +1,27 @@ +package Week_02; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; + +public class Leetcode_049_001 { + public List> groupAnagrams(String[] strs) { + HashMap> mapping = new HashMap<>(); + + for (String s : strs) { + char[] chars = s.toCharArray(); + Arrays.sort(chars); + + String temp = String.valueOf(chars); + + if (!mapping.containsKey(temp)) { + mapping.put(temp, new ArrayList()); + } + + mapping.get(temp).add(s); + } + + return new ArrayList(mapping.values()); + } +} diff --git a/Week_02/G20200343030001/Leetcode_077_001.java b/Week_02/G20200343030001/Leetcode_077_001.java new file mode 100644 index 00000000..83f694b7 --- /dev/null +++ b/Week_02/G20200343030001/Leetcode_077_001.java @@ -0,0 +1,35 @@ +package Week_02; + +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; + +public class Leetcode_077_001 { + private List> res = new ArrayList<>(); + + private void findCombinations(int n, int k, int begin, Stack pre) { + if (pre.size() == k) { + res.add(new ArrayList<>(pre)); + + return; + } + + for (int i = begin; i <= n; i++) { + pre.add(i); + + findCombinations(n, k, i + 1, pre); + + pre.pop(); + } + } + + public List> combine(int n, int k) { + if (n <= 0 || k <= 0 || n < k) { + return res; + } + + findCombinations(n, k, 1, new Stack<>()); + + return res; + } +} diff --git a/Week_02/G20200343030001/Leetcode_590_001.java b/Week_02/G20200343030001/Leetcode_590_001.java new file mode 100644 index 00000000..c447b691 --- /dev/null +++ b/Week_02/G20200343030001/Leetcode_590_001.java @@ -0,0 +1,23 @@ +package Week_02; + +import java.util.ArrayList; +import java.util.List; + +public class Leetcode_590_001 { + private List res = new ArrayList<>(); + + public List postorder(Node root) { + if(root == null){ + return res; + } + + for(Node c : root.children){ + postorder(c); + } + + res.add(root.val); + + return res; + + } +} diff --git a/Week_02/G20200343030001/Node.java b/Week_02/G20200343030001/Node.java new file mode 100644 index 00000000..e49e7744 --- /dev/null +++ b/Week_02/G20200343030001/Node.java @@ -0,0 +1,19 @@ +package Week_02; + +import java.util.List; + +public class Node { + public int val; + public List children; + + public Node() {} + + public Node(int _val) { + val = _val; + } + + public Node(int _val, List _children) { + val = _val; + children = _children; + } +} diff --git a/Week_02/G20200343030005/Leetcode_001_001.js b/Week_02/G20200343030005/Leetcode_001_001.js new file mode 100644 index 00000000..3a423128 --- /dev/null +++ b/Week_02/G20200343030005/Leetcode_001_001.js @@ -0,0 +1,132 @@ +/** +1. 两数之和 + +方法一:暴力法 + +暴力法很简单,遍历每个元素 x,并查找是否存 target=x1+x2 相等的目标元素。 +暴力法很简单,遍历每个元素 x,并查找是否存在一个值与 target−x 相等的目标元素。 +*/ +var nums = [2, 7, 11, 15]; +var target = 9; +/** + * @param {number[]} nums + * @param {number} target + * @return {number[]} + */ + +var twoSum = function(nums, target) { + var arr = []; + for (var i = 0; i < nums.length - 1; i++) { + for (var j = i + 1; j < nums.length; j++) { + if (nums[i] + nums[j] == target) { + arr.push(i, j); + } + } + } + return arr; +}; + +/** + * @param {number[]} nums + * @param {number} target + * @return {number[]} + */ + +var twoSum = function(nums, target) { + var arr = []; + for (var i = 0; i < nums.length - 1; i++) { + for (var j = i + 1; j < nums.length; j++) { + if (nums[j] == target - nums[i]) { + arr.push(i, j); + } + } + } + return arr; +}; +console.log(twoSum(nums, target)); + +/** +方法二:两遍哈希表 + + + + +为了对运行时间复杂度进行优化,我们需要一种更有效的方法来检查数组中是否存在目标元素。如果存在,我们需要找出它的索引。保持数组中的每个元素与其索引相互对应的最好方法是什么?哈希表。 + +通过以空间换取速度的方式,我们可以将查找时间从 O(n)O(n) 降低到 O(1)O(1)。哈希表正是为此目的而构建的,它支持以 近似 恒定的时间进行快速查找。我用“近似”来描述,是因为一旦出现冲突,查找用时可能会退化到 O(n)O(n)。但只要你仔细地挑选哈希函数,在哈希表中进行查找的用时应当被摊销为 O(1)O(1)。 + +一个简单的实现使用了两次迭代。在第一次迭代中,我们将每个元素的值和它的索引添加到表中。然后,在第二次迭代中,我们将检查每个元素所对应的目标元素(target - nums[i]target−nums[i])是否存在于表中。注意,该目标元素不能是 nums[i]nums[i] 本身! + +作者:LeetCode +链接:https://leetcode-cn.com/problems/two-sum/solution/liang-shu-zhi-he-by-leetcode-2/ +*/ + +/** + * @param {number[]} nums + * @param {number} target + * @return {number[]} + */ + +var twoSum = function(nums, target) { + var hashMap = new Map(); + for (var i = 0; i < nums.length; i++) { + hashMap.set(nums[i], i); // [值value,索引index] + } + + console.log(hashMap); + var arr = []; + for (var i = 0; i < nums.length; i++) { + var hash_key = target - nums[i]; + // 注意,该目标元素不能是 nums[i]本身! + if (hashMap.has(hash_key) && hashMap.get(hash_key) != i) { + arr.push(i, hashMap.get(hash_key)); + return arr; + } + } + // return arr; +}; +console.log(twoSum(nums, target)); + +/** +不能用 +if (hashMap.has(hash_key) && hash_key != nums[i]) { + arr.push(i, hashMap.get(hash_key)); + return arr; +} + +输入:[3,3] 6 预期:[0,1] 用例通过不了 +*/ + +/** +方法三:一遍哈希表 +事实证明,我们可以一次完成。在进行迭代并将元素插入到表中的同时,我们还会回过头来检查表中是否已经存在当前元素所对应的目标元素。如果它存在,那我们已经找到了对应解,并立即将其返回。 + +作者:LeetCode +链接:https://leetcode-cn.com/problems/two-sum/solution/liang-shu-zhi-he-by-leetcode-2/ + +*/ +var nums = [3, 2, 4]; +// var nums = [3, 3]; +var target = 6; +/** + * @param {number[]} nums + * @param {number} target + * @return {number[]} + */ + +var twoSum = function(nums, target) { + var hashMap = new Map(); + var arr = []; + for (var i = 0; i < nums.length; i++) { + var hash_key = target - nums[i]; + if (hashMap.has(hash_key)) { + arr.push(hashMap.get(hash_key), i); + return arr; + } + hashMap.set(nums[i], i); // [值value,索引index] + } + console.log(hashMap); + console.log(arr); + return arr; +}; +console.log(twoSum(nums, target)); diff --git a/Week_02/G20200343030005/Leetcode_049_001.js b/Week_02/G20200343030005/Leetcode_049_001.js new file mode 100644 index 00000000..16691e02 --- /dev/null +++ b/Week_02/G20200343030005/Leetcode_049_001.js @@ -0,0 +1,206 @@ +/** +49. 字母异位词分组 + + +解法一:常规解法 + + +解法二 +我们将每个字符串按照字母顺序排序,这样的话就可以把 eat,tea,ate 都映射到 aet。其他的类似。 + +*/ + +/** + * @param {string[]} strs + * @return {string[][]} + */ + +var groupAnagrams = function(strs) { + var strMap = new Map(); + for (var str of strs) { + var chars = [...str]; + chars.sort(); + var key = chars.join(""); + if (!strMap.has(key)) { + strMap.set(key, []); + } + strMap.get(key).push(str); + } + console.log(strMap); + var sArr = []; + for (let value of strMap.values()) { + console.log(value); + sArr.push(value); + } + console.log(sArr); + return sArr; + return [...strMap.values()]; +}; +console.log(groupAnagrams(arr)); + +/** + * @param {string[]} strs + * @return {string[][]} + */ + +var groupAnagrams = function(strs) { + var hashMap = new Map(); + for (var str of strs) { + var chars = [...str]; + chars.sort(); + var key = chars.join(""); + if (!hashMap.has(key)) { + hashMap.set(key, [str]); + } else { + hashMap.get(key).push(str); + } + } + console.log(hashMap); + var arr = []; + for (let value of hashMap.values()) { + // console.log(value); + arr.push(value); + } + console.log(arr); + return arr; +}; + +/** + * @param {string[]} strs + * @return {string[][]} + */ + +var groupAnagrams = function(strs) { + var hashMap = new Map(); + for (var str of strs) { + var key = [...str].sort().join(""); + if (hashMap.has(key)) { + hashMap.get(key).push(str); + } else { + hashMap.set(key, [str]); + } + } + console.log(hashMap); + return [...hashMap.values()]; +}; + +/** + +解法三 +算术基本定理,又称为正整数的唯一分解定理,即:每个大于1的自然数,要么本身就是质数,要么可以写为2个以上的质数的积,而且这些质因子按大小排列之后,写法仅有一种方式。 + +利用这个,我们把每个字符串都映射到一个正数上。 + +用一个数组存储质数 prime = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103}。 + +然后每个字符串的字符减去 ' a ' ,然后取到 prime 中对应的质数。把它们累乘。 + +例如 abc ,就对应 'a' - 'a', 'b' - 'a', 'c' - 'a',即 0, 1, 2,也就是对应素数 2 3 5,然后相乘 2 * 3 * 5 = 30,就把 "abc" 映射到了 30。 + + +作者:windliang +链接:https://leetcode-cn.com/problems/group-anagrams/solution/xiang-xi-tong-su-de-si-lu-fen-xi-duo-jie-fa-by--16/ + +*/ +/** +//26个字母的质数对应表 + int char_hash[26] = { + 2, 3, 5, 7, 11, + 13, 17, 19, 23, 29, + 31, 37, 41, 43, 47, + 53, 59, 61, 67, 71, + 73, 79, 83, 89, 97, + 101 + } ; + +作者:xu-zhou-geng +链接:https://leetcode-cn.com/problems/group-anagrams/solution/cpp-24mszhi-shu-de-miao-yong-1-by-xu-zhou-geng/ + + +*/ + +/** + * @param {string[]} strs + * @return {string[][]} + */ + +var groupAnagrams = function(strs) { + var hashMap = new Map(); + //每个字母对应一个质数 + var sprime = + "2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101"; + // 29, 31, 41, + + var prime = sprime.split(","); + + console.log("质数:", prime.length); + var A_ASCII = 97; + for (var str of strs) { + var hash = 1; + for (var i = 0; i < str.length; i++) { + // console.log("index:", str.charCodeAt(i) - A_ASCII); + hash *= prime[str.charCodeAt(i) - A_ASCII]; + } + console.log("hash:", hash); + + if (!hashMap.has(hash)) { + hashMap.set(hash, [str]); + } + hashMap.get(hash).push(str); + } + console.log(hashMap); + return [...hashMap.values()]; +}; +console.log(groupAnagrams(arr)); + +/** +解法四 +首先初始化 key = "0#0#0#0#0#",数字分别代表 abcde 出现的次数,# 用来分割。 + +这样的话,"abb" 就映射到了 "1#2#0#0#0"。 + +"cdc" 就映射到了 "0#0#2#1#0"。 + +"dcc" 就映射到了 "0#0#2#1#0"。 + +作者:windliang +链接:https://leetcode-cn.com/problems/group-anagrams/solution/xiang-xi-tong-su-de-si-lu-fen-xi-duo-jie-fa-by--16/ + + + */ + +/** + * @param {string[]} strs + * @return {string[][]} + */ + +var groupAnagrams = function(strs) { + var hashMap = new Map(); + var A_ASCII = 97; + var SIZE = 26; + for (let i = 0; i < strs.length; i++) { + var str = strs[i]; + var arr = new Array(SIZE).fill(0); //size:26 + for (var j = 0; j < str.length; j++) { + arr[str.charCodeAt(j) - A_ASCII]++; + } + //转成 0#2#2# 类似的形式 + var key = ""; + for (var j = 0; j < SIZE; j++) { + key += arr[j] + "#"; + } + console.log("------------------"); + console.log("arr:", arr); + console.log("key:", key); + + if (hashMap.has(key)) { + hashMap.get(key).push(str); + } else { + hashMap.set(key, [str]); + } + } + console.log("-------hashMap:-----------"); + console.log("hashMap:", hashMap); + + return [...hashMap.values()]; +}; diff --git a/Week_02/G20200343030005/Leetcode_242_001.js b/Week_02/G20200343030005/Leetcode_242_001.js new file mode 100644 index 00000000..fbc68065 --- /dev/null +++ b/Week_02/G20200343030005/Leetcode_242_001.js @@ -0,0 +1,173 @@ +/** +242. 有效的字母异位词 + +字符替换 +*/ +var isAnagram = function(s, t) { + if (s.length !== t.length) return false; + for (var char of t) { + if (s.includes(char)) { + s = s.replace(char, ""); + } + } + return !s; //s == "" +}; +/** +排序sort +*/ +var isAnagram = function(s, t) { + if (s.length !== t.length) return false; + + var arr1 = [...s]; + var arr2 = [...t]; + arr1.sort(); + arr2.sort(); + + return arr1.join("") == arr2.join(""); +}; + +/** +哈希表 统计的方法: + +算法: + + +为了检查 tt 是否是 ss 的重新排列,我们可以计算两个字符串中每个字母的出现次数并进行比较。因为 SS 和 TT 都只包含 A-ZA−Z 的字母,所以一个简单的 26 位计数器表就足够了。 +我们需要两个计数器数表进行比较吗?实际上不是,因为我们可以用一个计数器表计算 ss 字母的频率,用 tt 减少计数器表中的每个字母的计数器,然后检查计数器是否回到零。 + +作者:LeetCode +链接:https://leetcode-cn.com/problems/valid-anagram/solution/you-xiao-de-zi-mu-yi-wei-ci-by-leetcode/ + */ +var isAnagram = function(s, t) { + if (s.length !== t.length) return false; + var A_ASCII = "a".charCodeAt(); //97 + // var Z_ASCII = "z".charCodeAt(); + var arr = []; //size:26 + arr.length = 26; + arr.fill(0); + for (var i = 0; i < s.length; i++) { + // [ 3, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0 ] + arr[s.charCodeAt(i) - A_ASCII]++; + // [ -3, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, -1, -1, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0 ] + arr[t.charCodeAt(i) - A_ASCII]--; + } + console.log(arr); + for (var value of arr) { + if (value !== 0) return false; + } + return true; +}; + +var isAnagram = function(s, t) { + if (s.length !== t.length) return false; + var map = {}; + for (let i = 0; i < s.length; i++) { + map[s[i]] = (map[s[i]] || 0) + 1; + map[t[i]] = (map[t[i]] || 0) - 1; + } + console.log(map); + for (var key in map) { + if (map[key] !== 0) return false; + } + return true; +}; + +/** +错误题解: + +var isAnagram = function(s, t) { + if (s.length !== t.length) return false; + var n = 0; + for (var i = 0; i < s.length; i++) { + n += s.charCodeAt(i); + n -= t.charCodeAt(i); + } + return !n; +}; + +输入:"ac" "bb" +输出:true +预期:false + +*/ + +var isAnagram = function(s, t) { + if (s.length !== t.length) return false; + var A_ASCII = "a".charCodeAt(); //97 + // var Z_ASCII = "z".charCodeAt(); + var arr = []; //size:26 + arr.length = 26; + arr.fill(0); + for (var i = 0; i < s.length; i++) { + //[ 3, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0 ] + arr[s.charCodeAt(i) - A_ASCII]++; + } + for (var i = 0; i < t.length; i++) { + var index = t.charCodeAt(i) - A_ASCII; + if (--arr[index] < 0) { + return false; + } + } + return true; +}; + +var isAnagram = function(s, t) { + if (s.length !== t.length) return false; + var json = {}; + for (var i = 0; i < s.length; i++) { + var name = s[i]; + if (json[name]) { + json[name]++; + } else { + json[name] = 1; + } + } + for (var i = 0; i < t.length; i++) { + var name = t[i]; + if (!json[name]) return false; + if (--json[name] < 0) return false; + } + return true; +}; + +var isAnagram = function(s, t) { + if (s.length !== t.length) return false; + var map = {}; + for (var char of s) { + if (char in map) { + map[char]++; + } else { + map[char] = 1; + } + } + for (var char of t) { + if (char in map && map[char] > 0) { + map[char]--; + } else { + return false; + } + } + return true; +}; + +var isAnagram = function(s, t) { + if (s.length !== t.length) return false; + var map = new Map(); + for (var char of s) { + if (map.has(char)) { + var n = map.get(char); + map.set(char, ++n); + } else { + map.set(char, 1); + } + } + for (var char of t) { + if (map.has(char) && map.get(char) > 0) { + var n = map.get(char); + map.set(char, --n); + } else { + return false; + } + } + return true; +}; diff --git a/Week_02/G20200343030005/NOTE.md b/Week_02/G20200343030005/NOTE.md index 50de3041..df4fb23e 100644 --- a/Week_02/G20200343030005/NOTE.md +++ b/Week_02/G20200343030005/NOTE.md @@ -1 +1,7 @@ -学习笔记 \ No newline at end of file +学习笔记 + +本周学的 哈希集合还行,本来树和二叉树,遍历也还好, + +但是遇到习题就很蒙圈,好多都不会做,可能做一个知识点就要花费1整天的时间, + +难难难! diff --git a/Week_02/G20200343030007/Leetcode_007_144.java b/Week_02/G20200343030007/Leetcode_007_144.java new file mode 100644 index 00000000..52f19ef0 --- /dev/null +++ b/Week_02/G20200343030007/Leetcode_007_144.java @@ -0,0 +1,12 @@ +public List preorderTraversal(TreeNode root) { + List res = new ArrayList(); + preorder(root, res); + return res; +} + +private void preorder(TreeNode root, List res) { + if (root == null) return; + res.add(root.val); + preorder(root.left, res); + preorder(root.right, res); +} \ No newline at end of file diff --git a/Week_02/G20200343030007/Leetcode_007_242.js b/Week_02/G20200343030007/Leetcode_007_242.js new file mode 100644 index 00000000..dd64c87e --- /dev/null +++ b/Week_02/G20200343030007/Leetcode_007_242.js @@ -0,0 +1,40 @@ +/** + * @param {string} s + * @param {string} t + * @return {boolean} + * 1. 暴力法 + * + */ +var isAnagram = function(s, t) { + // 将字符串转为数组 + const sortedStr1 = Array.from(s); + const sortedStr2 = Array.from(t); + + // 将数组 sort + const a = sortedStr1.sort(); + const b = sortedStr2.sort(); + return a == b; +}; + +var isAnagram = function(s, t) { + return s.split('').sort().join('') === t.split('').sort().join(''); +}; + + +const s = 'anagram', t = 'nagaram'; +const result = isAnagram(s, t); +console.log(result); + + +/** + * 解题四件套 + * 1. 和面试官问清楚题目 + * 2. 想出所有的解法,找出复杂度最低的最优解 + * 3. 开始编写 + * 4. 写测试样例 + * + * + * 解法: + * 1. 暴力法,sort 后判断字符串是否相同 + * 2. hash,map 统计每个字母出现的频次 + */ \ No newline at end of file diff --git a/Week_02/G20200343030007/Leetcode_007_49.java b/Week_02/G20200343030007/Leetcode_007_49.java new file mode 100644 index 00000000..3250fc70 --- /dev/null +++ b/Week_02/G20200343030007/Leetcode_007_49.java @@ -0,0 +1,15 @@ + public List> groupAnagrams(String[] strings) { + if (strings.length == 0) return new ArrayList>(); + // key -> value, key: 排序后的字符串,value:当前字符串的所有可能组成的数组 + Map> ans = new HashMap>(); + for (String s : strings) { + char[] ca = s.toCharArray(); + Arrays.sort(ca); + String key = String.valueOf(ca); + if (!ans.containsKey(key)) ans.put(key, new ArrayList()); + ans.get(key).add(s); + } + + return new ArrayList>(ans.values()); + } + diff --git a/Week_02/G20200343030007/Leetcode_007_94.java b/Week_02/G20200343030007/Leetcode_007_94.java new file mode 100644 index 00000000..4cff2261 --- /dev/null +++ b/Week_02/G20200343030007/Leetcode_007_94.java @@ -0,0 +1,17 @@ +public List inorderTraversal(TreeNode root) { + List res = new ArrayList<>(); + inorder(root, res); + return res; + } + + public void inorder(TreeNode root, List res) { + if (root.val != null) { + if (root.left != null) { + inorder(root.left, res); + } + res.add(root.val); + if (root.right != null) { + inorder(root.right, res); + } + } + } diff --git a/Week_02/G20200343030009/LeetCode_144_009.js b/Week_02/G20200343030009/LeetCode_144_009.js new file mode 100644 index 00000000..319f6d54 --- /dev/null +++ b/Week_02/G20200343030009/LeetCode_144_009.js @@ -0,0 +1,58 @@ +/* + 给定一个二叉树,返回它的 前序 遍历。 +  示例: + 输入: [1,null,2,3] + 1 + \ + 2 + / + 3 + 输出: [1,2,3] + 进阶: 递归算法很简单,你可以通过迭代算法完成吗? +*/ +/** + * Definition for a binary tree node. + * function TreeNode(val) { + * this.val = val; + * this.left = this.right = null; + * } + */ +/** + * Definition for a binary tree node. + * function TreeNode(val) { + * this.val = val; + * this.left = this.right = null; + * } + */ +/** + * @param {TreeNode} root + * @return {number[]} + */ +var preorderTraversal = function(root) { + // 方法1:迭代法 + /* + 从根节点开始,每次迭代弹出当前栈顶元素,并将其孩子节点压入栈中,先压右孩子再压左孩子。 + 在这个算法中,输出到最终结果的顺序按照 Top->Bottom 和 Left->Right,符合前序遍历的顺序 + */ + let stack = [] + let output = [] + if (root === null) return output + // 推入根节点 + stack.push(root) + while (stack.length) { + // 弹出栈顶元素, 并推入output + let node = stack.pop() + output.push(node.val) + // 先考察弹出的元素是否有右节点,再考察是否有左节点,先推右节点后推左节点, + // 保证推入后,左节点在右节点上面,保证先弹出左节点,后弹出右节点--故为前序遍历 + if (node.right !== null) { + // 有右节点,推入 + stack.push(node.right) + } + if (node.left !== null) { + // 有左节点,推入 + stack.push(node.left) + } + } + return output +}; \ No newline at end of file diff --git a/Week_02/G20200343030009/LeetCode_49_009.js b/Week_02/G20200343030009/LeetCode_49_009.js new file mode 100644 index 00000000..0a1dfdec --- /dev/null +++ b/Week_02/G20200343030009/LeetCode_49_009.js @@ -0,0 +1,42 @@ +/** + * 给定一个字符串数组,将字母异位词组合在一起。字母异位词指字母相同,但排列不同的字符串。 + 示例: + 输入: ["eat", "tea", "tan", "ate", "nat", "bat"], + 输出: + [ + ["ate","eat","tea"], + ["nat","tan"], + ["bat"] + ] + 说明: + 所有输入均为小写字母。 + 不考虑答案输出的顺序。 + */ + /** + * @param {string[]} strs + * @return {string[][]} + */ +var groupAnagrams = function(strs) { + // 方法1: 排序数组分类 -- 以排序后的字符串为key,数据项对应的key相同时,存入该key对于的list值里 + // 遍历字符串数组,将每个字符串转为list并按照字符顺序排序,再转回为字符串, + // 此时的字符串作为key存入哈希表中,当前key不存在,则先初始化当前key对应的值为空list + if (!strs || !strs.length) return [] + let res = [] + let map = new Map() + for (let i = 0; i < strs.length; i++) { + let arr = strs[i].split('') + arr.sort() + let strKey = arr.join('') // 目的即是得到该str做key,存哈希表 + if (!map.has(strKey)) map.set(strKey, []) // 当前key不存在,先初始化对应的值为空list + map.get(strKey).push(strs[i]) + // if (!map.has(strKey)){ + // map.set(strKey, [strs[i]]) + // } else { + // map.get(strKey).push(strs[i]) + // } + } + map.forEach((value, key) => { + res.push(value) + }) + return res +}; \ No newline at end of file diff --git a/Week_02/G20200343030015/LeetCode_105_015.java b/Week_02/G20200343030015/LeetCode_105_015.java new file mode 100644 index 00000000..cd4b1194 --- /dev/null +++ b/Week_02/G20200343030015/LeetCode_105_015.java @@ -0,0 +1,69 @@ +package G20200343030015.week_02; + +import java.util.HashMap; +import java.util.Map; + +/** + * 105. 从前序与中序遍历序列构造二叉树 + * 根据一棵树的前序遍历与中序遍历构造二叉树。 + *

+ * 注意: + * 你可以假设树中没有重复的元素。 + *

+ * 例如,给出 + *

+ * 前序遍历 preorder = [3,9,20,15,7] + * 中序遍历 inorder = [9,3,15,20,7] + * 返回如下的二叉树: + *

+ * 3 + * / \ + * 9 20 + * / \ + * 15 7 + *

+ * 来源:力扣(LeetCode) + * 链接:https://leetcode-cn.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal + * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + * Created by majiancheng on 2020/2/23. + */ +public class LeetCode_105_015 { + + int preIndex = 0; + + int[] preorder; + + int[] inorder; + + Map inOrderMap = new HashMap(); + + public TreeNode helper(int leftIdx, int rightIdx) { + if (leftIdx == rightIdx) { + return null; + } + + //处理当前节点逻辑 + int rootVal = preorder[preIndex]; + TreeNode rootNode = new TreeNode(rootVal); + preIndex++; + + int inIndex = inOrderMap.get(rootVal); + rootNode.left = helper(leftIdx, inIndex); + rootNode.right = helper(inIndex + 1, rightIdx); + + return rootNode; + } + + //先根据前序遍历数组 找到根节点,然后切割中序数组,依次迭代计算 + public TreeNode buildTree(int[] preorder, int[] inorder) { + this.preorder = preorder; + this.inorder = inorder; + + for (int i = 0; i < inorder.length; i++) { + inOrderMap.put(inorder[i], i); + } + + return helper(0, preorder.length); + } + +} diff --git a/Week_02/G20200343030015/LeetCode_144_015.java b/Week_02/G20200343030015/LeetCode_144_015.java new file mode 100644 index 00000000..e75991b0 --- /dev/null +++ b/Week_02/G20200343030015/LeetCode_144_015.java @@ -0,0 +1,45 @@ +package G20200343030015.week_02; + +import java.util.LinkedList; +import java.util.List; +import java.util.Stack; + +/** + * 144. 二叉树的前序遍历 + * 给定一个二叉树,返回它的 前序 遍历。 + *

+ *  示例: + *

+ * 输入: [1,null,2,3] + * 1 + * \ + * 2 + * / + * 3 + *

+ * 输出: [1,2,3] + * 进阶: 递归算法很简单,你可以通过迭代算法完成吗? + *

+ * 来源:力扣(LeetCode) + * 链接:https://leetcode-cn.com/problems/binary-tree-preorder-traversal + * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + * Created by majiancheng on 2020/2/23. + */ +public class LeetCode_144_015 { + + public List preorderTraversal(TreeNode root) { + List nodeVals = new LinkedList(); + Stack nodes = new Stack(); + while (nodes.size() > 0 || root != null) { + if (root != null) { + nodeVals.add(root.val); + nodes.push(root); + root = root.left; + } else { + root = nodes.pop().right; + } + + } + return nodeVals; + } +} diff --git a/Week_02/G20200343030015/LeetCode_236_015.java b/Week_02/G20200343030015/LeetCode_236_015.java new file mode 100644 index 00000000..bd601a3e --- /dev/null +++ b/Week_02/G20200343030015/LeetCode_236_015.java @@ -0,0 +1,42 @@ +package G20200343030015.week_02; + +/** + * 236. 二叉树的最近公共祖先 + * 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。 + *

+ * 百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。” + *

+ * 例如,给定如下二叉树:  root = [3,5,1,6,2,0,8,null,null,7,4] + *

+ * Created by majiancheng on 2020/2/23. + */ +public class LeetCode_236_015 { + + private TreeNode ans; + + public boolean doSearch(TreeNode root, TreeNode p, TreeNode q) { + //处理边界值 + if (root == null) { + return false; + } + //处理本次循环数据 + int currStatus = (root.val == p.val || root.val == q.val) ? 1 : 0; + + //进入下一次迭代 + int leftStatus = doSearch(root.left, p, q) ? 1 : 0; + int rightStatus = doSearch(root.right, p, q) ? 1 : 0; + if ((currStatus + leftStatus + rightStatus) == 2) { + this.ans = root; + return true; + } + + return (currStatus + leftStatus + rightStatus) > 0; + } + + //暴力破解,判断左子树和右子树是否有包含p或q,假如在一个根节点处 左子树+右子树 == 2 就表示找到该节点 + public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { + doSearch(root, p, q); + + return this.ans; + } +} diff --git a/Week_02/G20200343030015/LeetCode_429_015.java b/Week_02/G20200343030015/LeetCode_429_015.java new file mode 100644 index 00000000..9beb7fdf --- /dev/null +++ b/Week_02/G20200343030015/LeetCode_429_015.java @@ -0,0 +1,43 @@ +package G20200343030015.week_02; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; + +/** + * 429. N叉树的层序遍历 + * 给定一个 N 叉树,返回其节点值的层序遍历。 (即从左到右,逐层遍历)。 + *

+ * 例如,给定一个 3叉树 : + * 返回其层序遍历: + *

+ * [ + * [1], + * [3,2,4], + * [5,6] + * ] + *

+ * Created by majiancheng on 2020/2/23. + */ +public class LeetCode_429_015 { + + //通过循环模拟递归的方式解决 + public List> levelOrder(Node root) { + if (root == null) return new ArrayList<>(); + List> datas = new ArrayList>(); + LinkedList list = new LinkedList(); + list.add(root); + while (!list.isEmpty()) { + List level = new ArrayList(); + int size = list.size(); + for (int i = 0; i < size; i++) { + Node node = list.poll(); + level.add(node.val); + list.addAll(node.children); + } + + datas.add(level); + } + return datas; + } +} diff --git a/Week_02/G20200343030015/LeetCode_46_015.java b/Week_02/G20200343030015/LeetCode_46_015.java new file mode 100644 index 00000000..fe77b46e --- /dev/null +++ b/Week_02/G20200343030015/LeetCode_46_015.java @@ -0,0 +1,57 @@ +package G20200343030015.week_02; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; + +/** + * 46. 全排列 + * 给定一个没有重复数字的序列,返回其所有可能的全排列。 + *

+ * 示例: + *

+ * 输入: [1,2,3] + * 输出: + * [ + * [1,2,3], + * [1,3,2], + * [2,1,3], + * [2,3,1], + * [3,1,2], + * [3,2,1] + * ] + *

+ * 来源:力扣(LeetCode) + * 链接:https://leetcode-cn.com/problems/permutations + * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + * Created by majiancheng on 2020/2/23. + */ +public class LeetCode_46_015 { + + List> result = new ArrayList>(); + + public List> permute(int[] nums) { + LinkedList arr = new LinkedList(); + helper(nums, arr); + + return result; + } + + public void helper(int[] nums, LinkedList arr) { + if (nums.length == arr.size()) { + result.add(new ArrayList<>(arr)); + return; + } + + for (int i = 0; i < nums.length; i++) { + if (arr.contains(nums[i])) { + continue; + } + + arr.add(nums[i]); + helper(nums, arr); + arr.removeLast(); + } + } + +} diff --git a/Week_02/G20200343030015/LeetCode_47_015.java b/Week_02/G20200343030015/LeetCode_47_015.java new file mode 100644 index 00000000..90ca4acc --- /dev/null +++ b/Week_02/G20200343030015/LeetCode_47_015.java @@ -0,0 +1,75 @@ +package G20200343030015.week_02; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Stack; + +/** + * 47. 全排列 II + * 给定一个可包含重复数字的序列,返回所有不重复的全排列。 + *

+ * 示例: + *

+ * 输入: [1,1,2] + * 输出: + * [ + * [1,1,2], + * [1,2,1], + * [2,1,1] + * ] + *

+ * 来源:力扣(LeetCode) + * 链接:https://leetcode-cn.com/problems/permutations-ii + * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + * Created by majiancheng on 2020/2/23. + */ +public class LeetCode_47_015 { + + List> result = new ArrayList>(); + + public List> permuteUnique(int[] nums) { + Arrays.sort(nums); + dfs(nums, new boolean[nums.length], new Stack()); + + return result; + } + + /** + * 套用回溯模板 + * result = [] + * def backtrack(路径, 选择列表): + * if 满足结束条件: + * result.add(路径) + * return + *

+ * for 选择 in 选择列表: + * 做选择 + * backtrack(路径, 选择列表) + * 撤销选择 + */ + public void dfs(int[] nums, boolean[] used, Stack stack) { + if (stack.size() == nums.length) { + this.result.add(new ArrayList<>(stack)); + return; + } + + for (int i = 0; i < nums.length; i++) { + //已使用当前元素需要过滤 + if (used[i] == true) continue; + //判断是否需要剪枝 + //如果当前元素等于上一个元素 并且还未被使用则剪枝 + //讲解视频 + if (i > 0 && nums[i] == nums[i - 1] && used[i - 1] == false) continue; + stack.push(nums[i]); + used[i] = true; + + dfs(nums, used, stack); + + used[i] = false; + stack.pop(); + } + + } + +} diff --git a/Week_02/G20200343030015/LeetCode_49_015.java b/Week_02/G20200343030015/LeetCode_49_015.java new file mode 100644 index 00000000..f163a0ce --- /dev/null +++ b/Week_02/G20200343030015/LeetCode_49_015.java @@ -0,0 +1,44 @@ +package G20200343030015.week_02; + +import java.util.*; + +/** + * 49. 字母异位词分组 + * 给定一个字符串数组,将字母异位词组合在一起。字母异位词指字母相同,但排列不同的字符串。 + *

+ * 示例: + * 输入: ["eat", "tea", "tan", "ate", "nat", "bat"], + * 输出: + * [ + * ["ate","eat","tea"], + * ["nat","tan"], + * ["bat"] + * ] + * 说明: + * 所有输入均为小写字母。 + * 不考虑答案输出的顺序。 + * Created by majiancheng on 2020/2/23. + */ +public class LeetCode_49_015 { + + //1.暴力破解,求出每个元素的唯一key,然后通过map操作 + //2.通过sort字符串数据,生成字符串key信息 + public List> groupAnagrams(String[] strs) { + if (strs == null || strs.length == 0) { + return new ArrayList>(); + } + + Map> result = new HashMap>(); + for (int i = 0; i < strs.length; i++) { + char[] chars = strs[i].toCharArray(); + Arrays.sort(chars); + String key = Arrays.toString(chars); + if (result.get(key) == null) { + result.put(key, new ArrayList()); + } + result.get(key).add(strs[i]); + } + + return new ArrayList>(result.values()); + } +} diff --git a/Week_02/G20200343030015/LeetCode_589_015.java b/Week_02/G20200343030015/LeetCode_589_015.java new file mode 100644 index 00000000..b88dc6c1 --- /dev/null +++ b/Week_02/G20200343030015/LeetCode_589_015.java @@ -0,0 +1,41 @@ +package G20200343030015.week_02; + +import java.util.LinkedList; +import java.util.List; +import java.util.Stack; + +/** + * 589. N叉树的前序遍历 + * 给定一个 N 叉树,返回其节点值的前序遍历。 + *

+ * 例如,给定一个 3叉树 : + *

+ * 返回其前序遍历: [1,3,5,6,2,4]。 + *

+ * Created by majiancheng on 2020/2/23. + */ +public class LeetCode_589_015 { + + /** + * 先向栈中添加元素,然后逆序添加元素信息 + */ + public List preorder(Node root) { + if (root == null) return new LinkedList(); + List output = new LinkedList(); + Stack stack = new Stack(); + + stack.push(root); + while (!stack.isEmpty()) { + Node tmpNode = stack.pop(); + output.add(tmpNode.val); + + for (int i = tmpNode.children.size() - 1; i >= 0; i--) { + if (tmpNode.children.get(i) != null) { + stack.push(tmpNode.children.get(i)); + } + } + } + + return output; + } +} diff --git a/Week_02/G20200343030015/LeetCode_590_015.java b/Week_02/G20200343030015/LeetCode_590_015.java new file mode 100644 index 00000000..9fde901d --- /dev/null +++ b/Week_02/G20200343030015/LeetCode_590_015.java @@ -0,0 +1,30 @@ +package G20200343030015.week_02; + +import java.util.LinkedList; +import java.util.List; + +/** + * Created by majiancheng on 2020/2/23. + */ +public class LeetCode_590_015 { + + public List postorder(Node root) { + LinkedList stack = new LinkedList(); + LinkedList output = new LinkedList(); + if (root == null) { + return output; + } + stack.add(root); + while (!stack.isEmpty()) { + Node tmp = stack.pollLast(); + output.addFirst(tmp.val); + for (Node child : tmp.children) { + if (child != null) { + stack.add(child); + } + } + } + + return output; + } +} diff --git a/Week_02/G20200343030015/LeetCode_77_015.java b/Week_02/G20200343030015/LeetCode_77_015.java new file mode 100644 index 00000000..3aeb4168 --- /dev/null +++ b/Week_02/G20200343030015/LeetCode_77_015.java @@ -0,0 +1,55 @@ +package G20200343030015.week_02; + +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; + +/** + * 77. 组合 + * 给定两个整数 n 和 k,返回 1 ... n 中所有可能的 k 个数的组合。 + *

+ * 示例: + *

+ * 输入: n = 4, k = 2 + * 输出: + * [ + * [2,4], + * [3,4], + * [2,3], + * [1,2], + * [1,3], + * [1,4], + * ] + *

+ * 来源:力扣(LeetCode) + * 链接:https://leetcode-cn.com/problems/combinations + * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + * Created by majiancheng on 2020/2/23. + */ +public class LeetCode_77_015 { + + List> result = new ArrayList<>(); + + //循环遍历+迭代遍历,判断 + public List> combine(int n, int k) { + helper(n, k, 1, new Stack()); + + return result; + } + + public void helper(int n, int k, int begin, Stack val) { + if (val.size() == k) { + result.add(new ArrayList<>(val)); + return; + } + + //每次进入下一个循环 i+1 + for (int i = begin; i <= n - (k - val.size()) + 1; i++) { + val.push(i); + //迭代添加之后的元素 + helper(n, k, i + 1, val); + val.pop(); + } + } + +} diff --git a/Week_02/G20200343030015/NOTE.md b/Week_02/G20200343030015/NOTE.md index 50de3041..29c5a710 100644 --- a/Week_02/G20200343030015/NOTE.md +++ b/Week_02/G20200343030015/NOTE.md @@ -1 +1,56 @@ -学习笔记 \ No newline at end of file +学习笔记 + +树的遍历定义 + 前序遍历:根结点 —> 左子树 —> 右子树 + 中序遍历:左子树—> 根结点 —> 右子树 + 后序遍历:左子树 —> 右子树 —> 根结点 + 层次遍历:按层次遍历 + +前序 OR 中序 OR 后序 判断标准:根节点在 前中后的哪个位置 + +递归注意点 + 1、不要人肉递归 + 2、找到最近最简方法,将其拆解成可重复解决的问题(重复子问题) + 3、数学归纳法思维 (1、2都成立的时候 能证明n和n-1都成立) + + +递归代码模板 + public void recur(int level, int param) { + //terminator + if(level > MAX_LEVEL) { + //process result + return ; + } + + //处理当前逻辑 + process(level, param); + + //进入下一个递归 + recur(level:level + 1, newParam); + //restore current status + } + +回溯算法模板 +result = [] +def backtrack(路径, 选择列表): + if 满足结束条件: + result.add(路径) + return + + for 选择 in 选择列表: + 做选择 + backtrack(路径, 选择列表) + 撤销选择 + +多叉树遍历模板 +void traverse(TreeNode root) { + for (TreeNode child : root.childern) + // 前序遍历需要的操作 + traverse(child); + // 后序遍历需要的操作 +} + +广度优先搜索 + 使用队列 +深度优先搜索 + 使用栈 diff --git a/Week_02/G20200343030015/Node.java b/Week_02/G20200343030015/Node.java new file mode 100644 index 00000000..a1f7a20e --- /dev/null +++ b/Week_02/G20200343030015/Node.java @@ -0,0 +1,25 @@ +package G20200343030015.week_02; + +import java.util.List; + +/** + * Created by majiancheng on 2020/2/23. + */ +public class Node { + + public int val; + + public List children; + + public Node() { + } + + public Node(int _val) { + val = _val; + } + + public Node(int _val, List _children) { + val = _val; + children = _children; + } +} diff --git a/Week_02/G20200343030015/TreeNode.java b/Week_02/G20200343030015/TreeNode.java new file mode 100644 index 00000000..7171d47f --- /dev/null +++ b/Week_02/G20200343030015/TreeNode.java @@ -0,0 +1,17 @@ +package G20200343030015.week_02; + +/** + * Created by majiancheng on 2020/2/23. + */ +public class TreeNode { + + int val; + + TreeNode left; + + TreeNode right; + + TreeNode(int x) { + val = x; + } +} diff --git a/Week_02/G20200343030017/binary_tree_preorder_traversal/Solution.java b/Week_02/G20200343030017/binary_tree_preorder_traversal/Solution.java new file mode 100644 index 00000000..3146a98e --- /dev/null +++ b/Week_02/G20200343030017/binary_tree_preorder_traversal/Solution.java @@ -0,0 +1,24 @@ +package week2.binary_tree_preorder_traversal; + +import java.util.ArrayList; +import java.util.List; + +public class Solution { + public List preorderTraversal(TreeNode root) { + List list = new ArrayList<>(); + recursion(root,list); + return list; + } + public void recursion(TreeNode root, List list){ + if (root==null){ + return; + } + list.add(root.val); + if (root.left!=null){ + recursion(root.left,list); + } + if (root.right!=null){ + recursion(root.right,list); + } + } +} diff --git a/Week_02/G20200343030017/binary_tree_preorder_traversal/TreeNode.java b/Week_02/G20200343030017/binary_tree_preorder_traversal/TreeNode.java new file mode 100644 index 00000000..d69eba0e --- /dev/null +++ b/Week_02/G20200343030017/binary_tree_preorder_traversal/TreeNode.java @@ -0,0 +1,8 @@ +package week2.binary_tree_preorder_traversal; + +public class TreeNode { + int val; + TreeNode left; + TreeNode right; + TreeNode(int x) { val = x; } +} diff --git a/Week_02/G20200343030017/combinations/Solution.java b/Week_02/G20200343030017/combinations/Solution.java new file mode 100644 index 00000000..96dbca91 --- /dev/null +++ b/Week_02/G20200343030017/combinations/Solution.java @@ -0,0 +1,31 @@ +package week2.combinations; + +import java.util.ArrayList; +import java.util.List; + +public class Solution { + public List> combine(int n, int k) { + List> list =new ArrayList<>(); + List temp = new ArrayList<>(); + recursion(list,temp,n,k,1); + return list; + } + + public void recursion(List> list,List temp,int n, int k,int begin){ + if (temp.size()==k){ + list.add(new ArrayList<>(temp)); + return; + } + for (int a=begin;a<=n;a++){ + temp.add(a); + recursion(list,temp,n,k,a+1); + temp.remove(temp.size()-1); + } + } + + public static void main(String[] args) { + Solution s = new Solution(); + List> list = s.combine(4,2); + System.out.println(list.toString()); + } +} diff --git a/Week_02/G20200343030017/construct_binary_tree_from_preorder_and_inorder_traversal/Solution.java b/Week_02/G20200343030017/construct_binary_tree_from_preorder_and_inorder_traversal/Solution.java new file mode 100644 index 00000000..e2dda4d4 --- /dev/null +++ b/Week_02/G20200343030017/construct_binary_tree_from_preorder_and_inorder_traversal/Solution.java @@ -0,0 +1,24 @@ +package week2.construct_binary_tree_from_preorder_and_inorder_traversal; + +public class Solution { + public TreeNode buildTree(int[] preorder, int[] inorder) { + return recursion(preorder,inorder,0,preorder.length,0,inorder.length); + } + public TreeNode recursion(int[] p,int[] i,int pb,int pe,int ib,int ie){ + if (pb==pe||ib==ie){ + return null; + } + TreeNode treeNode = new TreeNode(p[pb]); + int temp = 0; + for(int a=0;a> groupAnagrams(String[] strs) { + List> groupAnagrams = new ArrayList<>(); + HashMap> map = new HashMap<>(); + for (String temp:strs){ + Integer aaa = countWord(temp); + if (map.isEmpty()||!map.containsKey(aaa)){ + List list = new ArrayList<>(); + list.add(temp); + map.put(aaa,list); + }else{ + List list = map.get(aaa); + list.add(temp); + map.put(aaa,list); + } + } + System.out.println(map); + for (int key:map.keySet()){ + groupAnagrams.add(map.get(key)); + } + return groupAnagrams; + } + + public Integer countWord(String word){ + char[] str = word.toCharArray(); + Arrays.sort(str); + return String.valueOf(str).hashCode(); + } + + public static void main(String[] args) { + String[] strs = new String[]{ + "eat","tea","tan","ate","nat","bat"}; + Solution s = new Solution(); + System.out.println(s.groupAnagrams(strs).toString()); + } +} diff --git a/Week_02/G20200343030017/lowest_common_ancestor_of_a_binary_tree/Solution.java b/Week_02/G20200343030017/lowest_common_ancestor_of_a_binary_tree/Solution.java new file mode 100644 index 00000000..e1846303 --- /dev/null +++ b/Week_02/G20200343030017/lowest_common_ancestor_of_a_binary_tree/Solution.java @@ -0,0 +1,24 @@ +package week2.lowest_common_ancestor_of_a_binary_tree; + +public class Solution { + public TreeNode answer = null; + public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { + recursion(root,p,q); + return this.answer; + } + public boolean recursion(TreeNode node, TreeNode p, TreeNode q){ + if (node == null){ + return false; + } + int left = this.recursion(node.left,p,q)?1:0; + int right = this.recursion(node.right,p,q)?1:0; + int root = (node==p||node==q)?1:0; + + if (left+right+root == 2){ + this.answer = node; + } + return (left+right+root>0); + } + + +} diff --git a/Week_02/G20200343030017/lowest_common_ancestor_of_a_binary_tree/TreeNode.java b/Week_02/G20200343030017/lowest_common_ancestor_of_a_binary_tree/TreeNode.java new file mode 100644 index 00000000..37d3b72f --- /dev/null +++ b/Week_02/G20200343030017/lowest_common_ancestor_of_a_binary_tree/TreeNode.java @@ -0,0 +1,8 @@ +package week2.lowest_common_ancestor_of_a_binary_tree; + +public class TreeNode { + int val; + TreeNode left; + TreeNode right; + TreeNode(int x) { val = x; } +} diff --git a/Week_02/G20200343030017/n_ary_tree_level_order_traversal/Node.java b/Week_02/G20200343030017/n_ary_tree_level_order_traversal/Node.java new file mode 100644 index 00000000..daab1afb --- /dev/null +++ b/Week_02/G20200343030017/n_ary_tree_level_order_traversal/Node.java @@ -0,0 +1,19 @@ +package week2.n_ary_tree_level_order_traversal; + +import java.util.List; + +public class Node { + public int val; + public List children; + + public Node() {} + + public Node(int _val) { + val = _val; + } + + public Node(int _val, List _children) { + val = _val; + children = _children; + } +} diff --git a/Week_02/G20200343030017/n_ary_tree_level_order_traversal/Solution.java b/Week_02/G20200343030017/n_ary_tree_level_order_traversal/Solution.java new file mode 100644 index 00000000..d752c230 --- /dev/null +++ b/Week_02/G20200343030017/n_ary_tree_level_order_traversal/Solution.java @@ -0,0 +1,46 @@ +package week2.n_ary_tree_level_order_traversal; + +import java.util.ArrayList; +import java.util.List; + +public class Solution { + public List> levelOrder(Node root) { + List> list = new ArrayList<>(); + if (root == null){ + return list; + } + recursion(root,list,0); + return list; + } + public void recursion(Node root, List> list,int level){ + List temp; + if (level+1>list.size()){ + temp=new ArrayList<>(); + list.add(temp); + } + list.get(level).add(root.val); + for (int n=0;n list1 = new ArrayList<>(); + List list3 = new ArrayList<>(); + Node node1 = new Node(1,list1); + Node node2 = new Node(2); + Node node3 = new Node(3,list3); + Node node4 = new Node(4); + Node node5 = new Node(5); + Node node6 = new Node(6); + + node3.children.add(node5); + node3.children.add(node6); + node1.children.add(node3); + node1.children.add(node2); + node1.children.add(node4); + Solution s = new Solution(); + System.out.println(s.levelOrder(node1)); + } +} diff --git a/Week_02/G20200343030017/n_ary_tree_postorder_traversal/Node.java b/Week_02/G20200343030017/n_ary_tree_postorder_traversal/Node.java new file mode 100644 index 00000000..06987b80 --- /dev/null +++ b/Week_02/G20200343030017/n_ary_tree_postorder_traversal/Node.java @@ -0,0 +1,19 @@ +package week2.n_ary_tree_postorder_traversal; + +import java.util.List; + +public class Node { + public int val; + public List children; + + public Node() {} + + public Node(int _val) { + val = _val; + } + + public Node(int _val, List _children) { + val = _val; + children = _children; + } +} diff --git a/Week_02/G20200343030017/n_ary_tree_postorder_traversal/Solution.java b/Week_02/G20200343030017/n_ary_tree_postorder_traversal/Solution.java new file mode 100644 index 00000000..d41b355d --- /dev/null +++ b/Week_02/G20200343030017/n_ary_tree_postorder_traversal/Solution.java @@ -0,0 +1,43 @@ +package week2.n_ary_tree_postorder_traversal; + +import java.util.ArrayList; +import java.util.List; + +public class Solution { + public List postorder(Node root) { + List list = new ArrayList<>(); + if (root == null){ + return list; + } + recursion(root,list); + return list; + } + public void recursion(Node root,List list){ + if (root.children == null || root.children.isEmpty()){ + list.add(root.val); + }else{ + for (int n=0;n list1 = new ArrayList<>(); + List list3 = new ArrayList<>(); + Node node1 = new Node(1,list1); + Node node2 = new Node(2); + Node node3 = new Node(3,list3); + Node node4 = new Node(4); + Node node5 = new Node(5); + Node node6 = new Node(6); + + node3.children.add(node5); + node3.children.add(node6); + node1.children.add(node3); + node1.children.add(node2); + node1.children.add(node4); + Solution s = new Solution(); + System.out.println(s.postorder(node1)); + } +} diff --git a/Week_02/G20200343030017/n_ary_tree_preorder_traversal/Node.java b/Week_02/G20200343030017/n_ary_tree_preorder_traversal/Node.java new file mode 100644 index 00000000..583c0aad --- /dev/null +++ b/Week_02/G20200343030017/n_ary_tree_preorder_traversal/Node.java @@ -0,0 +1,19 @@ +package week2.n_ary_tree_preorder_traversal; + +import java.util.List; + +public class Node { + public int val; + public List children; + + public Node() {} + + public Node(int _val) { + val = _val; + } + + public Node(int _val, List _children) { + val = _val; + children = _children; + } +} diff --git a/Week_02/G20200343030017/n_ary_tree_preorder_traversal/Solution.java b/Week_02/G20200343030017/n_ary_tree_preorder_traversal/Solution.java new file mode 100644 index 00000000..7922da22 --- /dev/null +++ b/Week_02/G20200343030017/n_ary_tree_preorder_traversal/Solution.java @@ -0,0 +1,43 @@ +package week2.n_ary_tree_preorder_traversal; + +import java.util.ArrayList; +import java.util.List; + +public class Solution { + public List preorder(Node root) { + List list = new ArrayList<>(); + if (root == null){ + return list; + } + recursion(root,list); + return list; + } + public void recursion(Node root, List list){ + list.add(root.val); + if (root.children == null || root.children.isEmpty()){ + //list.add(root.val); + }else{ + for (int n=0;n list1 = new ArrayList<>(); + List list3 = new ArrayList<>(); + Node node1 = new Node(1,list1); + Node node2 = new Node(2); + Node node3 = new Node(3,list3); + Node node4 = new Node(4); + Node node5 = new Node(5); + Node node6 = new Node(6); + + node3.children.add(node5); + node3.children.add(node6); + node1.children.add(node3); + node1.children.add(node2); + node1.children.add(node4); + Solution s = new Solution(); + System.out.println(s.preorder(node1)); + } +} diff --git a/Week_02/G20200343030017/permutations/Solution.java b/Week_02/G20200343030017/permutations/Solution.java new file mode 100644 index 00000000..0281698e --- /dev/null +++ b/Week_02/G20200343030017/permutations/Solution.java @@ -0,0 +1,34 @@ +package week2.permutations; + +import java.util.ArrayList; +import java.util.List; + +public class Solution { + public List> permute(int[] nums) { + List> list =new ArrayList<>(); + List temp = new ArrayList<>(); + recursion(list,temp,nums); + return list; + } + public void recursion(List> list,List temp,int[] nums){ + if (temp.size()==nums.length){ + list.add(new ArrayList<>(temp)); + return; + } + for (int a=0;a> list = s.permute(nums); + System.out.println(list.toString()); + } +} diff --git a/Week_02/G20200343030017/permutations_ii/Solution.java b/Week_02/G20200343030017/permutations_ii/Solution.java new file mode 100644 index 00000000..4f755694 --- /dev/null +++ b/Week_02/G20200343030017/permutations_ii/Solution.java @@ -0,0 +1,43 @@ +package week2.permutations_ii; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +public class Solution { + public List> permuteUnique(int[] nums) { + List> list =new ArrayList<>(); + List temp = new ArrayList<>(); + HashMap map = new HashMap<>(); + for (int n=0;n> list,List temp,int[] nums,HashMap map,HashMap tempmap){ + if (temp.size()==nums.length){ + list.add(new ArrayList<>(temp)); + return; + } + for (int a=0;a> list = s.permuteUnique(nums); + System.out.println(list.toString()); + } +} diff --git "a/Week_02/G20200343030017/\346\257\217\345\221\250\346\200\273\347\273\223.txt" "b/Week_02/G20200343030017/\346\257\217\345\221\250\346\200\273\347\273\223.txt" new file mode 100644 index 00000000..9e10f7d0 --- /dev/null +++ "b/Week_02/G20200343030017/\346\257\217\345\221\250\346\200\273\347\273\223.txt" @@ -0,0 +1,4 @@ +这周的主要学习内容是哈希表,树,还有递归 +哈希表在平时的工作中使用比较多,数据查找几乎是最快的(O(1)),不过hashcode会重复,从而发生数据碰撞,又JAVA源码得知,如果碰撞发生大于8时候,碰撞的数据以红黑树的形式存放。平时运用中,主要是需要频繁查询的列表,可以使用哈希表这种数据结构。 +由于是非科班的,树结构在之前几乎没多接触过(mysql的B+树),在数据量很大的情况下,O(n)都是很大的量,而平衡树的查询只需要O(logn),类似于二分查找法的拓展,之后接触了前序,中序,后序的遍历,这个老师讲的很好,之前做开学考试时候有百度过,讲得比较晦涩,老师讲的比较易懂,某些课后习题很简单就搞定了。树结构适合上下层节点有关联的数据,比如数据库索引,通过索引,一层一层,可以在叶子节点获取数据。老师如果可以讲一下平衡树的生成会更好,比如翻转什么的。 +从树的遍历中,我们引申到了递归,递归真的是我最怕的题目,感觉代码要各种人肉遍历,十分麻烦,通过习题,基本上能很好使用递归了,最后几道题还学会了回溯法,用来解排列组合问题比较不错。 \ No newline at end of file diff --git a/Week_02/G20200343030019/LeetCode_105_019.java b/Week_02/G20200343030019/LeetCode_105_019.java new file mode 100644 index 00000000..ab947079 --- /dev/null +++ b/Week_02/G20200343030019/LeetCode_105_019.java @@ -0,0 +1,21 @@ +class Solution { + public TreeNode buildTree(int[] preorder, int[] inorder) { + return build(preorder, inorder, new int[]{0}, new int[]{0}, Integer.MAX_VALUE); + } + + private TreeNode build(int[] preorder, int[] inorder, int[] pre, int[] index, int max) { + if (index[0] == inorder.length || inorder[index[0]] == max) { + return null; + } + + TreeNode node = new TreeNode(preorder[pre[0]]); + pre[0] ++; + TreeNode left = build(preorder, inorder, pre, index, node.val); + + index[0] ++; + TreeNode right = build(preorder, inorder, pre, index, max); + node.left = left; + node.right = right; + return node; + } +} \ No newline at end of file diff --git a/Week_02/G20200343030019/LeetCode_144_019.java b/Week_02/G20200343030019/LeetCode_144_019.java new file mode 100644 index 00000000..1036c970 --- /dev/null +++ b/Week_02/G20200343030019/LeetCode_144_019.java @@ -0,0 +1,17 @@ +class Solution { + public List preorderTraversal(TreeNode root) { + if (root == null) return new LinkedList(); + LinkedList stack = new LinkedList(); + LinkedList result = new LinkedList(); + + stack.add(root); + TreeNode node = null; + while (!stack.isEmpty()) { + node = stack.poll(); + result.add(node.val); + if (node.right != null) stack.addFirst(node.right); + if (node.left != null) stack.addFirst(node.left); + } + return result; + } +} \ No newline at end of file diff --git a/Week_02/G20200343030019/LeetCode_236_019.java b/Week_02/G20200343030019/LeetCode_236_019.java new file mode 100644 index 00000000..c290b725 --- /dev/null +++ b/Week_02/G20200343030019/LeetCode_236_019.java @@ -0,0 +1,34 @@ +class Solution { + public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { + TreeNode result = new TreeNode(0); + findNodeRoad(root, p, q, result); + return result.left; + } + + private boolean findNodeRoad(TreeNode node, TreeNode p, TreeNode q, TreeNode result) { + boolean self = false, left = false, right = false; + if (node.val == p.val || node.val == q.val) { + self = true; + } + if (node.left != null) { + if (findNodeRoad(node.left, p, q, result)) { + left = true; + } + } + + if (node.right != null) { + if (findNodeRoad(node.right, p, q, result)) { + right = true; + } + } + if ((self && left) || + (self && right) || + (left && right)) { + result.left = node; + } + if (self || left || right) { + return true; + } + return false; + } +} \ No newline at end of file diff --git a/Week_02/G20200343030019/LeetCode_429_019.java b/Week_02/G20200343030019/LeetCode_429_019.java new file mode 100644 index 00000000..ffbe3a6f --- /dev/null +++ b/Week_02/G20200343030019/LeetCode_429_019.java @@ -0,0 +1,19 @@ +class Solution { + public List> levelOrder(Node root) { + if (root == null) return new ArrayList(); + List> result = new ArrayList(); + traversal(1, root, result); + return result; + } + + private void traversal(int layer, Node node, List> list) { + if (node == null) return; + if (layer > list.size()) { + list.add(new ArrayList()); + } + list.get(layer - 1).add(node.val); + for (Node n: node.children) { + traversal(layer + 1, n, list); + } + } +} \ No newline at end of file diff --git a/Week_02/G20200343030019/LeetCode_46_019.java b/Week_02/G20200343030019/LeetCode_46_019.java new file mode 100644 index 00000000..ad2fcb5b --- /dev/null +++ b/Week_02/G20200343030019/LeetCode_46_019.java @@ -0,0 +1,23 @@ +class Solution { + public List> permute(int[] nums) { + List> result = new ArrayList(); + ArrayList numsList = new ArrayList(); + for (int i: nums) { + numsList.add(i); + } + generate(numsList.size(), numsList, 0, result); + return result; + } + + private void generate(int n, ArrayList nums, int first, List> result) { + if (first == n) { + result.add((List) nums.clone()); + return ; + } + for (int index = first; index < n; index ++) { + Collections.swap(nums, first, index); + generate(n, nums, first + 1, result); + Collections.swap(nums, index, first); + } + } +} \ No newline at end of file diff --git a/Week_02/G20200343030019/LeetCode_47_019.java b/Week_02/G20200343030019/LeetCode_47_019.java new file mode 100644 index 00000000..8476b416 --- /dev/null +++ b/Week_02/G20200343030019/LeetCode_47_019.java @@ -0,0 +1,29 @@ +class Solution { + public List> permuteUnique(int[] nums) { + List> result = new ArrayList(); + Arrays.sort(nums); + LinkedList stack = new LinkedList(); + boolean[] used = new boolean[nums.length]; + generate(nums.length, nums, used, stack, result); + return result; + } + + private void generate(int n, int[] nums, boolean[] used, LinkedList stack, List> result) { + if (n == stack.size()) { + result.add((List) stack.clone()); + return; + } + int upValue = -11111; + for (int index = 0; index < n; index ++) { + if (used[index] || nums[index] == upValue) { + continue; + } + used[index] = true; + stack.addLast(nums[index]); + generate(n, nums, used, stack, result); + upValue = nums[index]; + stack.pollLast(); + used[index] = false; + } + } +} \ No newline at end of file diff --git a/Week_02/G20200343030019/LeetCode_49_019.java b/Week_02/G20200343030019/LeetCode_49_019.java new file mode 100644 index 00000000..9bae8bd0 --- /dev/null +++ b/Week_02/G20200343030019/LeetCode_49_019.java @@ -0,0 +1,18 @@ +class Solution { + public List> groupAnagrams(String[] strs) { + Map> rules = new HashMap(); + if (strs == null || strs.length == 0) { + return new ArrayList(); + } + for (String s: strs) { + char[] arr = s.toCharArray(); + Arrays.sort(arr); + String sortStr = new String(arr); + if (!rules.containsKey(sortStr)) { + rules.put(sortStr, new ArrayList()); + } + rules.get(sortStr).add(s); + } + return new ArrayList(rules.values()); + } +} \ No newline at end of file diff --git a/Week_02/G20200343030019/LeetCode_589_019.java b/Week_02/G20200343030019/LeetCode_589_019.java new file mode 100644 index 00000000..5418c1b5 --- /dev/null +++ b/Week_02/G20200343030019/LeetCode_589_019.java @@ -0,0 +1,23 @@ +class Solution { + public List preorder(Node root) { + LinkedList stack = new LinkedList(); + LinkedList result = new LinkedList(); + + if (root == null) { + return result; + } + + stack.add(root); + Node node = null; + while (!stack.isEmpty()) { + node = stack.poll(); + result.add(node.val); + for (int index = node.children.size() - 1; index >= 0; index --) { + if (node.children.get(index) != null) { + stack.addFirst(node.children.get(index)); + } + } + } + return result; + } +} \ No newline at end of file diff --git a/Week_02/G20200343030019/LeetCode_590_019.java b/Week_02/G20200343030019/LeetCode_590_019.java new file mode 100644 index 00000000..23207e87 --- /dev/null +++ b/Week_02/G20200343030019/LeetCode_590_019.java @@ -0,0 +1,23 @@ +class Solution { + public List postorder(Node root) { + LinkedList stack = new LinkedList(); + LinkedList result = new LinkedList(); + if (root == null) { + return result; + } + + stack.add(root); + Node node = null; + while (!stack.isEmpty()) { + node = stack.pollLast(); + result.addFirst(node.val); + + for(Node n: node.children) { + if (n != null) { + stack.add(n); + } + } + } + return result; + } +} \ No newline at end of file diff --git a/Week_02/G20200343030019/LeetCode_77_019.java b/Week_02/G20200343030019/LeetCode_77_019.java new file mode 100644 index 00000000..0add51a0 --- /dev/null +++ b/Week_02/G20200343030019/LeetCode_77_019.java @@ -0,0 +1,23 @@ +class Solution { + public List> combine(int n, int k) { + if (n < k || k <= 0) return new ArrayList(); + ArrayList> result = new ArrayList(); + ArrayList list = new ArrayList(); + build(1, n, k, list, result); + return result; + } + + private void build(int layer, int n, int k, ArrayList curList, ArrayList> result) { + if (layer > k) { + result.add((List) curList.clone()); + return; + } + int begin = layer > 1?curList.get(layer - 2) + 1: 1; + ArrayList arr = null; + for (; begin <= n - k + layer; begin ++) { + curList.add(begin); + build(layer + 1, n, k, curList, result); + curList.remove(layer - 1); + } + } +} \ No newline at end of file diff --git a/Week_02/G20200343030019/NOTE.md b/Week_02/G20200343030019/NOTE.md index 50de3041..43ff1500 100644 --- a/Week_02/G20200343030019/NOTE.md +++ b/Week_02/G20200343030019/NOTE.md @@ -1 +1,5 @@ -学习笔记 \ No newline at end of file +学习笔记 +# +1.对于回溯法还需要练习\ +2.剪枝掌握不熟练\ +3.多画图 \ No newline at end of file diff --git a/Week_02/G20200343030021/LeetCode_144_021.java b/Week_02/G20200343030021/LeetCode_144_021.java new file mode 100644 index 00000000..17083d12 --- /dev/null +++ b/Week_02/G20200343030021/LeetCode_144_021.java @@ -0,0 +1,75 @@ +import java.util.ArrayList; +import java.util.List; + +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; } + * } + */ +class Solution { + public class TreeNode { + int val; + TreeNode left; + TreeNode right; + + TreeNode(int x) { + val = x; + } + } + +// 普通递归 + public List preorderTraversal(TreeNode root) { + ArrayList list = new ArrayList<>(); +// 递归终结条件是什么? root == null ;递归每层的作用是什么? 获取每层的值,按照中-前-后的前序遍历方式 + helper(0, root, list); + return list; + } + + private void helper(int n, TreeNode root, ArrayList list) { +// 递归终止条件 + if (root == null) { + System.out.println(list); + return; + } +// 当期层逻辑 + list.add(root.val); +// 进入下一层 + helper(n + 1, root.left, list); + helper(n + 1, root.right, list); +// 清理当前层 + } + + + //栈模拟递归 ,迭代 + public List preorderTraversal(TreeNode root) { +// 用链表实现栈 + LinkedList stack = new LinkedList<>(); +// 输出的链表 + LinkedList output = new LinkedList<>(); + if (root == null) { + return output; + } +// 存入根节点,中 + stack.add(root); +// 遍历栈,使用栈模拟递归,终结条件:栈不空 + while (!stack.isEmpty()) { +// 检索并删除此列表的最后一个元素,返回此列表的最后一个元素,如果此列表为空,则为{@codenull} + TreeNode node = stack.pollLast(); +// 中 + output.add(node.val); +// 栈:先入后出,取出时右结点最后出来 + if (node.right != null) { + stack.add(node.right); + } +// 同上 + if (node.left != null) { + stack.add(node.left); + } + } + return output; + } +} \ No newline at end of file diff --git a/Week_02/G20200343030021/LeetCode_49_021.java b/Week_02/G20200343030021/LeetCode_49_021.java new file mode 100644 index 00000000..d9db445e --- /dev/null +++ b/Week_02/G20200343030021/LeetCode_49_021.java @@ -0,0 +1,76 @@ +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; + +class Solution { +// 1.排序数组分类 + public List> groupAnagrams(String[] strs) { +// 1.判断字符串长度是否为 0 + if (strs.length == 0) { +// 为零返回初始化数组 + return new ArrayList<>(); + } +// 2.初始化hashMap string,lsit + HashMap ans = new HashMap<>(); +// 3.循环 字符串数组 + for (String s : strs) { +// 4.原始字符串转数组 + char[] chars = s.toCharArray(); +// 5.数组排序,为了得到异位词统一的字符串 + Arrays.sort(chars); +// 6.排序数组转为字符串 + String key = String.valueOf(chars); +// 7.判断 哈希表中是否存在排序后的字符串 + if (!ans.containsKey(key)) { +// 不存在表示:这个字符是新的异位词,key:排序后字符串,value:初始化数组list + ans.put(key, new ArrayList()); + } +// 8.存在该统一字符串,将原始字符串放入value中的list中 +// List list = ans.get(key); +// list.add(s); + ans.get(key).add(s); + } +// 9.返回结果 values()将map值结果转换为数组 + return new ArrayList(ans.values()); + } + +// 2.计数分类 + public List> groupAnagrams(String[] strs) { +// 判断长度 + if (strs.length == 0){ + return new ArrayList<>(); + } +// 初始化hashmap string,lsit + HashMap map = new HashMap<>(); + int[] count = new int[26]; +// 循环字符串数组 + for (String s :strs) { +// 将计数器所有位置填充为 0 + Arrays.fill(count, 0); +// 遍历字符串 + for (char c : s.toCharArray()) { +// 计数器对每个字母出现的频率计数 ++ + count[c - 'a']++; + } +// 初始化拼接字符串 + StringBuilder sb = new StringBuilder(""); +// 特殊化处理 将每个字母计数器的梳理追加在字符串后面 26个字母 + for (int i = 0;i < 26; i++) { + sb.append("#"); + sb.append(count[i]); + } +// 类型转换为string + String key = sb.toString(); +// 判断排序后的字符串 key 在不在map的key中 + if (!map.containsKey(key)) { +// 不在:key:排序后的字符串,value:初始化数组list + map.put(key, new ArrayList()); + } +// 将原始字符串放到每个map key 的list 中 + map.get(key).add(s); + } +// 返回map转list + return new ArrayList(map.values()); + } +} \ No newline at end of file diff --git a/Week_02/G20200343030025/LeetCode_1_025.java b/Week_02/G20200343030025/LeetCode_1_025.java new file mode 100644 index 00000000..a1c0be7e --- /dev/null +++ b/Week_02/G20200343030025/LeetCode_1_025.java @@ -0,0 +1,34 @@ +/** + * 给定一个字符串数组,将字母异位词组合在一起。字母异位词指字母相同,但排列不同的字符串。 + *

+ * 示例: + *

+ * 输入: ["eat", "tea", "tan", "ate", "nat", "bat"], + * 输出: + * [ + * ["ate","eat","tea"], + * ["nat","tan"], + * ["bat"] + * ] + * 说明: + *

+ * 所有输入均为小写字母。 + * 不考虑答案输出的顺序。 + *

+ * 来源:力扣(LeetCode) + * 链接:https://leetcode-cn.com/problems/group-anagrams + * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + */ +public class LeetCode_1_025 { + public List> groupAnagrams(String[] strs) { + Map> map = new HashMap<>(); + for (String str : strs) { + char[] chars = str.toCharArray(); + Arrays.sort(chars); + String key = new String(chars).toLowerCase(); + List list = map.computeIfAbsent(key, k -> new ArrayList<>()); + list.add(str); + } + return new ArrayList<>(map.values()); + } +} \ No newline at end of file diff --git a/Week_02/G20200343030025/LeetCode_2_025.java b/Week_02/G20200343030025/LeetCode_2_025.java new file mode 100644 index 00000000..d5ec23d5 --- /dev/null +++ b/Week_02/G20200343030025/LeetCode_2_025.java @@ -0,0 +1,56 @@ +/** + * 给定一个二叉树,返回它的 前序 遍历。 + *

+ *  示例: + *

+ * 输入: [1,null,2,3] + * 1 + * \ + * 2 + * / + * 3 + *

+ * 输出: [1,2,3] + * 进阶: 递归算法很简单,你可以通过迭代算法完成吗? + *

+ * 来源:力扣(LeetCode) + * 链接:https://leetcode-cn.com/problems/binary-tree-preorder-traversal + * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + */ +public class LeetCode_2_025 { + /** + * 迭代方式 + */ + public List preorderTraversal(TreeNode root) { + List res = new ArrayList<>(); + Deque stack = new LinkedList<>(); + TreeNode tmp = root; + while (tmp != null || !stack.isEmpty()) { + // 所有的左子树 + while (tmp != null) { + res.add(tmp.val); + stack.push(tmp); + tmp = tmp.left; + } + tmp = stack.pop().right; + } + return res; + } + + /** + * 递归方式 + */ + public List preorderTraversal0(TreeNode root) { + List res = new ArrayList<>(); + doPreorderTraversal0(res, root); + return res; + } + + private void doPreorderTraversal0(List res, TreeNode root) { + if (root != null) { + res.add(root.val); + this.doPreorderTraversal0(res, root.left); + this.doPreorderTraversal0(res, root.right); + } + } +} \ No newline at end of file diff --git a/Week_02/G20200343030025/LeetCode_3_025.java b/Week_02/G20200343030025/LeetCode_3_025.java new file mode 100644 index 00000000..d5296804 --- /dev/null +++ b/Week_02/G20200343030025/LeetCode_3_025.java @@ -0,0 +1,54 @@ + +/** + * 给定一个 N 叉树,返回其节点值的层序遍历。 (即从左到右,逐层遍历)。 + * + * 例如,给定一个 3叉树 : + * + * https://assets.leetcode-cn.com/aliyun-lc-upload/uploads/2018/10/12/narytreeexample.png + * + * + * 返回其层序遍历: + * + * [ + * [1], + * [3,2,4], + * [5,6] + * ] + *   + * + * 说明: + * + * 树的深度不会超过 1000。 + * 树的节点总数不会超过 5000。 + * + * 来源:力扣(LeetCode) + * 链接:https://leetcode-cn.com/problems/n-ary-tree-level-order-traversal + * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + */ +public class LeetCode_3_025 { + public List> levelOrder(Node root) { + if (root == null) { + return new ArrayList<>(); + } + List> res = new ArrayList<>(); + Deque queue = new LinkedList<>(); + queue.add(root); + while (!queue.isEmpty()) { + int leveSize = queue.size(); + List list = new ArrayList<>(leveSize); + for (int i = 0; i < leveSize; i++) { + Node node = queue.removeFirst(); + list.add(node.val); + List children = node.children; + for (Node child : children) { + if (child == null) { + continue; + } + queue.add(child); + } + } + res.add(list); + } + return res; + } +} \ No newline at end of file diff --git a/Week_02/G20200343030025/NOTE.md b/Week_02/G20200343030025/NOTE.md index 50de3041..9db0ad00 100644 --- a/Week_02/G20200343030025/NOTE.md +++ b/Week_02/G20200343030025/NOTE.md @@ -1 +1,71 @@ -学习笔记 \ No newline at end of file +学习笔记 +#### 树形结构 +* 二叉树结点定义 + ```java + public class TreeNode { + public int value; + public TreeNode left,right; + + public TreeNode(int value) { + this.value = value; + this.left = null; + this.right = null; + } + } + ``` +* 二叉树结构的前中后序遍历 + ```java + import java.util.List; + + public class General { + private List traversePath; + + public void preorder(TreeNode root){ + if (root != null) { + this.traversePath.add(root.value); + this.preorder(root.left); + this.preorder(root.right); + } + } + + public void inorder(TreeNode root) { + if (root != null) { + this.inorder(root.left); + this.traversePath.add(root.value); + this.inorder(root.right); + } + } + + public void postorder(TreeNode root) { + if (root != null) { + this.postorder(root.left); + this.postorder(root.right); + this.traversePath.add(root.value); + } + } + } + ``` +* 树形结构的时间复杂度为 O(log n) +* 二叉搜索树的中序遍历是递增的 +#### 泛型递归 +* 代码模版 + ```java + public void recursion(int level, int param){ + // recursion terminal + if (level > MAX_LEVEL) { + // process result + return; + } + // process current logic + process(level, param); + + // drill down + recursion(level, level + 1, param); + + // restore current status + } + ``` +* 思维要点 + 1. 拒绝人肉进行递归(最大误区) + 2. 找到最近最简方法,将其拆解为可重复解决的问题(重复子问题) + 3. 数学归纳法思维 diff --git a/Week_02/G20200343030029/LeetCode_2_029.java b/Week_02/G20200343030029/LeetCode_2_029.java new file mode 100644 index 00000000..37433d5d --- /dev/null +++ b/Week_02/G20200343030029/LeetCode_2_029.java @@ -0,0 +1,43 @@ +class LeetCode_2_029 { + + // 题目:给定一个 N 叉树,返回其节点值的后序遍历(左右根) + + private static List array = new ArrayList(); + + + public static List recursiveSolution(Node node){ + recursiveHelper(node); + return array; + } + + private static void recursiveHelper(Node node) { + if(null == node) { + return; + } + + for(int i = 0; i < node.children.size(); i++) { + recursiveHelper(node.children.get(i)); + } + + array.add(node.val); + } + + // Node class + private static class Node { + + public static int val; + public static List children; + + public Node() { + } + + public Node(int _val) { + val = _val; + } + + public Node(int _val, List _children) { + val = _val; + children = _children; + } + } +} \ No newline at end of file diff --git a/Week_02/G20200343030029/LeetCode_3_029.java b/Week_02/G20200343030029/LeetCode_3_029.java new file mode 100644 index 00000000..2f8433ed --- /dev/null +++ b/Week_02/G20200343030029/LeetCode_3_029.java @@ -0,0 +1,42 @@ +class LeetCode_3_029 { + + // 题目:给定一个 N 叉树,返回其节点值的前序遍历。(根左右) + + private static List array = new ArrayList(); + + public List postorder(Node root) { + helper(root); + return array; + } + + private void helper(Node node) { + + if(null == node) { + return; + } + + array.add(node.val); + + for(int i = 0; i < node.children.size(); i++){ + helper(node.children.get(i)); + } + + // Node class + private static class Node { + + public static int val; + public static List children; + + public Node() { + } + + public Node(int _val) { + val = _val; + } + + public Node(int _val, List _children) { + val = _val; + children = _children; + } + } +} \ No newline at end of file diff --git a/Week_02/G20200343030029/NOTE.md b/Week_02/G20200343030029/NOTE.md index 50de3041..211d6907 100644 --- a/Week_02/G20200343030029/NOTE.md +++ b/Week_02/G20200343030029/NOTE.md @@ -1 +1,23 @@ -学习笔记 \ No newline at end of file +#HashMap 理解 +*** +* 存储方式(存储结构为key value形式) + + 存储结构包括(数组+链表+红黑树 [^jdk 1.8以及之后版本包括红黑树]) + + 数组主要存储 针对Key hash()之后的值 + + 链表主要存储相同key hash()之后的key value 以及下一个节点指针(在jdk 1.8之后,相同hash()值所产生的链表长度 + 超过8时转换链表为红黑树存储) + +* put() + * ①判断键值对数组table[i]是否为空或为null,否则执行resize()进行扩容; + * ②根据键值key计算hash值得到插入的数组索引i,如果table[i]==null,直接新建节点添加,转向⑥,如果table[i]不为空,转向③; + * ③判断table[i]的首个元素是否和key一样,如果相同直接覆盖value,否则转向④,这里的相同指的是hashCode以及equals; + * ④判断table[i] 是否为treeNode,即table[i] 是否是红黑树,如果是红黑树,则直接在树中插入键值对,否则转向⑤; + * ⑤遍历table[i],判断链表长度是否大于8,大于8的话把链表转换为红黑树,在红黑树中执行插入操作,否则进行链表的插入操作;遍历过程中若发现key已经存在直接覆盖value即可; + * ⑥插入成功后,判断实际存在的键值对数量size是否超多了最大容量threshold,如果超过,进行扩容。 +* get() + + 根据(hash() & n-1)找到数据在数组中存储位置,然后根据key在数组指向的链表中查找。 + + 具体参考连接 [hashMap理解](https://www.jianshu.com/p/30bffabb2e5c) \ No newline at end of file diff --git a/Week_02/G20200343030035/LeetCode_589_035.py b/Week_02/G20200343030035/LeetCode_589_035.py new file mode 100644 index 00000000..026c5aae --- /dev/null +++ b/Week_02/G20200343030035/LeetCode_589_035.py @@ -0,0 +1,17 @@ +# N叉树前序遍历 + +""" +# Definition for a Node. +class Node: + def __init__(self, val=None, children=None): + self.val = val + self.children = children +""" +class Solution(): + def preorder(self, root): + if not root: + return [] + traversal = [root.val] + for child in root.children: + traversal.extend(self.preorder(child)) + return traversal \ No newline at end of file diff --git a/Week_02/G20200343030035/LeetCode_590_035.py b/Week_02/G20200343030035/LeetCode_590_035.py new file mode 100644 index 00000000..500ce091 --- /dev/null +++ b/Week_02/G20200343030035/LeetCode_590_035.py @@ -0,0 +1,21 @@ +# N叉树后序遍历 + +""" +# Definition for a Node. +class Node: + def __init__(self, val=None, children=None): + self.val = val + self.children = children +""" +class Solution: + def postorder(self, root): + res = [] + if root == None: return res + + def recursion(root, res): + for child in root.children: + recursion(child, res) + res.append(root.val) + + recursion(root, res) + return res diff --git a/Week_02/G20200343030361/LeetCode_144_361.js b/Week_02/G20200343030361/LeetCode_144_361.js new file mode 100644 index 00000000..34e57717 --- /dev/null +++ b/Week_02/G20200343030361/LeetCode_144_361.js @@ -0,0 +1,31 @@ +// iteration +// var preorderTraversal = function(root) { +// if (!root) return [] +// let stack = [root]; +// let res = []; +// let curr; + +// while (stack.length > 0) { +// curr = stack.pop(); +// res.push(curr.val) + +// if (curr.right) stack.push(curr.right); +// if (curr.left) stack.push(curr.left); +// } + +// return res; +// }; + +// recursive +const preorderTraversal = root => { + let res = []; + helper(root, res); + return res; +}; + +const helper = (root, res) => { + if (!root) return; + res.push(root.val); + helper(root.left, res); + helper(root.right, res); +}; diff --git a/Week_02/G20200343030361/LeetCode_429_361.js b/Week_02/G20200343030361/LeetCode_429_361.js new file mode 100644 index 00000000..820e9811 --- /dev/null +++ b/Week_02/G20200343030361/LeetCode_429_361.js @@ -0,0 +1,37 @@ +// method 1 +const levelOrder = root => { + let res = []; + + const helper = (node, level) => { + if (res.length == level) res.push([]); + + res[level].push(node.val); + + node.children.forEach(cNode => helper(cNode, level + 1)); + }; + + if (root) helper(root, 0); + + return res; +}; + +// method 2 +// var levelOrder = function(root) { +// let res = []; +// if (!root) return res; +// let currStack = [root]; + +// while (currStack.length > 0) { +// let curr = []; +// let nextLevel = []; +// currStack.forEach((node) => { +// if (!isNaN(node.val)) curr.push(node.val); +// if (node.children.length > 0) nextLevel = nextLevel.concat(node.children); +// }) + +// res.push(curr); +// currStack = nextLevel; +// } + +// return res; +// }; diff --git a/Week_02/G20200343030361/LeetCode_49_361.js b/Week_02/G20200343030361/LeetCode_49_361.js new file mode 100644 index 00000000..1fedcc45 --- /dev/null +++ b/Week_02/G20200343030361/LeetCode_49_361.js @@ -0,0 +1,32 @@ +var groupAnagrams = function(strs) { + let records = {}; + + for (let i = 0; i < strs.length; i++) { + let apperanceCalculator = {}; + let splitted = strs[i].split(""); + + for (char of splitted) { + let charCode = char.charCodeAt(); + isNaN(apperanceCalculator[charCode]) + ? (apperanceCalculator[charCode] = 1) + : (apperanceCalculator[charCode] += 1); + } + + let startCharCode = "a".charCodeAt(); + let hashKey = ""; + for (let i = "a".charCodeAt(); i < startCharCode + 26; i++) { + hashKey += "#"; + hashKey += apperanceCalculator[i] ? apperanceCalculator[i] : 0; + } + + records[hashKey] + ? records[hashKey].push(strs[i]) + : (records[hashKey] = [strs[i]]); + } + let result = []; + for (key in records) { + result.push(records[key]); + } + + return result; +}; diff --git a/Week_02/G20200343030363/LeetCode_001_363.java b/Week_02/G20200343030363/LeetCode_001_363.java new file mode 100644 index 00000000..71e2667d --- /dev/null +++ b/Week_02/G20200343030363/LeetCode_001_363.java @@ -0,0 +1,46 @@ +package cn.geek.week2; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author lemon + * @version 1.0.0 + * @Description TODO + * @createTime 2020年02月18日 14:22:00 + */ +public class LeetCode_001_363 { + + /** + * Two sum int [ ]. 两数之和 使用hash表处理 + * + * 给定 nums = [2, 7, 11, 15], target = 9 + * + * 因为 nums[0] + nums[1] = 2 + 7 = 9 所以返回 [0, 1] + * + * @param nums + * the nums + * @param target + * the target + * @return the int [ ] + */ + public int[] twoSum(int[] nums, int target) { + Map map = new HashMap<>(); + for (int i = 0; i < nums.length; i++) { + int number = target - nums[i]; + if (map.containsKey(number)) { + return new int[] {map.get(number), i}; + } + map.put(nums[i], i); + } + throw new IllegalArgumentException("No two sum solution"); + } + + public static void main(String[] args) { + LeetCode_001_363 leetCode = new LeetCode_001_363(); + int[] result = leetCode.twoSum(new int[] {2, 15, 11, 7}, 9); + for (int t : result) { + System.out.print(t + " "); + } + } +} diff --git a/Week_02/G20200343030363/LeetCode_022_363.java b/Week_02/G20200343030363/LeetCode_022_363.java new file mode 100644 index 00000000..4b516be6 --- /dev/null +++ b/Week_02/G20200343030363/LeetCode_022_363.java @@ -0,0 +1,64 @@ +package cn.geek.week2; + +import java.util.ArrayList; +import java.util.List; + +/** + * + * 所谓递归就是找规律, 找重复子循环 + * + * @author lemon + * @version 1.0.0 + * @Description TODO + * @createTime 2020年02月20日 09:08:00 + */ +public class LeetCode_022_363 { + + /** + * Generate parenthesis list. ((())) + * + * @param n + * the n + * @return the list + */ + public List generateParenthesis(int n) { + List resList = new ArrayList<>(); + generate(resList, "", 0, 0, n); + return resList; + } + + /** + * Generate. + * + * @param resList + * the res list + * @param cur + * the cur + * @param left + * the left + * @param right + * the right + * @param max + * the max + */ + public void generate(List resList, String cur, int left, int right, int max) { + + if (cur.length() == max * 2) { + resList.add(cur); + return; + } + + if (left < max) { + generate(resList, cur + "(", left + 1, right, max); + } + + if (right < left) { + generate(resList, cur + ")", left, right + 1, max); + } + } + + public static void main(String[] args) { + LeetCode_022_363 leetcode = new LeetCode_022_363(); + leetcode.generateParenthesis(3).forEach(System.out::println); + } +} diff --git a/Week_02/G20200343030363/LeetCode_046_363.java b/Week_02/G20200343030363/LeetCode_046_363.java new file mode 100644 index 00000000..3a59a7d0 --- /dev/null +++ b/Week_02/G20200343030363/LeetCode_046_363.java @@ -0,0 +1,48 @@ +package cn.geek.week2; + +import java.util.LinkedList; +import java.util.List; + +/** + * + * 给定一个没有重复数字的序列,返回其所有可能的全排列 + * + * @author lemon + * @version 1.0.0 + * @Description TODO + * @createTime 2020年02月23日 07:51:00 + */ +public class LeetCode_046_363 { + + public List> permute(int[] nums) { + LinkedList tempLink = new LinkedList<>(); + List> res = new LinkedList<>(); + backtrack(nums, tempLink, res); + return res; + } + + public void backtrack(int[] nums, LinkedList track, List> res) { + + if (nums.length == track.size()) { + res.add(new LinkedList<>(track)); + } + + for (int i = 0; i < nums.length; i++) { + + if (track.contains(nums[i])) { + continue; + } + track.add(nums[i]); + backtrack(nums, track, res); + track.removeLast(); + } + } + + public static void main(String[] args) { + LeetCode_046_363 leetcode = new LeetCode_046_363(); + List> resList = leetcode.permute(new int[] {1, 2, 3}); + for (List list : resList) { + System.out.println(list); + } + } +} diff --git a/Week_02/G20200343030363/LeetCode_049_363.java b/Week_02/G20200343030363/LeetCode_049_363.java new file mode 100644 index 00000000..790f815c --- /dev/null +++ b/Week_02/G20200343030363/LeetCode_049_363.java @@ -0,0 +1,60 @@ +package cn.geek.week2; + +import java.util.*; + +/** + * @author lemon + * @version 1.0.0 + * @Description TODO + * @createTime 2020年02月18日 14:07:00 + */ +public class LeetCode_049_363 { + + private final static int ENGLISH_LENGTH = 26; + + /** + * Group anagrams list. 找出数组里面的异位词 暴力解法 + * + * @param strs + * the strs + * @return the list + */ + public List> groupAnagrams(String[] strs) { + + Map map = new HashMap<>(); + + int[] count = new int[26]; + for (String str : strs) { + Arrays.fill(count, 0); + + char[] charArr = str.toCharArray(); + for (char c : charArr) { + count[c - 'a']++; + } + + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < ENGLISH_LENGTH; i++) { + sb.append('#'); + sb.append(count[i]); + } + String key = sb.toString(); + + if (!map.containsKey(key)) { + map.put(key, new ArrayList()); + } + map.get(key).add(str); + } + return new ArrayList(map.values()); + } + + public static void main(String[] args) { + LeetCode_049_363 leetcode = new LeetCode_049_363(); + List> result = leetcode.groupAnagrams(new String[] {"eat", "tea", "tan", "ate", "nat", "bat"}); + for (List list : result) { + for (String str : list) { + System.out.print(str + " "); + } + System.out.println(); + } + } +} diff --git a/Week_02/G20200343030363/LeetCode_077_363.java b/Week_02/G20200343030363/LeetCode_077_363.java new file mode 100644 index 00000000..858be556 --- /dev/null +++ b/Week_02/G20200343030363/LeetCode_077_363.java @@ -0,0 +1,42 @@ +package cn.geek.week2; + +import java.util.ArrayList; +import java.util.List; + +/** + * + * @author lemon + * @version 1.0.0 + * @Description TODO + * @createTime 2020年02月22日 16:28:00 + */ +public class LeetCode_077_363 { + + /** + * Combine list. + * + * @param n + * the n + * @param k + * the k + * @return the list + */ + public List> combine(int n, int k) { + List> res = new ArrayList<>(); + List selected = new ArrayList<>(); + backtrack(n, k, 1, selected, res); + return res; + } + + private void backtrack(int n, int k, int start, List selected, List> res) { + if (selected.size() == k) { + res.add(new ArrayList<>(selected)); + return; + } + for (int i = start; i <= n - (k - selected.size()) + 1; i++) { + selected.add(i); + backtrack(n, k, i + 1, selected, res); + selected.remove(selected.size() - 1); + } + } +} diff --git a/Week_02/G20200343030363/LeetCode_094_363.java b/Week_02/G20200343030363/LeetCode_094_363.java new file mode 100644 index 00000000..592eaa69 --- /dev/null +++ b/Week_02/G20200343030363/LeetCode_094_363.java @@ -0,0 +1,79 @@ +package cn.geek.week2; + +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; + +/** + * 给定一个二叉树,返回它的中序 遍历。 + * + * @author lemon + * @version 1.0.0 + * @Description TODO + * @createTime 2020年02月18日 15:36:00 + */ +public class LeetCode_094_363 { + + /** + * Inorder traversal by stack list. 中序遍历 通过迭代的方式 + * + * @param root + * the root + * @return the list + */ + public List inorderTraversalByStack(TreeNode root) { + List res = new ArrayList<>(); + Stack stack = new Stack<>(); + TreeNode curr = root; + + // 中序遍历 + while (curr != null || !stack.isEmpty()) { + while (curr != null) { + stack.push(curr); + curr = curr.left; + } + curr = stack.pop(); + res.add(curr.val); + curr = curr.right; + } + return res; + } + + /** + * + * Inorder traversal list. 递归算法很简单,你可以通过迭代算法完成吗? + * + * @param root + * the root + * @return the list + */ + public List inorderTraversal(TreeNode root) { + List res = new ArrayList<>(); + helper(root, res); + return res; + } + + /** + * Helper. + * + * @param root + * the root + * @param res + * the res + */ + public void helper(TreeNode root, List res) { + if (root != null) { + if (root.left != null) { + helper(root.left, res); + } + res.add(root.val); + if (root.right != null) { + helper(root.right, res); + } + } + } + + public static void main(String[] args) { + + } +} diff --git a/Week_02/G20200343030363/LeetCode_098_363.java b/Week_02/G20200343030363/LeetCode_098_363.java new file mode 100644 index 00000000..bc88a477 --- /dev/null +++ b/Week_02/G20200343030363/LeetCode_098_363.java @@ -0,0 +1,92 @@ +package cn.geek.week2; + +import java.util.Stack; + +/** + * 验证二叉搜索树 + * + * @author lemon + * @version 1.0.0 + * @Description TODO + * @createTime 2020年02月20日 11:25:00 + */ +public class LeetCode_098_363 { + + /** + * Is valid bst boolean. + * + * @param root + * the root + * @return the boolean + */ + public boolean isValidBST(TreeNode root) { + + return valid(root, null, null); + } + + /** + * Valid boolean. + * + * @param root + * the root + * @param max + * the max + * @param min + * the min + * @return the boolean + */ + private boolean valid(TreeNode root, Integer max, Integer min) { + if (null == root) { + return true; + } + + // 当前层逻辑 + if (max != null && root.val >= max) { + return false; + } + + if (min != null && root.val <= min) { + return false; + } + + if (!valid(root.left, root.val, min)) { + return false; + } + + if (!valid(root.right, max, root.val)) { + return false; + } + return true; + } + + /** + * Valid by stack boolean. + * + * @param root + * the root + * @return the boolean + */ + public boolean validByStack(TreeNode root) { + Stack stack = new Stack<>(); + double inorder = -Double.MAX_VALUE; + + while (!stack.isEmpty() || root != null) { + while (root != null) { + stack.push(root); + root = root.left; + } + root = stack.pop(); + if (root.val <= inorder) { + return false; + } + inorder = root.val; + root = root.right; + } + return true; + } + + public static void main(String[] args) { + LeetCode_098_363 leetcode = new LeetCode_098_363(); + + } +} diff --git a/Week_02/G20200343030363/LeetCode_104_363.java b/Week_02/G20200343030363/LeetCode_104_363.java new file mode 100644 index 00000000..951a8fcc --- /dev/null +++ b/Week_02/G20200343030363/LeetCode_104_363.java @@ -0,0 +1,62 @@ +package cn.geek.week2; + +import java.util.LinkedList; +import java.util.Queue; + +import javafx.util.Pair; + +/** + * 二叉树的最大深度 DFS Depth First Search 深度优先搜索 + * + * @author lemon + * @version 1.0.0 + * @Description TODO + * @createTime 2020年02月21日 09:54:00 + */ +public class LeetCode_104_363 { + + /** + * Max depth int. + * + * @param root + * the root + * @return the int + */ + public int maxDepth(TreeNode root) { + if (null == root) { + return 0; + } else { + int leftHeight = maxDepth(root.left); + int rightHeight = maxDepth(root.right); + return Math.max(leftHeight, rightHeight) + 1; + } + } + + /** + * Max depth by queue int. + * + * @param root + * the root + * @return the int + */ + public int maxDepthByQueue(TreeNode root) { + Queue> queue = new LinkedList<>(); + if (root != null) { + queue.add(new Pair(root, 1)); + } + int maxDepth = 1; + while (!queue.isEmpty()) { + Pair curr = queue.poll(); + root = curr.getKey(); + int currDepth = curr.getValue(); + + if (null != root) { + maxDepth = Math.max(maxDepth, currDepth); + queue.add(new Pair(root.left, currDepth + 1)); + queue.add(new Pair(root.right, currDepth + 1)); + } + } + return maxDepth; + } + +} diff --git a/Week_02/G20200343030363/LeetCode_111_363.java b/Week_02/G20200343030363/LeetCode_111_363.java new file mode 100644 index 00000000..3efa872f --- /dev/null +++ b/Week_02/G20200343030363/LeetCode_111_363.java @@ -0,0 +1,83 @@ +package cn.geek.week2; + +import javafx.util.Pair; + +import java.util.LinkedList; +import java.util.Queue; + +/** + * 二叉树的最小深度 + * + * + * 1、递归 2、深度优先 dfs depth first search 3、广度优先 + * + * @author lemon + * @version 1.0.0 + * @Description TODO + * @createTime 2020年02月21日 10:42:00 + */ +public class LeetCode_111_363 { + + /** + * Min depth int. + * + * @param root + * the root + * @return the int + */ + public int minDepth(TreeNode root) { + + // 1.递归 + + // 递归出口 + if (null == root) { + return 0; + } + + if (null == root.left && null == root.right) { + return 1; + } + + int minDepth = 1; + + if (null != root.left) { + minDepth = Math.min(minDepth(root.left), minDepth); + } + + if (null != root.right) { + minDepth = Math.min(minDepth(root.right), minDepth); + } + return minDepth + 1; + } + + /** + * Min depth by queue int. DFS + * + * @param root + * the root + * @return the int + */ + public int minDepthByDFS(TreeNode root) { + Queue> queue = new LinkedList<>(); + if (null == root) { + return 0; + } + queue.add(new Pair(root, 1)); + int minDepth = 1; + while (!queue.isEmpty()) { + Pair current = queue.poll(); + root = current.getKey(); + int currDepth = current.getValue(); + if (root.left == null && root.right == null) { + minDepth = Math.min(minDepth, currDepth); + } + if (root.left != null) { + queue.add(new Pair(root.left, currDepth + 1)); + } + if (root.right != null) { + queue.add(new Pair(root.right, currDepth + 1)); + } + } + return minDepth; + } +} diff --git a/Week_02/G20200343030363/LeetCode_114_363.java b/Week_02/G20200343030363/LeetCode_114_363.java new file mode 100644 index 00000000..ed5fa008 --- /dev/null +++ b/Week_02/G20200343030363/LeetCode_114_363.java @@ -0,0 +1,60 @@ +package cn.geek.week2; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; + +/** + * + * 给定一个二叉树,返回它的 前序 遍历 + * + * @author lemon + * @version 1.0.0 + * @Description TODO + * @createTime 2020年02月23日 07:07:00 + */ +public class LeetCode_114_363 { + + public List preorderTraversal(TreeNode root) { + List res = new ArrayList<>(); + preOrderRecur(root, res); + return res; + } + + private void preOrderRecur(TreeNode root, List res) { + if (null == root) { + return; + } + res.add(root.val); + preOrderRecur(root.left, res); + preOrderRecur(root.right, res); + } + + /** + * Preorder traversal by queue list. + * + * @param root + * the root + * @return the list + */ + public List preorderTraversalByQueue(TreeNode root) { + List res = new ArrayList<>(); + Queue queue = new LinkedList<>(); + if (null == root) { + return res; + } + queue.add(root); + while (!queue.isEmpty()) { + TreeNode curr = queue.poll(); + res.add(curr.val); + if (null != curr.left) { + queue.add(curr.left); + } + if (null != curr.right) { + queue.add(curr.right); + } + } + return res; + } +} diff --git a/Week_02/G20200343030363/LeetCode_226_363.java b/Week_02/G20200343030363/LeetCode_226_363.java new file mode 100644 index 00000000..6238ca57 --- /dev/null +++ b/Week_02/G20200343030363/LeetCode_226_363.java @@ -0,0 +1,56 @@ +package cn.geek.week2; + +import java.util.LinkedList; +import java.util.Queue; + +/** + * @author lemon + * @version 1.0.0 + * @Description TODO + * @createTime 2020年02月20日 09:15:00 + */ +public class LeetCode_226_363 { + + public TreeNode invertTree(TreeNode root) { + + // 递归出口 + if (root == null) { + return null; + } + TreeNode right = invertTree(root.right); + TreeNode left = invertTree(root.left); + root.left = right; + root.right = left; + return root; + } + + /** + * Invert tree by queue tree node. + * + * @param root + * the root + * @return the tree node + */ + public TreeNode invertTreeByQueue(TreeNode root) { + + // 队列是先进先出 + if (null == root) { + return null; + } + Queue queue = new LinkedList<>(); + queue.add(root); + while (!queue.isEmpty()) { + TreeNode current = queue.poll(); + TreeNode tempNode = current.left; + current.left = current.right; + current.right = tempNode; + if (current.left != null) { + queue.add(current.left); + } + if (current.right != null) { + queue.add(current.right); + } + } + return root; + } +} diff --git a/Week_02/G20200343030363/LeetCode_236_363.java b/Week_02/G20200343030363/LeetCode_236_363.java new file mode 100644 index 00000000..9e61806e --- /dev/null +++ b/Week_02/G20200343030363/LeetCode_236_363.java @@ -0,0 +1,33 @@ +package cn.geek.week2; + +/** + * @author lemon + * @version 1.0.0 + * @Description TODO + * @createTime 2020年02月22日 10:12:00 + */ +public class LeetCode_236_363 { + + /** + * Lowest common ancestor tree node. + * + * @param curr + * the curr + * @param p + * the p + * @param q + * the q + * @return the tree node + */ + public TreeNode lowestCommonAncestor(TreeNode curr, TreeNode p, TreeNode q) { + if (null == curr || curr == p || curr == q) { + return curr; + } + TreeNode left = lowestCommonAncestor(curr.left, p, q); + TreeNode right = lowestCommonAncestor(curr.right, p, q); + if (left != null && right != null) { + return curr; + } + return left == null ? right : left; + } +} diff --git a/Week_02/G20200343030363/LeetCode_242_363.java b/Week_02/G20200343030363/LeetCode_242_363.java new file mode 100644 index 00000000..30813055 --- /dev/null +++ b/Week_02/G20200343030363/LeetCode_242_363.java @@ -0,0 +1,101 @@ +package cn.geek.week2; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +/** + * + * 字母异位词 + * + * @author lemon + * @version 1.0.0 + * @Description TODO + * @createTime 2020年02月18日 11:07:00 + */ +public class LeetCode_242_363 { + + /** + * Is anagram boolean. 忽略大小写 + * + * @param source + * the source + * @param target + * the target + * @return the boolean + */ + public boolean isAnagram(String source, String target) { + + // 暴力解法 O(n) + Map map = new HashMap<>(); + for (int i = 0; i < source.length(); i++) { + char temp = source.charAt(i); + int count = map.get(temp) == null ? 0 : map.get(temp); + map.put(temp, ++count); + } + + for (int j = 0; j < target.length(); j++) { + char temp = target.charAt(j); + int count = map.get(temp) == null ? 0 : map.get(temp); + map.put(temp, --count); + } + + for (Integer count : map.values()) { + if (count != 0) { + return false; + } + } + return true; + } + + /** + * Is anagram by sort boolean. 暴力解法直接用java原生api + * + * @param source + * the source + * @param target + * the target + * @return the boolean + */ + public boolean isAnagramBySort(String source, String target) { + char[] sourceArr = source.toCharArray(); + char[] targetArr = target.toCharArray(); + Arrays.sort(sourceArr); + Arrays.sort(targetArr); + return sourceArr.equals(targetArr); + } + + /** + * Is anagram by hash boolean.使用hash表 + * + * @param source + * the source + * @param target + * the target + * @return the boolean + */ + public boolean isAnagramByHash(String source, String target) { + if (source.length() != target.length()) { + return false; + } + int[] table = new int[26]; + for (int i = 0; i < source.length(); i++) { + + // char的加减是ascii码的加减 + table[source.charAt(i) - 'a']++; + table[target.charAt(i) - 'a']--; + } + for (int count : table) { + if (count != 0) { + return false; + } + } + return true; + } + + public static void main(String[] args) { + LeetCode_242_363 leetcode = new LeetCode_242_363(); + System.out.println(leetcode.isAnagram("aaa", "aaa")); + System.out.println(leetcode.isAnagramBySort("aaa", "aaa")); + } +} diff --git a/Week_02/G20200343030363/LeetCode_429_363.java b/Week_02/G20200343030363/LeetCode_429_363.java new file mode 100644 index 00000000..4a1166db --- /dev/null +++ b/Week_02/G20200343030363/LeetCode_429_363.java @@ -0,0 +1,41 @@ +package cn.geek.week2; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; + +/** + * + * N叉树的层序遍历 BFS + * + * @author lemon + * @version 1.0.0 + * @Description TODO + * @createTime 2020年02月23日 07:25:00 + */ +public class LeetCode_429_363 { + public List> levelOrder(Node root) { + List> res = new ArrayList<>(); + Queue queue = new LinkedList<>(); + if (null == root) { + return res; + } + queue.add(root); + while (!queue.isEmpty()) { + List level = new ArrayList<>(); + int size = queue.size(); + + //队列和栈不能放到for循环判断里面 + for (int i = 0; i < size; i++) { + Node node = queue.poll(); + level.add(node.val); + + // 队列里面放的,始终是同一级的节点 + queue.addAll(node.children); + } + res.add(level); + } + return res; + } +} diff --git a/Week_02/G20200343030363/LeetCode_589_363.java b/Week_02/G20200343030363/LeetCode_589_363.java new file mode 100644 index 00000000..95b4b740 --- /dev/null +++ b/Week_02/G20200343030363/LeetCode_589_363.java @@ -0,0 +1,64 @@ +package cn.geek.week2; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; + +/** + * N叉树的前序遍历 + * + * @author lemon + * @version 1.0.0 + * @Description TODO + * @createTime 2020年02月22日 22:39:00 + */ +public class LeetCode_589_363 { + + /** + * Preorder list. + * + * @param root + * the root + * @return the list + */ + public List preorder(Node root) { + List res = new ArrayList<>(); + conver(root, res); + return res; + } + + private void conver(Node root, List res) { + if (root == null) { + return; + } + res.add(root.val); + if (null != root.children) { + for (Node children : root.children) { + conver(children, res); + } + } + } + + /** + * Preorder by stack list. 前序 根左右 + * + * @param root + * the root + * @return the list + */ + public List preorderByStack(Node root) { + LinkedList stack = new LinkedList<>(); + List res = new ArrayList<>(); + stack.add(root); + while (!stack.isEmpty()) { + Node node = stack.pollLast(); + res.add(node.val); + Collections.reverse(node.children); + for (Node item : node.children) { + stack.add(item); + } + } + return res; + } +} diff --git a/Week_02/G20200343030363/LeetCode_590_363.java b/Week_02/G20200343030363/LeetCode_590_363.java new file mode 100644 index 00000000..269dde10 --- /dev/null +++ b/Week_02/G20200343030363/LeetCode_590_363.java @@ -0,0 +1,41 @@ +package cn.geek.week2; + +import java.util.ArrayList; +import java.util.List; + +/** + * + * N叉树的后序遍历 + * + * @author lemon + * @version 1.0.0 + * @Description TODO + * @createTime 2020年02月22日 22:39:00 + */ +public class LeetCode_590_363 { + + /** + * Postorder list. + * + * @param root + * the root + * @return the list + */ + public List postorder(Node root) { + List res = new ArrayList<>(); + conver(root, res); + return res; + } + + private void conver(Node root, List res) { + if (root == null) { + return; + } + if (root.children != null) { + for (Node children : root.children) { + conver(children, res); + } + } + res.add(root.val); + } +} diff --git a/Week_02/G20200343030363/Node.java b/Week_02/G20200343030363/Node.java new file mode 100644 index 00000000..dc675779 --- /dev/null +++ b/Week_02/G20200343030363/Node.java @@ -0,0 +1,24 @@ +package cn.geek.week2; + +import java.util.List; + +/** + * @author lemon + * @version 1.0.0 + * @Description TODO + * @createTime 2020年02月22日 22:38:00 + */ +public class Node { + public int val; + public List children; + + public Node() {} + + public Node(int _val) { + val = _val; + } + public Node(int _val, List _children) { + val = _val; + children = _children; + } +} diff --git a/Week_02/G20200343030363/TreeNode.java b/Week_02/G20200343030363/TreeNode.java new file mode 100644 index 00000000..a7a3641f --- /dev/null +++ b/Week_02/G20200343030363/TreeNode.java @@ -0,0 +1,17 @@ +package cn.geek.week2; + +/** + * @author lemon + * @version 1.0.0 + * @Description TODO + * @createTime 2020年02月18日 15:36:00 + */ +public class TreeNode { + int val; + TreeNode left; + TreeNode right; + + TreeNode(int x) { + val = x; + } +} diff --git "a/Week_02/G20200343030369/105.\344\273\216\345\211\215\345\272\217\344\270\216\344\270\255\345\272\217\351\201\215\345\216\206\345\272\217\345\210\227\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221.swift" "b/Week_02/G20200343030369/105.\344\273\216\345\211\215\345\272\217\344\270\216\344\270\255\345\272\217\351\201\215\345\216\206\345\272\217\345\210\227\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221.swift" new file mode 100644 index 00000000..d235bb23 --- /dev/null +++ "b/Week_02/G20200343030369/105.\344\273\216\345\211\215\345\272\217\344\270\216\344\270\255\345\272\217\351\201\215\345\216\206\345\272\217\345\210\227\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221.swift" @@ -0,0 +1,80 @@ +/* + * @lc app=leetcode.cn id=105 lang=golang + * + * [105] 从前序与中序遍历序列构造二叉树 + * + * https://leetcode-cn.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/description/ + * + * algorithms + * Medium (63.98%) + * Likes: 347 + * Dislikes: 0 + * Total Accepted: 44K + * Total Submissions: 68.5K + * Testcase Example: '[3,9,20,15,7]\n[9,3,15,20,7]' + * + * 根据一棵树的前序遍历与中序遍历构造二叉树。 + * + * 注意: + * 你可以假设树中没有重复的元素。 + * + * 例如,给出 + * + * 前序遍历 preorder = [3,9,20,15,7] + * 中序遍历 inorder = [9,3,15,20,7] + * + * 返回如下的二叉树: + * + * ⁠ 3 + * ⁠ / \ + * ⁠ 9 20 + * ⁠ / \ + * ⁠ 15 7 + * + */ + +// @lc code=start +public class TreeNode { + public var val: Int + public var left: TreeNode? + public var right: TreeNode? + public init(_ val: Int) { + self.val = val + self.left = nil + self.right = nil + } +} + +class Solution { + + var preIndex = 0 + var indexMap: [Int: Int] = Dictionary() + var inorder, preorder: [Int] + + func buildTree(_ preorder: [Int], _ inorder: [Int]) -> TreeNode? { + + } + + func buildTree0(_ preorder: [Int], _ inorder: [Int]) -> TreeNode? { + self.preorder = preorder; self.inorder = inorder + for (item, index) in inorder.enumerated() { + indexMap[item] = index + } + return _helper(0, preorder.count) + } + + func _helper(_ inLeft: Int, _ inRight: Int) -> TreeNode? { + if inLeft == inRight {return nil} + let rootVal = self.preorder[preIndex] + let root = TreeNode(rootVal) + if let index = self.inorder.firstIndex(of: rootVal) { + preIndex += 1 + root.left = _helper(inLeft, index) + root.right = _helper(index + 1, inRight) + return root + } + return nil + } +} +// @lc code=end + diff --git "a/Week_02/G20200343030369/144.\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\351\201\215\345\216\206.swift" "b/Week_02/G20200343030369/144.\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\351\201\215\345\216\206.swift" new file mode 100644 index 00000000..1c9c8ccb --- /dev/null +++ "b/Week_02/G20200343030369/144.\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\351\201\215\345\216\206.swift" @@ -0,0 +1,87 @@ +/* + * @lc app=leetcode.cn id=144 lang=golang + * + * [144] 二叉树的前序遍历 + * + * https://leetcode-cn.com/problems/binary-tree-preorder-traversal/description/ + * + * algorithms + * Medium (64.00%) + * Likes: 207 + * Dislikes: 0 + * Total Accepted: 69.3K + * Total Submissions: 108K + * Testcase Example: '[1,null,2,3]' + * + * 给定一个二叉树,返回它的 前序 遍历。 + * + * 示例: + * + * 输入: [1,null,2,3] + * ⁠ 1 + * ⁠ \ + * ⁠ 2 + * ⁠ / + * ⁠ 3 + * + * 输出: [1,2,3] + * + * + * 进阶: 递归算法很简单,你可以通过迭代算法完成吗? + * + */ + +// @lc code=start +/** + * Definition for a binary tree node. + * type TreeNode struct { + * Val int + * Left *TreeNode + * Right *TreeNode + * } + */ + +public class TreeNode { + var val: Int + var left, right: TreeNode? + init(_ val: Int) { + self.val = val + } +} + +class Solution { + func preorderTraversal(_ root: TreeNode?) -> [Int] { + + } + + // 递归 + func preorderTraversal0(_ root: TreeNode?) -> [Int] { + guard let p = root else {return []} + var res: [Int] = [p.val] + res.append(contentsOf: preorderTraversal0(p.left)) + res.append(contentsOf: preorderTraversal0(p.right)) + return res + } + + // 迭代 + func preorderTraversal1(_ root: TreeNode?) -> [Int] { + if root == nil {return []} + var res: [Int] = Array(), stack: [TreeNode] = Array() + var p = root + stack.append(p!) + while !stack.isEmpty { + p = stack.popLast()! + res.append(p!.val) + if p!.right != nil { + stack.append(p!.right!) + } + if p!.left != nil { + stack.append(p!.left!) + } + } + return res + } +} + +// @lc code=end + diff --git "a/Week_02/G20200343030369/236.\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\350\277\221\345\205\254\345\205\261\347\245\226\345\205\210.go" "b/Week_02/G20200343030369/236.\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\350\277\221\345\205\254\345\205\261\347\245\226\345\205\210.go" new file mode 100644 index 00000000..5a68e2d0 --- /dev/null +++ "b/Week_02/G20200343030369/236.\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\350\277\221\345\205\254\345\205\261\347\245\226\345\205\210.go" @@ -0,0 +1,86 @@ +/* + * @lc app=leetcode.cn id=236 lang=golang + * + * [236] 二叉树的最近公共祖先 + * + * https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-tree/description/ + * + * algorithms + * Medium (59.69%) + * Likes: 380 + * Dislikes: 0 + * Total Accepted: 45.3K + * Total Submissions: 75.5K + * Testcase Example: '[3,5,1,6,2,0,8,null,null,7,4]\n5\n1' + * + * 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。 + * + * 百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x + * 的深度尽可能大(一个节点也可以是它自己的祖先)。” + * + * 例如,给定如下二叉树:  root = [3,5,1,6,2,0,8,null,null,7,4] + * + * + * + * + * + * 示例 1: + * + * 输入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1 + * 输出: 3 + * 解释: 节点 5 和节点 1 的最近公共祖先是节点 3。 + * + * + * 示例 2: + * + * 输入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4 + * 输出: 5 + * 解释: 节点 5 和节点 4 的最近公共祖先是节点 5。因为根据定义最近公共祖先节点可以为节点本身。 + * + * + * + * + * 说明: + * + * + * 所有节点的值都是唯一的。 + * p、q 为不同节点且均存在于给定的二叉树中。 + * + * + */ + +// @lc code=start + +package leetcode + +type TreeNode struct { + Val int + Left *TreeNode + Right *TreeNode +} + +func lowestCommonAncestor(root, p, q *TreeNode) *TreeNode { + +} + +var ancestor *TreeNode = nil +func lowestCommonAncestor0(root, p, q *TreeNode) *TreeNode { + _helper(root, p, q) + return ancestor +} + +func _helper(root, p, q *TreeNode) bool { + if root == nil {return false} + leftOK := _helper(root.Left, p, q) + rightOK := _helper(root.Right, p, q) + midOK := false + if root == p || root == q {midOK = true} + if leftOK && midOK || rightOK && midOK || leftOK && rightOK { + ancestor = root + } + return leftOK || rightOK || midOK +} + + +// @lc code=end + diff --git "a/Week_02/G20200343030369/49.\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215\345\210\206\347\273\204.swift" "b/Week_02/G20200343030369/49.\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215\345\210\206\347\273\204.swift" new file mode 100644 index 00000000..5213d230 --- /dev/null +++ "b/Week_02/G20200343030369/49.\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215\345\210\206\347\273\204.swift" @@ -0,0 +1,62 @@ +/* + * @lc app=leetcode.cn id=49 lang=golang + * + * [49] 字母异位词分组 + * + * https://leetcode-cn.com/problems/group-anagrams/description/ + * + * algorithms + * Medium (60.66%) + * Likes: 269 + * Dislikes: 0 + * Total Accepted: 51.1K + * Total Submissions: 84.1K + * Testcase Example: '["eat","tea","tan","ate","nat","bat"]' + * + * 给定一个字符串数组,将字母异位词组合在一起。字母异位词指字母相同,但排列不同的字符串。 + * + * 示例: + * + * 输入: ["eat", "tea", "tan", "ate", "nat", "bat"], + * 输出: + * [ + * ⁠ ["ate","eat","tea"], + * ⁠ ["nat","tan"], + * ⁠ ["bat"] + * ] + * + * 说明: + * + * + * 所有输入均为小写字母。 + * 不考虑答案输出的顺序。 + * + * + */ + +// @lc code=start +class Solution { + func groupAnagrams(_ strs: [String]) -> [[String]] { + + } + + // 哈希表 + func groupAnagrams0(_ strs: [String]) -> [[String]] { + var groups: [String: [String]] = Dictionary() + for s in strs { + let key = String(s.sorted()) + var g: [String] + if groups[key] != nil { + g = [String](groups[key]!) + } else { + g = Array() + } + g.append(s) + groups[key] = g + } + return [[String]](groups.values) + } +} + +// @lc code=end + diff --git "a/Week_02/G20200343030369/77.\347\273\204\345\220\210.swift" "b/Week_02/G20200343030369/77.\347\273\204\345\220\210.swift" new file mode 100644 index 00000000..adf14ed4 --- /dev/null +++ "b/Week_02/G20200343030369/77.\347\273\204\345\220\210.swift" @@ -0,0 +1,62 @@ +/* + * @lc app=leetcode.cn id=77 lang=golang + * + * [77] 组合 + * + * https://leetcode-cn.com/problems/combinations/description/ + * + * algorithms + * Medium (72.62%) + * Likes: 220 + * Dislikes: 0 + * Total Accepted: 35K + * Total Submissions: 48K + * Testcase Example: '4\n2' + * + * 给定两个整数 n 和 k,返回 1 ... n 中所有可能的 k 个数的组合。 + * + * 示例: + * + * 输入: n = 4, k = 2 + * 输出: + * [ + * ⁠ [2,4], + * ⁠ [3,4], + * ⁠ [2,3], + * ⁠ [1,2], + * ⁠ [1,3], + * ⁠ [1,4], + * ] + * + */ + +// @lc code=start +class Solution { + func combine(_ n: Int, _ k: Int) -> [[Int]] { + + } + + func combine0(_ n: Int, _ k: Int) -> [[Int]] { + + } + + func _helper(_ i: Int, _ n: Int, _ k: Int) -> [[Int]] { + var res: [[Int]] = Array() + if k == 1 { + for j in i...n { + res.append([j]) + } + return res + } + + + for j in i...n-k+1 { + for arr in _helper(j + 1, n, k - 1) { + res.append([j] + arr) + } + } + return res + } +} +// @lc code=end + diff --git a/Week_02/G20200343030373/LeetCode_104_373/LeetCode_104_373_test.go b/Week_02/G20200343030373/LeetCode_104_373/LeetCode_104_373_test.go new file mode 100644 index 00000000..cb79de11 --- /dev/null +++ b/Week_02/G20200343030373/LeetCode_104_373/LeetCode_104_373_test.go @@ -0,0 +1,87 @@ +//https://leetcode-cn.com/problems/maximum-depth-of-binary-tree/ +package max_depth_binary_tree_test + +import ( + "github.com/stretchr/testify/assert" + "testing" +) + +func TestMaxDepth(t *testing.T) { + t.Log("Max Depth of Binary Tree: BFS, DFS") + + root := TreeNode{ + Val: 3, + Left: &TreeNode{ + Val: 9, + Left: nil, + Right: nil, + }, + Right: &TreeNode{ + Val: 20, + Left: &TreeNode{ + Val: 15, + Left: nil, + Right: nil, + }, + Right: &TreeNode{ + Val: 7, + Left: nil, + Right: nil, + }, + }, + } + assert.Equal(t, 3, maxDepth(&root)) + assert.Equal(t, 3, dfsMaxDepth(&root)) + assert.Equal(t, 3, bfsMaxDepth(&root)) +} + +type TreeNode struct { + Val int + Left *TreeNode + Right *TreeNode +} + +func maxDepth(root *TreeNode) int { + return dfsMaxDepth(root) +} + +func max(a, b int) int { + if a > b { + return a + } + return b +} + +func dfsMaxDepth(root *TreeNode) int { + //递归终止条件,当前节点为空 + if root == nil { + return 0 + } + return 1 + max(dfsMaxDepth(root.Left), dfsMaxDepth(root.Right)) +} + +func bfsMaxDepth(root *TreeNode) int { + if root == nil { + return 0 + } + + var queue []*TreeNode //BFS使用队列 + queue = append(queue, root) //根节点入队 + depth := 0 //初始化深度为0,MinDepth初始化为1 + + for len(queue) > 0 { + n := len(queue) //怎样确定本层结束?Batch Process,获得长度后再遍历 + for i := 0; i < n; i++ { //遍历当前层的各个节点 + root = queue[0] //以当前节点作为根节点,将其左右子节点入队 + queue = queue[1:] + if root.Left != nil { + queue = append(queue, root.Left) + } + if root.Right != nil { + queue = append(queue, root.Right) + } + } + depth++ //本层结束后,深度累加;什么时候是最大深度?BFS遍历结束后即是最大深度 + } + return depth +} diff --git a/Week_02/G20200343030373/LeetCode_111_373/LeetCode_111_373_test.go b/Week_02/G20200343030373/LeetCode_111_373/LeetCode_111_373_test.go new file mode 100644 index 00000000..6786da6b --- /dev/null +++ b/Week_02/G20200343030373/LeetCode_111_373/LeetCode_111_373_test.go @@ -0,0 +1,148 @@ +//https://leetcode-cn.com/problems/minimum-depth-of-binary-tree/ +package min_depth_binary_tree_test + +import ( + "github.com/stretchr/testify/assert" + "testing" +) + +func TestMinDepth(t *testing.T) { + t.Log("Min Depth of Binary Tree: BFS, DFS") + + root := TreeNode{ + Val: 3, + Left: &TreeNode{ + Val: 9, + Left: nil, + Right: nil, + }, + Right: &TreeNode{ + Val: 20, + Left: &TreeNode{ + Val: 15, + Left: nil, + Right: nil, + }, + Right: &TreeNode{ + Val: 7, + Left: nil, + Right: nil, + }, + }, + } + assert.Equal(t, 2, minDepth(&root)) + assert.Equal(t, 2, dfsOriginal(&root)) + assert.Equal(t, 2, dfsSimplified(&root)) + assert.Equal(t, 2, bfsMinDepth(&root)) + + root1 := TreeNode{ + Val: 1, + Left: &TreeNode{ + Val: 2, + Left: nil, + Right: nil, + }, + Right: nil, + } + assert.Equal(t, 2, minDepth(&root1)) + assert.Equal(t, 2, dfsOriginal(&root1)) + assert.Equal(t, 2, dfsSimplified(&root1)) + assert.Equal(t, 2, bfsMinDepth(&root1)) +} + +type TreeNode struct { + Val int + Left *TreeNode + Right *TreeNode +} + +func minDepth(root *TreeNode) int { + return dfsSimplified(root) +} + +func min(a, b int) int { + if a < b { + return a + } + return b +} + +//dfs original +func dfsOriginal(root *TreeNode) int { + if root == nil { + return 0 + } + + //当左右孩子都为空时,返回1 + if root.Left == nil && root.Right == nil { + return 1 + } + + left := dfsOriginal(root.Left) + right := dfsOriginal(root.Right) + + //当左右孩子又一个为空时,返回不为空的深度 + if root.Left == nil { + return 1 + right + } + if root.Right == nil { + return 1 + left + } + + //最后,当左右孩子都不为空时,返回左右较小的深度 + return 1 + min(left, right) +} + +//dfs original -> simplified +func dfsSimplified(root *TreeNode) int { + if root == nil { + return 0 + } + + left := dfsOriginal(root.Left) + right := dfsOriginal(root.Right) + + //简化:左或右为空时,即为0 + if root.Left == nil || root.Right == nil { + return 1 + left + right + } + + return 1 + min(left, right) +} + +//bfs +func bfsMinDepth(root *TreeNode) int { + if root == nil { + return 0 + } + + var queue []*TreeNode + queue = append(queue, root) + + //初始化深度为1, MaxDepth初始化为0 - 容易出错! + //max是遍历完当前层后再返回,所以从0自加 + //min是在当前层就有可能直接返回,所以先设置为1,否则可能没机会自加 + depth := 1 + + for len(queue) > 0 { + n := len(queue) + for i := 0; i < n; i++ { + root := queue[0] + queue = queue[1:] + + //找到第一个叶子节点后直接返回 + if root.Left == nil && root.Right == nil { + return depth + } + + if root.Left != nil { + queue = append(queue, root.Left) + } + if root.Right != nil { + queue = append(queue, root.Right) + } + } + depth++ + } + return depth //肯定会在第一个叶子节点出返回,此处不会走到 +} diff --git a/Week_02/G20200343030373/LeetCode_1_373/LeetCode_1_373_test.go b/Week_02/G20200343030373/LeetCode_1_373/LeetCode_1_373_test.go new file mode 100644 index 00000000..968bf063 --- /dev/null +++ b/Week_02/G20200343030373/LeetCode_1_373/LeetCode_1_373_test.go @@ -0,0 +1,36 @@ +//https://leetcode-cn.com/problems/two-sum/ +package two_sum_test + +import ( + "github.com/stretchr/testify/assert" + "testing" +) + +func TestTwoSum(t *testing.T) { + t.Log("Two Sum") + + target := 9 + nums := []int{2, 7, 11, 15} + expect := []int{0, 1} + assert.Equal(t, expect, twoSum(nums, target)) + + target1 := 6 + nums1 := []int{3, 3} + expect1 := []int{0, 1} + assert.Equal(t, expect1, twoSum(nums1, target1)) +} + +func twoSum(nums []int, target int) []int { + myMap := make(map[int]int) + for index, value := range nums { + //TwoSum: 将'target-当前值'作为key存入Map,当前值的索引作为value存入Map; + //遍历后面的元素,如果'后面的元素值'作为Map的key已经存在,则找到,返回索引 + //Special: '后面的元素值'存在于Map的既有索引值,例如3+3=6,不应该覆盖 + if vIndexOld, ok := myMap[value]; !ok { + myMap[target-value] = index + } else { + return []int{vIndexOld, index} + } + } + return nil +} diff --git a/Week_02/G20200343030373/LeetCode_22_373/LeetCode_22_373_test.go b/Week_02/G20200343030373/LeetCode_22_373/LeetCode_22_373_test.go new file mode 100644 index 00000000..c217dec2 --- /dev/null +++ b/Week_02/G20200343030373/LeetCode_22_373/LeetCode_22_373_test.go @@ -0,0 +1,48 @@ +//https://leetcode-cn.com/problems/generate-parentheses/ +package generate_parentheses_test + +import ( + "github.com/stretchr/testify/assert" + "testing" +) + +func TestGenerateParentheses(t *testing.T) { + t.Log("Generate Parentheses") + + expect := []string{ + "((()))", + "(()())", + "(())()", + "()(())", + "()()()", + } + assert.Equal(t, expect, generateParenthesis(3)) +} + +//字符串长度为2n,每个元素有两种选择,则O(2^(2n)),再判断合法 +//改进,DFS+Prune +//记录左右括号各使用多少个,最多n +//保证左括号比右括号先用 +//O(2^n) +func generateParenthesis(n int) []string { + if n <= 0 { + return []string{} + } + var result []string + generateOneByOne(&result, "", n, n) + return result +} + +func generateOneByOne(result *[]string, sublist string, left, right int) { + if left == 0 && right == 0 { + *result = append(*result, sublist) + return + } + + if left > 0 { //left和right的个数为n + generateOneByOne(result, sublist+"(", left-1, right) + } + if right > left { //剩余右括号比左括号多:左括号先用,右括号后用 - 则无需在判断right>0 + generateOneByOne(result, sublist+")", left, right-1) + } +} diff --git a/Week_02/G20200343030373/LeetCode_236_373/LeetCode_236_373_test.go b/Week_02/G20200343030373/LeetCode_236_373/LeetCode_236_373_test.go new file mode 100644 index 00000000..980e6b78 --- /dev/null +++ b/Week_02/G20200343030373/LeetCode_236_373/LeetCode_236_373_test.go @@ -0,0 +1,101 @@ +//https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-tree/ +package lowest_common_ancestor_BT_test + +import ( + "github.com/stretchr/testify/assert" + "testing" +) + +func TestLowestAncestorBT(t *testing.T) { + node1 := TreeNode{ + Val: 7, + Left: nil, + Right: nil, + } + + node2 := TreeNode{ + Val: 4, + Left: nil, + Right: nil, + } + + node3 := TreeNode{ + Val: 6, + Left: nil, + Right: nil, + } + + node4 := TreeNode{ + Val: 2, + Left: &node1, + Right: &node2, + } + + node5 := TreeNode{ + Val: 0, + Left: nil, + Right: nil, + } + + node6 := TreeNode{ + Val: 8, + Left: nil, + Right: nil, + } + + node7 := TreeNode{ + Val: 5, + Left: &node3, + Right: &node4, + } + + node8 := TreeNode{ + Val: 1, + Left: &node5, + Right: &node6, + } + + root := TreeNode{ + Val: 3, + Left: &node7, + Right: &node8, + } + + assert.Equal(t, 3, lowestCommonAncestor(&root, &node7, &node8).Val) + assert.Equal(t, 5, lowestCommonAncestor(&root, &node7, &node2).Val) +} + +type TreeNode struct { + Val int + Left *TreeNode + Right *TreeNode +} + +func lowestCommonAncestor(root, p, q *TreeNode) *TreeNode { + //如果当前节点为空,返回空 + if root == nil { + return root + } + + //如果当前节点就是目标节点p或q,则返回当前节点 + if root == p || root == q { + return root + } + + //递归到左右子树上处理 + left := lowestCommonAncestor(root.Left, p, q) + right := lowestCommonAncestor(root.Right, p, q) + + //如果左右子树上各找到一个节点,则当前根节点root就是最小公共祖先 + //如果只有一个非空,则返回那个非空的节点 + //如果都为空,则返回空指针 + if left != nil && right != nil { + return root + } else if left != nil { + return left + } else if right != nil { + return right + } else { + return nil + } +} diff --git a/Week_02/G20200343030373/LeetCode_242_373/LeetCode_242_373_test.go b/Week_02/G20200343030373/LeetCode_242_373/LeetCode_242_373_test.go new file mode 100644 index 00000000..800ca4ae --- /dev/null +++ b/Week_02/G20200343030373/LeetCode_242_373/LeetCode_242_373_test.go @@ -0,0 +1,64 @@ +//https://leetcode-cn.com/problems/valid-anagram/ +package valid_anagram_test + +import ( + "github.com/stretchr/testify/assert" + "reflect" + "testing" +) + +func TestValidAnagram(t *testing.T) { + t.Log("Valid Anagram - Map") + + s1 := "anagram" + t1 := "nagaram" + assert.Equal(t, true, isAnagram(s1, t1)) + assert.Equal(t, true, isAnagramOneMapUnicode(s1, t1)) + assert.Equal(t, true, isAnagramTwoMap(s1, t1)) + + s2 := "rat" + t2 := "car" + assert.Equal(t, false, isAnagram(s2, t2)) + assert.Equal(t, false, isAnagramOneMapUnicode(s2, t2)) + assert.Equal(t, false, isAnagramTwoMap(s2, t2)) +} + +func isAnagram(s string, t string) bool { + return isAnagramOneMapUnicode(s, t) +} + +func isAnagramOneMapUnicode(s string, t string) bool { + //字母异位词的字符数相等,则len取出的字节数也必相等 + //注意:字节数相等,字符数不一定相等 + if len(s) != len(t) { + return false + } + //rune,可兼容string和unicode + hash := make(map[rune]int, len(s)) + //range string 得到的是rune,也就是int32,如需使用string需类型转换 + //index of string 得到的是byte,不是rune + for i := 0; i < len(s); i++ { + hash[rune(s[i])]++ + hash[rune(t[i])]-- + } + for _, v := range hash { + if v != 0 { + return false + } + } + return true +} + +func isAnagramTwoMap(s string, t string) bool { + sMap, tMap := make(map[string]int), make(map[string]int) + + for _, v := range s { + sMap[string(v)]++ + } + + for _, v := range t { + tMap[string(v)]++ + } + + return reflect.DeepEqual(sMap, tMap) +} diff --git a/Week_02/G20200343030373/LeetCode_49_373/LeetCode_49_373_test.go b/Week_02/G20200343030373/LeetCode_49_373/LeetCode_49_373_test.go new file mode 100644 index 00000000..04cec491 --- /dev/null +++ b/Week_02/G20200343030373/LeetCode_49_373/LeetCode_49_373_test.go @@ -0,0 +1,73 @@ +//https://leetcode-cn.com/problems/group-anagrams/ +package group_anagrams_test + +//ToDo +import ( + "sort" + "strconv" + "testing" +) + +func TestGroupAnagrams(t *testing.T) { + t.Log("Group Anagrams") +} + +func groupAnagrams(strs []string) [][]string { + return mapCompare(strs) +} + +//方法1:字符串排序 +//O(n*klogk), k是字符串数组中最大字符串的长度 +//O(n*k) +func stringSort(strs []string) [][]string { + var res [][]string + record := make(map[string][]string) + for _, str := range strs { + s := []rune(str) // 把错位词的字符顺序重新排列,那么会得到相同的结果 + sort.Sort(sortRunes(s)) // 以此作为key,将所有错位词都保存到字符串数组中 + val, _ := record[string(s)] // 建立key和字符串数组之间的映射 + val = append(val, str) + record[string(s)] = val + } + for _, v := range record { + res = append(res, v) + } + return res +} + +type sortRunes []rune + +func (s sortRunes) Len() int { return len(s) } +func (s sortRunes) Less(i, j int) bool { return s[i] < s[j] } +func (s sortRunes) Swap(i, j int) { s[i], s[j] = s[j], s[i] } + +//方法2:Map +//用一个大小为26的int数组来统计每个单词中字符出现的次数 +//然后将int数组转为一个唯一的字符串,跟字符串数组进行映射 +//O(n*k), O(n*k) +func mapCompare(strs []string) [][]string { + var res [][]string + m := make(map[string][]string) + for _, str := range strs { + key := getKey(str) + m[key] = append(m[key], str) + } + for _, v := range m { + res = append(res, v) + } + return res +} + +// 用一个大小为26的int数组来统计每个单词中字符出现的次数, +// 然后将int数组转为一个唯一的字符串,跟字符串数组进行映射, +func getKey(s string) string { + freq := make([]int, 26) + for _, c := range s { + freq[c-'a']++ + } + key := "" + for _, n := range freq { + key += strconv.Itoa(n) + "/" + } + return key +} diff --git a/Week_02/G20200343030373/LeetCode_509_373/LeetCode_509_373_test.go b/Week_02/G20200343030373/LeetCode_509_373/LeetCode_509_373_test.go new file mode 100644 index 00000000..611f24c0 --- /dev/null +++ b/Week_02/G20200343030373/LeetCode_509_373/LeetCode_509_373_test.go @@ -0,0 +1,213 @@ +//https://leetcode-cn.com/problems/fibonacci-number/ +//https://leetcode-cn.com/problems/powx-n/ +//https://leetcode-cn.com/problems/sqrtx/ +package fibonacci_test + +import ( + "github.com/stretchr/testify/assert" + "math" + "testing" +) + +func TestFib(t *testing.T) { + //Fibonacci + //0,1,1,2,3,5,8,13 + assert.Equal(t, 13, fib(7)) + assert.Equal(t, 13, recursionFib(7)) + assert.Equal(t, 13, memorizeFib(7)) + assert.Equal(t, 13, dpFib(7)) + assert.Equal(t, 13, dpSpaceFib(7)) + assert.Equal(t, 13, formulaFib(7)) + assert.Equal(t, 13, tableFib(7)) + assert.Equal(t, 13, matrixFib(7)) + assert.Equal(t, 13, tailRecursionFib(7, 0, 1, 2)) + + //公式法举例 + //1+2+3+4=10 + n := 4 + sum1 := 0 + for i := 1; i <= n; i++ { + sum1 += i + } + sum2 := n * (n + 1) / 2 + assert.Equal(t, 10, sum1) //O(n) + assert.Equal(t, 10, sum2) //O(1) + + //power(x,n) + //sqrt(x) +} + +func fib(N int) int { + return matrixFib(N) +} + +//method1: recursion +//Go中无三目运算符 +//TC: O(2^n), SC:O(n) - 递归调用栈的空间 +//AC, 12ms +func recursionFib(n int) int { + //terminator + if n <= 1 { + return n + } + //process + //drill down + return recursionFib(n-1) + recursionFib(n-2) + //clear +} + +//method2: speedup2-1 - space to time - memorize or cache +//if n >= 2, 算过一次就存储起来,递归下次使用时直接取(缓存的概念,O(1)) +//TC: O(n), SC: O(n) +//AC, 0ms +var hash = make(map[int]int) + +func memorizeFib(n int) int { + if n <= 1 { + return n + } + if _, ok := hash[n]; !ok { + hash[n] = memorizeFib(n-1) + memorizeFib(n-2) + } + return hash[n] +} + +//method3: dp = recursion + memorize = transition +//recursion: 下沉后,反向返回结果 +//transition: 正向递推 +//TC: O(n), SC: O(n) +func dpFib(n int) int { + //状态定义: dp[i], 累加到当前位置的结果值 + //初始值: dp[0], dp[1] + //最终值: dp[n] + //状态方程: dp[i]=dp[i-1]+dp[i-2] + if n <= 1 { + return n + } + dp := make([]int, n+1) //因为要使用n,所以长度是n+1 + dp[0], dp[1] = 0, 1 + for i := 2; i <= n; i++ { + dp[i] = dp[i-1] + dp[i-2] + } + return dp[n] +} + +//method4: dp - space decrease +//dp[]存储了每个步骤的值,但最终结果只需要比它小前两个的结果,所以可以通过变量滚动 +//TC: O(n), SC: O(1) +func dpSpaceFib(n int) int { + //prePre, pre + //0, 1 + //pre + //prePre, pre = pre, prePre+pre + if n <= 1 { + return n + } + prePre, pre := 0, 1 + for i := 2; i <= n; i++ { + pre, prePre = prePre+pre, pre + } + return pre +} + +//method5: 通项公式法 +//f(n) = a1(b1)^n + a2(b2)^n +//b1 = (1 + √5)/2 (goldenRatio) +//b2 = (1 - √5)/2 +//a1 = 1/√5 +//a2 = -1/√5 +//b2^n , b2是小于1的数,幂次会在最后四舍五入时省略 +//最终结果:f(n) = (goldenRation^n)/√5 +//TC: O(logn), SC: O(logn) - math.Pow的实现 +func formulaFib(n int) int { + goldenRatio := (1 + math.Sqrt(5)) / 2 + fn := math.Pow(goldenRatio, float64(n)) / math.Sqrt(5) + return int(math.Round(fn)) +} + +//method6: 矩阵求幂 +//线代公式: +//x y = a b * e f +//z w c d g h +//则 +//x = ae + bg +//y = af + bh +//z = ce + dg +//w = cf + dh +//代入fib: +//f(n) 0 = f(n-1) 0 * 1 1 = f(1) * 1 1 ^n-1 +//f(n-1) 0 f(n-2) 0 1 0 f(0) 1 0 +//最终方案:求power(A,N) +//最终结果:可见f(n)在最终的A[0,0]上 +//TC: O(logn) SC: O(logn) - x^n递归时使用栈空间 +//speedup2-2: 升维 +func matrixFib(n int) int { + if n <= 1 { + return n + } + A := [2][2]int{ + {1, 1}, + {1, 0}, + } + A = matrixPower(A, n-1) + return A[0][0] +} + +//x^n +//method1: recursion + divide&conquer +//power(a,n), a是正数,n是自然数,只需要考虑n的奇偶性 +//递归+分治,O(logn) +func matrixPower(A [2][2]int, n int) [2][2]int { + //terminator + if n <= 1 { + return A + } + //process + //drill down + R := matrixPower(A, n/2) + //clear + if n&1 == 1 { + return multiply(A, multiply(R, R)) + } + return multiply(R, R) +} + +//线代公式 +func multiply(A [2][2]int, B [2][2]int) [2][2]int { + x := A[0][0]*B[0][0] + A[0][1]*B[1][0] + y := A[0][0]*B[0][1] + A[0][1]*B[1][1] + z := A[1][0]*B[0][0] + A[1][1]*B[0][1] + w := A[1][0]*B[0][1] + A[1][1]*B[1][1] + + A[0][0] = x + A[0][1] = y + A[1][0] = z + A[1][1] = w + + return A +} + +//method7: table +//leetcode: 0 <= n <= 30 +//TC: O(1) :) +var fibs = [31]int{0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946, 17711, 28657, 46368, 75025, 121393, 196418, 317811, 514229, 832040} + +func tableFib(n int) int { + return fibs[n] +} + +//method8: tail recursion +//对递归的优化手段一般是尾递归 +//尾递归是指,在函数返回的时候,调用自身本身,并且return语句不能包含表达式 +//这样,编译器就可以对尾递归做优化,使递归无论调用多少次,都只占用一个栈帧,栈不会增长,不会出现栈溢出 +//recursionFib(4), 6次调用 +//tailRecursionFib(4), 2次调用 +func tailRecursionFib(n int, b1, b2 int, c int) int { + if n <= 1 { + return n + } + if n == c { + return b1 + b2 + } + return tailRecursionFib(n, b2, b1+b2, c+1) +} diff --git a/Week_02/G20200343030373/LeetCode_70_373/LeetCode_70_373_test.go b/Week_02/G20200343030373/LeetCode_70_373/LeetCode_70_373_test.go new file mode 100644 index 00000000..c66727b2 --- /dev/null +++ b/Week_02/G20200343030373/LeetCode_70_373/LeetCode_70_373_test.go @@ -0,0 +1,346 @@ +//https://leetcode-cn.com/problems/climbing-stairs/description/ +package climb_stair_test + +import ( + "github.com/stretchr/testify/assert" + "math" + "testing" +) + +func TestDP(t *testing.T) { + t.Log("Climbing Stairs: DP Fibonacci") + //题目描述,给定n是一个正整数,即n从1开始 + //n: 1, 2, 3, 4, 5... + //f: 1, 2, 3, 5, 8... + //区别Fibonacci, 爬楼梯n从1开始,斐波那次n从0开始;爬楼梯题目的 i和n 分别要比斐波那契 多1 + assert.Equal(t, 2, climbStairs(2)) + assert.Equal(t, 5, climbStairs(4)) + assert.Equal(t, 5, resOriginal(4)) + assert.Equal(t, 5, resMemoOut(4)) + assert.Equal(t, 5, resMemoIn(4)) + assert.Equal(t, 5, dpOriginal(4)) + assert.Equal(t, 5, dpShrink(4)) + assert.Equal(t, 5, formula(4)) + assert.Equal(t, 5, matrix(4)) + + //升级1:每次可以走1,2,3步 + assert.Equal(t, 4, dpStep3(3)) + assert.Equal(t, 7, dpStep3(4)) + assert.Equal(t, 13, dpStep3(5)) + assert.Equal(t, 24, dpStep3(6)) + + //升级2:每次可以走1,2,3步,前后走的步数不能重复 + assert.Equal(t, 3, dpStep3NoRepeat1(3)) + assert.Equal(t, 3, dpStep3NoRepeat1(4)) + assert.Equal(t, 4, dpStep3NoRepeat1(5)) + assert.Equal(t, 8, dpStep3NoRepeat2(6)) + assert.Equal(t, 9, dpStep3NoRepeat2(7)) + + //升级3:每次走的步数是在一个数组里定义的,类似coin change; 且不重复 + //步数数组首先要去重(必须),然后最好排序(非必须) + //直白版 与 美化版 + steps := []int{1, 2, 3} + assert.Equal(t, 3, dpSteps(3, steps)) + assert.Equal(t, 3, dpSteps(4, steps)) + assert.Equal(t, 4, dpSteps(5, steps)) + assert.Equal(t, 8, dpSteps2(6, steps)) + assert.Equal(t, 9, dpSteps2(7, steps)) + + //升级4:每次可以走1,2,3,..., m步,m<=n + //纯记忆:前m阶初始值是2^(m-1)种,后面m+1是dp[i] = dp[i-1]*2 - dp[i-m-1] + //https://www.cnblogs.com/wxdjss/p/5450749.html + assert.Equal(t, 5, dpStepM(4, 2)) + assert.Equal(t, 29, dpStepM(6, 4)) + assert.Equal(t, 31, dpStepM(6, 5)) +} + +func climbStairs(n int) int { + return matrix(n) +} + +//1. original recursion +//Not AC, TimeOut +func resOriginal(n int) int { + if n <= 2 { //区别Fibonacci + return n + } + return resOriginal(n-1) + resOriginal(n-2) +} + +//2.1. recursion + memory +var hash = make(map[int]int) + +func resMemoOut(n int) int { + if n <= 2 { + return n + } + if _, ok := hash[n]; !ok { + hash[n] = resMemoOut(n-1) + resMemoOut(n-2) + } + return hash[n] +} + +//2.2. recursion + memory + drill down the memory +func resMemoIn(n int) int { + hash := make(map[int]int) + return resMemo(n, hash) +} + +func resMemo(n int, hash map[int]int) int { + if n <= 2 { + hash[n] = n + return hash[n] + } + if _, ok := hash[n]; !ok { + hash[n] = resMemo(n-1, hash) + resMemo(n-2, hash) + } + return hash[n] +} + +//3. dp original +func dpOriginal(n int) int { + if n <= 2 { + return n + } + dp := make([]int, n+1) + dp[1], dp[2] = 1, 2 //区别Fibonacci + for i := 3; i <= n; i++ { //区别Fibonacci + dp[i] = dp[i-1] + dp[i-2] + } + return dp[n] +} + +//4. dp + shrink space +func dpShrink(n int) int { + if n <= 2 { + return n + } + low, high := 1, 2 + for i := 3; i <= n; i++ { + high, low = high+low, high + } + return high +} + +//5. formula +func formula(n int) int { + goldenRation := (1 + math.Sqrt(5)) / 2 + res := math.Pow(goldenRation, float64(n+1)) / math.Sqrt(5) //区别 Fibonacci + return int(math.Round(res)) +} + +//6. matrix +func matrix(n int) int { + if n <= 2 { + return n + } + + A := [2][2]int{ + {1, 1}, + {1, 0}, + } + + A = pow(A, n) //区别Fibonacci + return A[0][0] +} + +func pow(A [2][2]int, n int) [2][2]int { + if n <= 1 { + return A + } //递归终止条件,n<=1;与Power n==0 不同 + + R := pow(A, n/2) + + if n&1 == 1 { + return mul(A, mul(R, R)) + } + return mul(R, R) +} + +func mul(A, B [2][2]int) [2][2]int { + x := A[0][0]*B[0][0] + A[0][1]*B[1][0] + y := A[0][0]*B[0][1] + A[0][1]*B[1][1] + z := A[1][0]*B[0][0] + A[1][1]*B[0][1] + w := A[1][0]*B[0][1] + A[1][1]*B[1][1] + + A[0][0] = x + A[0][1] = y + A[1][0] = z + A[1][1] = w + + return A +} + +//升级1:每次可以走1,2,3步 +func dpStep3(n int) int { + if n <= 1 { + return 1 + } + dp := make([]int, n+1) + dp[1], dp[2] = 1, 2 + dp[3] = 1 + dp[2] + dp[1] + for i := 4; i <= n; i++ { + dp[i] = dp[i-1] + dp[i-2] + dp[i-3] + } + return dp[n] +} + +//升级2:前后走的步数不能重复 +//升维,上一步走的步数 +func dpStep3NoRepeat1(n int) int { + if n == 1 { + return 1 + } + dp := make([][4]int, n+1) + dp[1][1], dp[1][2], dp[1][3] = 1, 0, 0 + dp[2][1], dp[2][2], dp[2][3] = 0, 1, 0 + dp[3][1], dp[3][2], dp[3][3] = 1, 1, 1 //之前走了1步上来的第3个台阶,且不重复,的情况种类是1种 + for i := 4; i <= n; i++ { //遍历每一层台阶 + for last := 1; last <= 3; last++ { //以last步到达的当前台阶 + dp[i][last] = dp[i-last][1] + dp[i-last][2] + dp[i-last][3] - dp[i-last][last] + } + } + return dp[n][1] + dp[n][2] + dp[n][3] +} + +func dpStep3NoRepeat2(n int) int { + if n == 1 { + return 1 + } + dp := make([][4]int, n+1) + dp[1][1], dp[1][2], dp[1][3] = 1, 0, 0 + dp[2][1], dp[2][2], dp[2][3] = 0, 1, 0 + dp[3][1], dp[3][2], dp[3][3] = 1, 1, 1 //之前走了1步上来的第3个台阶,且不重复,的情况种类是1种 + for i := 4; i <= n; i++ { //遍历每一层台阶 + for last := 1; last <= 3; last++ { //以last步到达的当前台阶 + //dp[i][last] = dp[i-last][1] + dp[i-last][2] + dp[i-last][3] - dp[i-last][last] + for pre := 1; pre <= 3; pre++ { //以pre步到达的i-last层台阶 + if last == pre { + continue + } + dp[i][last] += dp[i-last][pre] + } + } + } + return dp[n][1] + dp[n][2] + dp[n][3] +} + +//升级3:每次走的步数是在一个数组里定义,且前后不重复 +func dpSteps(n int, steps []int) int { + if n <= 1 { + return 1 + } + + //步数数组首先要去重(必须),然后最好排序(非必须) + + //状态定义,二维数组 + dp := make([][]int, n+1) + length := len(steps) + for i := range dp { //初始化二维数组,否则未将对象引用到对象的实例 + dp[i] = make([]int, length+1) + } + + //初始值 + //初始化全部为0;在递推的时候考虑步长和累加 + + //状态方程 + for i := 1; i <= n; i++ { //当前台阶 + for j := 0; j < length; j++ { //遍历步长 + last := steps[j] //从上一台阶跨last步到当前台阶 + if last > i { + //跨last步到当前台阶,比当前台阶大,不可能 + continue + } + if last == i { + //跨last步到当前台阶,刚好是第一次跨last步到此台阶,走法+1 + dp[i][j] += 1 + continue + } + for k := 0; k < length; k++ { + //'上一台阶'跨last步到'当前台阶','上上一台阶'跨pre步到'上一台阶',不允许重复 + pre := steps[k] + if last == pre { + continue + } + dp[i][j] += dp[i-last][k] + } + } + } + + //最终值 + res := 0 + for step := range steps { + res += dp[n][step] + } + return res +} + +//升级3:每次走的步数是在一个数组里定义,且前后不重复 +//美化版 +func dpSteps2(n int, steps []int) int { + if n <= 1 { + return 1 + } + + //步数数组首先要去重(必须),然后最好排序(非必须) + + //状态定义,二维数组 + dp := make([][]int, n+1) + length := len(steps) + for i := range dp { //初始化二维数组,否则未将对象引用到对象的实例 + dp[i] = make([]int, length+1) + } + + res := 0 + + //初始值 + //初始化全部为0;在递推的时候考虑步长和累加 + + //状态方程 + for i := 1; i <= n; i++ { //当前台阶 + for j := 0; j < length; j++ { //遍历步长 + last := steps[j] //从上一台阶跨last步到当前台阶 + if last >= i { + if last == i { + //刚好是第一次跨last步到此台阶,走法+1,就这一种情况,直接返回 + dp[i][j] += 1 + } + //比当前台阶大,不可能,直接返回 + continue + } + + for k := 0; k < length; k++ { + //'上一台阶'跨last步到'当前台阶','上上一台阶'跨pre步到'上一台阶',不允许重复 + pre := steps[k] + if last == pre { + continue + } + dp[i][j] += dp[i-last][k] + } + + if i == n { + res += dp[i][j] + } + } + } + + return res +} + +//升级4:每次可以走1,2,3,..., m步,m<=n +//纯记忆:前m阶初始值是2^(m-1)种,后面m+1是dp[i] = dp[i-1]*2 - dp[i-m-1] +func dpStepM(n, m int) int { + if n <= 1 { + return 1 + } + + dp := make([]int, n+1) + dp[0], dp[1] = 1, 1 + for i := 2; i <= m; i++ { + dp[i] = 2 * dp[i-1] + } + for i := m + 1; i <= n; i++ { + dp[i] = 2*dp[i-1] - dp[i-m-1] + } + return dp[n] +} diff --git a/Week_02/G20200343030373/LeetCode_98_373/LeetCode_98_373_test.go b/Week_02/G20200343030373/LeetCode_98_373/LeetCode_98_373_test.go new file mode 100644 index 00000000..3f5ed8af --- /dev/null +++ b/Week_02/G20200343030373/LeetCode_98_373/LeetCode_98_373_test.go @@ -0,0 +1,205 @@ +//https://leetcode-cn.com/problems/validate-binary-search-tree/ +package validate_BST_test + +import ( + "github.com/stretchr/testify/assert" + "math" + "sort" + "testing" +) + +func TestValidBST(t *testing.T) { + t.Log("Validate Binary Search Tree") + + left := TreeNode{ + Val: 1, + Left: nil, + Right: nil, + } + + right := TreeNode{ + Val: 3, + Left: nil, + Right: nil, + } + + root := TreeNode{ + Val: 2, + Left: &left, + Right: &right, + } + + assert.Equal(t, true, isValidBST(&root)) + assert.Equal(t, true, isValidBSTConquerDivider(&root)) + assert.Equal(t, true, isValidBSTInOrderTraversal(&root)) + assert.Equal(t, true, isValidBSTInOrderTraversalPre(&root)) + + node1 := TreeNode{ + Val: 3, + Left: nil, + Right: nil, + } + + node2 := TreeNode{ + Val: 6, + Left: nil, + Right: nil, + } + + node3 := TreeNode{ + Val: 4, + Left: &node1, + Right: &node2, + } + + node4 := TreeNode{ + Val: 1, + Left: nil, + Right: nil, + } + + root1 := TreeNode{ + Val: 5, + Left: &node4, + Right: &node3, + } + + assert.Equal(t, false, isValidBST(&root1)) + assert.Equal(t, false, isValidBSTConquerDivider(&root1)) + assert.Equal(t, false, isValidBSTInOrderTraversal(&root1)) + assert.Equal(t, false, isValidBSTInOrderTraversalPre(&root1)) + + root2 := TreeNode{ + Val: 0, + Left: nil, + Right: nil, + } + assert.Equal(t, true, isValidBSTInOrderTraversalPre(&root2)) + + root3 := TreeNode{ + Val: 1, + Left: &TreeNode{ + Val: 1, + Left: nil, + Right: nil, + }, + Right: nil, + } + assert.Equal(t, false, isValidBSTInOrderTraversalPre(&root3)) +} + +type TreeNode struct { + Val int + Left *TreeNode + Right *TreeNode +} + +func isValidBST(root *TreeNode) bool { + return isValidBSTConquerDivider(root) +} + +//Method1: Recursively - Conquer and Divider +//T: O(N), S:O(1) +func isValidBSTConquerDivider(root *TreeNode) bool { + return isBST(root, math.MinInt64, math.MaxInt64) +} + +//这个节点root,要比left大,要比right小 +func isBST(root *TreeNode, left, right int) bool { + if root == nil { + return true + } + + if left >= root.Val || right <= root.Val { + return false + } + + //root的左子节点,要比left大,要比root的值小 + //root的右子节点,要比root的值大,要比right小 + return isBST(root.Left, left, root.Val) && isBST(root.Right, root.Val, right) +} + +//Method2: InOrder Traversal to a Sorted List +//T: O(N). S:O(N) +func isValidBSTInOrderTraversal(root *TreeNode) bool { + nums := InOrderTraversal(root) + + //每个节点不重复 + hash := make(map[int]int) + for index, value := range nums { + if _, ok := hash[value]; ok { + return false + } + + hash[value] = index + } + + //判断是否为升序 + return sort.IntsAreSorted(nums) +} + +func InOrderTraversal(root *TreeNode) []int { + if root == nil { + return nil + } + + var ret []int + + //...语法,slice被打散进行传递 + ret = append(ret, InOrderTraversal(root.Left)...) + ret = append(ret, root.Val) + ret = append(ret, InOrderTraversal(root.Right)...) + + return ret +} + +//Method3: InOrder Traversal Upgrade: Current bigger than Previous +//T: O(N), S:O(1) +//这个解法是基于二叉树的中序遍历 +//定义一个变量用于存储上一遍历结点的值 +//递归遍历二叉树 +//如果左子树返回true,对比根节点与缓存变量的值 +//如果2.4的对比成立,则将根节点的值赋给缓存变量 +//递归遍历右子树 + +//Method3: 方法1:pre作为全局变量, +//LeetCode,Not AC, Error ! - 上[0]这个测试用例是错误的 +//但在单元测试却是AC +/* +var pre int = math.MinInt64 + +func isValidBSTInOrderTraversalPre(root *TreeNode) bool { + if root == nil { + return true + } + + if isValidBSTInOrderTraversalPre(root.Left) { + if pre < root.Val { + pre = root.Val + return isValidBSTInOrderTraversalPre(root.Right) + } + } + return false +} +*/ + +//Method3: 方法2:pre作为局部变量,且传递的是地址,则每次遍历对pre做的修改都有效 +//LeetCode通过,AC +func isValidBSTInOrderTraversalPre(root *TreeNode) bool { + pre := math.MinInt64 + return isValidBSTInOrderPre(root, &pre) //注意要传地址,否则[1,1]测试用例不通过 +} + +func isValidBSTInOrderPre(root *TreeNode, pre *int) bool { + if root == nil { + return true + } + + if isValidBSTInOrderPre(root.Left, pre) { + if *pre < root.Val { + *pre = root.Val + return isValidBSTInOrderPre(root.Right, pre) + } + } + return false +} diff --git a/Week_02/G20200343030373/geek_fib/fib.md b/Week_02/G20200343030373/geek_fib/fib.md new file mode 100644 index 00000000..25ec4433 --- /dev/null +++ b/Week_02/G20200343030373/geek_fib/fib.md @@ -0,0 +1,310 @@ +[TOC] + +# 管中窥豹,斐波那契 + +## 自我介绍 +- 大家好,我叫逄淑松,很荣幸能与大家一起交流 +- 逄,pang,二声;淑是我的辈份 +- 英文名或昵称:Pontus +- 语言:C++/C#, Go(Go新手,刷题语言) +- 工作:交易系统后端研发与管理 +- 选题原因: + - Fibonacci和爬楼梯问题是面试常考题,在课程中也屡次提及,今天我们一起梳理总结 + - 题目涉及的知识点比较全面,爬楼梯问题还有升级版,面试时可能被考察上限,**升级版代码绝对的独家一手分享(详细内容请见附件,走过路过千万不要错过呦)** + - 相关的算法或理念也在实际工作有所体现 + +## Fibonacci +- [LeetCode Topic](https://leetcode-cn.com/problems/fibonacci-number/) +- Description + > F(0) = 0, F(1) = 1 + > F(N) = F(N - 1) + F(N - 2), 其中 N > 1. + > 0 ≤ N ≤ 30 + > e.g. 0,1,1,2,3,5,8,13... + +## Solution + +### Recursion 递归 +- [动画演示](https://visualgo.net/zh/recursion) +- 递归思路 + - 思考时不要一层层陷入 + - **可直接假定下一层调用(递)能够正确返回(归)**,然后在本层正常处理 + - 最后只需保证最深一层的逻辑,也就是递归的终止条件正确即可 +- 代码 + + ```c++ + //C++ + int fib(int n) { + return n <= 1 ? n : fib(n-1) + fib(n-1); + } + ``` + + ```go + //以下代码均使用Go语言 + //Go中无三目运算符 + //TC: O(2^n), SC:O(n) - 递归调用栈的空间 + //AC, 12ms + func recursionFib(n int) int { + //terminator + if n <= 1 { + return n + } + //process + //drill down + return recursionFib(n-1) + recursionFib(n-2) + //clear + } + ``` +- 注意 + - 警惕堆栈溢出,如有需要主动计数并返回 + - 警惕重复计算(`Fib方案:Memorize 存储,如下`) + - 可将递归代码写成递推代码 + - 递归,调用函数本身进行循环(从结束到开始归来) + - 递推,迭代循环递推公式 (从开始到结束推导)(`Fib方案:DP 递推,如下`) + +### Memorize 存储 +- 加速 + - 升维:如索引 + - 空间换时间:如缓存 +- 问题:递归方法有重复计算 +- 方法:if n >= 2, 算过一次就存储起来,递归下次使用时直接取(缓存的概念,O(1)) +- 代码 + ```go + //TC: O(n), SC: O(n) + //AC, 0ms + var hash = make(map[int]int) + + func memorizeFib(n int) int { + if n <= 1 { + return n + } + if _, ok := hash[n]; !ok { + hash[n] = memorizeFib(n-1) + memorizeFib(n-2) + } + return hash[n] + } + ``` + +### DP 递推 +- 动态规划 + - dp = recursion + memorize = transition 递归加记忆化就是递推,也就是动态规划 + - recursion: 下沉后,反向返回结果 + - transition: 正向递推 +- 代码 + ```go + //TC: O(n), SC: O(n) + func dpFib(n int) int { + //状态定义: dp[i], 累加到当前位置的结果值 + //初始值: dp[0], dp[1] + //最终值: dp[n] + //状态方程: dp[i]=dp[i-1]+dp[i-2] + if n <= 1 { + return n + } + dp := make([]int, n+1) //因为要使用n,所以长度是n+1 + dp[0], dp[1] = 0, 1 + for i := 2; i <= n; i++ { + dp[i] = dp[i-1] + dp[i-2] + } + return dp[n] + } + ``` +- 注意点 + - 动态规划可能涉及到空间的多余使用(`Fib方案:DP+Space Decrease 递推+空间缩减,如下`) + +### DP+Space Decrease 递推+空间缩减 +- 方法:dp[]存储了每个步骤的值,但最终结果只需比它小前两个的结果,所以可通过变量滚动 +- 代码 + ```go + //TC: O(n), SC: O(1) + func dpSpaceFib(n int) int { + //状态定义: prePre, pre + //初始值: 0, 1 + //最终值: pre + //状态方程: pre, prePre = prePre+pre, pre + if n <= 1 { + return n + } + prePre, pre := 0, 1 + for i := 2; i <= n; i++ { + prePre, pre = pre, prePre+pre + } + return pre + } + ``` + +### Formula 通项公式法 +- 公式法举例 + ``` + //1+2+3+4=10 + n := 4 + sum1 := 0 + for i := 1; i <= n; i++ { + sum1 += i + } + sum2 := n * (n + 1) / 2 + assert.Equal(t, 10, sum1) //O(n) + assert.Equal(t, 10, sum2) //O(1) + ``` +- Fib公式(在此不书写md版公式) + > f(n) = a1(b1)^n + a2(b2)^n + b1 = (1 + √5)/2 (goldenRatio) + b2 = (1 - √5)/2 + a1 = 1/√5 + a2 = -1/√5 + b2^n , b2是小于1的数,幂次会在最后四舍五入时省略 + 最终结果:f(n) = (goldenRatio^n)/√5 +- 结论 + - goldenRatio = (1 + √5)/2 + - f(n) = (goldenRatio^n)/√5 +- 代码 + ```go + //TC: O(logn), SC: O(logn) - math.Pow的实现 + func formulaFib(n int) int { + goldenRatio := (1 + math.Sqrt(5)) / 2 + fn := math.Pow(goldenRatio, float64(n)) / math.Sqrt(5) + return int(math.Round(fn)) + } + ``` + +### Matrix 矩阵求幂 +- 公式 + + + +- 方案:求power(A,N) +- 结果:可见f(n)在最终的A[0,0]上 +- 代码 + ```go + func matrixFib(n int) int { + if n <= 1 { + return n + } + A := [2][2]int{ + {1, 1}, + {1, 0}, + } + A = matrixPower(A, n-1) + return A[0][0] + } + + //x^n + //method1: recursion + divide&conquer + //power(a,n), a是正数,n是自然数,只需要考虑n的奇偶性 + //递归+分治,O(logn) + func matrixPower(A [2][2]int, n int) [2][2]int { + //terminator + if n <= 1 { + return A + } + //process + //drill down + R := matrixPower(A, n/2) + //clear + if n&1 == 1 { + return multiply(A, multiply(R, R)) + } + return multiply(R, R) + } + + //线代公式 + func multiply(A [2][2]int, B [2][2]int) [2][2]int { + x := A[0][0]*B[0][0] + A[0][1]*B[1][0] + y := A[0][0]*B[0][1] + A[0][1]*B[1][1] + z := A[1][0]*B[0][0] + A[1][1]*B[0][1] + w := A[1][0]*B[0][1] + A[1][1]*B[1][1] + + A[0][0] = x + A[0][1] = y + A[1][0] = z + A[1][1] = w + + return A + } + ``` + +### Table 查表法 +- 代码 + ```go + //leetcode: 0 <= n <= 30 + //TC: O(1) :) + var fibs = [31]int{0, 1, 1, 2, 3, + 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, + 610, 987, 1597, 2584, 4181, 6765, 10946, + 17711, 28657, 46368, 75025, 121393, 196418, + 317811, 514229, 832040} + + func tableFib(n int) int { + return fibs[n] + } + ``` + +## Summary 管中窥豹 + +### 知识点汇总 + +#### 递归 +- 递归思路 + - 思考时不要一层层陷入 + - 可直接假定下一层调用(递)能够正确返回(归),然后在本层正常处理 + - 最后只需保证最深一层的逻辑,也就是递归的终止条件正确即可 +- 对递归的优化:尾递归 + - 尾递归是指,在函数返回的时候,调用自身本身,并且return语句不能包含表达式 + - 这样,编译器就可以对尾递归做优化,使递归无论调用多少次,都只占用一个栈帧,栈不会增长,不会出现栈溢出 + ```go + func tailRecursionFib(n int, b1, b2 int, c int) int { + if n <= 1 { + return n + } + if n == c { + return b1 + b2 + } + return tailRecursionFib(n, b2, b1+b2, c+1) + } + ``` +- 递归警惕重复计算 +#### 加速 +- 加速 + - 升维:如索引 + - 空间换时间:如缓存 +#### 位运算 +- 举例 + - x & 1, 结果为0或1,来判断偶、奇(`Fib方案:Formula 通项公式法,如上`) + - x = x & (x-1), 用于清零最低位的1,如面试题找x中有多少个1 + - x & -x,用于得到最低位的1,-x是取反加一 +#### 动态规划 +- 递归+记忆=递推,即动态规划 +- 动态规划可能涉及降低空间使用 +#### 爬楼梯问题 +- [LeetCode Topic](https://leetcode-cn.com/problems/climbing-stairs) +- 区别Fibonacci + - 爬楼梯n从1开始,斐波那次n从0开始 + - 爬楼梯题目的 i和n 分别要比斐波那契 多1 + - if n <= **2** + - for i := **3**; i <= n; i++ {} + - res := math.Pow(goldenRation, float64(**n+1**)) / math.Sqrt(5) + - A = pow(A, **n**) +- 升级 + 1. 每次可以走1,2,3步 + 2. 前后走的步数不能重复 + 3. 每次走的步数是在一个数组里定义,且前后不重复 + +### 学习方法 + +#### TDD +- 学习方法:四步拆题 与 五毒神掌 +- 其中, 在进行四步拆题时,与覃超老师不同的是,我会把测试用例提前,先写测试用例和边界,再进行编程,直观自动判断正确与否 +- TDD, 测试驱动,单元测试,结构编程 + ```go + func TestFib(t *testing.T) { + //Fibonacci + //0,1,1,2,3,5,8,13 + assert.Equal(t, 13, fib(7)) + } + ``` + +## 附件 +- 代码 + - [Fibonacci](https://github.com/pangshusong/algorithm006-class01/blob/master/Week_02/G20200343030373/LeetCode_509_373/LeetCode_509_373_test.go) + - [Climb Stairs](https://github.com/pangshusong/algorithm006-class01/blob/master/Week_02/G20200343030373/LeetCode_70_373/LeetCode_70_373_test.go) +- 本文 + - [Geek.Pontus.Fib](https://github.com/pangshusong/algorithm006-class01/blob/master/Week_02/G20200343030373/geek_fib/fib.md) \ No newline at end of file diff --git a/Week_02/G20200343030373/geek_fib/src/fib-matrix.png b/Week_02/G20200343030373/geek_fib/src/fib-matrix.png new file mode 100644 index 00000000..cde49983 Binary files /dev/null and b/Week_02/G20200343030373/geek_fib/src/fib-matrix.png differ diff --git a/Week_02/G20200343030375/Leet_code_590_375.java b/Week_02/G20200343030375/Leet_code_590_375.java new file mode 100644 index 00000000..1ca894d3 --- /dev/null +++ b/Week_02/G20200343030375/Leet_code_590_375.java @@ -0,0 +1,50 @@ +package G20200343030375; + +import java.util.ArrayList; +import java.util.List; + +/** + * leedcode 执行,时间复杂度还可以,空间复杂度,比较高 + * 执行用时 : 1 ms , 在所有 Java 提交中击败了 99.73% 的用户 + * 内存消耗 : 41.2 MB , 在所有 Java 提交中击败了 5.01% 的用户 + */ +public class Leet_code_590_375 { + public static List postorder(Node root) { + List result = new ArrayList<>(); + if(root ==null){ + return result; + } + if(root.children !=null || root.children.size()>0) { + recur(result, root); + }else{ + result.add(root.val); + } + return result; + } + + private static void recur(List result, Node node) { + if(node.children !=null &&node.children.size()>0) { + for(Node childNode : node.children){ + recur(result, childNode); + } + } + + result.add(node.val); + return; + } + private class Node { + public int val; + public List children; + + public Node() {} + + public Node(int _val) { + val = _val; + } + + public Node(int _val, List _children) { + val = _val; + children = _children; + } + } +} diff --git a/Week_02/G20200343030375/Leetcode_144_375.java b/Week_02/G20200343030375/Leetcode_144_375.java new file mode 100644 index 00000000..58a01e0a --- /dev/null +++ b/Week_02/G20200343030375/Leetcode_144_375.java @@ -0,0 +1,31 @@ +package G20200343030375; + +import java.util.ArrayList; +import java.util.List; + +/** + * 内存消耗 : 37.4 MB , 在所有 Java 提交中击败了 5.19% 的用户 + */ + +public class Leetcode_144_375 { + public List preorderTraversal(TreeNode root) { + List result = new ArrayList<>(); + if(root != null){ + recur(root,result); + } + return result; + } + private void recur(TreeNode node,List result){ + result.add(node.val); + if(node.left != null) recur(node.left,result); + if(node.right != null) recur(node.right,result); + return; + } + + private class TreeNode { + int val; + TreeNode left; + TreeNode right; + TreeNode(int x) { val = x; } + } +} diff --git a/Week_02/G20200343030375/Leetcode_49_375.java b/Week_02/G20200343030375/Leetcode_49_375.java new file mode 100644 index 00000000..95b74eb1 --- /dev/null +++ b/Week_02/G20200343030375/Leetcode_49_375.java @@ -0,0 +1,37 @@ +package G20200343030375; + +import java.util.*; + +/** + * 执行用时 : 7 ms , 在所有 Java 提交中击败了 99.98% 的用户 + * 内存消耗 : 44.6 MB , 在所有 Java 提交中击败了 28.73% 的用户 + */ +public class Leetcode_49_375 { + public List> groupAnagrams(String[] strs) { + List> result = new ArrayList>() ; + Map> map = new HashMap<>(); + for(String str : strs){ + char[] c = str.toCharArray(); + Arrays.sort(c); + String key = String.valueOf(c); + List childList = map.get(key); + if(childList == null){ + childList = new ArrayList<>(); + childList.add(str); + map.put(key,childList); + result.add(childList); + }else{ + childList.add(str); + } + } + + return result; + } + + public static void main(String[] args){ + String [] arr = new String[]{"eat", "tea", "tan", "ate", "nat", "bat"}; + + Leetcode_49_375 lc = new Leetcode_49_375(); + lc.groupAnagrams(arr); + } +} diff --git a/Week_02/G20200343030377/LeetCode_144_377.java b/Week_02/G20200343030377/LeetCode_144_377.java new file mode 100644 index 00000000..4975b3dc --- /dev/null +++ b/Week_02/G20200343030377/LeetCode_144_377.java @@ -0,0 +1,39 @@ +class Solution { + + //迭代 + public List preorderTraversal(TreeNode root) { + List res = new ArrayList<>(); + if (root == null) { + return res; + } + Stack stack = new Stack(); + stack.push(root); + while (!stack.isEmpty()) { + TreeNode pop = stack.pop(); + res.add(pop.val); + if (pop.right != null) { + stack.push(pop.right); + } + if (pop.left != null) { + stack.push(pop.left); + } + } + return res; + } + + //递归 + public List preorderTraversal1(TreeNode root) { + List res = new ArrayList<>(); + recur(root, res); + return res; + } + + private void recur(TreeNode root, List res) { + if (root == null) { + return; + } + res.add(root.val); + recur(root.left, res); + recur(root.right, res); + } +} diff --git a/Week_02/G20200343030377/LeetCode_236_377.java b/Week_02/G20200343030377/LeetCode_236_377.java new file mode 100644 index 00000000..0cd0070d --- /dev/null +++ b/Week_02/G20200343030377/LeetCode_236_377.java @@ -0,0 +1,40 @@ +class Solution { + public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { + Map parent = new HashMap<>(); + parent.put(root, null); + Deque stack = new ArrayDeque<>(); + stack.push(root); + while (!parent.containsKey(p) || !parent.containsKey(q)) { + TreeNode pop = stack.pop(); + if (pop.left != null) { + parent.put(pop.left, pop); + stack.push(pop.left); + } + if (pop.right != null) { + parent.put(pop.right, pop); + stack.push(pop.right); + } + } + Set ancestor = new HashSet<>(); + while (p != null) { + ancestor.add(p); + p = parent.get(p); + } + while (!ancestor.contains(q)) { + q = parent.get(q); + } + return q; + } + + public TreeNode lowestCommonAncestor1(TreeNode root, TreeNode p, TreeNode q) { + if (root == null || root == p || root == q) { + return root; + } + TreeNode left = lowestCommonAncestor(root.left, p, q); + TreeNode right = lowestCommonAncestor(root.right, p, q); + if (left != null && right != null) { + return root; + } + return left != null ? left : right; + } +} diff --git a/Week_02/G20200343030377/LeetCode_429_377.java b/Week_02/G20200343030377/LeetCode_429_377.java new file mode 100644 index 00000000..8ac6d820 --- /dev/null +++ b/Week_02/G20200343030377/LeetCode_429_377.java @@ -0,0 +1,25 @@ +import java.util.*; + +class Solution { + public List> levelOrder(Node root) { + List> res = new ArrayList<>(); + if (root == null) { + return res; + } + Queue queue = new LinkedList<>(); + queue.offer(root); + while (!queue.isEmpty()) { + List level = new ArrayList<>(); + int levelSize = queue.size(); + for (int i = 0; i < levelSize; i++) { + Node node = queue.poll(); + level.add(node.val); + for (Node n1 : node.children) { + queue.offer(n1); + } + } + res.add(level); + } + return res; + } +} diff --git a/Week_02/G20200343030377/LeetCode_49_377.java b/Week_02/G20200343030377/LeetCode_49_377.java new file mode 100644 index 00000000..4c83165e --- /dev/null +++ b/Week_02/G20200343030377/LeetCode_49_377.java @@ -0,0 +1,45 @@ +class Solution { + //按计数分组 + public List> groupAnagrams(String[] strs) { + if (strs.length == 0) { + return new ArrayList<>(); + } + int[] counter = new int[26]; + Map> map = new HashMap<>(); + for (String str : strs) { + char[] chars = str.toCharArray(); + Arrays.fill(counter, 0); + for (char c : chars) { + counter[c - 'a']++; + } + StringBuilder sb = new StringBuilder(); + for (int cnt : counter) { + sb.append("#").append(cnt); + } + String key = sb.toString(); + if (!map.containsKey(key)) { + map.put(key, new ArrayList<>()); + } + map.get(key).add(str); + } + return new ArrayList<>(map.values()); + } + + //按排序数组分类 + public List> groupAnagrams1(String[] strs) { + if (strs.length == 0) { + return new ArrayList<>(); + } + Map> map = new HashMap<>(); + for (String str : strs) { + char[] chars = str.toCharArray(); + Arrays.sort(chars); + String key = new String(chars); + if (!map.containsKey(key)) { + map.put(key, new ArrayList<>()); + } + map.get(key).add(str); + } + return new ArrayList<>(map.values()); + } +} diff --git a/Week_02/G20200343030377/LeetCode_589_377.java b/Week_02/G20200343030377/LeetCode_589_377.java new file mode 100644 index 00000000..c20aa7eb --- /dev/null +++ b/Week_02/G20200343030377/LeetCode_589_377.java @@ -0,0 +1,35 @@ +import java.util.*; +class Solution { + public List preorder(Node root) { + if (root == null) { + return new ArrayList<>(); + } + List res = new ArrayList<>(); + Stack stack = new Stack<>(); + stack.push(root); + while (!stack.isEmpty()) { + Node pop = stack.pop(); + res.add(pop.val); + for (int i = pop.children.size() - 1; i >= 0; i--) { + stack.push(pop.children.get(i)); + } + } + return res; + } + + public List preorder1(Node root) { + List res = new ArrayList<>(); + recurPreorder(root, res); + return res; + } + + private void recurPreorder(Node root, List res) { + if (root == null) { + return; + } + res.add(root.val); + for (Node node : root.children) { + recurPreorder(node, res); + } + } +} diff --git a/Week_02/G20200343030377/LeetCode_590_377.java b/Week_02/G20200343030377/LeetCode_590_377.java new file mode 100644 index 00000000..2a713193 --- /dev/null +++ b/Week_02/G20200343030377/LeetCode_590_377.java @@ -0,0 +1,39 @@ +import java.util.*; + +class Solution { + //前序遍历倒置 + public List postorder(Node root) { + if (root == null) { + return Collections.EMPTY_LIST; + } + List res = new ArrayList<>(); + Stack stack = new Stack(); + stack.push(root); + while (!stack.isEmpty()) { + Node pop = stack.pop(); + res.add(0, pop.val); + for (Node node : pop.children) { + stack.push(node); + } + } + return res; + } + + //递归 + public List postorder1(Node root) { + List res = new ArrayList<>(); + postorderRecur(root, res); + return res; + } + + private void postorderRecur(Node root, List res) { + if (root == null) { + return; + } + List children = root.children; + for (Node node : children) { + postorderRecur(node, res); + } + res.add(root.val); + } +} diff --git a/Week_02/G20200343030377/LeetCode_77_377.java b/Week_02/G20200343030377/LeetCode_77_377.java new file mode 100644 index 00000000..8e79886a --- /dev/null +++ b/Week_02/G20200343030377/LeetCode_77_377.java @@ -0,0 +1,23 @@ +class Solution { + private List> res = new ArrayList<>(); + + public List> combine(int n, int k) { + if (n <= 0 || k <= 0 || n < k) { + return res; + } + combineRecur(n, k, 1, new Stack()); + return res; + } + + private void combineRecur(int n, int k, int begin, Stack tmp) { + if (tmp.size() == k) { + res.add(new ArrayList(tmp)); + return; + } + for (int i = begin; i <= n; i++) { + tmp.push(i); + combineRecur(n, k, i + 1, tmp); + tmp.pop(); + } + } +} diff --git a/Week_02/G20200343030379/LeetCode_105_379.java b/Week_02/G20200343030379/LeetCode_105_379.java new file mode 100644 index 00000000..ad1bb99a --- /dev/null +++ b/Week_02/G20200343030379/LeetCode_105_379.java @@ -0,0 +1,60 @@ +package G20200343030379; + +import java.time.Period; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.function.Predicate; + +//105. ǰй +public class LeetCode_105_379 { + public class TreeNode { + int val; + TreeNode left; + TreeNode right; + TreeNode(int x) { val = x; } + } + + + private int pre_index=0; + private int[] preOrder; + private int[] inOrder; + private Map inxMap=new HashMap<>(); + + public TreeNode buildTree(int[] preorder, int[] inorder) { + this.preOrder=preorder; + this.inOrder=inorder; + + for (int i = 0; i < inorder.length; i++) { + inxMap.put(inorder[i],i); + } + return helper(0, inorder.length); + + } + + private TreeNode helper(int left, int right) { + //˳ + if(left==right){ + return null; + } + + //ִ߼ + int val=preOrder[pre_index]; + TreeNode node=new TreeNode(val); + int index=inxMap.get(val); + pre_index++; + + //ݹ + node.left=helper(left,index); + node.right=helper(index+1,right); + + + return node; + } + + public static void main(String[] args) { + + } +} diff --git a/Week_02/G20200343030379/LeetCode_144_379.java b/Week_02/G20200343030379/LeetCode_144_379.java new file mode 100644 index 00000000..2dea969b --- /dev/null +++ b/Week_02/G20200343030379/LeetCode_144_379.java @@ -0,0 +1,39 @@ +package G20200343030379; + +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; + +//144. ǰ +public class LeetCode_144_379 { + + public class TreeNode { + int val; + TreeNode left; + TreeNode right; + TreeNode(int x) { val = x; } + } + //1ݹ鷨 + public List inorderTraversal(TreeNode root) { + List list=new ArrayList<>(); + helper(root,list); + return list; + } + + private void helper(TreeNode root, List list) { + if (root != null) { + list.add(root.val); + if (root.left != null) { + helper(root.left,list); + } + if (root.right != null) { + helper(root.right,list); + } + } + } + + + public static void main(String[] args) { + + } +} diff --git a/Week_02/G20200343030379/LeetCode_236_379.java b/Week_02/G20200343030379/LeetCode_236_379.java new file mode 100644 index 00000000..60d39503 --- /dev/null +++ b/Week_02/G20200343030379/LeetCode_236_379.java @@ -0,0 +1,40 @@ +package G20200343030379; + +import java.util.ArrayList; +import java.util.Currency; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; + +//236. +public class LeetCode_236_379 { + public class TreeNode { + int val; + TreeNode left; + TreeNode right; + TreeNode(int x) { val = x; } + } + + private TreeNode ans; + public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { + this.recuresTree(root,p,q); + return this.ans; + } + + //һݹ + private boolean recuresTree(TreeNode cur, TreeNode p, TreeNode q) { + if(cur==null) return false; + + int left=recuresTree(cur.left,p,q)?1:0; + int right=recuresTree(cur.right,p,q)?1:0; + int mid=(cur==p ||cur==q)?1:0; + + if((left+right+mid)>=2){ + ans=cur; + } + + return (left+mid+right)>0; + } + + +} diff --git a/Week_02/G20200343030379/LeetCode_242_379.java b/Week_02/G20200343030379/LeetCode_242_379.java new file mode 100644 index 00000000..2884d51f --- /dev/null +++ b/Week_02/G20200343030379/LeetCode_242_379.java @@ -0,0 +1,72 @@ +package G20200343030379; + +import java.util.Arrays; + +//JavaЧĸλ +public class LeetCode_242_379 { + public static void main(String[] args) { + //Solution solution = new P242ValidAnagram().new Solution(); + // TO TEST + String s="abcd"; + char[] chars = s.toCharArray(); + for (char aChar : chars) { + System.out.println(aChar-'a'); + } + + } + //leetcode submit region begin(Prohibit modification and deletion) + class Solution { + //ϣ ʵǼ + public boolean isAnagram(String s, String t) { + if(s.length()!=t.length()){ + return false; + } + + int[] counter=new int[26]; + for (int i = 0; i < s.length(); i++) { + counter[s.charAt(i)-'a']++; + } + + for (int i = 0; i < t.length(); i++) { + counter[t.charAt(i)-'a']--; + if(counter[t.charAt(i)-'a']<0){ + return false; + } + } + return true; + } + //ϣ ʵǼ + public boolean isAnagram3(String s, String t) { + if(s.length()!=t.length()){ + return false; + } + + int[] counter=new int[26]; + for (int i = 0; i < s.length(); i++) { + counter[s.charAt(i)-'a']++; + counter[t.charAt(i)-'a']--; + } + + for (int c : counter) { + if(c!=0){ + return false; + } + } + return true; + } + // + public boolean isAnagram2(String s, String t) { + char[] a = s.toCharArray(); + char[] b = t.toCharArray(); + Arrays.sort(a); + Arrays.sort(b); + if(a.length != b.length) { + return false; + } + + boolean equals = Arrays.equals(a, b); + + return equals; + } + } +} diff --git a/Week_02/G20200343030379/LeetCode_429_379.java b/Week_02/G20200343030379/LeetCode_429_379.java new file mode 100644 index 00000000..6cfc25ec --- /dev/null +++ b/Week_02/G20200343030379/LeetCode_429_379.java @@ -0,0 +1,71 @@ +package G20200343030379; + +import com.sun.org.apache.regexp.internal.RE; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; + +//429. NIJ +public class LeetCode_429_379 { + class Node { + public int val; + public List children; + + public Node() {} + + public Node(int _val) { + val = _val; + } + + public Node(int _val, List _children) { + val = _val; + children = _children; + } + }; + + //ݹ鷽ʽĹ + List> result=new ArrayList<>(); + public List> levelOrder2(Node root) { + if (root != null) { + traversNode(root,0); + } + return result; + } + + private void traversNode(Node node, int level) { + if(result.size()<=level){ + result.add(new ArrayList<>()); + } + result.get(level).add(node.val); + for (Node child : node.children) { + traversNode(child,level+1); + } + } + + //һöʵֹ + public List> levelOrder(Node root) { + List> result=new ArrayList<>(); + if (root == null) { + return result; + } + + Queue quere=new LinkedList<>(); + quere.add(root); + while (!quere.isEmpty()){ + List level=new ArrayList<>(); + int size=quere.size(); + for (int i = 0; i < size; i++) { + Node poll = quere.poll(); + level.add(poll.val); + quere.addAll(poll.children); + } + + result.add(level); + } + + return result; + } +} diff --git a/Week_02/G20200343030379/LeetCode_46_379.java b/Week_02/G20200343030379/LeetCode_46_379.java new file mode 100644 index 00000000..cb0ca18c --- /dev/null +++ b/Week_02/G20200343030379/LeetCode_46_379.java @@ -0,0 +1,97 @@ +package G20200343030379; + +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; + +//46. ȫ +public class LeetCode_46_379 { + // ¼· + private List> res=new ArrayList<>(); + + public List> permute(int[] nums) { + backtrack(nums,new Stack()); + return res; + } + + //㷨·Ŀ + //οⷨhttps://leetcode-cn.com/problems/permutations/solution/hui-su-suan-fa-xiang-jie-by-labuladong-2/ + // ·¼ track + // ѡбnums в track ЩԪ + // nums еԪȫ track г + private void backtrack(int[] nums,Stack stack) { + //˳ + // + if(stack.size()>=nums.length){ + res.add(new ArrayList<>(stack)); + return; + } + + //ִ߼ + + //ѭݹ + for (int i = 0; i < nums.length; i++) { + // ųϷѡջȥ + //ַԴظջȥء + //ظջȥأֻint[] ȥء + if(stack.contains(nums[i])){ + continue; + } + // ѡ + stack.add(nums[i]); + // һ + backtrack(nums,stack); + // ȡѡ񣬳ǻѡ + stack.pop(); + } + + } + + public List> permute2(int[] nums) { + int[] visited=new int[nums.length]; + backtrack2(nums,visited,new Stack()); + return res; + } + + //㷨·Ŀ + //οⷨhttps://leetcode-cn.com/problems/permutations/solution/hui-su-suan-fa-by-powcai-2/ong-2/ + // ·¼ track + // ѡбnums в track ЩԪ + // nums еԪȫ track г + private void backtrack2(int[] nums,int[] visited,Stack stack) { + //˳ + // + if(stack.size()>=nums.length){ + res.add(new ArrayList<>(stack)); + return; + } + + //ִ߼ + + //ѭݹ + for (int i = 0; i < nums.length; i++) { + // ųϷѡȥ--ӳȥ + //ַԴظջȥء + //ظջȥأֻint[] ȥء + //1߹0Լ + if(visited[i]==1){ + continue; + } + visited[i]=1; + + // ѡ + stack.add(nums[i]); + // һ + backtrack2(nums,visited,stack); + // ȡѡ񣬳ǻѡ + visited[i]=0; + stack.pop(); + } + + } + + + public static void main(String[] args) { + + } +} diff --git a/Week_02/G20200343030379/LeetCode_47_379.java b/Week_02/G20200343030379/LeetCode_47_379.java new file mode 100644 index 00000000..b3e6ce81 --- /dev/null +++ b/Week_02/G20200343030379/LeetCode_47_379.java @@ -0,0 +1,123 @@ +package G20200343030379; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.Stack; + +//47. ȫ II + +/*** + * 㷨ܣ + * result = [] + * def backtrack(·, ѡб): + * if : + * result.add(·) + * return + * + * for ѡ in ѡб: + * ѡ + * backtrack(·, ѡб) + * ѡ + * + * ߣlabuladong + * ӣhttps://leetcode-cn.com/problems/permutations/solution/hui-su-suan-fa-xiang-jie-by-labuladong-2/ + * ԴۣLeetCode + * ȨСҵתϵ߻Ȩҵתע + */ +public class LeetCode_47_379 { + public static void main(String[] args) { + new LeetCode_47_379().permuteUnique(new int[]{1,2,1}); + } + private List> res=new ArrayList<>(); + private Set set=new HashSet<>(); + public List> permuteUnique(int[] nums) { + int[] visited=new int[nums.length]; + //Ϊ㷨ǸǰֵжǷظԱź + Arrays.sort(nums); + backtrack(nums,visited,new Stack()); + System.out.println(res); + return res; + } + + //㷨·Ŀ + //οⷨhttps://leetcode-cn.com/problems/permutations/solution/hui-su-suan-fa-xiang-jie-by-labuladong-2/ + //index Ƿ + private void backtrack(int[] nums,int[] visite,Stack stack) { + /**˳,ɸѡܺʱ**/ + if(stack.size()>=nums.length){ + if(!set.contains(stack.toString())){ + res.add(new ArrayList<>(stack)); + set.add(stack.toString()); + } + return; + } + + //ִ߼ + + //ѭݹ + // for ѡ in ѡб: + for (int i = 0; i < nums.length; i++) { + //ظģø÷ųϷѡ + if(visite[i]==1){ + continue; + } + visite[i]=1; + stack.add(nums[i]); + + //һ + backtrack(nums,visite,stack); + + //ѡ + visite[i]=0; + stack.pop(); + } + + } + + //㷨·Ŀ,Ż汾 + //οⷨhttps://leetcode-cn.com/problems/permutations-ii/solution/hui-su-suan-fa-by-powcai-3/ + //index Ƿ + private void backtrack2(int[] nums,int[] visite,Stack stack) { + /**˳,ɸѡܺʱ**/ + /*if(stack.size()>=nums.length){ + if(!set.contains(stack.toString())){ + res.add(new ArrayList<>(stack)); + set.add(stack.toString()); + } + return; + }*/ + if(stack.size()>=nums.length){ + res.add(new ArrayList<>(stack)); + return; + } + + //ִ߼ + + //ѭݹ + for (int i = 0; i < nums.length; i++) { + //ظģø÷ųϷѡ + //visite[i]==1 ǰڵ߹visite[i-1]==0 ֵѾ꣬Ѿ1ֵΪ0ҵǰڵֵܽڵһظ + if(visite[i]==1 || (i>0 && visite[i-1]==0 && nums[i-1]==nums[i])){ + continue; + } + + visite[i]=1; + stack.add(nums[i]); + + //һ + backtrack2(nums,visite,stack); + + //ѡ + visite[i]=0; + stack.pop(); + } + + + } + +} diff --git a/Week_02/G20200343030379/LeetCode_49_379.java b/Week_02/G20200343030379/LeetCode_49_379.java new file mode 100644 index 00000000..42343816 --- /dev/null +++ b/Week_02/G20200343030379/LeetCode_49_379.java @@ -0,0 +1,64 @@ +package G20200343030379; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +//JavaЧĸλ +public class LeetCode_49_379 { + public static void main(String[] args) { + + } + class Solution { + //ϣ- + public List> groupAnagrams(String[] strs) { + Map> hash=new HashMap>(); + for (int i = 0; i < strs.length; i++) { + char[] s_arr = strs[i].toCharArray(); + Arrays.sort(s_arr); + String key=String.valueOf(s_arr); + if(hash.containsKey(key)){ + hash.get(key).add(strs[i]); + }else{ + List list=new ArrayList<>(); + list.add(strs[i]); + hash.put(key,list); + + } + } + return new ArrayList<>(hash.values()); + } + + //ϣ-ַ + public List> groupAnagrams2(String[] strs) { + Map> hash=new HashMap<>(); + for (int i = 0; i < strs.length; i++) { + + int nums[]=new int[26]; + for (int j = 0; j < strs[i].length(); j++) { + nums[strs[i].charAt(j)-'a']++; + } + + StringBuilder sb=new StringBuilder(); + + // 0#2# + for (int j = 0; j < nums.length; j++) { + sb.append(nums[j]).append('#'); + } + + String key=sb.toString(); + if(hash.containsKey(key)){ + hash.get(key).add(strs[i]); + }else{ + List temp=new ArrayList<>(); + temp.add(strs[i]); + hash.put(key,temp); + } + } + + return new ArrayList<>(hash.values()); + } + } +} diff --git a/Week_02/G20200343030379/LeetCode_589_379.java b/Week_02/G20200343030379/LeetCode_589_379.java new file mode 100644 index 00000000..87d70b06 --- /dev/null +++ b/Week_02/G20200343030379/LeetCode_589_379.java @@ -0,0 +1,93 @@ +package G20200343030379; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; + +//589. Nǰ +public class LeetCode_589_379 { + + class Node { + public int val; + public List children; + + public Node() {} + + public Node(int _val) { + val = _val; + } + + public Node(int _val, List _children) { + val = _val; + children = _children; + } + }; + //1ʹջ + public List postorder(LeetCode_590_379.Node root) { + LinkedList statck=new LinkedList(); + LinkedList res=new LinkedList(); + statck.add(root); + while (!statck.isEmpty()){ + LeetCode_590_379.Node node = statck.pollLast(); + res.add(node.val); + + Collections.reverse(node.children); + for (LeetCode_590_379.Node child : node.children) { + if(child!=null){ + statck.add(child); + } + } + } + return res; + } + //1ʹջ + public List preorder2(Node root) { + + LinkedList stack = new LinkedList<>(); + LinkedList res = new LinkedList<>(); + + //Ҳһ + if(root==null){ + return res; + } + + stack.add(root); + while (!stack.isEmpty()){ + Node node = stack.pollLast(); + // + res.addFirst(node.val); + Collections.reverse(node.children); + for (Node child : node.children) { + if(child!=null){ + stack.add(child); + } + } + } + return res; + } + //2ݹ鷨 + public List preorder(Node root) { + List res=new ArrayList<>(); + if(root==null){ + return res; + } + helper(root,res); + return res; + } + + private void helper(Node root, List res) { + res.add(root.val); + for (Node child : root.children) { + if(child!=null){ + helper(child,res); + } + } + + } + + + public static void main(String[] args) { + + } +} diff --git a/Week_02/G20200343030379/LeetCode_590_379.java b/Week_02/G20200343030379/LeetCode_590_379.java new file mode 100644 index 00000000..f8affa40 --- /dev/null +++ b/Week_02/G20200343030379/LeetCode_590_379.java @@ -0,0 +1,75 @@ +package G20200343030379; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; + +//590. Nĺ +public class LeetCode_590_379 { + + class Node { + public int val; + public List children; + + public Node() {} + + public Node(int _val) { + val = _val; + } + + public Node(int _val, List _children) { + val = _val; + children = _children; + } + }; + + //1ʹջ + public List postorder(Node root) { + LinkedList stack = new LinkedList<>(); + LinkedList res = new LinkedList<>(); + + //Ҳһ + if(root==null){ + return res; + } + stack.add(root); + while (!stack.isEmpty()){ + Node node = stack.pollLast(); + // + res.addFirst(node.val); + + for (Node child : node.children) { + if(child!=null){ + stack.add(child); + } + } + } + return res; + } + + //2ݹ鷨 + public List postorder2(Node root) { + List res=new ArrayList<>(); + if(root==null){ + return res; + } + helper(root,res); + return res; + } + + private void helper(Node root, List res) { + for (Node child : root.children) { + if(child!=null){ + helper(child,res); + } + } + + res.add(root.val); + } + + + public static void main(String[] args) { + + } +} diff --git a/Week_02/G20200343030379/LeetCode_77_379.java b/Week_02/G20200343030379/LeetCode_77_379.java new file mode 100644 index 00000000..7f688b46 --- /dev/null +++ b/Week_02/G20200343030379/LeetCode_77_379.java @@ -0,0 +1,37 @@ +package G20200343030379; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Stack; + +//77. +public class LeetCode_77_379 { + private List> res=new ArrayList<>(); + public List> combine(int n, int k) { + findCombinations(n,k,1,new Stack()); + return res; + } + + //㷨 + private void findCombinations(int n, int k, int cur, Stack stack) { + if(stack.size()>=k){ + res.add(new ArrayList<>(stack)); + return; + } + + for (int i = cur; i <= n; i++) { + stack.add(i); + findCombinations(n,k,i+1,stack); + stack.pop(); + + } + + } + + + public static void main(String[] args) { + + } +} diff --git a/Week_02/G20200343030379/LeetCode_94_379.java b/Week_02/G20200343030379/LeetCode_94_379.java new file mode 100644 index 00000000..1ac07026 --- /dev/null +++ b/Week_02/G20200343030379/LeetCode_94_379.java @@ -0,0 +1,61 @@ +package G20200343030379; + +import javax.swing.tree.TreeNode; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Stack; + +//94. +public class LeetCode_94_379 { + + public class TreeNode { + int val; + TreeNode left; + TreeNode right; + TreeNode(int x) { val = x; } + } + //2ջı + public List inorderTraversal2(TreeNode root) { + Stack stack=new Stack(); + List res=new ArrayList<>(); + TreeNode cur=root; + while (cur!=null || !stack.isEmpty()){ + while (cur!=null){ + stack.push(cur); + cur=cur.left; + } + cur = stack.pop(); + res.add(cur.val); + cur=cur.right; + + } + + return res; + } + //1ݹ鷨 + public List inorderTraversal(TreeNode root) { + List list=new ArrayList<>(); + helper(root,list); + return list; + } + + private void helper(TreeNode root, List list) { + if(root!=null){ + if (root.left != null) { + helper(root.left,list); + } + list.add(root.val); + if (root.right != null) { + helper(root.right,list); + } + } + } + + + public static void main(String[] args) { + + } +} diff --git a/Week_02/G20200343030379/NOTE.md b/Week_02/G20200343030379/NOTE.md index 50de3041..5e41b24e 100644 --- a/Week_02/G20200343030379/NOTE.md +++ b/Week_02/G20200343030379/NOTE.md @@ -1 +1,15 @@ -学习笔记 \ No newline at end of file +学习笔记 + +这周把所有题目大致练了一遍,哈希没啥问题。 +二叉树主要靠递归解决,到了递归方面方面很多用到回溯,之前只听过回溯完成没做过类似的题目。 +想了好久,发现也是有套路,也就是把递归的套路法和回溯的套路法结合起来,弄懂套路后,想问题就会明朗一点,但是发现做了好几道题,虽然类似,但是只要一点改动就想破头脑,说明做的题还是太少了。 +还有一个递归需要出现耗时的问题,我们一般想到的都是在最后做筛选,其实也可以,但是也是很耗时,最好的办法还是在过程中做筛选,然后在中间把重复项去除,这样是最快的,还避免了栈空间的使用。。 + + +======回溯套路====== +def backtrack(路径, 选择列表): +满足退出条件,则退出 +for循环兄弟节点: +做选择 +backtrack(路径,或者其他参数, 原数据) +撤销选择 diff --git a/Week_02/G20200343030383/LeetCode_105_383.go b/Week_02/G20200343030383/LeetCode_105_383.go new file mode 100644 index 00000000..b92a625e --- /dev/null +++ b/Week_02/G20200343030383/LeetCode_105_383.go @@ -0,0 +1,37 @@ +// https://leetcode-cn.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/ +package leetcode + +/** + * Definition for a binary tree node. + * type TreeNode struct { + * Val int + * Left *TreeNode + * Right *TreeNode + * } + */ +func buildTree(preorder []int, inorder []int) *TreeNode { + inorderMap := make(map[int]int) + for i, v := range inorder { + inorderMap[v] = i + } + _, root := walk(preorder, 0, inorderMap, 0, len(inorder)-1) + return root +} + +func walk(preorder []int, pId int, inorderMap map[int]int, istart, iend int) (int, *TreeNode) { + if istart > iend { + return pId, nil + } + + /* make root node */ + root := &TreeNode{Val: preorder[pId]} + splitID := inorderMap[preorder[pId]] + + /* build left */ + pId, root.Left = walk(preorder, pId+1, inorderMap, istart, splitID-1) + + /* build right */ + pId, root.Right = walk(preorder, pId, inorderMap, splitID+1, iend) + + return pId, root +} diff --git a/Week_02/G20200343030383/LeetCode_236_383.go b/Week_02/G20200343030383/LeetCode_236_383.go new file mode 100644 index 00000000..69af99c9 --- /dev/null +++ b/Week_02/G20200343030383/LeetCode_236_383.go @@ -0,0 +1,78 @@ +// https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-tree/ +package leetcode + +/** + * Definition for TreeNode. + * type TreeNode struct { + * Val int + * Left *ListNode + * Right *ListNode + * } + */ +func lowestCommonAncestor(root, p, q *TreeNode) *TreeNode { + if _, n := findAncestor(root, p, q); n != nil { + return n + } + return root +} + +func findAncestor(root, p, q *TreeNode) (flag int,ret *TreeNode) { + if root == nil { + return + } + var froot,fleft,fright int + if root == p || root == q { + froot = 1 + } + if fleft, ret = findAncestor(root.Left, p, q);ret!=nil{ + return + } + if fright, ret= findAncestor(root.Right, p, q);ret!=nil{ + return + } + + if froot+fleft+fright>1 { + ret = root + } + return froot+fleft+fright,ret +} + +func lowestCommonAncestor2(root, p, q *TreeNode) *TreeNode { + s := &st{} + s.findAncestor(root, p, q, nil) + size := min(len(s.ppath), len(s.qpath)) + for i := 0; i < size; i++ { + if s.ppath[i] == s.qpath[i] && (i == size-1 || s.ppath[i+1] != s.qpath[i+1]) { + return s.ppath[i] + } + } + return root +} +func min(a, b int) int { + if a > b { + return b + } + return a +} + +type st struct { + ppath, qpath []*TreeNode +} + +func (t *st) findAncestor(root, p, q *TreeNode, path []*TreeNode) { + if root == nil { + return + } + path = append(path, root) + if root == p { + t.ppath = path + } + if root == q { + t.qpath = path + } + if len(t.ppath) > 0 && len(t.qpath) > 0 { + return + } + t.findAncestor(root.Left, p, q, path) + t.findAncestor(root.Right, p, q, path) +} diff --git a/Week_02/G20200343030383/LeetCode_242_383.go b/Week_02/G20200343030383/LeetCode_242_383.go new file mode 100644 index 00000000..00083100 --- /dev/null +++ b/Week_02/G20200343030383/LeetCode_242_383.go @@ -0,0 +1,13 @@ +// https://leetcode-cn.com/problems/valid-anagram/ +package leetcode + +func isAnagram(s string, t string) bool { + var note [26]byte + for _, b := range []byte(s) { + note[b-'a']++ + } + for _, b := range []byte(t) { + note[b-'a']-- + } + return note == ([26]byte{}) +} diff --git a/Week_02/G20200343030383/LeetCode_46_383.go b/Week_02/G20200343030383/LeetCode_46_383.go new file mode 100644 index 00000000..54f89c01 --- /dev/null +++ b/Week_02/G20200343030383/LeetCode_46_383.go @@ -0,0 +1,29 @@ +// https://leetcode-cn.com/problems/permutations/submissions/ +package leetcode + +func permute(nums []int) [][]int { + return new(pst).doPermute(nums, 0, make([]int, 0, len(nums))).res +} + +type pst struct { + res [][]int +} + +func (p *pst) addRes(a []int) *pst { + s := make([]int, len(a)) + copy(s, a) + p.res = append(p.res, s) + return p +} + +func (p *pst) doPermute(nums []int, start int, memo []int) *pst { + if start >= len(nums) { + return p.addRes(memo) + } + for i := start; i < len(nums); i++ { + nums[start], nums[i] = nums[i], nums[start] + p.doPermute(nums, start+1, append(memo, nums[start])) + nums[i], nums[start] = nums[start], nums[i] + } + return p +} diff --git a/Week_02/G20200343030383/LeetCode_47_383.go b/Week_02/G20200343030383/LeetCode_47_383.go new file mode 100644 index 00000000..329fa527 --- /dev/null +++ b/Week_02/G20200343030383/LeetCode_47_383.go @@ -0,0 +1,33 @@ +// https://leetcode-cn.com/problems/permutations-ii/ +package leetcode + +func permuteUnique(nums []int) [][]int { + return new(pst).doPermute(nums, 0, make([]int, 0, len(nums))).res +} + +type pst struct { + res [][]int +} + +func (p *pst) addRes(a []int) *pst { + s := make([]int, len(a)) + copy(s, a) + p.res = append(p.res, s) + return p +} +func (p *pst) doPermute(nums []int, start int, memo []int) *pst { + if start >= len(nums) { + return p.addRes(memo) + } + dup := make(map[int]bool) + for i := start; i < len(nums); i++ { + if dup[nums[i]] { + continue + } + dup[nums[i]] = true + nums[start], nums[i] = nums[i], nums[start] + p.doPermute(nums, start+1, append(memo, nums[start])) + nums[i], nums[start] = nums[start], nums[i] + } + return p +} diff --git a/Week_02/G20200343030383/LeetCode_49_383.go b/Week_02/G20200343030383/LeetCode_49_383.go new file mode 100644 index 00000000..d8c1eb12 --- /dev/null +++ b/Week_02/G20200343030383/LeetCode_49_383.go @@ -0,0 +1,24 @@ +// https://leetcode-cn.com/problems/group-anagrams/submissions/ +package leetcode + +func groupAnagrams(strs []string) [][]string { + table := make(map[[26]byte][]string) + for _, str := range strs { + key := getWordKey(str) + table[key] = append(table[key], str) + } + return mapTo2DimensionSlice(table) +} + +func mapTo2DimensionSlice(t map[[26]byte][]string) (ret [][]string) { + for _, v := range t { + ret = append(ret, v) + } + return +} +func getWordKey(str string) (key [26]byte) { + for _, b := range []byte(str) { + key[b-'a']++ + } + return +} diff --git a/Week_02/G20200343030383/LeetCode_77_383.go b/Week_02/G20200343030383/LeetCode_77_383.go new file mode 100644 index 00000000..f7c182b7 --- /dev/null +++ b/Week_02/G20200343030383/LeetCode_77_383.go @@ -0,0 +1,24 @@ +// https://leetcode-cn.com/problems/combinations/ +package leetcode + +func combine(n int, k int) [][]int { + return new(comSt).findAllComb(n, k, 1, make([]int, 0, k)).res +} + +type comSt struct { + res [][]int +} + +func (st *comSt) findAllComb(n int, k int, position int, memo []int) *comSt { + if len(memo) == k { + s := make([]int, k) + copy(s, memo) + st.res = append(st.res, s) + return st + } + for i := position; i <= n; i++ { + slice := append(memo, i) + st.findAllComb(n, k, i+1, slice[:]) + } + return st +} diff --git a/Week_02/G20200343030383/LeetCode_94_383.go b/Week_02/G20200343030383/LeetCode_94_383.go new file mode 100644 index 00000000..5fb74598 --- /dev/null +++ b/Week_02/G20200343030383/LeetCode_94_383.go @@ -0,0 +1,59 @@ +// https://leetcode-cn.com/problems/binary-tree-inorder-traversal/ +package leetcode + +/* pretty cool code, so I repeat it here */ + +/** + * Definition for a binary tree node. + * type TreeNode struct { + * Val int + * Left *TreeNode + * Right *TreeNode + * } + */ +func inorderTraversal(root *TreeNode) (ret []int) { + st := &Stack{} + st.Push(root, White) + for !st.IsEmpty() { + if n, color := st.Pop(); color == White { + st.Push(n.Right, White) + st.Push(n, Gray) + st.Push(n.Left, White) + } else { + ret = append(ret, n.Val) + } + + } + return +} + +const ( + White = 1 + Gray = 2 +) + +type Stack struct { + nodes []*TreeNode + color []int +} + +func (st *Stack) Push(n *TreeNode, color int) { + if n != nil { + st.nodes = append(st.nodes, n) + st.color = append(st.color, color) + } +} + +func (st *Stack) IsEmpty() bool { + return len(st.nodes) == 0 +} +func (st *Stack) Pop() (n *TreeNode, c int) { + if len(st.nodes) > 0 { + size := len(st.nodes) + n, c = st.nodes[size-1], st.color[size-1] + + st.nodes = st.nodes[:size-1] + st.color = st.color[:size-1] + } + return +} diff --git a/Week_02/G20200343030383/NOTE.md b/Week_02/G20200343030383/NOTE.md deleted file mode 100644 index 50de3041..00000000 --- a/Week_02/G20200343030383/NOTE.md +++ /dev/null @@ -1 +0,0 @@ -学习笔记 \ No newline at end of file diff --git a/Week_02/G20200343030383/NOTE.org b/Week_02/G20200343030383/NOTE.org new file mode 100644 index 00000000..a27a55c1 --- /dev/null +++ b/Week_02/G20200343030383/NOTE.org @@ -0,0 +1,7 @@ +学习笔记 + +** 学习到两个cool技巧 +*** 染色法遍历二叉树 +*** 怎样记录数组是否已经访问过 + +访问过的移动到前面,记录一个当前访问游标即可 diff --git a/Week_02/G20200343030387/LeetCode_144_387.js b/Week_02/G20200343030387/LeetCode_144_387.js new file mode 100644 index 00000000..fbbe1cf4 --- /dev/null +++ b/Week_02/G20200343030387/LeetCode_144_387.js @@ -0,0 +1,54 @@ +/** + * Definition for a binary tree node. + * function TreeNode(val) { + * this.val = val; + * this.left = this.right = null; + * } + */ +/** + * @param {TreeNode} root + * @params {number[]} + * @return {undefined} + */ +// 系统栈 +const helper = function (root, res) { + if (root) { + res.push(root.val) + helper(root.left, res) + helper(root.right, res) + } +} +/** + * @param {TreeNode} root + * @return {number[]} + */ +var preorderTraversal1 = function (root) { + const res = [] + helper(root, res) + return res +}; + +/** + * @param {TreeNode} root + * @return {number[]} + */ +// 自定义栈 +var preorderTraversal = function (root) { + const res = [] + const stack = [] + let current = root + stack.push(current) + while (stack.length) { + current = stack.pop() + if (current) { + res.push(current.val) + if (current.right) { + stack.push(current.right) + } + if (current.left) { + stack.push(current.left) + } + } + } + return res +} \ No newline at end of file diff --git a/Week_02/G20200343030387/LeetCode_1_387.js b/Week_02/G20200343030387/LeetCode_1_387.js new file mode 100644 index 00000000..bc3399e6 --- /dev/null +++ b/Week_02/G20200343030387/LeetCode_1_387.js @@ -0,0 +1,55 @@ +/** + * @param {number[]} nums + * @param {number} target + * @return {number[]} + */ +// 暴力法 +// 时间复杂度:O(n^2) +var twoSum1 = function(nums, target) { + const size = nums.length + for (let i = 0; i < size; i++) { + for (let j = i + 1; j < size; j++) { + if (nums[i] + nums[j] === target) { + return [i, j] + } + } + } + return [] +} + +// 两遍哈希法 +// 先循环一遍数组构造hash表,再循环一遍数组进行判断 +// 时间复杂度:O(2n) +var twoSum2 = function(nums, target) { + const size = nums.length + const hash = {} + for (let i = 0; i < size; i++) { + hash[nums[i]] = i + } + let j + for (i = 0; i < size; i++) { + j = hash[target - nums[i]] + if (Number.isInteger(j) && i !== j) { + return [i, j] + } + } + return [] +} + +// 一遍哈希法 +// 遍历一次数组进行判断,同时构造hash表,因为前面构建完成在后面也会被用来判断 +// 时间复杂度:O(n) +var twoSum = function(nums, target) { + const hash = {} + let j + for (let i = 0; i < nums.length; i++) { + j = hash[target - nums[i]] + if (Number.isInteger(j) && i !== j) { + return [i, j] + } + if (!Number.isInteger(hash[nums[i]])) { + hash[nums[i]] = i + } + } + return [] +} diff --git a/Week_02/G20200343030387/LeetCode_236_387.js b/Week_02/G20200343030387/LeetCode_236_387.js new file mode 100644 index 00000000..134660d7 --- /dev/null +++ b/Week_02/G20200343030387/LeetCode_236_387.js @@ -0,0 +1,77 @@ +/** + * Definition for a binary tree node. + * function TreeNode(val) { + * this.val = val; + * this.left = this.right = null; + * } + */ +// 递归 +// 深度递归左右子树节点,找到p,q并返回节点; +// 最外层顶点得到的情况就只有三种:在左或右子树上,或者在根节点上; +/** + * @param {TreeNode} root + * @param {TreeNode} p + * @param {TreeNode} q + * @return {TreeNode} + */ +var lowestCommonAncestor1 = function (root, p, q) { + const helper = function (root, p, q) { + if (!root) return null + if (root.val === p.val || root.val === q.val) return root + const left = helper(root.left, p, q) + const right = helper(root.right, p, q) + if (left && right) { + // p, q在root的左右子节点上 + return root + } else if (left) { + return left + } else if (right) { + return right + } + return null + } + return helper(root, p, q) +}; + +// 父指针 +// 找出p和q的所有父节点指针parents; +// 再其中分离出p的所有父节点parentsSetOfP; +// q根据parents逐层向上遍历父节点,最先落在parentsSetOfP上的父节点就是要求的节点 +/** + * @param {TreeNode} root + * @param {TreeNode} p + * @param {TreeNode} q + * @return {TreeNode} + */ +var lowestCommonAncestor = function (root, p, q) { + if (!root) return null + const helper = function (root, parents) { + if (root) { + if (root.left) { + parents[root.left.val] = root + helper(root.left, parents) + } + if (root.right) { + parents[root.right.val] = root + helper(root.right, parents) + } + } + } + const parents = {} + helper(root, parents) + // 找出p的所有父节点 + const parentsSetOfP = [] + while (p) { + parentsSetOfP.push(p.val) + p = parents[p.val] + } + if (!parentsSetOfP.length) return null + // 判断q的父节点是否在p的所有父节点中 + while (q) { + if (parentsSetOfP.includes(q.val)) { + return q + } + q = parents[q.val] + } + return null +} \ No newline at end of file diff --git a/Week_02/G20200343030387/LeetCode_242_387.js b/Week_02/G20200343030387/LeetCode_242_387.js new file mode 100644 index 00000000..a5d17c9e --- /dev/null +++ b/Week_02/G20200343030387/LeetCode_242_387.js @@ -0,0 +1,16 @@ +var isAnagram = function(s, t) { + if (s.length !== t.length) return false + const counterArr = new Array(26).fill(0) + const base = "a".charCodeAt() + const buildCharIndex = function(char) { + return char.charCodeAt() - base + } + for (let i = 0; i < s.length; i++) { + counterArr[buildCharIndex(s.charAt(i))]++ + counterArr[buildCharIndex(t.charAt(i))]-- + } + for (let key of counterArr) { + if (counterArr[key] !== 0) return false + } + return true +} diff --git a/Week_02/G20200343030387/LeetCode_429._387.js b/Week_02/G20200343030387/LeetCode_429._387.js new file mode 100644 index 00000000..341cd942 --- /dev/null +++ b/Week_02/G20200343030387/LeetCode_429._387.js @@ -0,0 +1,112 @@ +/** + * // Definition for a Node. + * function Node(val,children) { + * this.val = val; + * this.children = children; + * }; + */ +// 队列版的广度优先遍历 +/** + * @param {Node} root + * @return {number[][]} + */ +var levelOrder1 = function (root) { + if (!root) return [] + const res = [] + const queue = [] + queue.push(root) + let child = null + let size = 0 + let level = [] + while (queue.length) { + level = [] + size = queue.length + for (let i = 0; i < size; i++) { + child = queue.shift() + level.push(child.val) + child.children.forEach(item => { + queue.push(item) + }) + } + res.push(level) + } + return res +}; + +// 队列变形版的广度优先遍历 +// 每个队列元素都是树的一层节点,这样能减少出队次数,因为js用数组代替队列,出队性能可能比较差 +/** + * @param {Node} root + * @return {number[][]} + */ +var levelOrder2 = function (root) { + if (!root) return [] + const res = [] + const queue = [] + let level = [] + let levelQueue = [] + queue.push([root]) + while (queue.length) { + levelQueue = [] + level = queue.shift().map(item => { + item.children.forEach(child => { + levelQueue.push(child) + }) + return item.val + }) + if (levelQueue.length) { + queue.push(levelQueue) + } + res.push(level) + } + return res +} + +// 简化版的广度优先遍历 +// 不使用队列,用变量的形式存储下一层树要处理的所有子节点 +/** + * @param {Node} root + * @return {number[][]} + */ +var levelOrder3 = function (root) { + if (!root) return [] + const res = [] + let currentLayer = [root] + let nextLayer = [] + let level = [] + while (currentLayer.length) { + nextLayer = [] + level = [] + currentLayer.forEach(item => { + level.push(item.val) + item.children.forEach(child => { + nextLayer.push(child) + }) + }) + res.push(level) + currentLayer = nextLayer + } + return res +} + +// 递归方法 +// 找到最近最少重复的环节:先遍历根,再遍历children +/** + * @param {Node} root + * @return {number[][]} + */ +var levelOrder = function (root) { + if (!root) return [] + const helper = function (root, levelIndex, res) { + if (!res[levelIndex]) { + res[levelIndex] = [] + } + res[levelIndex].push(root.val) + root.children.forEach(child => { + helper(child, levelIndex + 1, res) + }) + } + const res = [] + helper(root, 0, res) + return res +} \ No newline at end of file diff --git a/Week_02/G20200343030387/LeetCode_49_387.js b/Week_02/G20200343030387/LeetCode_49_387.js new file mode 100644 index 00000000..5d6ff2ec --- /dev/null +++ b/Week_02/G20200343030387/LeetCode_49_387.js @@ -0,0 +1,45 @@ +/** + * @param {string[]} strs + * @return {string[][]} + */ +// 利用js自带的sort排序为每个字符串排序,再放入hash分组 +var groupAnagrams1 = function(strs) { + if (!strs.length) return [] + const groupObj = {} + let key = "" + strs.forEach(str => { + key = str + .split("") + .sort() + .join("") + if (!groupObj[key]) { + groupObj[key] = [] + } + groupObj[key].push(str) + }) + return Object.values(groupObj) +} + +// 利用字符数组,将异位字母字符串归类后hash分组 +var groupAnagrams = function(strs) { + if (!strs.length) return [] + const base = "a".charCodeAt() + const buildIndex = function(char) { + return char.charCodeAt() - base + } + const groupObj = {} + const baseCharArr = new Array(26).fill(0) + strs.forEach(str => { + const charArr = baseCharArr.slice() + // 也可以用split将str转换为字符数组再遍历 + for (let i = 0; i < str.length; i++) { + charArr[buildIndex(str.charAt(i))]++ + } + const key = charArr.join("#") + if (!groupObj[key]) { + groupObj[key] = [] + } + groupObj[key].push(str) + }) + return Object.values(groupObj) +} diff --git a/Week_02/G20200343030387/LeetCode_589_387.js b/Week_02/G20200343030387/LeetCode_589_387.js new file mode 100644 index 00000000..e034345e --- /dev/null +++ b/Week_02/G20200343030387/LeetCode_589_387.js @@ -0,0 +1,47 @@ +/** + * // Definition for a Node. + * function Node(val, children) { + * this.val = val; + * this.children = children; + * }; + */ +// 系统栈 +/** + * @param {Node} root + * @return {number[]} + */ +var preorder1 = function (root) { + const helper = function (root, res) { + if (root) { + res.push(root.val) + root.children.forEach(item => { + helper(item, res) + }) + } + return res + } + const res = [] + helper(root, res) + return res +}; + +// 自定义栈 +var preorder = function (root) { + const stack = [] + const res = [] + let current = root + stack.push(current) + while (stack.length) { + current = stack.pop() + if (current) { + res.push(current.val) + if (current.children) { + // 栈先入后出,所以要reverse + current.children.reverse().forEach(child => { + stack.push(child) + }) + } + } + } + return res +} \ No newline at end of file diff --git a/Week_02/G20200343030387/LeetCode_590_387.js b/Week_02/G20200343030387/LeetCode_590_387.js new file mode 100644 index 00000000..905f0dd2 --- /dev/null +++ b/Week_02/G20200343030387/LeetCode_590_387.js @@ -0,0 +1,30 @@ +/** + * // Definition for a Node. + * function Node(val,children) { + * this.val = val; + * this.children = children; + * }; + */ +// 系统栈递归 +// 后序遍历:先遍历完该节点的子树节点,再添加上根 +/** + * @param {Node} root + * @return {number[]} + */ +var postorder = function (root) { + const helper = function (root, res) { + if (root) { + if (root.children) { + // 递归该子节点的所有子树节点 + root.children.forEach(child => { + helper(child, res) + }) + } + // 添加上根节点 + res.push(root.val) + } + } + const res = [] + helper(root, res) + return res +}; \ No newline at end of file diff --git a/Week_02/G20200343030387/LeetCode_94_387.js b/Week_02/G20200343030387/LeetCode_94_387.js new file mode 100644 index 00000000..27d75189 --- /dev/null +++ b/Week_02/G20200343030387/LeetCode_94_387.js @@ -0,0 +1,53 @@ +/** + * Definition for a binary tree node. + * function TreeNode(val) { + * this.val = val; + * this.left = this.right = null; + * } + */ +// 方法1:系统栈 +/** + * @param {TreeNode} root + * @return {number[]} + */ +const helper1 = function (root, res) { + if (root !== null) { + // 中序遍历:左根右(根在中间,所以称中序) + helper(root.left, res) + res.push(root.val) + helper(root.right, res) + } +} +/** + * @param {TreeNode} root + * @return {number[]} + */ +var inorderTraversal1 = function (root) { + const res = [] + helper(root, res) + return res +} + + +/* ====================================================================== */ + +/** + * 方法2:自定义栈 + * @param {TreeNode} root + * @return {number[]} + */ +var inorderTraversal = function (root) { + const res = [] + const stack = [] // 自定义的栈空间 + let current = root + while (current || stack.length) { + while (current) { + stack.push(current) // 需要将结点push入栈,而不是结点的值 + current = current.left + } + current = stack.pop() // pop出结点,从该结点继续开始遍历 + res.push(current.val) + current = current.right + } + return res +} \ No newline at end of file diff --git a/Week_02/G20200343030387/NOTE.md b/Week_02/G20200343030387/NOTE.md index 50de3041..c0922b3a 100644 --- a/Week_02/G20200343030387/NOTE.md +++ b/Week_02/G20200343030387/NOTE.md @@ -1 +1,68 @@ -学习笔记 \ No newline at end of file +# 学习笔记 + +## 哈希表 +构造hash函数; +防止hash碰撞:扩容或链表节点; + +### java12 HashMap put/get源码分析 +* HashMap基本数组结构,元素是Node类,继承Map,记录节点的值、hash等信息; +* get 每次操作都需要执行hash方法,判断key是否存在,存在则返回Node的值,否则返回Null; +* set 每次操作都需要执行hash方法,判断key是否存在,存在则调整Node的值和hash,否则需要添加Node; +* 添加Node前需要判断当前Node数量是否赶出阈值(该值由加载因子决定),超出则增加多一倍的HashMap容量,防止hash碰撞; + +## 树 +* 二叉搜索树 +* 前、中、后序遍历 +* 一般用递归方法 + +## 递归 +写二叉树遍历的时候,递归代码十分简洁,逻辑清晰; + +### 思维要点 +* 类比盗梦空间:向下递,向上归;每一层环境独立;通过某种条件回到上层,归来时能携带信息; +* 不要人肉递归(最大误区) +* 找最近重复问题,拆解成重复的子问题 +* 数学归纳法思维 + +### 写代码代码: +* 1、递归终结条件 +* 2、处理层当前逻辑 +* 3、下探到下一层 +* 4、清理当前层 + +#### 代码模板 +```python +def recursion(level, param1, param2, ...): + # recursion terminator + if level > MAX_LEVEL: + process_result + return + + # process logic in current level + process(level, data...) + + # drill down + self.recursion(level + 1, p1, ...) + + # reverse the current level status if needed +``` + +```java +public void recur(int level, int param) { + + // terminator + if (level > MAX_LEVEL) { + // process result + return; + } + + // process current logic + process(level, param); + + // drill down + recur( level: level + 1, newParam); + + // restore current status + +} +``` \ No newline at end of file diff --git a/Week_02/G20200343030389/BinaryTreePrevOrder.java b/Week_02/G20200343030389/BinaryTreePrevOrder.java new file mode 100644 index 00000000..92a13399 --- /dev/null +++ b/Week_02/G20200343030389/BinaryTreePrevOrder.java @@ -0,0 +1,56 @@ +package follow.phenix.ice.algorithm.weektwo; + +import java.util.*; + +/** + * @author admin + */ +public class BinaryTreePrevOrder { + + public static void main(String[] args) { + + } + + public List prevOrderByStack(TreeNode root) { + if (root == null) { + return Collections.emptyList(); + } + Stack stack = new Stack<>(); + stack.add(root); + List result = new ArrayList<>(); + while (!stack.isEmpty()) { + TreeNode pop = stack.pop(); + result.add(pop.val); + TreeNode right = pop.right; + if (right != null) { + stack.add(right); + } + TreeNode left = pop.left; + if (left != null) { + stack.add(left); + } + } + return result; + } + + public List prevOrderByRecursion(TreeNode root) { + if (root == null) { + return Collections.emptyList(); + } + List result = new ArrayList<>(); + prevOrderRecursion(result, root); + return result; + } + + private void prevOrderRecursion(List integerList, TreeNode node) { + integerList.add(node.val); + TreeNode left = node.left; + if (left != null) { + prevOrderRecursion(integerList, left); + } + TreeNode right = node.right; + if (right != null) { + prevOrderRecursion(integerList, right); + } + } +} diff --git a/Week_02/G20200343030389/GroupAnagrams.java b/Week_02/G20200343030389/GroupAnagrams.java new file mode 100644 index 00000000..585b0d6b --- /dev/null +++ b/Week_02/G20200343030389/GroupAnagrams.java @@ -0,0 +1,91 @@ +package follow.phenix.ice.algorithm.weektwo; + +import java.util.*; + +/** + * @author admin + */ +public class GroupAnagrams { + + public static void main(String[] args) { + String[] stringArray = new String[]{"ea_t", "t_ea", "tan__", "ate_", "__nat", "bat"}; + GroupAnagrams groupAnagrams = new GroupAnagrams(); + System.out.println(groupAnagrams.groupAnagrams(stringArray)); + System.out.println(groupAnagrams.groupAnagramsBySortChar(stringArray)); + } + + private List> groupAnagrams(String[] strs) { + if (strs == null || strs.length == 0) { + return Collections.emptyList(); + } + Map charIntMap = getCharIntMap(strs); + Map intCharMap = getIntCharMap(charIntMap); + Map> resultMap = new HashMap<>(20); + for (String str : strs) { + String strAfterOrder = getStringAfterOrder(charIntMap, intCharMap, str); + if (resultMap.containsKey(strAfterOrder)) { + List stringList = resultMap.get(strAfterOrder); + stringList.add(str); + } else { + List stringList = new ArrayList<>(); + stringList.add(str); + resultMap.put(strAfterOrder, stringList); + } + } + return new ArrayList<>(resultMap.values()); + } + + private List> groupAnagramsBySortChar(String[] stringArray) { + Map> resultMap = new HashMap<>(20); + for (String string : stringArray) { + char[] chars = string.toCharArray(); + Arrays.sort(chars); + String stringAfterOrder = Arrays.toString(chars); + if (resultMap.containsKey(stringAfterOrder)) { + resultMap.get(stringAfterOrder).add(string); + } else { + List stringList = new ArrayList<>(); + stringList.add(string); + resultMap.put(stringAfterOrder, stringList); + } + } + return new ArrayList<>(resultMap.values()); + } + + private Map getCharIntMap(String[] stringArray) { + int baseNum = 1; + Map result = new HashMap<>(100); + for (String str : stringArray) { + char[] chars = str.toCharArray(); + for (char aChar : chars) { + if (result.containsKey(aChar)) { + continue; + } + result.put(aChar, baseNum++); + } + } + return result; + } + + private Map getIntCharMap(Map charIntMap) { + Map result = new HashMap<>(100); + charIntMap.forEach((k, v) -> result.put(v, k)); + return result; + } + + private String getStringAfterOrder(Map charIntMap, + Map intCharMap, + String str) { + char[] strCharArray = str.toCharArray(); + List orderIntList = new ArrayList<>(); + for (char aChar : strCharArray) { + orderIntList.add(charIntMap.get(aChar)); + } + orderIntList.sort(Comparator.comparingInt(o -> o)); + StringBuilder orderBuilder = new StringBuilder(); + for (Integer integer : orderIntList) { + orderBuilder.append(intCharMap.get(integer)); + } + return orderBuilder.toString(); + } +} diff --git a/Week_02/G20200343030389/LowestCommonAncestorOfBinaryTree.java b/Week_02/G20200343030389/LowestCommonAncestorOfBinaryTree.java new file mode 100644 index 00000000..92d96e4e --- /dev/null +++ b/Week_02/G20200343030389/LowestCommonAncestorOfBinaryTree.java @@ -0,0 +1,62 @@ +package follow.phenix.ice.algorithm.weektwo; + +import java.util.*; + +/** + * @author admin + */ +public class LowestCommonAncestorOfBinaryTree { + + private TreeNode answer; + + public TreeNode lowestCommonAncestorOne(TreeNode root, TreeNode p, TreeNode q) { + hit(root, p, q); + return answer; + } + + private boolean hit(TreeNode self, TreeNode p, TreeNode q) { + if (self == null) { + return false; + } + boolean hitSelf; + boolean hitLeft; + boolean hitRight; + hitSelf = (self == p || self == q); + hitLeft = hit(self.left, p, q); + hitRight = hit(self.right, p, q); + boolean thisTreeNode = (hitSelf && hitLeft) || (hitSelf && hitRight) || (hitLeft && hitRight); + if (thisTreeNode) { + answer = self; + } + return hitSelf || hitLeft || hitRight; + } + + public TreeNode lowestCommonAncestorTwo(TreeNode root, TreeNode p, TreeNode q) { + Map parentMap = new HashMap<>(20); + parentMap.put(root, null); + Stack stack = new Stack<>(); + stack.push(root); + while (!parentMap.containsKey(p) || !parentMap.containsKey(q)) { + TreeNode pop = stack.pop(); + if (pop.left != null) { + parentMap.put(pop.left, pop); + stack.push(pop.left); + } + if (pop.right != null) { + parentMap.put(pop.right, pop); + stack.push(pop.right); + } + } + List pParentList = new ArrayList<>(); + TreeNode thisNode = p; + while (thisNode != null) { + pParentList.add(thisNode); + thisNode = parentMap.get(thisNode); + } + thisNode = q; + while (!pParentList.contains(thisNode)) { + thisNode = parentMap.get(thisNode); + } + return thisNode; + } +} diff --git a/Week_02/G20200343030389/NOTE.md b/Week_02/G20200343030389/NOTE.md index 50de3041..aa7ee9ad 100644 --- a/Week_02/G20200343030389/NOTE.md +++ b/Week_02/G20200343030389/NOTE.md @@ -1 +1,37 @@ -学习笔记 \ No newline at end of file +#### Hash Table +- 哈希表,也叫散列表,是根据关键码值而直接进行访问的数据结构。它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数(Hash Function),存放记录的数组叫做哈希表。 +- 时间复杂度 + 1. 查找:O(1) + 2. 新增:O(1) + 3. 删除:O(1) + 4. 当哈希碰撞很多,或者哈希表的size太小,就会导致链表链的太长,导致查找、新增、删除的都是O(1) + +#### 树 +- 相关概念 + 1. 根节点 + 2. 父节点 + 3. 子节点 + 4. 兄弟节点 + 5. 层级,一层、两层、三层 +- 数组遍历 + 1. 前序(Pre-order):根-左-右 + 2. 中序(In-order):左-根-右 + 3. 后序(Post-order):左-右-根 +- 二叉搜索树 + - 也称二叉搜索排序树,有序二叉树、排序二叉树。是指一颗空树或者具有如下性质的二叉树 + - 特性 + 1. 左子树上所有节点的值均小于它的根节点的值 + 2. 右子树上所有节点的值均大于它的根节点的值 + 3. 以此类推:左、右子树也分别为二叉查找树。(这是重复性) + - 时间复杂度 + 1. 查找:O(logn) + 2. 新增:O(logn) + 3. 删除:O(logn) + +#### 递归 +- 递归-循环,通过函数体来进行的循环 +- 递归代码模板 + 1. 递归终结条件 + 2. 处理当前层的逻辑 + 3. 下探到下一层 + 4. 清理当前层 diff --git a/Week_02/G20200343030389/NnArrayTreeLevelOrder.java b/Week_02/G20200343030389/NnArrayTreeLevelOrder.java new file mode 100644 index 00000000..a43afa28 --- /dev/null +++ b/Week_02/G20200343030389/NnArrayTreeLevelOrder.java @@ -0,0 +1,56 @@ +package follow.phenix.ice.algorithm.weektwo; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * @author admin + */ +public class NnArrayTreeLevelOrder { + + public List> levelOrderByWhile(Node root) { + if (root == null) { + return Collections.emptyList(); + } + List> result = new ArrayList<>(); + List needCheckNodeList = new ArrayList<>(); + needCheckNodeList.add(root); + while (needCheckNodeList.size() > 0) { + List childrenList = new ArrayList<>(); + List valList = new ArrayList<>(); + for (Node node : needCheckNodeList) { + valList.add(node.val); + List children = node.children; + if (children != null) { + childrenList.addAll(node.children); + } + } + result.add(valList); + needCheckNodeList = childrenList; + } + return result; + } + + public List> levelOrderByRecursion(Node root) { + if (root == null) { + return Collections.emptyList(); + } + List> result = new ArrayList<>(); + recursion(result, root, 0); + return result; + } + + private void recursion(List> result, Node node, int level) { + if (result.size() < level + 1) { + result.add(new ArrayList<>()); + } + result.get(level).add(node.val); + List children = node.children; + if (children != null) { + for (Node child : children) { + recursion(result, child, level + 1); + } + } + } +} diff --git a/Week_02/G20200343030389/NnArrayTreeOrder.java b/Week_02/G20200343030389/NnArrayTreeOrder.java new file mode 100644 index 00000000..400e7825 --- /dev/null +++ b/Week_02/G20200343030389/NnArrayTreeOrder.java @@ -0,0 +1,59 @@ +package follow.phenix.ice.algorithm.weektwo; + +import java.util.ArrayList; +import java.util.List; + +; + +/** + * N叉树的后序遍历 + * 1:使用递归的方式 + * 2:官方题解中的迭代手动维护了一个栈,实际和递归是一样的,只不过递归是程序帮我们维护了一个栈 + *

+ * N叉树的前序遍历 + * 1:使用递归的方式 + * + * @author double_ice + */ +@SuppressWarnings("unused") +public class NnArrayTreeOrder { + + public List postOrderByRecursion(Node root) { + List result = new ArrayList<>(); + if (root == null) { + return result; + } + postOrderRecursion(result, root); + return result; + } + + private void postOrderRecursion(List valList, Node node) { + List children = node.children; + if (children != null) { + for (Node child : children) { + postOrderRecursion(valList, child); + } + } + valList.add(node.val); + } + + public List prevOrderByRecursion(Node root) { + List result = new ArrayList<>(); + if (root == null) { + return result; + } + prevOrderRecursion(result, root); + return result; + } + + private void prevOrderRecursion(List valList, Node node) { + valList.add(node.val); + List children = node.children; + if (children == null) { + return; + } + for (Node child : children) { + prevOrderRecursion(valList, child); + } + } +} diff --git a/Week_02/G20200343030389/Node.java b/Week_02/G20200343030389/Node.java new file mode 100644 index 00000000..a6f9b768 --- /dev/null +++ b/Week_02/G20200343030389/Node.java @@ -0,0 +1,20 @@ +package follow.phenix.ice.algorithm.weektwo; + +import java.util.List; + +class Node { + int val; + List children; + + public Node() { + } + + public Node(int _val) { + val = _val; + } + + public Node(int _val, List _children) { + val = _val; + children = _children; + } +} diff --git a/Week_02/G20200343030389/TreeNode.java b/Week_02/G20200343030389/TreeNode.java new file mode 100644 index 00000000..38e4ec02 --- /dev/null +++ b/Week_02/G20200343030389/TreeNode.java @@ -0,0 +1,21 @@ +package follow.phenix.ice.algorithm.weektwo; + +class TreeNode { + int val; + TreeNode left; + TreeNode right; + + TreeNode(int x) { + val = x; + } + + @Override + public boolean equals(Object obj) { + return super.equals(obj); + } + + @Override + public int hashCode() { + return super.hashCode(); + } +} diff --git a/Week_02/G20200343030391/LeetCode_105_391.java b/Week_02/G20200343030391/LeetCode_105_391.java new file mode 100644 index 00000000..2e3f745c --- /dev/null +++ b/Week_02/G20200343030391/LeetCode_105_391.java @@ -0,0 +1,73 @@ +package G20200343030391; + +import java.util.HashMap; + +public class LeetCode_105_391 { + public static void main(String[] args) { + //前序遍历 + int[] preorder = {3, 9, 20, 15, 7}; + //中序遍历 + int[] inorder = {9, 3, 15, 20, 7}; + + TreeNode treeNode = new LeetCode_105_391().buildTree(preorder, inorder); + System.out.println(treeNode); + + } + + int[] preorder; + int[] inorder; + int root_preorder = 0; + HashMap inorder_idx_map = new HashMap(); + + /** + * @param preorder + * @param inorder + * @return + */ + public TreeNode buildTree(int[] preorder, int[] inorder) { + this.inorder = inorder; + this.preorder = preorder; +// 中序遍历数组作为左右子树拆分的入口 + for (int i = 0; i < inorder.length; i++) { + this.inorder_idx_map.put(inorder[i], i); + } + return help(0, inorder.length - 1); + } + + /** + * 递归 + * + * @param inorder_start + * @param inorder_end + * @return + */ + private TreeNode help(int inorder_start, int inorder_end) { + //递归终止条件 + if (inorder_start > inorder_end) { + return null; + } + //根节点值 + int root_val = preorder[root_preorder]; + TreeNode root_node = new TreeNode(root_val); + //以根节点下标分割中序遍历数组左右子树 + int root_idx_inorder = inorder_idx_map.get(root_val); + //开始递归 + //前序遍历下一个根节点下标 + root_preorder++; + //构建左子树 + root_node.left = help(inorder_start, root_idx_inorder - 1); + //构建右子树 + root_node.right = help(root_idx_inorder + 1, inorder_end); + return root_node; + } + + public static class TreeNode { + int val; + TreeNode left; + TreeNode right; + + TreeNode(int x) { + val = x; + } + } +} diff --git a/Week_02/G20200343030391/LeetCode_106_391.java b/Week_02/G20200343030391/LeetCode_106_391.java new file mode 100644 index 00000000..63351e5a --- /dev/null +++ b/Week_02/G20200343030391/LeetCode_106_391.java @@ -0,0 +1,70 @@ +package G20200343030391; + +import java.util.HashMap; + +public class LeetCode_106_391 { + + public static void main(String[] args) { + //中序遍历 + int[] inorder = {9, 3, 15, 20, 7}; + //后序遍历 + int[] postorder = {9, 15, 7, 20, 3}; + TreeNode treeNode = new LeetCode_106_391().buildTree(inorder, postorder); + System.out.println(treeNode); + + } + + int[] inorder; + int[] postorder; + int root_postorder; + HashMap inorder_index_map = new HashMap(); + + /** + * 递归 + * + * @param inorder + * @param postorder + * @return + */ + public TreeNode buildTree(int[] inorder, int[] postorder) { + this.inorder = inorder; + this.postorder = postorder; + for (int i = 0; i < inorder.length; i++) { + inorder_index_map.put(inorder[i], i); + } + root_postorder = postorder.length - 1; + return help(0, inorder.length - 1); + } + + /** + * @param inorder_start + * @param inorder_end + * @return + */ + private TreeNode help(int inorder_start, int inorder_end) { + // 数组长度=0 递归结束条件 + if (inorder_start > inorder_end) { + return null; + } + // 根节点 + int root_val = postorder[root_postorder]; + TreeNode root = new TreeNode(root_val); + int root_index_inorder = inorder_index_map.get(root_val); + + //开始递归 + root_postorder--; + root.right = help(root_index_inorder + 1, inorder_end); + root.left = help(inorder_start, root_index_inorder - 1); + return root; + } + + public static class TreeNode { + int val; + TreeNode left; + TreeNode right; + + TreeNode(int x) { + val = x; + } + } +} diff --git a/Week_02/G20200343030391/LeetCode_144_391.java b/Week_02/G20200343030391/LeetCode_144_391.java new file mode 100644 index 00000000..116f4591 --- /dev/null +++ b/Week_02/G20200343030391/LeetCode_144_391.java @@ -0,0 +1,73 @@ +package G20200343030391; + +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; + +public class LeetCode_144_391 { + + public static void main(String[] args) { + TreeNode node1 = new TreeNode(1); + TreeNode node2 = new TreeNode(2); + TreeNode node3 = new TreeNode(3); + node1.right = node2; + node2.left = node3; + List integers = preorderTraversalByRecursion(node1); + System.out.println(integers); + } + + public static class TreeNode { + int val; + TreeNode left; + TreeNode right; + + TreeNode(int x) { + val = x; + } + } + + /** + * 循环遍历:stack 保存根节点,先访问根节点,然后循环左子树,为空则循环右子树 + * 时间复杂度:O(n) + * + * @param root + * @return + */ + public static List preorderTraversalByLoop(TreeNode root) { + Stack stack = new Stack<>(); + ArrayList result = new ArrayList<>(); + TreeNode node = root; + while (node != null || !stack.isEmpty()) { + if (node != null) { + result.add(node.val); + stack.push(node); + node = node.left; + } else { + TreeNode pop = stack.pop(); + node = pop.right; + } + } + return result; + } + + /** + * 递归遍历:递归查找最左节点,根节点,右节点 + * 时间复杂度:O(n) + * + * @param root + * @return + */ + public static List preorderTraversalByRecursion(TreeNode root) { + ArrayList result = new ArrayList<>(); + recursion(root, result); + return result; + } + + public static void recursion(TreeNode node, ArrayList list) { + if (node != null) { + list.add(node.val); + recursion(node.left, list); + recursion(node.right, list); + } + } +} diff --git a/Week_02/G20200343030391/LeetCode_145_391.java b/Week_02/G20200343030391/LeetCode_145_391.java new file mode 100644 index 00000000..77c1814a --- /dev/null +++ b/Week_02/G20200343030391/LeetCode_145_391.java @@ -0,0 +1,86 @@ +package G20200343030391; + +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; + +public class LeetCode_145_391 { + + public static void main(String[] args) { + TreeNode node1 = new TreeNode(1); + TreeNode node2 = new TreeNode(2); + TreeNode node3 = new TreeNode(3); + TreeNode node4 = new TreeNode(4); + TreeNode node5 = new TreeNode(5); + TreeNode node6 = new TreeNode(6); + node1.right = node2; + node2.left = node3; + node3.left = node4; + node4.right = node5; + node5.right = node6; + List integers = postorderTraversallByLoop(node1); + System.out.println(integers); + } + + public static class TreeNode { + int val; + TreeNode left; + TreeNode right; + + TreeNode(int x) { + val = x; + } + } + + /** + * 循环遍历:stack 保存未访问节点,node保存当前指向的节点(为空代表左子树到头),last代表上次访问的最后节点,栈顶元素右子树不为空 + * 遍历右子树;上次循环最后访问节点!=栈顶元素右节点代表栈顶 + * 时间复杂度:O(n) + * + * @param root + * @return + */ + public static List postorderTraversallByLoop(TreeNode root) { + ArrayList list = new ArrayList<>(); + Stack stack = new Stack<>(); + TreeNode node = root; + TreeNode last = null; + while (node != null || !stack.isEmpty()) { + if (node != null) { + stack.push(node); + node = node.left; + } else { + TreeNode pop = stack.peek(); + if (pop.right != null && pop.right != last) { + node = pop.right; + } else { + list.add(pop.val); + last = pop; + stack.pop(); + } + } + } + return list; + } + + /** + * 递归遍历:递归查找最左节点,右节点,根节点 + * 时间复杂度:O(n) + * + * @param root + * @return + */ + public static List postorderTraversalByRecursion(TreeNode root) { + ArrayList list = new ArrayList<>(); + recursion(root, list); + return list; + } + + public static void recursion(TreeNode node, ArrayList list) { + if (node != null) { + recursion(node.left, list); + recursion(node.right, list); + list.add(node.val); + } + } +} diff --git a/Week_02/G20200343030391/LeetCode_235_391.java b/Week_02/G20200343030391/LeetCode_235_391.java new file mode 100644 index 00000000..142343a2 --- /dev/null +++ b/Week_02/G20200343030391/LeetCode_235_391.java @@ -0,0 +1,59 @@ +package G20200343030391; + +public class LeetCode_235_391 { + public static void main(String[] args) { + TreeNode node3 = new TreeNode(3); + TreeNode node5 = new TreeNode(5); + TreeNode node6 = new TreeNode(6); + TreeNode node2 = new TreeNode(2); + TreeNode node7 = new TreeNode(7); + TreeNode node4 = new TreeNode(4); + TreeNode node1 = new TreeNode(1); + TreeNode node9 = new TreeNode(9); + TreeNode node8 = new TreeNode(8); + node6.left = node2; + node2.left = node9; + node2.right = node4; + node4.left = node3; + node4.right = node5; + node6.right = node8; + node8.left = node7; + node8.right = node9; + TreeNode treeNode = lowestCommonAncestor(node6, node2, node8); + System.out.println(treeNode.val); + } + + /** + * 递归: + * 1.p q 同时小于根节点,则p q 祖先在左子树 + * 2.p q 同时大于根节点,则p q 祖先在右子树 + * 3.p q 位于根节点两侧,则root 为根节点 + * + * @param root + * @param p + * @param q + * @return + */ + public static TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { + if (root == null || root == p || root == q) { + return root; + } + if (root.val > p.val && root.val > q.val) { + return lowestCommonAncestor(root.left, p, q); + } else if (root.val < p.val && root.val < q.val) { + return lowestCommonAncestor(root.right, p, q); + } else { + return root; + } + } + + public static class TreeNode { + int val; + TreeNode left; + TreeNode right; + + TreeNode(int x) { + val = x; + } + } +} diff --git a/Week_02/G20200343030391/LeetCode_236_391.java b/Week_02/G20200343030391/LeetCode_236_391.java new file mode 100644 index 00000000..37206bce --- /dev/null +++ b/Week_02/G20200343030391/LeetCode_236_391.java @@ -0,0 +1,61 @@ +package G20200343030391; + +public class LeetCode_236_391 { + public static void main(String[] args) { + TreeNode node3 = new TreeNode(3); + TreeNode node5 = new TreeNode(5); + TreeNode node6 = new TreeNode(6); + TreeNode node2 = new TreeNode(2); + TreeNode node7 = new TreeNode(7); + TreeNode node4 = new TreeNode(4); + TreeNode node1 = new TreeNode(1); + TreeNode node0 = new TreeNode(0); + TreeNode node8 = new TreeNode(8); + node3.left = node5; + node3.right = node1; + node5.left = node6; + node5.right = node2; + node2.left = node7; + node2.right = node4; + node1.left = node0; + node1.right = node8; + TreeNode treeNode = lowestCommonAncestor(node3, node5, node1); + System.out.println(treeNode.val); + } + + /** + * 递归: 分别递归左右子树查找p,p; + * 若同时存在,则祖先为root; + * 若存在p或q中的 + * + * @param root + * @param p + * @param q + * @return + */ + public static TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { + if (root == null || root == p || root == q) { + return root; + } + TreeNode leftNode = lowestCommonAncestor(root.left, p, q); + TreeNode rightNode = lowestCommonAncestor(root.right, p, q); + // p q 分别存在于左右子树 + if (leftNode != null && rightNode != null) { + return root; + } else if (leftNode == null) {//p q 不在左子树 + return rightNode; + } else { + return leftNode; + } + } + + public static class TreeNode { + int val; + TreeNode left; + TreeNode right; + + TreeNode(int x) { + val = x; + } + } +} diff --git a/Week_02/G20200343030391/LeetCode_242_391.java b/Week_02/G20200343030391/LeetCode_242_391.java new file mode 100644 index 00000000..e953b1fe --- /dev/null +++ b/Week_02/G20200343030391/LeetCode_242_391.java @@ -0,0 +1,29 @@ +package G20200343030391; + +public class LeetCode_242_391 { + + public static void main(String[] args) { + String s = "anaagram"; + String t = "nagaaram"; + System.out.println(isAnagram(s, t)); + } + + public static boolean isAnagram(String s, String t) { + if (s.length() != t.length()) { + return false; + } + char[] sChar = s.toCharArray(); + char[] tChar = t.toCharArray(); + int[] hash = new int[26]; + for (int i = 0; i < sChar.length; i++) { + hash[sChar[i] - 97]++; + hash[tChar[i] - 97]--; + } + for (int i = 0; i < hash.length; i++) { + if (hash[i] != 0) { + return false; + } + } + return true; + } +} diff --git a/Week_02/G20200343030391/LeetCode_429_391.java b/Week_02/G20200343030391/LeetCode_429_391.java new file mode 100644 index 00000000..c4022fe3 --- /dev/null +++ b/Week_02/G20200343030391/LeetCode_429_391.java @@ -0,0 +1,99 @@ +package G20200343030391; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; + +public class LeetCode_429_391 { + + public static void main(String[] args) { + Node node1 = new Node(1, new ArrayList<>()); + Node node2 = new Node(2, new ArrayList<>()); + Node node3 = new Node(3, new ArrayList<>()); + Node node4 = new Node(4, new ArrayList<>()); + Node node5 = new Node(5, new ArrayList<>()); + Node node6 = new Node(6, new ArrayList<>()); + node1.children = new ArrayList() {{ + add(node3); + add(node2); + add(node4); + }}; + node3.children = new ArrayList() {{ + add(node5); + add(node6); + }}; + List> postorder = levelOrderByLoop(node1); + System.out.println(postorder); + } + + /** + * 深度优先:子节点全部加入队列,队列当前长度即为当前从层的元素个数 + * + * @param root + * @return + */ + public static List> levelOrderByLoop(Node root) { + List> result = new ArrayList<>(); + if (root == null) { + return result; + } + Queue queue = new LinkedList<>(); + queue.add(root); + while (!queue.isEmpty()) { + ArrayList level = new ArrayList<>(); + int currentLevelSize = queue.size(); + for (int i = 0; i < currentLevelSize; i++) { + Node node = queue.poll(); + level.add(node.val); + queue.addAll(node.children); + } + result.add(level); + } + return result; + } + + /** + * 递归 + * + * @param root + * @return + */ + public static List> levelOrderByRecursion(Node root) { + List> result = new ArrayList<>(); + if (root == null) { + return result; + } + recursion(root, 0, result); + return result; + } + + public static void recursion(Node node, int level, List> list) { + if (list.size() <= level) { + list.add(new ArrayList<>()); + } + list.get(level).add(node.val); + for (Node child : node.children) { + recursion(child, level + 1, list); + } + } + + public static class Node { + public int val; + public List children; + + public Node() { + } + + public Node(int _val) { + val = _val; + } + + public Node(int _val, List _children) { + val = _val; + children = _children; + } + } + + +} diff --git a/Week_02/G20200343030391/LeetCode_46_391.java b/Week_02/G20200343030391/LeetCode_46_391.java new file mode 100644 index 00000000..9e79ee32 --- /dev/null +++ b/Week_02/G20200343030391/LeetCode_46_391.java @@ -0,0 +1,56 @@ +package G20200343030391; + +import java.util.ArrayList; +import java.util.List; + +public class LeetCode_46_391 { + + public static void main(String[] args) { + int nums[] = {1, 2, 3}; + List> permute = new LeetCode_46_391().permute(nums); + System.out.println(permute); + + } + + public List> permute(int[] nums) { + + List> res = new ArrayList<>(); + boolean[] used = new boolean[nums.length]; + backtrack(res, nums, new ArrayList(), used); + return res; + + } + + /** + * 回溯 + * @param res + * @param nums + * @param tmp + * @param used + */ + private void backtrack(List> res, int[] nums, ArrayList tmp, boolean[] used) { + //递归跳出条件,拿满一组返回结果 + if (tmp.size() == nums.length) { + res.add(new ArrayList<>(tmp)); + return; + } + for (int i = 0; i < nums.length; i++) { + // 当前元素在这一组已经使用过 + if (used[i]) { + continue; + } + + //递归逻辑 元素标记为已经使用过,加入本组 + used[i] = true; + tmp.add(nums[i]); + System.out.println(nums[i]); + + //递归 + backtrack(res, nums, tmp, used); + //回溯,撤销选择重置当前元素为未使用 + used[i] = false; + tmp.remove(tmp.size() - 1); + } + } + +} diff --git a/Week_02/G20200343030391/LeetCode_47_391.java b/Week_02/G20200343030391/LeetCode_47_391.java new file mode 100644 index 00000000..2ee42026 --- /dev/null +++ b/Week_02/G20200343030391/LeetCode_47_391.java @@ -0,0 +1,55 @@ +package G20200343030391; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class LeetCode_47_391 { + + public static void main(String[] args) { + int[] nums = {1, 1, 2}; + List> lists = new LeetCode_47_391().permuteUnique(nums); + System.out.println(lists); + + } + + public List> permuteUnique(int[] nums) { + List> result = new ArrayList<>(); + boolean[] used = new boolean[nums.length]; + // 修改 1:排序(这里用升序),为了剪枝方便 + Arrays.sort(nums); + backtrack(result, nums, used, new ArrayList<>()); + return result; + } + + /** + * 回溯 + * + * @param result + * @param used + * @param group + */ + private void backtrack(List> result, int[] nums, boolean[] used, ArrayList group) { + //递归终止条件 + if (group.size() == used.length) { + result.add(new ArrayList<>(group)); + } + for (int i = 0; i < nums.length; i++) { + //执行逻辑 跳过已经使用过的 + if (used[i]) { + continue; + } + //跳过上一个已经用过,而且更当前元素相同 + if (i > 0 && used[i - 1] && nums[i] == nums[i - 1]) { + continue; + } + used[i] = true; + group.add(nums[i]); + backtrack(result, nums, used, group); + //回溯,撤销决策 + used[i] = false; + group.remove(group.size() - 1); + } + } + +} diff --git a/Week_02/G20200343030391/LeetCode_49_391.java b/Week_02/G20200343030391/LeetCode_49_391.java new file mode 100644 index 00000000..4c3bea99 --- /dev/null +++ b/Week_02/G20200343030391/LeetCode_49_391.java @@ -0,0 +1,38 @@ +package G20200343030391; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class LeetCode_49_391 { + + public static void main(String[] args) { + String[] strings = {"eat", "tea", "tan", "ate", "nat", "bat"}; + List> lists = groupAnagrams(strings); + System.out.println(lists); + } + + public static List> groupAnagrams(String[] strs) { + HashMap> map = new HashMap<>(); + for (int i = 0; i < strs.length; i++) { + String str = strs[i]; + char[] charArray = str.toCharArray(); + Arrays.sort(charArray); + String key = Arrays.toString(charArray); + ArrayList list = map.putIfAbsent(key, new ArrayList() {{ + add(str); + }}); + if (list != null) { + list.add(str); + } + } + List> resultList = new ArrayList<>(); + for (Map.Entry> entry : map.entrySet()) { + resultList.add(entry.getValue()); + } + return resultList; + } + +} diff --git a/Week_02/G20200343030391/LeetCode_589_391.java b/Week_02/G20200343030391/LeetCode_589_391.java new file mode 100644 index 00000000..0eb50628 --- /dev/null +++ b/Week_02/G20200343030391/LeetCode_589_391.java @@ -0,0 +1,93 @@ +package G20200343030391; + +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; + +public class LeetCode_589_391 { + + public static void main(String[] args) { + Node node1 = new Node(1, new ArrayList<>()); + Node node2 = new Node(2, new ArrayList<>()); + Node node3 = new Node(3, new ArrayList<>()); + Node node4 = new Node(4, new ArrayList<>()); + Node node5 = new Node(5, new ArrayList<>()); + Node node6 = new Node(6, new ArrayList<>()); + node1.children = new ArrayList() {{ + add(node3); + add(node2); + add(node4); + }}; + node3.children = new ArrayList() {{ + add(node5); + add(node6); + }}; + List postorder = preorderByLoop(node1); + System.out.println(postorder); + } + + /** + * 循环遍历:先访问根节点,倒叙遍历子节点加入栈 + * + * @param root + * @return + */ + public static List preorderByLoop(Node root) { + ArrayList result = new ArrayList<>(); + if (root == null) { + return result; + } + Stack stack = new Stack<>(); + Node node = root; + stack.add(node); + while (!stack.isEmpty()) { + node = stack.pop(); + result.add(node.val); + for (int i = node.children.size() - 1; i >= 0; i--) { + stack.push(node.children.get(i)); + } + } + + return result; + } + + /** + * 递归 + * + * @param root + * @return + */ + public static List preorderByRecursion(Node root) { + ArrayList result = new ArrayList<>(); + recursion(root, result); + return result; + } + + public static void recursion(Node node, ArrayList list) { + if (node != null) { + list.add(node.val); + for (Node child : node.children) { + recursion(child, list); + } + } + } + + public static class Node { + public int val; + public List children; + + public Node() { + } + + public Node(int _val) { + val = _val; + } + + public Node(int _val, List _children) { + val = _val; + children = _children; + } + } + + +} diff --git a/Week_02/G20200343030391/LeetCode_590_391.java b/Week_02/G20200343030391/LeetCode_590_391.java new file mode 100644 index 00000000..4f52260b --- /dev/null +++ b/Week_02/G20200343030391/LeetCode_590_391.java @@ -0,0 +1,92 @@ +package G20200343030391; + +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; + +public class LeetCode_590_391 { + + public static void main(String[] args) { + Node node1 = new Node(1, new ArrayList<>()); + Node node2 = new Node(2, new ArrayList<>()); + Node node3 = new Node(3, new ArrayList<>()); + Node node4 = new Node(4, new ArrayList<>()); + Node node5 = new Node(5, new ArrayList<>()); + Node node6 = new Node(6, new ArrayList<>()); + node1.children = new ArrayList() {{ + add(node3); + add(node2); + add(node4); + }}; + node3.children = new ArrayList() {{ + add(node5); + add(node6); + }}; + List postorder = postorderByLoop(node1); + System.out.println(postorder); + } + + /** + * 循环遍历:子节点不为空,倒叙遍历子节点,加入栈;子节点为空,且为取值循环步骤,当前节点的最后一个子节点!=上次遍历最后节点,取值加入结果集, + * + * @param root + * @return + */ + public static List postorderByLoop(Node root) { + List result = new ArrayList<>(); + if (root == null) { + return result; + } + Stack stack = new Stack<>(); + Node node = root; + Node last = null; + stack.push(node); + while (!stack.isEmpty()) { + node = stack.peek(); + if (node.children.size() > 0 && node.children.get(node.children.size() - 1) != last) { + for (int i = node.children.size() - 1; i >= 0; i--) { + stack.add(node.children.get(i)); + } + } else { + result.add(node.val); + stack.pop(); + last = node; + } + } + return result; + } + + public static List postorderByRecursion(Node root) { + ArrayList result = new ArrayList<>(); + recursion(root, result); + return result; + } + + public static void recursion(Node node, ArrayList list) { + if (node != null) { + for (Node child : node.children) { + recursion(child, list); + } + list.add(node.val); + } + } + + public static class Node { + public int val; + public List children; + + public Node() { + } + + public Node(int _val) { + val = _val; + } + + public Node(int _val, List _children) { + val = _val; + children = _children; + } + } + + +} diff --git a/Week_02/G20200343030391/LeetCode_77_391.java b/Week_02/G20200343030391/LeetCode_77_391.java new file mode 100644 index 00000000..cff01e82 --- /dev/null +++ b/Week_02/G20200343030391/LeetCode_77_391.java @@ -0,0 +1,47 @@ +package G20200343030391; + +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; + +public class LeetCode_77_391 { + + public static void main(String[] args) { + int n = 1; + int k = 1; + List> combine = new LeetCode_77_391().combine(n, k); + System.out.println(combine); + } + + private List> result = new ArrayList<>(); + + public List> combine(int n, int k) { + if (n <= 1 || k <= 0 || n < k) { + return result; + } + findCombines(n, k, 1, new Stack<>()); + return result; + } + + /** + * 回溯 stack实现回溯功能,保存起点数字 + * + * @param n + * @param k + * @param start + * @param pre + */ + private void findCombines(int n, int k, int start, Stack pre) { + // 递归跳出条件,拿满k个 + if (pre.size() == k) { + result.add(new ArrayList<>(pre)); + return; + } + //起点数字push,用完pop + for (int i = start; i <= n; i++) { + pre.push(i); + findCombines(n, k, i + 1, pre); + pre.pop(); + } + } +} diff --git a/Week_02/G20200343030391/LeetCode_94_391.java b/Week_02/G20200343030391/LeetCode_94_391.java new file mode 100644 index 00000000..46c0dec3 --- /dev/null +++ b/Week_02/G20200343030391/LeetCode_94_391.java @@ -0,0 +1,72 @@ +package G20200343030391; + +import java.util.LinkedList; +import java.util.List; +import java.util.Stack; + +public class LeetCode_94_391 { + + public static void main(String[] args) { + TreeNode node1 = new TreeNode(1); + TreeNode node2 = new TreeNode(2); + TreeNode node3 = new TreeNode(3); + node1.right = node2; + node2.left = node3; + List integers = inorderTraversalByRecursion(node1); + System.out.println(integers); + } + + public static class TreeNode { + int val; + TreeNode left; + TreeNode right; + + TreeNode(int x) { + val = x; + } + } + + /** + * 循环遍历:stack 保存根节点,内存循环查找最左节点 + * 时间复杂度:O(n) + * + * @param root + * @return + */ + public static List inorderTraversalByLoop(TreeNode root) { + Stack stack = new Stack<>(); + LinkedList list = new LinkedList<>(); + TreeNode node = root; + while (node != null || !stack.isEmpty()) { + while (node != null) { + stack.push(node); + node = node.left; + } + node = stack.pop(); + list.add(node.val); + node = node.right; + } + return list; + } + + /** + * 递归遍历:递归查找最左节点,根节点,右节点 + * 时间复杂度:O(n) + * + * @param root + * @return + */ + public static List inorderTraversalByRecursion(TreeNode root) { + LinkedList list = new LinkedList<>(); + recursion(root, list); + return list; + } + + public static void recursion(TreeNode node, LinkedList list) { + if (node != null) { + recursion(node.left, list); + list.add(node.val); + recursion(node.right, list); + } + } +} diff --git a/Week_02/G20200343030391/NOTE.md b/Week_02/G20200343030391/NOTE.md index 50de3041..feba2bd7 100644 --- a/Week_02/G20200343030391/NOTE.md +++ b/Week_02/G20200343030391/NOTE.md @@ -1 +1,45 @@ -学习笔记 \ No newline at end of file +学习笔记 +# 树 + - 深度、层、前中后序遍历、层序遍历 +## 二叉树 + - 每个节点最多左右两个子节点 +## 二叉搜索树 + - 左节点小于根节点,右节点大于根节点;左子树全小于根节点,右子树全大于根节点 + - 中序遍历为升序数组 + +# 递归 +## 盗梦空间 + - 模板 + ```java + public void recur(int lever,int param) { + // terminator + if(leverl > max_level){ + // process result + return; + } + //process current logic + process(level,param); + + //drill down + recur(level:level+1,newParam); + + //restore current status + } + ``` + - 注意 + 1. 抵制人肉递归 + 2. 找最近重复性 + 3. 数学归纳法思维 + +#. HashMap + + 1. 基于Hash表的非同步实现,允许K-V 为null; + 1. 底层基于数组实现(HashMap.Entry[]),单项为一个链表 + 1. HashMap.Entry 包含K,V,next Entry,hash + 1. put(K,V) 通过hash(key.hashCode())计算出hash值决定其在数组中的存储位置,如果此位置上有对象的话,再去使用 equals方法进行比较,如果对此链上的每个对象的 equals 方法比较都为 false,则将该对象放到数组当中,然后将数组中该位置以前存在的那个对象链接到此对象的后面 + 1. get(K) 首先计算key的hashCode,找到数组中对应位置的某一元素,然后通过key的equals方法在对应位置的链表中找到需要的元素。 + 1. 当hash冲突很多时,HashMap退化成链表。 + 1. key为null时,都放到table[0] + 1. 扩容默认负载因子0.75,重新计算位置单个Entry在新数组中的位置 (resize) + 1. fast-fail volatile modCount + 1. java 8 HashMap 改为 数组+链表/红黑树,同一hash位下链表元素>=8时,链表转换为红黑树 \ No newline at end of file diff --git a/Week_02/G20200343030393/LeetCode_105_393.py b/Week_02/G20200343030393/LeetCode_105_393.py new file mode 100644 index 00000000..fc780794 --- /dev/null +++ b/Week_02/G20200343030393/LeetCode_105_393.py @@ -0,0 +1,13 @@ +class Solution(object): + def buildTree(self, preorder, inorder): + """ + :type preorder: List[int] + :type inorder: List[int] + :rtype: TreeNode + """ + if inorder: + inx = inorder.index(preorder.pop(0)) + root = TreeNode(inorder[inx]) + root.left = self.buildTree(preorder, inorder[0: inx]) + root.right = self.buildTree(preorder, inorder[inx + 1:]) + return root \ No newline at end of file diff --git a/Week_02/G20200343030393/LeetCode_144_393.py b/Week_02/G20200343030393/LeetCode_144_393.py new file mode 100644 index 00000000..edd92e1f --- /dev/null +++ b/Week_02/G20200343030393/LeetCode_144_393.py @@ -0,0 +1,15 @@ +class Solution(object): + def preorderTraversal(self, root): + """ + :type root: TreeNode + :rtype: List[int] + """ + res = [] + def dfs(root): + if not root: + return + res.append(root.val) + dfs(root.left) + dfs(root.right) + dfs(root) + return res \ No newline at end of file diff --git a/Week_02/G20200343030393/LeetCode_1_393.py b/Week_02/G20200343030393/LeetCode_1_393.py new file mode 100644 index 00000000..4d679824 --- /dev/null +++ b/Week_02/G20200343030393/LeetCode_1_393.py @@ -0,0 +1,13 @@ +class Solution(object): + def twoSum(self, nums, target): + """ + :type nums: List[int] + :type target: int + :rtype: List[int] + """ + dir_values = {} + for k, v in enumerate(nums): + value = dir_values.get(target - v) + if value is not None: + return [k, value] + dir_values[v] = k \ No newline at end of file diff --git a/Week_02/G20200343030393/LeetCode_236_393.py b/Week_02/G20200343030393/LeetCode_236_393.py new file mode 100644 index 00000000..848bd8e3 --- /dev/null +++ b/Week_02/G20200343030393/LeetCode_236_393.py @@ -0,0 +1,29 @@ +class Solution(object): + def lowestCommonAncestor(self, root, p, q): + """ + :type root: TreeNode + :type p: TreeNode + :type q: TreeNode + :rtype: TreeNode + """ + if root in (None, p, q): + return root + left = self.lowestCommonAncestor(root.left, p, q) + + if left not in (None, p, q): + return left + right = self.lowestCommonAncestor(root.right, p, q) + + if left and right: + return root + else: + return left or right + + # if root in (None, p, q): + # return root + # + # left, right = (self.lowestCommonAncestor(kid, p, q) for kid in (root.left, root.right)) + # if left and right: + # return root + # else: + # return left or right \ No newline at end of file diff --git a/Week_02/G20200343030393/LeetCode_242_393.py b/Week_02/G20200343030393/LeetCode_242_393.py new file mode 100644 index 00000000..94f46056 --- /dev/null +++ b/Week_02/G20200343030393/LeetCode_242_393.py @@ -0,0 +1,38 @@ +class Solution(object): + def isAnagram(self, s, t): + """ + :type s: str + :type t: str + :rtype: bool + """ + # if len(s) != len(t): + # return False + # + # letter = {} + # for i in s: + # if i in letter.keys(): + # letter[i] += 1 + # else: + # letter[i] = 1 + # + # for i in t: + # if i in letter.keys(): + # letter[i] -= 1 + # else: + # return False + # + # for _, v in letter.items(): + # if v != 0: + # return False + # return True + + if len(s) != len(t): return False + if s == t: return True + + se = set(s) + if se == set(t): + for i in se: + if s.count(i) != t.count(i): return False + return True + else: + return False \ No newline at end of file diff --git a/Week_02/G20200343030393/LeetCode_49_393.py b/Week_02/G20200343030393/LeetCode_49_393.py new file mode 100644 index 00000000..6b00e8a2 --- /dev/null +++ b/Week_02/G20200343030393/LeetCode_49_393.py @@ -0,0 +1,22 @@ +import collections + + +class Solution(object): + def groupAnagrams(self, strs): + """ + :type strs: List[str] + :rtype: List[List[str]] + """ + ans = collections.defaultdict(list) + for s in strs: + count = [0] * 26 + for c in s: + count[ord(c) - ord('a')] += 1 + ans[tuple(count)].append(s) + return ans.values() + + # d = {} + # for w in strs: + # key = tuple(sorted(w)) + # d[key] = d.get(key, []) + [w] + # return d.values() \ No newline at end of file diff --git a/Week_02/G20200343030393/LeetCode_589_393.py b/Week_02/G20200343030393/LeetCode_589_393.py new file mode 100644 index 00000000..b0f2c345 --- /dev/null +++ b/Week_02/G20200343030393/LeetCode_589_393.py @@ -0,0 +1,24 @@ +class Solution(object): + def preorder(self, root, res=None): + """ + :type root: Node + :rtype: List[int] + """ + # if not root: return [] + # if not res: res = [] + # + # for i in root.children: res += self.preorder(i) + # return [root.val] + res + + if not root: return [] + res = [] + + def dfs(root): + if not root: + return + res.append(root.val) + for i in root.children: + dfs(i) + + dfs(root) + return res \ No newline at end of file diff --git a/Week_02/G20200343030393/LeetCode_590_393.py b/Week_02/G20200343030393/LeetCode_590_393.py new file mode 100644 index 00000000..45f2b47a --- /dev/null +++ b/Week_02/G20200343030393/LeetCode_590_393.py @@ -0,0 +1,10 @@ +class Solution(object): + def postorder(self, root, res=None): + """ + :type root: Node + :rtype: List[int] + """ + if not root: return [] + if not res: res = [] + for i in root.children: res += self.postorder(i) + return res + [root.val] \ No newline at end of file diff --git a/Week_02/G20200343030393/LeetCode_77_393.py b/Week_02/G20200343030393/LeetCode_77_393.py new file mode 100644 index 00000000..05629385 --- /dev/null +++ b/Week_02/G20200343030393/LeetCode_77_393.py @@ -0,0 +1,27 @@ +class Solution(object): + def combine(self, n, k): + """ + :type n: int + :type k: int + :rtype: List[List[int]] + """ + ans = [] + stack = [] + x = 1 + while True: + l = len(stack) + if l == k: + ans.append(stack[:]) + if l == k or x > n - k + l + 1: + if not stack: + return ans + x = stack.pop() + 1 + else: + stack.append(x) + x += 1 + + +n = 4 +k = 2 +aa = Solution() +print(aa.combine(n, k)) diff --git a/Week_02/G20200343030393/LeetCode_94_393.py b/Week_02/G20200343030393/LeetCode_94_393.py new file mode 100644 index 00000000..48996534 --- /dev/null +++ b/Week_02/G20200343030393/LeetCode_94_393.py @@ -0,0 +1,15 @@ +class Solution(object): + def inorderTraversal(self, root): + """ + :type root: TreeNode + :rtype: List[int] + """ + res = [] + def dfs(root): + if not root: + return + dfs(root.right) + res.append(root.val) + dfs(root.left) + dfs(root) + return res \ No newline at end of file diff --git a/Week_02/G20200343030395/LeetCode_3_395.java b/Week_02/G20200343030395/LeetCode_3_395.java new file mode 100644 index 00000000..f71bb066 --- /dev/null +++ b/Week_02/G20200343030395/LeetCode_3_395.java @@ -0,0 +1,38 @@ +package Week_02.G20200343030395; + +import java.util.*; + +public class LeetCode_3_395 { + + public static void main(String[] args) { + + String[] strs = new String[]{"eat", "tea", "tan", "ate", "nat", "bat"}; + + if(strs.length == 0) { + } + } + + public List> groupAnagrams(String[] strs) { + if(strs.length == 0) { + return new ArrayList>(); + } + + Map map = new HashMap(); + //循环 + for (String s : strs) { + char[] ca = s.toCharArray(); + //排序 + Arrays.sort(ca); + String key = String.valueOf(ca); + //分组 + if(!map.containsKey(key)) { + map.put(key, new ArrayList()); + } + + map.get(key).add(s); + } + + //直接返回 + return new ArrayList(map.values()); + } +} diff --git a/Week_02/G20200343030395/LeetCode_4_395.java b/Week_02/G20200343030395/LeetCode_4_395.java new file mode 100644 index 00000000..21a09fde --- /dev/null +++ b/Week_02/G20200343030395/LeetCode_4_395.java @@ -0,0 +1,31 @@ +package Week_02.G20200343030395; +import java.util.ArrayList; +import java.util.List; + +public class LeetCode_4_395 { + + public class TreeNode { + int val; + TreeNode left; + TreeNode right; + TreeNode(int x) { val = x; } + } + + List list = new ArrayList<>(); + + public List preorderTraversal(TreeNode root) { + if(root == null) { + return list; + } + + list.add(root.val); + + preorderTraversal(root.left); + + preorderTraversal(root.right); + + return list; + } +} + + diff --git a/Week_02/G20200343030395/LeetCode_5_395.java b/Week_02/G20200343030395/LeetCode_5_395.java new file mode 100644 index 00000000..64b1e720 --- /dev/null +++ b/Week_02/G20200343030395/LeetCode_5_395.java @@ -0,0 +1,55 @@ +package Week_02.G20200343030395; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; + +public class LeetCode_5_395 { + + class Node { + public int val; + public List children; + + public Node() {} + + public Node(int _val) { + val = _val; + } + + public Node(int _val, List _children) { + val = _val; + children = _children; + } + }; + + + public List> levelOrder(Node root) { + List> result = new ArrayList<>(); + if(root == null) { + return result; + } + + Queue queue = new LinkedList<>(); + //第一个节点放入队列 + queue.add(root); + + while(!queue.isEmpty()) { + //新建一个这个等级的,用于保存 + List level = new ArrayList<>(); + int size = queue.size(); + + for (int i=0; i idxMap = new HashMap(); + + public TreeNode helper(int inLeft, int inRight) { + if(inLeft == inRight) { + return null; + } + + //取出当前节点 + int rootVal = preOrder[preIdx]; + TreeNode root = new TreeNode(rootVal); + + //取出当前节点在中序遍历中的位置 + int index = idxMap.get(rootVal); + preIdx ++; + + //从当前位置,左前序遍历 + root.left = helper(inLeft, index); + //从当前位置,右前序遍历 + root.right = helper(index+1, inRight); + + return root; + } + + public TreeNode buildTree(int[] preorder, int[] inorder){ + + this.preOrder = preorder; + this.inOrder = inorder; + + int idx = 0; + //按中序遍历建立一个map + for (Integer val : inorder) { + idxMap.put(val, idx++); + } + + return helper(0, inorder.length); + } + +} diff --git a/Week_02/G20200343030395/NOTE.md b/Week_02/G20200343030395/NOTE.md index 50de3041..f5e41415 100644 --- a/Week_02/G20200343030395/NOTE.md +++ b/Week_02/G20200343030395/NOTE.md @@ -1 +1,19 @@ -学习笔记 \ No newline at end of file +学习笔记 +## 2020/2/17 +* 哈希函数(散列函数) 平均O(1) 会退化成链表 +* 层序遍历 用队列实现,每次塞入当前层的节点,然后取出队列中的节点用于输出 +再遍历塞入当前节点的所有子节点 + +## 2020/2/19 +递归:循环 +找最近重复子问题 + +递归四个结构 +1. 递归终结条件,结束逻辑 +2. 当前逻辑 +3. 递归逻辑,下探 +4. 清理(可能不需要) + +## 2020/2/23 +1. 不要人肉递归 +2. 找最近重复子问题就行 diff --git a/Week_02/G20200343030401/LeetCode_105_401.java b/Week_02/G20200343030401/LeetCode_105_401.java new file mode 100644 index 00000000..6c407875 --- /dev/null +++ b/Week_02/G20200343030401/LeetCode_105_401.java @@ -0,0 +1,57 @@ +//题目链接: https://leetcode-cn.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/ + + /** + * 方法: 递归 + * 时间复杂度: O(N) + * 空间复杂度:O(N),存储整棵树的开销 + */ +public class TreeNode { + int val; + TreeNode left; + TreeNode right; + + TreeNode(int x) { + val = x; + } + } + +class Solution { + // start from first preorder element + int pre_idx = 0; + int[] preorder; + int[] inorder; + HashMap idx_map = new HashMap(); + + public TreeNode helper(int in_left, int in_right) { + // if there is no elements to construct subtrees + if (in_left == in_right) + return null; + + // pick up pre_idx element as a root + int root_val = preorder[pre_idx]; + TreeNode root = new TreeNode(root_val); + + // root splits inorder list + // into left and right subtrees + int index = idx_map.get(root_val); + + // recursion + pre_idx++; + // build left subtree + root.left = helper(in_left, index); + // build right subtree + root.right = helper(index + 1, in_right); + return root; + } + + public TreeNode buildTree(int[] preorder, int[] inorder) { + this.preorder = preorder; + this.inorder = inorder; + + // build a hashmap value -> its index + int idx = 0; + for (Integer val : inorder) + idx_map.put(val, idx++); + return helper(0, inorder.length); + } + } \ No newline at end of file diff --git a/Week_02/G20200343030401/LeetCode_49_401.java b/Week_02/G20200343030401/LeetCode_49_401.java new file mode 100644 index 00000000..455bd174 --- /dev/null +++ b/Week_02/G20200343030401/LeetCode_49_401.java @@ -0,0 +1,47 @@ +//题目链接: https://leetcode-cn.com/problems/group-anagrams/ + +class Solution { + /** + * 方法1: 排序数组分类 + * 时间复杂度: O(NKlogK),其中 N 是 strs 的长度,而 K是 strs 中字符串的最大长度。当我们遍历每个字符串时,外部循环具有的复杂度为 O(N)。然后,我们在 O(KlogK) 的时间内对每个字符串排序。 + * 空间复杂度:O(NK),排序存储在 ans 中的全部信息内容。 + */ + public List> groupAnagrams1(String[] strs) { + if (strs.length == 0) return new ArrayList(); + Map ans = new HashMap(); + for (String s : strs) { + char[] ca = s.toCharArray(); + Arrays.sort(ca); + String key = String.valueOf(ca); + if (!ans.containsKey(key)) ans.put(key, new ArrayList()); + ans.get(key).add(s); + } + return new ArrayList(ans.values()); + } + + /** + * 方法2: 按计数分类 + * 时间复杂度: 时间复杂度:O(NK)O(NK),其中 NN 是 strs 的长度,而 KK 是 strs 中字符串的最大长度。计算每个字符串的字符串大小是线性的,我们统计每个字符串。 + * 空间复杂度:O(NK),排序存储在 ans 中的全部信息内容。 + */ + public List> groupAnagrams2(String[] strs) { + if (strs.length == 0) return new ArrayList(); + Map ans = new HashMap(); + int[] count = new int[26]; + for (String s : strs) { + Arrays.fill(count, 0); + for (char c : s.toCharArray()) count[c - 'a']++; + + StringBuilder sb = new StringBuilder(""); + for (int i = 0; i < 26; i++) { + sb.append('#'); + sb.append(count[i]); + } + String key = sb.toString(); + if (!ans.containsKey(key)) ans.put(key, new ArrayList()); + ans.get(key).add(s); + } + return new ArrayList(ans.values()); + } + +} \ No newline at end of file diff --git a/Week_02/G20200343030401/LeetCode_77_401.java b/Week_02/G20200343030401/LeetCode_77_401.java new file mode 100644 index 00000000..5207db4b --- /dev/null +++ b/Week_02/G20200343030401/LeetCode_77_401.java @@ -0,0 +1,58 @@ +//题目链接: https://leetcode-cn.com/problems/combinations/ + + +/** + * 方法1: 回溯法 + */ +class Solution { + List> output = new LinkedList(); + int n; + int k; + public List> combine(int n, int k) { + this.n = n; + this.k = k; + backtrack(1, new LinkedList()); + return output; + } + public void backtrack(int first, LinkedList curr) { + // if the combination is done + if (curr.size() == k) + output.add(new LinkedList(curr)); + + for (int i = first; i < n + 1; ++i) { + // add i into the current combination + curr.add(i); + // use next integers to complete the combination + backtrack(i + 1, curr); + // backtrack + curr.removeLast(); + } + } +} + +/** + * 方法2: 字典序 (二进制排序) 组合 + */ +class Solution { + public List> combine(int n, int k) { + // init first combination + LinkedList nums = new LinkedList(); + for(int i = 1; i < k + 1; ++i) + nums.add(i); + nums.add(n + 1); + + List> output = new ArrayList>(); + int j = 0; + while (j < k) { + // add current combination + output.add(new LinkedList(nums.subList(0, k))); + // increase first nums[j] by one + // if nums[j] + 1 != nums[j + 1] + j = 0; + while ((j < k) && (nums.get(j + 1) == nums.get(j) + 1)) + nums.set(j, j++ + 1); + nums.set(j, nums.get(j) + 1); + } + return output; + } + } diff --git a/Week_02/G20200343030401/NOTE.md b/Week_02/G20200343030401/NOTE.md index 50de3041..44ee65f9 100644 --- a/Week_02/G20200343030401/NOTE.md +++ b/Week_02/G20200343030401/NOTE.md @@ -1 +1,98 @@ -学习笔记 \ No newline at end of file +###极客大学算法训练营week02学习笔记 +#####2.源码以及原理分析 +######(1) Java中HashMap的实现原理 +* HashMap概述 +  HashMap底层就是一个数组结构,数组中的每一项又是一个链表。当新建一个HashMap的时候,就会初始化一个数组。 + +其中Java源码如下: +```Java +/** + * The table, resized as necessary. Length MUST Always be a power of two. + */ +transient Entry[] table; + +static class Entry implements Map.Entry { + final K key; + V value; + Entry next; + final int hash; + …… +} +``` +  可以看出,Entry就是数组中的元素,每个 Map.Entry 其实就是一个key-value对,它持有一个指向下一个元素的引用,这就构成了链表。 + +* HashMap实现存储和读取 +1)存储 +```Java +public V put(K key, V value) { + // HashMap允许存放null键和null值。 + // 当key为null时,调用putForNullKey方法,将value放置在数组第一个位置。 + if (key == null) + return putForNullKey(value); + // 根据key的keyCode重新计算hash值。 + int hash = hash(key.hashCode()); + // 搜索指定hash值在对应table中的索引。 + int i = indexFor(hash, table.length); + // 如果 i 索引处的 Entry 不为 null,通过循环不断遍历 e 元素的下一个元素。 + for (Entry e = table[i]; e != null; e = e.next) { + Object k; + if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { + // 如果发现已有该键值,则存储新的值,并返回原始值 + V oldValue = e.value; + e.value = value; + e.recordAccess(this); + return oldValue; + } + } + // 如果i索引处的Entry为null,表明此处还没有Entry。 + modCount++; + // 将key、value添加到i索引处。 + addEntry(hash, key, value, i); + return null; +} +``` +  根据hash值得到这个元素在数组中的位置(即下标),如果数组该位置上已经存放有其他元素了,那么在这个位置上的元素将以链表的形式存放,新加入的放在链头,最先加入的放在链尾。如果数组该位置上没有元素,就直接将该元素放到此数组中的该位置上。 +  hash(int h)方法根据key的hashCode重新计算一次散列。此算法加入了高位计算,防止低位不变,高位变化时,造成的hash冲突。 + +```Java + static int hash(int h) { + h ^= (h >>> 20) ^ (h >>> 12); + return h ^ (h >>> 7) ^ (h >>> 4); +} +``` +  我们可以看到在HashMap中要找到某个元素,需要根据key的hash值来求得对应数组中的位置。如何计算这个位置就是hash算法。前面说过HashMap的数据结构是数组和链表的结合,所以我们当然希望这个HashMap里面的元素位置尽量的分布均匀些,尽量使得每个位置上的元素数量只有一个,那么当我们用hash算法求得这个位置的时候,马上就可以知道对应位置的元素就是我们要的,而不用再去遍历链表,这样就大大优化了查询的效率。 +  根据上面 put 方法的源代码可以看出,当程序试图将一个key-value对放入HashMap中时,程序首先根据该 key的 hashCode() 返回值决定该 Entry 的存储位置:如果两个 Entry 的 key 的 hashCode() 返回值相同,那它们的存储位置相同。如果这两个 Entry 的 key 通过 equals 比较返回 true,新添加 Entry 的 value 将覆盖集合中原有 Entry的 value,但key不会覆盖。如果这两个 Entry 的 key 通过 equals 比较返回 false,新添加的 Entry 将与集合中原有 Entry 形成 Entry 链,而且新添加的 Entry 位于 Entry 链的头部——具体说明继续看 addEntry() 方法的说明。 +  通过这种方式就可以高效的解决HashMap的冲突问题。 + +2)读取 +```Java +public V get(Object key) { + if (key == null) + return getForNullKey(); + int hash = hash(key.hashCode()); + for (Entry e = table[indexFor(hash, table.length)]; + e != null; + e = e.next) { + Object k; + if (e.hash == hash && ((k = e.key) == key || key.equals(k))) + return e.value; + } + return null; +} +``` +  从HashMap中get元素时,首先计算key的hashCode,找到数组中对应位置的某一元素,然后通过key的equals方法在对应位置的链表中找到需要的元素。 + +3)归纳起来简单地说,HashMap 在底层将 key-value 当成一个整体进行处理,这个整体就是一个 Entry 对象。HashMap 底层采用一个 Entry[] 数组来保存所有的 key-value 对,当需要存储一个 Entry 对象时,会根据hash算法来决定其在数组中的存储位置,在根据equals方法决定其在该数组位置上的链表中的存储位置;当需要取出一个Entry时,也会根据hash算法找到其在数组中的存储位置,再根据equals方法从该位置上的链表中取出该Entry。 + +* HashMap的resize +  当hashmap中的元素越来越多的时候,碰撞的几率也就越来越高(因为数组的长度是固定的),所以为了提高查询的效率,就要对hashmap的数组进行扩容,数组扩容这个操作也会出现在ArrayList中,所以这是一个通用的操作,很多人对它的性能表示过怀疑,不过想想我们的“均摊”原理,就释然了,而在hashmap数组扩容之后,最消耗性能的点就出现了:原数组中的数据必须重新计算其在新数组中的位置,并放进去,这就是resize。 +  那么hashmap什么时候进行扩容呢?当hashmap中的元素个数超过数组大小*loadFactor时,就会进行数组扩容,loadFactor的默认值为0.75,也就是说,默认情况下,数组大小为16,那么当hashmap中元素个数超过16*0.75=12的时候,就把数组的大小扩展为2*16=32,即扩大一倍,然后重新计算每个元素在数组中的位置,而这是一个非常消耗性能的操作,所以如果我们已经预知hashmap中元素的个数,那么预设元素的个数能够有效的提高hashmap的性能。比如说,我们有1000个元素new HashMap(1000), 但是理论上来讲new HashMap(1024)更合适,不过上面annegu已经说过,即使是1000,hashmap也自动会将其设置为1024。 但是new HashMap(1024)还不是更合适的,因为0.75*1000 < 1000, 也就是说为了让0.75 * size > 1000, 我们必须这样new HashMap(2048)才最合适,既考虑了&的问题,也避免了resize的问题。 + +* 总结 +1)利用key的hashCode重新hash计算出当前对象的元素在数组中的下标 +存储时,如果出现hash值相同的key,此时有两种情况。 +2)如果key相同,则覆盖原始值;(2)如果key不同(出现冲突),则将当前的key-value放入链表中 +3)获取时,直接找到hash值对应的下标,在进一步判断key是否相同,从而找到对应值。 +4)理解了以上过程就不难明白HashMap是如何解决hash冲突的问题,核心就是使用了数组的存储方式,然后将冲突的key的对象放入链表中,一旦发现冲突就在链表中做进一步的对比。 + + diff --git "a/Week_02/G20200343030407/[144]\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\351\201\215\345\216\206.py" "b/Week_02/G20200343030407/[144]\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\351\201\215\345\216\206.py" new file mode 100644 index 00000000..07ef3c30 --- /dev/null +++ "b/Week_02/G20200343030407/[144]\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\351\201\215\345\216\206.py" @@ -0,0 +1,52 @@ +# 给定一个二叉树,返回它的 前序 遍历。 +# +# 示例: +# +# 输入: [1,null,2,3] +# 1 +# \ +# 2 +# / +# 3 +# +# 输出: [1,2,3] +# +# +# 进阶: 递归算法很简单,你可以通过迭代算法完成吗? +# Related Topics 栈 树 + + +# leetcode submit region begin(Prohibit modification and deletion) +# Definition for a binary tree node. +class TreeNode: + def __init__(self, x): + self.val = x + self.left = None + self.right = None + + +class Solution: + def preorderTraversal(self, root: TreeNode) -> List[int]: + res = [] + ''' + self.dfs(root, res) + ''' + + stack = [root] + while stack: + node = stack.pop() + if node: + res.append(node.val) + stack.append(node.right) + stack.append(node.left) + return res + + def dfs(self, root, res): + if root: + res.append(root.val) + self.dfs(root.left, res) + self.dfs(root.right, res) + + + +# leetcode submit region end(Prohibit modification and deletion) diff --git "a/Week_02/G20200343030407/[145]\344\272\214\345\217\211\346\240\221\347\232\204\345\220\216\345\272\217\351\201\215\345\216\206.py" "b/Week_02/G20200343030407/[145]\344\272\214\345\217\211\346\240\221\347\232\204\345\220\216\345\272\217\351\201\215\345\216\206.py" new file mode 100644 index 00000000..5daf4d22 --- /dev/null +++ "b/Week_02/G20200343030407/[145]\344\272\214\345\217\211\346\240\221\347\232\204\345\220\216\345\272\217\351\201\215\345\216\206.py" @@ -0,0 +1,51 @@ +# 给定一个二叉树,返回它的 后序 遍历。 +# +# 示例: +# +# 输入: [1,null,2,3] +# 1 +# \ +# 2 +# / +# 3 +# +# 输出: [3,2,1] +# +# 进阶: 递归算法很简单,你可以通过迭代算法完成吗? +# Related Topics 栈 树 + + +# leetcode submit region begin(Prohibit modification and deletion) +# Definition for a binary tree node. +class TreeNode: + def __init__(self, x): + self.val = x + self.left = None + self.right = None + + +class Solution: + def postorderTraversal(self, root: TreeNode) -> List[int]: + res = [] + ''' + self.dfs(root, res) + ''' + + stack = [root] + while stack: + node = stack.pop() + stack.append(root.right) + stack.append(root.left) + res + + return res + + def dfs(self, root, res): + if root: + self.dfs(root.left, res) + self.dfs(root.right, res) + res.append(root.val) + + + +# leetcode submit region end(Prohibit modification and deletion) diff --git "a/Week_02/G20200343030407/[429]N\345\217\211\346\240\221\347\232\204\345\261\202\345\272\217\351\201\215\345\216\206.py" "b/Week_02/G20200343030407/[429]N\345\217\211\346\240\221\347\232\204\345\261\202\345\272\217\351\201\215\345\216\206.py" new file mode 100644 index 00000000..6d9084ef --- /dev/null +++ "b/Week_02/G20200343030407/[429]N\345\217\211\346\240\221\347\232\204\345\261\202\345\272\217\351\201\215\345\216\206.py" @@ -0,0 +1,59 @@ +# 给定一个 N 叉树,返回其节点值的层序遍历。 (即从左到右,逐层遍历)。 +# +# 例如,给定一个 3叉树 : +# +# +# +# +# +# +# +# 返回其层序遍历: +# +# [ +# [1], +# [3,2,4], +# [5,6] +# ] +# +# +# +# +# 说明: +# +# +# 树的深度不会超过 1000。 +# 树的节点总数不会超过 5000。 +# Related Topics 树 广度优先搜索 + + +# leetcode submit region begin(Prohibit modification and deletion) +"""""" +from typing import List + + +# Definition for a Node. +class Node: + def __init__(self, val=None, children=None): + self.val = val + self.children = children + + +class Solution: + def levelOrder(self, root: 'Node') -> List[List[int]]: + if not root: + return [] + res = [] + stack = [root] + while stack: + temp = [] + next_stack = [] + for node in stack: + temp.append(node.val) + for child in node.children: + next_stack.append(child) + res.append(temp) + stack = next_stack + return res + +# leetcode submit region end(Prohibit modification and deletion) diff --git "a/Week_02/G20200343030407/[49]\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215\345\210\206\347\273\204.py" "b/Week_02/G20200343030407/[49]\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215\345\210\206\347\273\204.py" new file mode 100644 index 00000000..0386c7e4 --- /dev/null +++ "b/Week_02/G20200343030407/[49]\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215\345\210\206\347\273\204.py" @@ -0,0 +1,48 @@ +# 给定一个字符串数组,将字母异位词组合在一起。字母异位词指字母相同,但排列不同的字符串。 +# +# 示例: +# +# 输入: ["eat", "tea", "tan", "ate", "nat", "bat"], +# 输出: +# [ +# ["ate","eat","tea"], +# ["nat","tan"], +# ["bat"] +# ] +# +# 说明: +# +# +# 所有输入均为小写字母。 +# 不考虑答案输出的顺序。 +# +# Related Topics 哈希表 字符串 +import collections +from typing import List + + +# leetcode submit region begin(Prohibit modification and deletion) +class Solution: + def groupAnagrams(self, strs: List[str]) -> List[List[str]]: + ''' + res_dict = collections.defaultdict(list) + for s in strs: + s_sort = "".join(sorted(s)) + res_dict[s_sort].append(s) + return res_dict.values() + ''' + '''''' + res_dict = collections.defaultdict(list) + for st in strs: + a = [0] * 26 + for l in st: + a[ord(l) - ord('a')] += 1 + res_dict[tuple(a)].append(st) + return res_dict.values() + + + +strings = ["eat", "tea", "tan", "ate", "nat", "bat"] +print(Solution().groupAnagrams(strings)) + +# leetcode submit region end(Prohibit modification and deletion) diff --git "a/Week_02/G20200343030407/[\351\235\242\350\257\225\351\242\23068 - II]\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\350\277\221\345\205\254\345\205\261\347\245\226\345\205\210.py" "b/Week_02/G20200343030407/[\351\235\242\350\257\225\351\242\23068 - II]\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\350\277\221\345\205\254\345\205\261\347\245\226\345\205\210.py" new file mode 100644 index 00000000..c2566809 --- /dev/null +++ "b/Week_02/G20200343030407/[\351\235\242\350\257\225\351\242\23068 - II]\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\350\277\221\345\205\254\345\205\261\347\245\226\345\205\210.py" @@ -0,0 +1,58 @@ +# 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。 +# +# 百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大( +# 一个节点也可以是它自己的祖先)。” +# +# 例如,给定如下二叉树: root = [3,5,1,6,2,0,8,null,null,7,4] +# +# +# +# +# +# 示例 1: +# +# 输入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1 +# 输出: 3 +# 解释: 节点 5 和节点 1 的最近公共祖先是节点 3。 +# +# +# 示例 2: +# +# 输入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4 +# 输出: 5 +# 解释: 节点 5 和节点 4 的最近公共祖先是节点 5。因为根据定义最近公共祖先节点可以为节点本身。 +# +# +# +# +# 说明: +# +# +# 所有节点的值都是唯一的。 +# p、q 为不同节点且均存在于给定的二叉树中。 +# +# +# 注意:本题与主站 236 题相同:https://leetcode-cn.com/problems/lowest-common-ancestor-of-a +# -binary-tree/ +# Related Topics 树 + + +# leetcode submit region begin(Prohibit modification and deletion) +# Definition for a binary tree node. +class TreeNode: + def __init__(self, x): + self.val = x + self.left = None + self.right = None + + +class Solution: + def lowestCommonAncestor(self, root: TreeNode, p: TreeNode, q: TreeNode) -> TreeNode: + if root in (None, p, q): + return root + left, right = [self.lowestCommonAncestor(kid, p, q) + for kid in (root.left, root.right)] + return root if left and right else left or right + + +# leetcode submit region end(Prohibit modification and deletion) diff --git a/Week_02/G20200343030409/LeetCode_236_409.java b/Week_02/G20200343030409/LeetCode_236_409.java new file mode 100644 index 00000000..f99a9509 --- /dev/null +++ b/Week_02/G20200343030409/LeetCode_236_409.java @@ -0,0 +1,88 @@ +/* + 236. Lowest Common Ancestor of a Binary Tree + + 1. 終止條件 + 2. 找左子樹 + 3. 找右子樹 + 4. 如果在左右子樹找到pq, 代表pq一個在左一個在右, root就會是LCS + 5. 如果只有在某一邊找到, 代表pq在同一側, 所以LCS就是某一邊找到的本身結果(題目中有提到LCS可以是p或q本身) + + time complexity: O(n), space complexity: O(n) + + */ +class Solution { + public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { + if (root == null || root == p || root == q) return root; // 1.terminal condition, find p,q or not find pq => null + + TreeNode left = lowestCommonAncestor(root.left, p, q); //2.find left side for p, q + TreeNode right = lowestCommonAncestor(root.right, p, q); //3.find right side for p, q + + if (left != null && right != null) return root; // 4.if find p,q in left and right side, root is LCS ! + + return left != null ? left : right; // 5.if only one side find p or q (it means p,q are all in one side), it's the answer because in question we allow a node to be a descendant of itself + } +} + + +/* +同場加映...注意本題是 Binary Search Tree, 不是 binary tree + +235. Lowest Common Ancestor of a Binary Search Tree + +level: easy + +https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-search-tree/ + +https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-search-tree/ + + +因為 bst 有左小右大的特性 (左子樹所有節點皆小於root, 右子樹所有節點皆大於root + +1. 所以pq同時比root 大時, 代表pq在右邊, 所以要往右走 +2. 所以pq同時比root 小時, 代表pq在左邊, 所以要往左走 +3. 其他狀況, 代表找到了, p q在左右兩側了 + +Input: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 8 +Output: 6 +Explanation: The LCA of nodes 2 and 8 is 6. + + LCS: + + 判斷方式: 找到 LCS的方式 p, q 不在此 LCS 同一側 + + //說明1 + if (pVal > parentVal && qVal > parentVal) { + + // 往右走~~ + return lowestCommonAncestor(root.right, p, q); + + } else if (pVal < parentVal && qVal < parentVal) { //說明2 + // 往左走~~ + return lowestCommonAncestor(root.left, p, q); + + } else {//說明3 + //找到了 We have found the split point, i.e. the LCA node. + return root; + } + + + time complexity: O(n), space complexity: O(n) + + */ +class Solution { + public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { + int parentVal = root.val; + int pVal = p.val; + int qVal = q.val; + + if (pVal > parentVal && qVal > parentVal) { + return lowestCommonAncestor(root.right, p, q); + + } else if (pVal < parentVal && qVal < parentVal) { + return lowestCommonAncestor(root.left, p, q); + + } else { + return root; + } + } +} \ No newline at end of file diff --git a/Week_02/G20200343030409/LeetCode_46_409.java b/Week_02/G20200343030409/LeetCode_46_409.java new file mode 100644 index 00000000..0006cd04 --- /dev/null +++ b/Week_02/G20200343030409/LeetCode_46_409.java @@ -0,0 +1,60 @@ +/* + use backtrack again + + time complexity: O(n*n!), space complexity: O(n*n!), n is input array length + +*/ + +// use arraylist contains to judge it should pass or not, slower, 2ms +class Solution { + public List> permute(int[] nums) { + List> result = new ArrayList<>(); + backtrack(result, new ArrayList<>(), nums); + return result; + } + + private void backtrack(List> result, List tempList, int[] nums) { + if (tempList.size() == nums.length) { + result.add(new ArrayList<>(tempList)); + } else { + for (int i = 0; i < nums.length; i++) { + if (tempList.contains(nums[i])) continue; // skip duplicate result + + tempList.add(nums[i]); + backtrack(result, tempList, nums); + tempList.remove(tempList.size() - 1); + } + } + } +} + +// use boolean[] used to judge it should pass or not, faster, 1ms +class Solution { + public List> permute(int[] nums) { + List> result = new ArrayList<>(); + + boolean[] used = new boolean[nums.length]; + Arrays.fill(used, false); + + backtrack(result, new ArrayList<>(), used, nums); + return result; + } + + private void backtrack(List> result, List tempList, boolean[] used, int[] nums) { + if (tempList.size() == nums.length) { + result.add(new ArrayList<>(tempList)); + } else { + for (int i = 0; i < nums.length; i++) { + if (used[i]) continue; + + tempList.add(nums[i]); + used[i] = true; + + backtrack(result, tempList, used, nums); + + tempList.remove(tempList.size() - 1); + used[i] = false; + } + } + } +} \ No newline at end of file diff --git a/Week_02/G20200343030409/LeetCode_47_409.java b/Week_02/G20200343030409/LeetCode_47_409.java new file mode 100644 index 00000000..46a352ec --- /dev/null +++ b/Week_02/G20200343030409/LeetCode_47_409.java @@ -0,0 +1,36 @@ +/* + use backtrack again + + time complexity: O(n*n!), space complexity: O(n*n!), n is input array length + +*/ + +// use arraylist contains to judge it should pass or not, slower, 2ms +class Solution { + public List> permuteUnique(int[] nums) { + List> result = new ArrayList<>(); + boolean used[] = new boolean[nums.length]; + + Arrays.sort(nums); // need sort + backtrack(result, new ArrayList<>(), used, nums); + return result; + } + + private void backtrack(List> result, List tempList, boolean[] used, int[] nums) { + if (tempList.size() == nums.length) { + result.add(new ArrayList<>(tempList)); + } else { + for (int i = 0; i < nums.length; i++) { + if (used[i] || i > 0 && nums[i] == nums[i-1] && !used[i-1]) continue; // excluding used, and duplicate permutaion + + used[i] = true; + tempList.add(nums[i]); + + backtrack(result, tempList, used, nums); + + tempList.remove(tempList.size() - 1); + used[i] = false; + } + } + } +} \ No newline at end of file diff --git a/Week_02/G20200343030409/LeetCode_77_409.java b/Week_02/G20200343030409/LeetCode_77_409.java new file mode 100644 index 00000000..6b029bc0 --- /dev/null +++ b/Week_02/G20200343030409/LeetCode_77_409.java @@ -0,0 +1,23 @@ +/* + time complexity: O(C(n, k)), space complexity: O(k) +*/ +class Solution { + public List> combine(int n, int k) { + List> result = new ArrayList<>(); + backtrack(result, new ArrayList<>(), 1, n, k); //start from 1 + return result; + } + + public void backtrack(List> result, List tempList, int start, int n, int k) { + if (k == 0) { // terminal condition: when k == 0 + result.add(new ArrayList<>(tempList)); + return; + } else { + for (int i = start; i <= n - k + 1; i++) { // why n - k +1, it's a precise way to indicate the range, because when jump to next recursion level, k is changed, we should recaculate to "n - k + 1", not always to use n + tempList.add(i); + backtrack(result, tempList, i + 1, n, k - 1); + tempList.remove(tempList.size() - 1); // backtrack + } + } + } +} \ No newline at end of file diff --git a/Week_02/G20200343030413/LeetCode_049_413.java b/Week_02/G20200343030413/LeetCode_049_413.java new file mode 100644 index 00000000..088dd77e --- /dev/null +++ b/Week_02/G20200343030413/LeetCode_049_413.java @@ -0,0 +1,35 @@ +package com.kidand.homework.week02; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; + +/** + * ██╗ ██╗██╗██████╗ █████╗ ███╗ ██╗██████╗ + * ██║ ██╔╝██║██╔══██╗██╔══██╗████╗ ██║██╔══██╗ + * █████╔╝ ██║██║ ██║███████║██╔██╗ ██║██║ ██║ + * ██╔═██╗ ██║██║ ██║██╔══██║██║╚██╗██║██║ ██║ + * ██║ ██╗██║██████╔╝██║ ██║██║ ╚████║██████╔╝ + * ╚═╝ ╚═╝╚═╝╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═══╝╚═════╝ + * + * @description:LeetCode_049_413 + * @author: Kidand + * @date: 2020/2/21 7:26 下午 + * Copyright © 2019-Kidand. + */ +public class LeetCode_049_413 { + public List> groupAnagrams(String[] strs) { + HashMap> map = new HashMap<>(); + for (String s : strs) { + char[] ch = s.toCharArray(); + Arrays.sort(ch); + String key = String.valueOf(ch); + if (!map.containsKey(key)) { + map.put(key, new ArrayList<>()); + } + map.get(key).add(s); + } + return new ArrayList(map.values()); + } +} diff --git a/Week_02/G20200343030413/LeetCode_114_413.java b/Week_02/G20200343030413/LeetCode_114_413.java new file mode 100644 index 00000000..5cf84723 --- /dev/null +++ b/Week_02/G20200343030413/LeetCode_114_413.java @@ -0,0 +1,55 @@ +package com.kidand.homework.week02; + +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; + +/** + * ██╗ ██╗██╗██████╗ █████╗ ███╗ ██╗██████╗ + * ██║ ██╔╝██║██╔══██╗██╔══██╗████╗ ██║██╔══██╗ + * █████╔╝ ██║██║ ██║███████║██╔██╗ ██║██║ ██║ + * ██╔═██╗ ██║██║ ██║██╔══██║██║╚██╗██║██║ ██║ + * ██║ ██╗██║██████╔╝██║ ██║██║ ╚████║██████╔╝ + * ╚═╝ ╚═╝╚═╝╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═══╝╚═════╝ + * + * @description:LeetCode_114_413 + * @author: Kidand + * @date: 2020/2/22 5:28 下午 + * Copyright © 2019-Kidand. + */ + +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; } + * } + */ +public class LeetCode_114_413 { + public class TreeNode { + int val; + TreeNode left; + TreeNode right; + + TreeNode(int x) { + val = x; + } + } + + public List preorderTraversal(TreeNode root) { + List res = new ArrayList<>(); + Stack stack = new Stack<>(); + while (!stack.isEmpty() || root != null) { + while (root != null) { + stack.push(root); + res.add(root.val); + root = root.left; + } + TreeNode curr = stack.pop(); + root = curr.right; + } + return res; + } +} diff --git a/Week_02/G20200343030415/LeetCode-105-415.java b/Week_02/G20200343030415/LeetCode-105-415.java new file mode 100644 index 00000000..c4507a22 --- /dev/null +++ b/Week_02/G20200343030415/LeetCode-105-415.java @@ -0,0 +1,40 @@ +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; } + * } + */ +class Solution { + + HashMap map = new HashMap<>(); + int preIdx = 0; + int[] preorder; + int[] inorder; + + public TreeNode buildTree(int[] preorder, int[] inorder) { + this.preorder = preorder; + this.inorder = inorder; + int idx = 0; + for (int i : inorder) { + map.put(i,idx++); + } + return helper(0,inorder.length); + } + + public TreeNode helper(int inLeft, int inRight){ + if(inLeft == inRight){ + return null; + } + int rootVal = this.preorder[preIdx]; + TreeNode root = new TreeNode(rootVal); + int midIndex = map.get(rootVal); + preIdx++; + root.left = helper(inLeft,midIndex); + root.right = helper(midIndex+1,inRight); + return root; + + } +} \ No newline at end of file diff --git a/Week_02/G20200343030415/LeetCode-144-415.java b/Week_02/G20200343030415/LeetCode-144-415.java new file mode 100644 index 00000000..11680de9 --- /dev/null +++ b/Week_02/G20200343030415/LeetCode-144-415.java @@ -0,0 +1,29 @@ +import java.util.ArrayList; + +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; } + * } + */ +class Solution { + + private List res = new ArrayList<>(); + + public List preorderTraversal(TreeNode root) { + helper(root); + return res; + } + + public void helper(TreeNode root){ + if(root == null){ + return; + } + res.add(root.val); + helper(root.left); + helper(root.right); + } +} \ No newline at end of file diff --git a/Week_02/G20200343030415/LeetCode-236-415.java b/Week_02/G20200343030415/LeetCode-236-415.java new file mode 100644 index 00000000..a94a8f6a --- /dev/null +++ b/Week_02/G20200343030415/LeetCode-236-415.java @@ -0,0 +1,31 @@ +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; } + * } + */ +class Solution { + private TreeNode res = null; + + public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { + recur(root,p,q); + return res; + } + + public boolean recur(TreeNode currentNode,TreeNode p,TreeNode q){ + if(currentNode == null){ + return false; + } + int left = recur(currentNode.left,p,q) ? 1 : 0; + int right = recur(currentNode.right,p,q) ? 1 : 0; + int mid = (currentNode == p || currentNode == q) ? 1 : 0; + if(mid + left + right >= 2){ + res = currentNode; + } + return (mid + left + right) > 0; + + } +} \ No newline at end of file diff --git a/Week_02/G20200343030415/LeetCode-49-415.java b/Week_02/G20200343030415/LeetCode-49-415.java new file mode 100644 index 00000000..aae16e8c --- /dev/null +++ b/Week_02/G20200343030415/LeetCode-49-415.java @@ -0,0 +1,19 @@ +class Solution { + + public List> groupAnagrams(String[] strs){ + Map> map = new HashMap<>(); + for (int i = 0; i < strs.length; i++) { + char[] chars = strs[i].toCharArray(); + Arrays.sort(chars); + String key = String.valueOf(chars); + if(map.containsKey(key)){ + map.get(key).add(strs[i]); + }else { + List list = new ArrayList<>(); + list.add(strs[i]); + map.put(key,list); + } + } + return new ArrayList<>(map.values()); + } +} \ No newline at end of file diff --git a/Week_02/G20200343030415/LeetCode-589-415.java b/Week_02/G20200343030415/LeetCode-589-415.java new file mode 100644 index 00000000..b38def1b --- /dev/null +++ b/Week_02/G20200343030415/LeetCode-589-415.java @@ -0,0 +1,22 @@ +class Solution { + + private List res = new ArrayList<>(); + + public List preorder(Node root) { + helper(root); + return res; + } + + public void helper(Node root){ + if(root == null){ + return; + } + res.add(root.val); + int s = root.children.size(); + for (int i = 0; i < s; i++) { + helper(root.children.get(i)); + } + } + + +} \ No newline at end of file diff --git a/Week_02/G20200343030415/LeetCode-77-415.java b/Week_02/G20200343030415/LeetCode-77-415.java new file mode 100644 index 00000000..f6aa14b5 --- /dev/null +++ b/Week_02/G20200343030415/LeetCode-77-415.java @@ -0,0 +1,25 @@ +import java.util.LinkedList; + +//leetcode submit region begin(Prohibit modification and deletion) +class Solution { + public List> combine(int n, int k) { + this.n = n; + this.k = k; + recur(1,new LinkedList<>()); + return output; + } + List> output = new LinkedList<>(); + int n; + int k; + public void recur(int first,LinkedList curr){ + if(curr.size() == k){ + output.add(new LinkedList(curr)); + } + for (int i = first; i < n + 1; i++) { + curr.add(i); + recur(i + 1,curr); + curr.removeLast(); + } + + } +} \ No newline at end of file diff --git a/Week_02/G20200343030415/LeetCode_590_415.java b/Week_02/G20200343030415/LeetCode_590_415.java new file mode 100644 index 00000000..07c250ce --- /dev/null +++ b/Week_02/G20200343030415/LeetCode_590_415.java @@ -0,0 +1,20 @@ +class Solution { + + private List res = new ArrayList<>(); + + public List postorder(Node root) { + helper(root); + return res; + } + + public void helper(Node root){ + if(root == null){ + return; + } + int s = root.children.size(); + for (int i = 0; i < s; i++) { + helper(root.children.get(i)); + } + res.add(root.val); + } +} \ No newline at end of file diff --git a/Week_02/G20200343030417/NOTE.md b/Week_02/G20200343030417/NOTE.md index 50de3041..c53111b6 100644 --- a/Week_02/G20200343030417/NOTE.md +++ b/Week_02/G20200343030417/NOTE.md @@ -1 +1,51 @@ -学习笔记 \ No newline at end of file +学习笔记 + +# 本周学习主要算法模型代码 + +# + +# 树的遍历 +# 前序遍历模型 +def preorder_tree(root): + if root: + self.tree_nodes.append(root) + self.preorder_tree(root.left) + self.preorder_tree(root.right) + +# 中序遍历模型 +def inorder_tree(root): + if root: + + self.inorcer_tree(root.left) + self.tree_nodes.append(root) + self.inorder_tree(root.right) + +# 后序遍历模型 +def post_tree(root): + if root: + + self.postorder_tree(root.left) + self.postorcer_tree(root.right) + self.tree_nodes.append(root) + + + +# 递归模版代码 +def recursion(level,param1,param2,...): + # recursion terminator + # 递归终止条件 + if level > MAX_LEVEL: + process_result + return + + # process logic in current level + # 本层的程序逻辑代码 + process(level,data,...) + + # drill down + # 进入下一次 + self.recursion(level+1,p1,...) + + # reserve the current level status if needed + # 本层收尾代码 + diff --git a/Week_02/G20200343030417/homework.py b/Week_02/G20200343030417/homework.py new file mode 100644 index 00000000..575a42d5 --- /dev/null +++ b/Week_02/G20200343030417/homework.py @@ -0,0 +1,21 @@ + +# 49,字母异位词分组 +strs = ["eat", "tea", "tan", "ate", "nat", "bat"] + +def groupAnagrams(strs): + dic = {} + for i in strs: + a = sorted(i) + # print('-----',a) + b = tuple(a) + print(b) + if b not in dic: + dic[b] = [i] + else: + dic[b].append(i) + + m = [i for i in dic.values()] + return m + +# groupAnagrams(strs) + diff --git a/Week_02/G20200343030417/homework2.py b/Week_02/G20200343030417/homework2.py new file mode 100644 index 00000000..299eaad9 --- /dev/null +++ b/Week_02/G20200343030417/homework2.py @@ -0,0 +1,12 @@ +# 二叉树前序遍历 +def preorder_tree(root): + res = [] + p = root + stack = [] + while p or stack: + while p: + res.append(p.val) + stack.append(p) + p = p.left + p = stack.pop().right + return res \ No newline at end of file diff --git a/Week_02/G20200343030423/LeetCode_144_423.java b/Week_02/G20200343030423/LeetCode_144_423.java new file mode 100644 index 00000000..8148140c --- /dev/null +++ b/Week_02/G20200343030423/LeetCode_144_423.java @@ -0,0 +1,41 @@ +import java.util.ArrayList; +import java.util.List; + +public class LeetCode_144_423 { + + public static void main(String[] args) { + +// int[] a = {1, 1, 2}; +// printResult(a); +// +// int[] b = {0,0,1,1,1,2,2,3,3,4}; +// printResult(b); + } +} + + class TreeNode { + int val; + TreeNode left; + TreeNode right; + TreeNode(int x) { val = x; } + } + +class SolutionOne { + public List preorderTraversal(TreeNode root) { + List res = new ArrayList(); + helper(root ,res); + return res; + } + + public void helper(TreeNode root, List res) { + if (root != null) { + res.add(root.val); + if (root.left != null) { + helper(root.left, res); + } + if (root.right != null) { + helper(root.right, res); + } + } + } +} \ No newline at end of file diff --git a/Week_02/G20200343030423/LeetCode_49_423.java b/Week_02/G20200343030423/LeetCode_49_423.java new file mode 100644 index 00000000..e41cab8e --- /dev/null +++ b/Week_02/G20200343030423/LeetCode_49_423.java @@ -0,0 +1,44 @@ +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.ArrayList; + +public class LeetCode_49_423 { + + public static void main(String[] args) { + + String strs[] = {"eat", "tea", "tan", "ate", "nat", "bat"}; + System.out.println(new Solution().groupAnagrams(strs)); + + } + +} + +class Solution { + public List> groupAnagrams(String[] strs) { + HashMap> hash = new HashMap>(); + for(String c :strs) { + String sort = sortString(c); + if (hash.containsKey(sort)) { + hash.get(sort).add(c); + } else { + ArrayList t = new ArrayList(); + t.add(c); + hash.put(sort, t); + } + } + List t = new ArrayList(); + for(List a : hash.values()) { + t.add(a); + } + return t; + } + public static String sortString(String c) { + char tempArray[] = c.toCharArray(); + Arrays.sort(tempArray); + return new String(tempArray); + } +} + + + diff --git a/Week_02/G20200343030425/LeetCode_589_425/LeetCode_589_425.js b/Week_02/G20200343030425/LeetCode_589_425/LeetCode_589_425.js new file mode 100644 index 00000000..221e89f2 --- /dev/null +++ b/Week_02/G20200343030425/LeetCode_589_425/LeetCode_589_425.js @@ -0,0 +1,29 @@ +/* +* address: https://leetcode-cn.com/problems/n-ary-tree-preorder-traversal/ +* */ +const root = { + val: 1, + children: + [ + { + val: 3, children: [ + {val: 5, children: []}, + {val: 6, children: []}] + }, + {val: 2, children: []}, + {val: 4, children: []}] +}; + +const preorder = (root) => { + let list = []; + generate(root, list); + return list; +}; +const generate = (root, list) => { + if(root==null)return null; + list.push(root.val); + for (let i = 0; i < root.children.length; i++) { + generate(root.children[i], list); + } +}; +console.log(preorder(root)); diff --git a/Week_02/G20200343030425/LeetCode_590_425/LeetCode_590_425.js b/Week_02/G20200343030425/LeetCode_590_425/LeetCode_590_425.js new file mode 100644 index 00000000..00801ed7 --- /dev/null +++ b/Week_02/G20200343030425/LeetCode_590_425/LeetCode_590_425.js @@ -0,0 +1,46 @@ +/* +* address: https://leetcode-cn.com/problems/n-ary-tree-postorder-traversal/ +* input: { val: 1, + children: + [ { val: 3, children: [] }, + { val: 2, children: [] }, + { val: 4, children: [] } + ] + } +* output: [5,6,3,2,4,1] +* */ + +/* +Method 1: recursion +* */ +const root = { + val: 1, + children: + [ + { + val: 3, children: [ + {val: 5, children: []}, + {val: 6, children: []}] + }, + {val: 2, children: []}, + {val: 4, children: []}] +}; +const postorder = (root) => { + let list = []; + generate(root, list); + return list; +}; + +const generate = (root, list) => { + if (root == null) { + return null; + } + + for (let i = 0; i < root.children.length; i++) { + generate(root.children[i], list); + } + + list.push(root.val); + return list; +}; +console.log(postorder(list)); diff --git a/Week_02/G20200343030429/LeetCode_1_429.java b/Week_02/G20200343030429/LeetCode_1_429.java new file mode 100644 index 00000000..8ebde3a3 --- /dev/null +++ b/Week_02/G20200343030429/LeetCode_1_429.java @@ -0,0 +1,71 @@ +package com.study.week02; + +import com.study.Node; + +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; + +/** + * @author Abner + * @date 2020/2/23 21:15 + * @email songkd90@163.com + * @description 后序遍历树 + */ +public class LeetCode_1_429 { + + // 解法1 递归 (题目不建议使用递归) + // 后序遍历,顺序为左 -> 右 -> 根 + public List postorder(Node root) { + List list = new ArrayList<>(); + helper(root, list); + return list; + } + + public void helper(Node root, List list) { + // 1 terminator + if (root == null) { + return; + } + // 2 current + + // 3 drill down + for (Node child : root.children) { + helper(child, list); + } + // 待左右子节点添加完后,添加根节点 + list.add(root.val); + // 4 restore + } + + // 2 迭代法, 利用栈的FILO先进后出特性 + public List postorder2(Node root) { + List list = new ArrayList<>(); + if (root == null) { + return list; + } + + Node pre = null; + Stack stack = new Stack<>(); + stack.push(root); + + while (!stack.isEmpty()) { + Node cur = stack.peek(); + // 如果无子节点,或子节点包含有前节点 + if ((cur.children.size() == 0) || (pre != null && cur.children.contains(pre))) { + list.add(cur.val); + stack.pop(); + pre = cur; + } else { // 如果有子节点,倒序将子节点压入栈 + List children = cur.children; + for (int i = children.size() - 1; i >= 0; i--) { + stack.push(children.get(i)); + } + } + } + return list; + } + +} + + diff --git a/Week_02/G20200343030429/LeetCode_2_429.java b/Week_02/G20200343030429/LeetCode_2_429.java new file mode 100644 index 00000000..8b53569b --- /dev/null +++ b/Week_02/G20200343030429/LeetCode_2_429.java @@ -0,0 +1,61 @@ +package com.study.week02; + +import com.study.Node; + +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; + +/** + * @author Abner + * @date 2020/2/23 21:15 + * @email songkd90@163.com + * @description 前序遍历树 + */ +public class LeetCode_2_429 { + /** + * 解法一:递归 + * @param root + * @return + */ + public List preorder(Node root) { + List list = new ArrayList<>(); + helper(root, list); + return list; + } + + public void helper(Node root, List list) { + if (root == null) { + return; + } + // 前序遍历 根->左->右 先加入根节点 + list.add(root.val); + for (Node child : root.children) { + helper(child, list); + } + } + + /** + * 解法二:迭代 + * @param root + * @return + */ + public List preorder2(Node root) { + List list = new ArrayList<>(); + if (root == null) { + return list; + } + + Stack stack = new Stack<>(); + stack.add(root); + + while (!stack.empty()) { + root = stack.pop(); + list.add(root.val); + for (int i = root.children.size() - 1; i >= 0; i--) { + stack.add(root.children.get(i)); + } + } + return list; + } +} diff --git a/Week_02/G20200343030429/NOTE.md b/Week_02/G20200343030429/NOTE.md index 50de3041..c068f4f5 100644 --- a/Week_02/G20200343030429/NOTE.md +++ b/Week_02/G20200343030429/NOTE.md @@ -1 +1,28 @@ -学习笔记 \ No newline at end of file +#学习笔记 +## 一、递归四步: + 1. recursion terminator + 递归终结条件 + 2. process logic in current level + 处理当前层逻辑 + 3. drill down + 下探到下一层 + 4. restore current status + 清理当前层(有时不需要) + + public void recursion(int level, int param) { + // 递归终结条件 + if (level > MAX_VALUE) { + + return; + } + + // 处理当前层逻辑 + process(level, param); + // 下探到下一层 + recursion(level : level + 1, newParam); + // 清理 + } +## 二、思维要点 + 1. 不要人肉进行递归(最大误区) + 2. 找到最近最简的方法,将其拆解成可重复解决的问题(重复子问题) + 3. 数学归纳法思维 diff --git a/Week_02/G20200343030431/LeetCode_105_431.java b/Week_02/G20200343030431/LeetCode_105_431.java new file mode 100644 index 00000000..cd8e8d1b --- /dev/null +++ b/Week_02/G20200343030431/LeetCode_105_431.java @@ -0,0 +1,29 @@ +package secondWork; +//借助leetcode的解法 +import javax.swing.tree.TreeNode; +import java.util.Arrays; +import java.util.Stack; + +public class work105 { + + private int pre=0; + private int in=0; + public TreeNode buildTree(int [] preorder, int [] inorder) { + return buildTree(preorder,inorder,Integer.MAX_VALUE+1); + } + public TreeNode buildTree(int [] preorder,int [] inorder,long stop){ + if(pre==preorder.length){ + return null; + } + if(inorder[in]==stop){ + in++; + return null; + } + int val=preorder[pre++]; + TreeNode root= new TreeNode(val); + root.left=buildTree(preorder,inorder,val); + root.right=buildTree(preorder,inorder,stop); + return root; + } + } + diff --git a/Week_02/G20200343030431/LeetCode_590_431.java b/Week_02/G20200343030431/LeetCode_590_431.java new file mode 100644 index 00000000..67aaa227 --- /dev/null +++ b/Week_02/G20200343030431/LeetCode_590_431.java @@ -0,0 +1,18 @@ +package secondWork; + +import java.util.*; +//还是求助于letcode上面的解法 +public class work590 { + public List> groupAnagrams(String[] strs) { + HashMap> map=new HashMap>(); + for(String s:strs){ + char[] ch=s.toCharArray(); + Arrays.sort(ch); + String key=String.valueOf(ch); + if(!map.containsKey(key)) map.put(key,new ArrayList()); + map.get(key).add(s); + } + return new ArrayList(map.values()); + } +} + diff --git a/Week_02/G20200343030431/NOTE.md b/Week_02/G20200343030431/NOTE.md index 50de3041..6b0469c5 100644 --- a/Week_02/G20200343030431/NOTE.md +++ b/Week_02/G20200343030431/NOTE.md @@ -1 +1,20 @@ -学习笔记 \ No newline at end of file +学习笔记--HasMap小结 + +--HashMap的工作原理 +HashMap基于hashing原理,我们通过put()和get()方法储存和获取对象。 +当我们将键值对传递给put()方法时,它调用键对象的hashCode()方法来计算hashcode,让后找到bucket位置来储存值对象。 +当获取对象时,通过键对象的equals()方法找到正确的键值对,然后返回值对象。 +HashMap使用LinkedList来解决碰撞问题,当发生碰撞了,对象将会储存在LinkedList的下一个节点中。 + HashMap在每个LinkedList节点中储存键值对对象。 +当两个不同的键对象的hashcode相同时, 它们会储存在同一个bucket位置的LinkedList中。键对象的equals()方法用来找到键值对。 + +--HashMap的定义 +HashMap实现了Map接口,继承AbstractMap。 +其中Map接口定义了键映射到值的规则,而AbstractMap类提供 Map 接口的骨干实现,以最大限度地减少实现此接口所需的工作! + +--HashMap的数据结构 +HashMap的底层主要是基于数组和链表来实现的,它之所以有相当快的查询速度主要是因为它是通过计算散列码来决定存储的位置。 +HashMap中主要是通过key的hashCode来计算hash值的,只要hashCode相同,计算出来的hash值就一样。 +如果存储的对象对多了,就有可能不同的对象所算出来的hash值是相同的,这就出现了所谓的hash冲突。 +学过数据结构的同学都知道,解决hash冲突的方法有很多,HashMap底层是通过链表来解决hash冲突的。 + diff --git a/Week_02/G20200343030433/LeetCode_105_433.py b/Week_02/G20200343030433/LeetCode_105_433.py new file mode 100644 index 00000000..ef8cf452 --- /dev/null +++ b/Week_02/G20200343030433/LeetCode_105_433.py @@ -0,0 +1,26 @@ +# +# @lc app=leetcode.cn id=189 lang=python3 +# +# + +# @lc code=start +class Solution(object): + def buildTree(self, preorder, inorder): + """ + :type preorder: List[int] + :type inorder: List[int] + :rtype: TreeNode + """ + if len(inorder) == 0: + return None + # 前序遍历第一个值为根节点 + root = TreeNode(preorder[0]) + # 因为没有重复元素,所以可以直接根据值来查找根节点在中序遍历中的位置 + mid = inorder.index(preorder[0]) + # 构建左子树 + root.left = self.buildTree(preorder[1:mid+1], inorder[:mid]) + # 构建右子树 + root.right = self.buildTree(preorder[mid+1:], inorder[mid+1:]) + + return root + diff --git a/Week_02/G20200343030433/LeetCode_144_433.py b/Week_02/G20200343030433/LeetCode_144_433.py new file mode 100644 index 00000000..0c228542 --- /dev/null +++ b/Week_02/G20200343030433/LeetCode_144_433.py @@ -0,0 +1,26 @@ +# +# @lc app=leetcode.cn id=189 lang=python3 +# +# + +# @lc code=start +class Solution: + def preorderTraversal(self, root): + """ + Do not return anything, modify nums in-place instead. + """ + """ + Do not return anything, modify nums in-place instead. + """ + + ret = [] + stack = [root] + while stack: + node = stack.pop() + if node: + ret.append(node.val) + stack.append(node.right) + stack.append(node.left) + return ret +# @lc code=end + diff --git a/Week_02/G20200343030435/LeetCode_144_435.js b/Week_02/G20200343030435/LeetCode_144_435.js new file mode 100644 index 00000000..645155ea --- /dev/null +++ b/Week_02/G20200343030435/LeetCode_144_435.js @@ -0,0 +1,9 @@ +let preorderTraversal = root => { + return root + ? [ + root.val, + ...preorderTraversal(root.left), + ...preorderTraversal(root.right) + ] + : []; +}; diff --git a/Week_02/G20200343030435/LeetCode_46_435.js b/Week_02/G20200343030435/LeetCode_46_435.js new file mode 100644 index 00000000..54ca2a72 --- /dev/null +++ b/Week_02/G20200343030435/LeetCode_46_435.js @@ -0,0 +1,22 @@ +let permute = function(nums) { + const swap = (nums, i, j) => { + [nums[i], nums[j]] = [nums[j], nums[i]]; + }; + const dfs = (cur, index, len, nums, res) => { + if (cur.length === len) { + res.push(cur.concat()); + return; + } + for (let i = index; i < nums.length; i++) { + swap(nums, i, index); + cur.push(nums[index]); + dfs(cur, index + 1, len, nums, res); + cur.pop(); + swap(nums, i, index); + } + }; + const len = nums.length; + const res = []; + dfs([], 0, len, nums, res); + return res; +}; diff --git a/Week_02/G20200343030435/LeetCode_49_435.js b/Week_02/G20200343030435/LeetCode_49_435.js new file mode 100644 index 00000000..67be9b1e --- /dev/null +++ b/Week_02/G20200343030435/LeetCode_49_435.js @@ -0,0 +1,17 @@ +let groupAnagrams = function(strs) { + let hash = new Map(); + for (let i = 0; i < strs.length; i++) { + const str = strs[i] + .split("") + .sort() + .join(); + if (hash.has(str)) { + const tmp = hash.get(str); + tmp.push(strs[i]); + hash.set(str, tmp); + } else { + hash.set(str, [strs[i]]); + } + } + return [...hash.values()]; +}; diff --git a/Week_02/G20200343030435/LeetCode_589_435.js b/Week_02/G20200343030435/LeetCode_589_435.js new file mode 100644 index 00000000..67cd4a9e --- /dev/null +++ b/Week_02/G20200343030435/LeetCode_589_435.js @@ -0,0 +1,16 @@ +let preorder = function(root) { + if (!root) return []; + + const res = []; + const recusion = root => { + if (!root) return; + + res.push(root.val); + root.children.forEach(n => { + recusion(n); + }); + }; + + recusion(root); + return res; +}; diff --git a/Week_02/G20200343030435/LeetCode_590_435.js b/Week_02/G20200343030435/LeetCode_590_435.js new file mode 100644 index 00000000..c795f919 --- /dev/null +++ b/Week_02/G20200343030435/LeetCode_590_435.js @@ -0,0 +1,18 @@ +let postorder = function(root) { + if (!root) { + return []; + } + const res = []; + + let recusion = root => { + if (!root) return; + root.children.forEach(leaf => { + recusion(leaf); + }); + // 这个逻辑执行语句的位置很重要 + res.push(root.val); + }; + + recusion(root); + return res; +}; diff --git a/Week_02/G20200343030437/combinations.java b/Week_02/G20200343030437/combinations.java new file mode 100644 index 00000000..7cd5ecbd --- /dev/null +++ b/Week_02/G20200343030437/combinations.java @@ -0,0 +1,46 @@ +class Solution { + List> resultList = new ArrayList<>(); + int n; + int k; + + public List> combine(int n, int k) { + //深度优先题目 + //将所有符合条件的元素放在一个初始为0的多叉树中 + this.n = n; + this.k = k; + helper(new TreeNode(0), 0); + return resultList; + } + + public void helper(TreeNode node, int floor){ + if (floor == k) return; + floor++; + for (int i = node.val+1; i <= n; i++) { + TreeNode next = new TreeNode(i); + node.childs.add(next); + next.prev = node; + helper(next , floor); + + if (floor == k) { + //Deque deque = new ArrayDeque<>(); + LinkedList link = new LinkedList<>(); + link.addFirst(next.val); + for (int j = 1; j < k; j++) { + next = next.prev; + link.addFirst(next.val); + } + resultList.add(link); + } + } + } + + class TreeNode{ + int val; + List childs; + TreeNode prev; + public TreeNode(int val) { + childs = new ArrayList<>(); + this.val = val; + } + } +} diff --git a/Week_02/G20200343030437/generate-parenthese.java b/Week_02/G20200343030437/generate-parenthese.java new file mode 100644 index 00000000..8b9b256a --- /dev/null +++ b/Week_02/G20200343030437/generate-parenthese.java @@ -0,0 +1,18 @@ +List container; + int n; + public List generateParenthesis(int n) { + container = new ArrayList<>(); + this.n = n; + String str = ""; + helper(0, 0, str); + return container; + } + + public void helper(int left, int right, String str) { + if (left == n && right == n) { + container.add(str); + } + + if (left < n) helper(left+1, right, str + "("); + if (right < left) helper(left, right + 1, str + ")"); + } diff --git a/Week_02/G20200343030437/group-anagrams.java b/Week_02/G20200343030437/group-anagrams.java new file mode 100644 index 00000000..2217688c --- /dev/null +++ b/Week_02/G20200343030437/group-anagrams.java @@ -0,0 +1,17 @@ +class Solution { + public List> groupAnagrams(String[] strs) { + int length = strs.length; + if (length == 0) return null; + + Map> map = new HashMap<>(); + for (int i = 0; i < length; i++) { + char[] chars = strs[i].toCharArray(); + Arrays.sort(chars); + String str = String.valueOf(chars); + if (!map.containsKey(str)) map.put(str, new ArrayList<>()); + map.get(str).add(strs[i]); + } + return new ArrayList<>(map.values()); + + } +} diff --git a/Week_02/G20200343030437/lowest-common-ancestor-of-a-binary-tree.java b/Week_02/G20200343030437/lowest-common-ancestor-of-a-binary-tree.java new file mode 100644 index 00000000..19331311 --- /dev/null +++ b/Week_02/G20200343030437/lowest-common-ancestor-of-a-binary-tree.java @@ -0,0 +1,27 @@ +class Solution { + + public TreeNode ins; + public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { + // 后续遍历 + recursive(root, p, q); + return ins; + + } + public boolean recursive(TreeNode node, TreeNode p, TreeNode q) { + if (node == null) return false; + + int left = recursive(node.left, p, q) == true ? 1 : 0; + + int right = recursive(node.right, p, q) == true ? 1 : 0; + + int mid = (node == p || node == q) == true ? 1 : 0; + + if (left + right + mid >= 2) { + this.ins = node; + } + + return left + right + mid > 0; + } + + +} diff --git a/Week_02/G20200343030439/LeetCode_242_439.java b/Week_02/G20200343030439/LeetCode_242_439.java new file mode 100644 index 00000000..8c6bd839 --- /dev/null +++ b/Week_02/G20200343030439/LeetCode_242_439.java @@ -0,0 +1,103 @@ +import java.util.Arrays; + +/* + * @lc app=leetcode.cn id=242 lang=java + * + * [242] 有效的字母异位词 + * + * https://leetcode-cn.com/problems/valid-anagram/description/ + * + * algorithms + * Easy (57.64%) + * Likes: 159 + * Dislikes: 0 + * Total Accepted: 75.7K + * Total Submissions: 129.3K + * Testcase Example: '"anagram"\n"nagaram"' + * + * 给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。 + * + * 示例 1: + * + * 输入: s = "anagram", t = "nagaram" + * 输出: true + * + * + * 示例 2: + * + * 输入: s = "rat", t = "car" + * 输出: false + * + * 说明: + * 你可以假设字符串只包含小写字母。 + * + * 进阶: + * 如果输入字符串包含 unicode 字符怎么办?你能否调整你的解法来应对这种情况? + * + */ + +// @lc code=start +class Solution { + public static void main(String[] args) { + + System.out.println(isAnagram2("anagram", "nagaram")); + System.out.println(isAnagram2("rat", "car") ? "true" : "false"); + + /* + * for (int i = 0; i < result.length; i++) { System.out.println(result[i]); } + */ + } + + // 方法一:排序 + public static boolean isAnagram(String s, String t) { + if (s.length() != t.length()) { + return false; + } + char[] str1 = s.toCharArray(); + char[] str2 = t.toCharArray(); + + Arrays.sort(str1); + Arrays.sort(str2); + + return Arrays.equals(str1, str2); + } + + // 方法二:哈希表 + public static boolean isAnagram2(String s, String t) { + if (s.length() != t.length()) { + return false; + } + + int[] table = new int[26]; + for (int i = 0; i < s.length(); i++) { + table[s.charAt(i) - 'a']++; + } + for (int i = 0; i < t.length(); i++) { + int index = t.charAt(i) - 'a'; + table[index]--; + if (table[index] < 0) { + return false; + } + } + return true; + } + + // + public static boolean isAnagram3(String s, String t) { + int[] counts=new int[26]; + for(char ch:s.toCharArray()){ + counts[ch-'a']++; + } + for(char ch:t.toCharArray()){ + counts[ch-'a']--; + } + for(int i:counts){ + if(i!=0){ + return false; + } + } + return true; + } +} +// @lc code=end + diff --git a/Week_02/G20200343030439/LeetCode_589_439.java b/Week_02/G20200343030439/LeetCode_589_439.java new file mode 100644 index 00000000..5033bdb2 --- /dev/null +++ b/Week_02/G20200343030439/LeetCode_589_439.java @@ -0,0 +1,92 @@ +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; + +/* + * @lc app=leetcode.cn id=589 lang=java + * + * [589] N叉树的前序遍历 + * + * https://leetcode-cn.com/problems/n-ary-tree-preorder-traversal/description/ + * + * algorithms + * Easy (71.30%) + * Likes: 66 + * Dislikes: 0 + * Total Accepted: 18.4K + * Total Submissions: 25.6K + * Testcase Example: '[1,null,3,2,4,null,5,6]' + * + * 给定一个 N 叉树,返回其节点值的前序遍历。 + * + * 例如,给定一个 3叉树 : + * + * + * + * + * + * + * + * 返回其前序遍历: [1,3,5,6,2,4]。 + * + * + * + * 说明: 递归法很简单,你可以使用迭代法完成此题吗? + */ + +// @lc code=start +/* +// Definition for a Node. +class Node { + public int val; + public List children; + + public Node() {} + + public Node(int _val) { + val = _val; + } + + public Node(int _val, List _children) { + val = _val; + children = _children; + } +}; +*/ +class Solution { + public List res = new ArrayList<>(); + + // 递归法 + public List preorder(Node root) { + if (root == null) { + return res; + } + res.add(root.val); + for (Node c : root.children) { + preorder(c); + } + return res; + } + + // 迭代法 + public List preorder2(Node root) { + LinkedList stack = new LinkedList<>(); + LinkedList output = new LinkedList<>(); + if (root == null) { + return output; + } + + stack.add(root); + while (!stack.isEmpty()) { + Node node = stack.pollLast(); + output.add(node.val); + Collections.reverse(node.children); + for (Node item : node.children) { + stack.add(item); + } + } + return output; + } +} +// @lc code=end diff --git a/Week_02/G20200343030439/LeetCode_590_439.java b/Week_02/G20200343030439/LeetCode_590_439.java new file mode 100644 index 00000000..d236238d --- /dev/null +++ b/Week_02/G20200343030439/LeetCode_590_439.java @@ -0,0 +1,89 @@ +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +/* + * @lc app=leetcode.cn id=590 lang=java + * + * [590] N叉树的后序遍历 + * + * https://leetcode-cn.com/problems/n-ary-tree-postorder-traversal/description/ + * + * algorithms + * Easy (71.27%) + * Likes: 50 + * Dislikes: 0 + * Total Accepted: 16.2K + * Total Submissions: 22.4K + * Testcase Example: '[1,null,3,2,4,null,5,6]\r' + * + * 给定一个 N 叉树,返回其节点值的后序遍历。 + * + * 例如,给定一个 3叉树 : + * + * + * + * + * + * + * + * 返回其后序遍历: [5,6,3,2,4,1]. + * + * + * + * 说明: 递归法很简单,你可以使用迭代法完成此题吗? + */ + +// @lc code=start +/* +// Definition for a Node. +class Node { + public int val; + public List children; + + public Node() {} + + public Node(int _val) { + val = _val; + } + + public Node(int _val, List _children) { + val = _val; + children = _children; + } +}; +*/ +class Solution { + public static List res = new ArrayList<>(); + public static List postorder(Node root) { + + if (root == null) { + return res; + } + for (Node c : root.children) { + postorder(c); + } + res.add(root.val); + return res; + + } + + public static List postorder2(Node root) { + LinkedList stack = new LinkedList<>(); + LinkedList output = new LinkedList<>(); + if (root == null) { + return output; + } + + stack.add(root); + while (!stack.isEmpty()) { + Node node = stack.pollLast(); + output.addFirst(node.val); + for (Node item : node.children) { + stack.add(item); + } + } + return output; + } +} +// @lc code=end + diff --git a/Week_02/G20200343030439/Node.java b/Week_02/G20200343030439/Node.java new file mode 100644 index 00000000..9ac544ec --- /dev/null +++ b/Week_02/G20200343030439/Node.java @@ -0,0 +1,17 @@ +import java.util.List; + +class Node { + public int val; + public List children; + + public Node() {} + + public Node(int _val) { + val = _val; + } + + public Node(int _val, List _children) { + val = _val; + children = _children; + } +}; \ No newline at end of file diff --git a/Week_02/G20200343030441/LeetCode_104_441.java b/Week_02/G20200343030441/LeetCode_104_441.java new file mode 100644 index 00000000..709b9589 --- /dev/null +++ b/Week_02/G20200343030441/LeetCode_104_441.java @@ -0,0 +1,31 @@ +/* + * @lc app=leetcode.cn id=104 lang=java + * + * [104] 二叉树的最大深度 + */ + +// @lc code=start +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; } + * } + */ +class Solution { + public int maxDepth(TreeNode root) { + return helper(root, 0); + } + + private int helper(TreeNode root, int level){ + if (root == null) return level; + + level++; + + return Math.max(helper(root.left, level), helper(root.right, level)); + } +} +// @lc code=end + diff --git a/Week_02/G20200343030441/LeetCode_111_441.java b/Week_02/G20200343030441/LeetCode_111_441.java new file mode 100644 index 00000000..9af4029d --- /dev/null +++ b/Week_02/G20200343030441/LeetCode_111_441.java @@ -0,0 +1,41 @@ +/* + * @lc app=leetcode.cn id=111 lang=java + * + * [111] 二叉树的最小深度 + */ + +// @lc code=start +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; } + * } + */ +class Solution { + public int minDepth(TreeNode root) { + if (root == null) return 0; + return helper(root, 1); + } + + private int helper(TreeNode root, int level){ + if (root.left != null && root.right != null){ + level++; + return Math.min(helper(root.left, level), helper(root.right, level)); + } else if (root.left == null && root.right == null){ + return level; + } else if (root.left == null){ + level++; + return helper(root.right, level); + } else if (root.right == null){ + level++; + return helper(root.left, level); + } + + return level; + } +} +// @lc code=end + diff --git a/Week_02/G20200343030441/LeetCode_144_441.java b/Week_02/G20200343030441/LeetCode_144_441.java new file mode 100644 index 00000000..a79722aa --- /dev/null +++ b/Week_02/G20200343030441/LeetCode_144_441.java @@ -0,0 +1,35 @@ +/* + * @lc app=leetcode.cn id=144 lang=java + * + * [144] 二叉树的前序遍历 + */ + +// @lc code=start +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; } + * } + */ +class Solution { + + public List pre_order_list = new ArrayList<>(); + + public List preorderTraversal(TreeNode root) { + helper(root); + return pre_order_list; + } + + private void helper(TreeNode current_node){ + if (current_node == null) return; + + pre_order_list.add(current_node.val); + helper(current_node.left); + helper(current_node.right); + } +} +// @lc code=end + diff --git a/Week_02/G20200343030441/LeetCode_145_441.java b/Week_02/G20200343030441/LeetCode_145_441.java new file mode 100644 index 00000000..1e3c80b0 --- /dev/null +++ b/Week_02/G20200343030441/LeetCode_145_441.java @@ -0,0 +1,36 @@ +import java.util.List; + +/* + * @lc app=leetcode.cn id=145 lang=java + * + * [145] 二叉树的后序遍历 + */ + +// @lc code=start +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; } + * } + */ +class Solution { + public List postorder_list = new ArrayList<>(); + + public List postorderTraversal(TreeNode root) { + helper(root); + return postorder_list; + } + + private void helper(TreeNode current_node){ + if (current_node == null) return; + + helper(current_node.left); + helper(current_node.right); + postorder_list.add(current_node.val); + } +} +// @lc code=end + diff --git a/Week_02/G20200343030441/LeetCode_297_441.java b/Week_02/G20200343030441/LeetCode_297_441.java new file mode 100644 index 00000000..b19eee68 --- /dev/null +++ b/Week_02/G20200343030441/LeetCode_297_441.java @@ -0,0 +1,61 @@ +/* + * @lc app=leetcode.cn id=297 lang=java + * + * [297] 二叉树的序列化与反序列化 + */ + +// @lc code=start +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; } + * } + */ +public class Codec { + + private static final String spliter = ","; + private static final String NN = "X"; + + // Encodes a tree to a single string. + public String serialize(TreeNode root) { + StringBuilder sb = new StringBuilder(); + buildString(root, sb); + return sb.toString(); + } + + private void buildString(TreeNode node, StringBuilder sb) { + if (node == null) { + sb.append(NN).append(spliter); + } else { + sb.append(node.val).append(spliter); + buildString(node.left, sb); + buildString(node.right,sb); + } + } + // Decodes your encoded data to tree. + public TreeNode deserialize(String data) { + Deque nodes = new LinkedList<>(); + nodes.addAll(Arrays.asList(data.split(spliter))); + return buildTree(nodes); + } + + private TreeNode buildTree(Deque nodes) { + String val = nodes.remove(); + if (val.equals(NN)) return null; + else { + TreeNode node = new TreeNode(Integer.valueOf(val)); + node.left = buildTree(nodes); + node.right = buildTree(nodes); + return node; + } + } +} + +// Your Codec object will be instantiated and called as such: +// Codec codec = new Codec(); +// codec.deserialize(codec.serialize(root)); +// @lc code=end + diff --git a/Week_02/G20200343030441/LeetCode_429_441.java b/Week_02/G20200343030441/LeetCode_429_441.java new file mode 100644 index 00000000..f330e731 --- /dev/null +++ b/Week_02/G20200343030441/LeetCode_429_441.java @@ -0,0 +1,57 @@ +import java.util.ArrayList; +import java.util.Deque; +import java.util.LinkedList; + +/* + * @lc app=leetcode.cn id=429 lang=java + * + * [429] N叉树的层序遍历 + */ + +// @lc code=start +/* +// Definition for a Node. +class Node { + public int val; + public List children; + + public Node() {} + + public Node(int _val) { + val = _val; + } + + public Node(int _val, List _children) { + val = _val; + children = _children; + } +}; +*/ +class Solution { + + public List> levelOrder(Node root) { + List> ret = new LinkedList<>(); + + if (root == null) return ret; + + Queue queue = new LinkedList<>(); + + queue.offer(root); + + while (!queue.isEmpty()) { + List curLevel = new LinkedList<>(); + int len = queue.size(); + for (int i = 0; i < len; i++) { + Node curr = queue.poll(); + curLevel.add(curr.val); + for (Node c : curr.children) + queue.offer(c); + } + ret.add(curLevel); + } + + return ret; + } +} +// @lc code=end + diff --git a/Week_02/G20200343030441/LeetCode_46_441.java b/Week_02/G20200343030441/LeetCode_46_441.java new file mode 100644 index 00000000..c47f55c1 --- /dev/null +++ b/Week_02/G20200343030441/LeetCode_46_441.java @@ -0,0 +1,30 @@ +/* + * @lc app=leetcode.cn id=46 lang=java + * + * [46] 全排列 + */ + +// @lc code=start +class Solution { + public List> permute(int[] nums) { + List> list = new ArrayList<>(); + backtrack(list, new ArrayList<>(), nums); + return list; + } + + private void backtrack(List> list, List tempList, int [] nums){ + if(tempList.size() == nums.length){ + list.add(new ArrayList<>(tempList)); + } else{ + for(int i = 0; i < nums.length; i++){ + if(tempList.contains(nums[i])) continue; + tempList.add(nums[i]); + backtrack(list, tempList, nums); + // 在当前位置上尝试不同的值 + tempList.remove(tempList.size() - 1); + } + } + } +} +// @lc code=end + diff --git a/Week_02/G20200343030441/LeetCode_47_441.java b/Week_02/G20200343030441/LeetCode_47_441.java new file mode 100644 index 00000000..f42ebe40 --- /dev/null +++ b/Week_02/G20200343030441/LeetCode_47_441.java @@ -0,0 +1,32 @@ +/* + * @lc app=leetcode.cn id=47 lang=java + * + * [47] 全排列 II + */ + +// @lc code=start +class Solution { + public List> permuteUnique(int[] nums) { + List> list = new ArrayList<>(); + Arrays.sort(nums); + backtrack(list, new ArrayList<>(), nums, new boolean[nums.length]); + return list; + } + + private void backtrack(List> list, List tempList, int [] nums, boolean [] used){ + if(tempList.size() == nums.length){ + list.add(new ArrayList<>(tempList)); + } else{ + for(int i = 0; i < nums.length; i++){ + if(used[i] || i > 0 && nums[i] == nums[i-1] && !used[i - 1]) continue; + used[i] = true; + tempList.add(nums[i]); + backtrack(list, tempList, nums, used); + used[i] = false; + tempList.remove(tempList.size() - 1); + } + } + } +} +// @lc code=end + diff --git a/Week_02/G20200343030441/LeetCode_589_441.java b/Week_02/G20200343030441/LeetCode_589_441.java new file mode 100644 index 00000000..32976254 --- /dev/null +++ b/Week_02/G20200343030441/LeetCode_589_441.java @@ -0,0 +1,43 @@ +/* + * @lc app=leetcode.cn id=589 lang=java + * + * [589] N叉树的前序遍历 + */ + +// @lc code=start +/* +// Definition for a Node. +class Node { + public int val; + public List children; + + public Node() {} + + public Node(int _val) { + val = _val; + } + + public Node(int _val, List _children) { + val = _val; + children = _children; + } +}; +*/ +class Solution { + public List preorder_list = new ArrayList<>(); + public List preorder(Node root) { + _preorder(root); + return preorder_list; + } + private void _preorder(Node current_node){ + if (current_node == null) return; + + preorder_list.add(current_node.val); + + for (Node n: current_node.children){ + _preorder(n); + } + } +} +// @lc code=end + diff --git a/Week_02/G20200343030441/LeetCode_590_441.java b/Week_02/G20200343030441/LeetCode_590_441.java new file mode 100644 index 00000000..5b130b58 --- /dev/null +++ b/Week_02/G20200343030441/LeetCode_590_441.java @@ -0,0 +1,47 @@ +import java.util.List; + +/* + * @lc app=leetcode.cn id=590 lang=java + * + * [590] N叉树的后序遍历 + */ + +// @lc code=start +/* +// Definition for a Node. +class Node { + public int val; + public List children; + + public Node() {} + + public Node(int _val) { + val = _val; + } + + public Node(int _val, List _children) { + val = _val; + children = _children; + } +}; +*/ +class Solution { + + public List postorder_list = new ArrayList<>(); + + public List postorder(Node root) { + _postorder(root); + return postorder_list; + } + + private void _postorder(Node current_node){ + if (current_node == null) return; + + for (Node n: current_node.children){ + _postorder(n); + } + postorder_list.add(current_node.val); + } +} +// @lc code=end + diff --git a/Week_02/G20200343030443/P236LowestCommonAncestorOfABinaryTree.java b/Week_02/G20200343030443/P236LowestCommonAncestorOfABinaryTree.java new file mode 100644 index 00000000..2d046efd --- /dev/null +++ b/Week_02/G20200343030443/P236LowestCommonAncestorOfABinaryTree.java @@ -0,0 +1,52 @@ +//Java:二叉树的最近公共祖先 +public class P236LowestCommonAncestorOfABinaryTree { + + public static void main(String[] args) { + Solution solution = new P236LowestCommonAncestorOfABinaryTree().new Solution(); + // TO TEST + } + + + // Definition for a binary tree node. + public class TreeNode { + + int val; + TreeNode left; + TreeNode right; + + TreeNode(int x) { + val = x; + } + } + + //leetcode submit region begin(Prohibit modification and deletion) + class Solution { + + TreeNode rNode = null; + + public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { + findLowestCommonAncestor(root, p, q); + return rNode; + } + + private int findLowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { + if (root == null) { + return 0; + } + if (rNode != null) {//找到公共节点后不再遍历 + return 3; + } + int findSum = 0; + if (root == p || root == q) { + findSum++; + } + findSum += findLowestCommonAncestor(root.left, p, q); + findSum += findLowestCommonAncestor(root.right, p, q); + if (findSum == 2 && rNode == null) { + rNode = root; + } + return findSum; + } + } +//leetcode submit region end(Prohibit modification and deletion) +} diff --git a/Week_02/G20200343030443/P590NAryTreePostorderTraversal.java b/Week_02/G20200343030443/P590NAryTreePostorderTraversal.java new file mode 100644 index 00000000..729c523b --- /dev/null +++ b/Week_02/G20200343030443/P590NAryTreePostorderTraversal.java @@ -0,0 +1,71 @@ +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Stack; + +//Java:N叉树的后序遍历 +class P590NAryTreePostorderTraversal { + + public static void main(String[] args) { + Solution solution = new P590NAryTreePostorderTraversal().new Solution(); + // TO TEST + } + + // Definition for a Node. + class Node { + + public int val; + public List children; + + public Node() { + } + + public Node(int _val) { + val = _val; + } + + public Node(int _val, List _children) { + val = _val; + children = _children; + } + } + + ; + + //leetcode submit region begin(Prohibit modification and deletion) + class Solution { + + List result = new ArrayList<>(); + + public List postorder(Node root) { //递归写法,简便明了 + if (root != null) { + for (int i = 0; i < root.children.size(); i++) { + postorder(root.children.get(i)); + } + result.add(root.val); + } + return result; + } + } + + class Solution1 { + //迭代法,用栈辅助进行前右左遍历,再利用链表头插进行反序保存 + public List postorder(Node root) { + List result = new LinkedList<>(); + Stack stack = new Stack<>(); + if (root == null) { + return result; + } + stack.add(root); + while (!stack.empty()) { + Node father = stack.pop(); + result.add(0, father.val);//链表头插反序 + for (Node node : father.children) { + stack.add(node); + } + } + return result; + } + } +//leetcode submit region end(Prohibit modification and deletion) +} \ No newline at end of file diff --git a/Week_02/G20200343030445/LeetCode_144_445.py b/Week_02/G20200343030445/LeetCode_144_445.py new file mode 100644 index 00000000..7c382866 --- /dev/null +++ b/Week_02/G20200343030445/LeetCode_144_445.py @@ -0,0 +1,32 @@ +# +# @lc app=leetcode.cn id=144 lang=python3 +# +# [144] 二叉树的前序遍历 +# + +# @lc code=start +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution: + def preorderTraversal(self, root: TreeNode) -> List[int]: + output = [] + + def traversal(root): + if not root: + return + output.append(root.val) + traversal(root.left) + traversal(root.right) + + + traversal(root) + + return output + +# @lc code=end + diff --git a/Week_02/G20200343030445/LeetCode_46_445.py b/Week_02/G20200343030445/LeetCode_46_445.py new file mode 100644 index 00000000..5c1d3cc5 --- /dev/null +++ b/Week_02/G20200343030445/LeetCode_46_445.py @@ -0,0 +1,26 @@ +# +# @lc app=leetcode.cn id=46 lang=python3 +# +# [46] 全排列 +# + +# @lc code=start +class Solution: + def permute(self, nums: List[int]) -> List[List[int]]: + output = [] + + def per(nums, result): + if len(nums) == 0: + output.append(result[:]) + return + + for i in range(len(nums)): + result.append(nums[i]) + per(nums[:i] + nums[i+1:], result) + result.pop() + + per(nums, []) + return output + +# @lc code=end + diff --git a/Week_02/G20200343030445/LeetCode_49_445.py b/Week_02/G20200343030445/LeetCode_49_445.py new file mode 100644 index 00000000..29946a8b --- /dev/null +++ b/Week_02/G20200343030445/LeetCode_49_445.py @@ -0,0 +1,21 @@ +# +# @lc app=leetcode.cn id=49 lang=python3 +# +# [49] 字母异位词分组 +# + +# @lc code=start +import collections +class Solution: + def groupAnagrams(self, strs: List[str]) -> List[List[str]]: + ans = collections.defaultdict(list) + for s in strs: + count = [0]*26 + for c in s: + count[ord(c) - ord('a')] += 1 + ans[tuple(count)].append(s) + return ans.values() + + +# @lc code=end + diff --git a/Week_02/G20200343030449/LeetCode_144_449.cpp b/Week_02/G20200343030449/LeetCode_144_449.cpp new file mode 100644 index 00000000..7ade454b --- /dev/null +++ b/Week_02/G20200343030449/LeetCode_144_449.cpp @@ -0,0 +1,28 @@ +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Solution { +public: + vector preorderTraversal(TreeNode* root) { + vector ret; + preorderCore(root, ret); + + return ret; + } + + void preorderCore(TreeNode* node, vector& result) { + if (node!=nullptr) { + result.push_back(node->val); + preorderCore(node->left,result); + preorderCore(node->right,result); + } + + return; + } +}; diff --git a/Week_02/G20200343030449/LeetCode_236_449.coo b/Week_02/G20200343030449/LeetCode_236_449.coo new file mode 100644 index 00000000..88f86444 --- /dev/null +++ b/Week_02/G20200343030449/LeetCode_236_449.coo @@ -0,0 +1,68 @@ +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Solution { +public: + TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) { + if (root==nullptr||p==nullptr||q==nullptr) { + return nullptr; + } + + stack pParent; + stack qParent; + + // find the depth of both nodes + inorder(root, p, pParent); + inorder(root, q, qParent); + + stack* pLow; + stack* pHigh; + + pParent.size()size()!=pHigh->size()) { + pLow->pop(); + } + + while (pLow->top()!=pHigh->top()) { + pLow->pop(); + pHigh->pop(); + } + + return pLow->top(); + + } + + bool inorder(TreeNode* node, TreeNode* target, stack& parent) { + if (node!=nullptr) { + if (target==node) { + parent.push(node); + return true; + } + } + + if (node==nullptr) { + return false; + } + + parent.push(node); + + if (inorder(node->left, target, parent)) { + return true; + } + + if (inorder(node->right, target, parent)) { + return true; + } + + parent.pop(); + + return false; + } +}; diff --git a/Week_02/G20200343030449/LeetCode_46_449.cpp b/Week_02/G20200343030449/LeetCode_46_449.cpp new file mode 100644 index 00000000..db69d46b --- /dev/null +++ b/Week_02/G20200343030449/LeetCode_46_449.cpp @@ -0,0 +1,37 @@ +class Solution { +public: + vector> permute(vector& nums) { + int size = nums.size(); + bool* usedNums = new bool[size](); + vector> result; + vector num; + + _permute(num,usedNums,nums,result); + + delete[] usedNums; + + return result; + } + + void _permute(vector num, bool usedNums[], const vector& nums, vector>& result) { + // terminate + if (num.size() >= nums.size()) { + result.push_back(num); + return; + } + + // next level + for (auto i = 0; i < nums.size();i++) { + if (usedNums[i]==false) { + usedNums[i]=true; + num.push_back(nums[i]); + _permute(num, usedNums, nums, result); + usedNums[i]=false; + num.pop_back(); + } + } + + //other status + return; + } +}; diff --git a/Week_02/G20200343030449/LeetCode_47_449.cpp b/Week_02/G20200343030449/LeetCode_47_449.cpp new file mode 100644 index 00000000..d6942eec --- /dev/null +++ b/Week_02/G20200343030449/LeetCode_47_449.cpp @@ -0,0 +1,43 @@ +class Solution { +public: + vector> permuteUnique(vector& nums) { + sort(nums.begin(),nums.end()); + + vector> result; + vector permute; + bool* bUsed = new bool[nums.size()](); + + _permuteUnique(permute, bUsed, nums, result); + + delete[] bUsed; + + return result; + } + + void _permuteUnique(vector permute, bool* bUsed, const vector& nums, vector>& result) { + //Terminate + if (permute.size() == nums.size()) { + result.push_back(permute); + return; + } + + //Update Current Status + for (int i = 0; i < nums.size();i++) { + if ( i > 0 && nums[i-1]==nums[i] && !bUsed[i-1]) { + continue; + } + + if (!bUsed[i]) { + permute.push_back(nums[i]); + bUsed[i] = true; + // Drill Down to next level + _permuteUnique(permute, bUsed, nums, result); + bUsed[i] = false; + permute.pop_back(); + } + } + + //Other + return; + } +}; diff --git a/Week_02/G20200343030449/LeetCode_49_449.cpp b/Week_02/G20200343030449/LeetCode_49_449.cpp new file mode 100644 index 00000000..65eeb246 --- /dev/null +++ b/Week_02/G20200343030449/LeetCode_49_449.cpp @@ -0,0 +1,27 @@ +class Solution { +public: + vector> groupAnagrams(vector& strs) { + unordered_map> key2strs; + + for (auto &i:strs) { + auto temp = i; + sort(temp.begin(),temp.end()); + auto iter = key2strs.find(temp); + if (iter!=key2strs.end()) { + iter->second.push_back(i); + } + else { + vector str; + str.push_back(i); + key2strs.insert(make_pair(temp,str)); + } + } + + vector> result; + for (auto &i:key2strs) { + result.push_back(i.second); + } + + return result; + } +}; diff --git a/Week_02/G20200343030449/LeetCode_589_449.cpp b/Week_02/G20200343030449/LeetCode_589_449.cpp new file mode 100644 index 00000000..26419f89 --- /dev/null +++ b/Week_02/G20200343030449/LeetCode_589_449.cpp @@ -0,0 +1,45 @@ +/* +// Definition for a Node. +class Node { +public: + int val; + vector children; + + Node() {} + + Node(int _val) { + val = _val; + } + + Node(int _val, vector _children) { + val = _val; + children = _children; + } +}; +*/ +class Solution { +public: + vector preorder(Node* root) { + vector result; + + _preorder(root, result); + + return result; + } + + void _preorder(Node* node, vector& ret) { + // terminate + if (node==nullptr) { + return; + } + + // next level + ret.push_back(node->val); + + for (auto &i:node->children) { + _preorder(i, ret); + } + + return; + } +}; diff --git a/Week_02/G20200343030449/LeetCode_77_449.cpp b/Week_02/G20200343030449/LeetCode_77_449.cpp new file mode 100644 index 00000000..28502551 --- /dev/null +++ b/Week_02/G20200343030449/LeetCode_77_449.cpp @@ -0,0 +1,28 @@ +class Solution { +public: + vector> combine(int n, int k) { + vector> result; + vector combine; + + _combine(1, combine, n, k, result); + + return result; + } + + void _combine(unsigned int start, vector combined, const int MAX_NUM, const int k, vector>& ret) { + // terminate + if (combined.size()==k) { + ret.push_back(combined); + return; + } + + for (int i = start; i < MAX_NUM+1; i++) { + combined.push_back(i); + _combine(++start, combined, MAX_NUM, k, ret); + combined.pop_back(); + } + + // other status + return; + } +}; diff --git a/Week_02/G20200343030451/LeetCode_589_451.cpp b/Week_02/G20200343030451/LeetCode_589_451.cpp new file mode 100644 index 00000000..cc9a2a4f --- /dev/null +++ b/Week_02/G20200343030451/LeetCode_589_451.cpp @@ -0,0 +1,48 @@ +/* +// Definition for a Node. +class Node { +public: + int val; + vector children; + + Node() {} + + Node(int _val) { + val = _val; + } + + Node(int _val, vector _children) { + val = _val; + children = _children; + } +}; +*/ +class Solution { +public: + vector preorder(Node* root) { + vector ve; + if (!root) return ve; + + stack st; + st.push(root); + while(!st.empty()) { + Node *node = st.top(); + st.pop(); + + if (node) { + ve.emplace_back(node->val); + } else { + //continue; + } + + if ( !node->children.empty() ) { + int size = node->children.size(); + for ( int i=size-1; i>=0; i-- ) { //倒序 stack LIFO ,后压入先访问children + Node *n = node->children[i]; + if (n) st.push(n); + } + } + } + return ve; + } +}; \ No newline at end of file diff --git a/Week_02/G20200343030451/LeetCode_590_451.cpp b/Week_02/G20200343030451/LeetCode_590_451.cpp new file mode 100644 index 00000000..74e931ad --- /dev/null +++ b/Week_02/G20200343030451/LeetCode_590_451.cpp @@ -0,0 +1,51 @@ +/* +// Definition for a Node. +class Node { +public: + int val; + vector children; + + Node() {} + + Node(int _val) { + val = _val; + } + + Node(int _val, vector _children) { + val = _val; + children = _children; + } +}; +*/ +class Solution { +public: + vector postorder(Node* root) { + + vector ve; + if (!root) return ve; + + stack st; + st.push(root); + + while (!st.empty()) { + Node *node = st.top(); + st.pop(); + + if (node) { + ve.emplace_back(node->val); //正序存vector val,再反转 + + vector chs = node->children; + if (!chs.empty()) { + int size = chs.size(); + for (int i =0; i< size; i++) { + Node *n = chs[i]; + if (n) st.push(n); //stack为了倒序访问Node + } + } + } + } + reverse(ve.begin(),ve.end()); + return ve; + } +}; + diff --git a/Week_02/G20200343030451/NOTE.md b/Week_02/G20200343030451/NOTE.md index 50de3041..18bc1723 100644 --- a/Week_02/G20200343030451/NOTE.md +++ b/Week_02/G20200343030451/NOTE.md @@ -1 +1,35 @@ -学习笔记 \ No newline at end of file +学习笔记 + +本次总结:本周学习了二叉树相关的。 +以前没有太用C去做相关的题目,发现leetcode上面对于此题590,589只能使用C++类语言。 +对我来说也是一次小小的变化。早想看看其他语言的方法。 +这次学习到了。尽量不使用递归,使用stack,vector方法。 + +这次做的题比如少,但主要看看高级语言的方法。 +使用不同的思想来实现一下。 + 并学习了C++以下新知识与方法 + C++ vector是向量类型,可以容纳许多类型的数据,因此也被称为容器 + C++ stack,C++ 栈 是一个容器类的改编.STL为用户提供了多种名为容器(Container)的类 + C++ emplace_back 能就地通过参数构造对象,不需要拷贝或者移动内存, + 相比push_back能更好地避免内存的拷贝与移动。 + C++ std::pair主要的作用是将两个数据组合成一个数据,两个数据可以是同一类型或者不同类型。 + pair实质上是一个结构体,其主要的两个成员变量是first和second,这两个变量可以直接使用。 + make_pair,无需写出型别, 就可以生成一个pair对象 + +590 N叉树的后序遍历,使用迭代。 + 两个vector,一个stack。存放顺序看似是按前序,实际从root开始,每一层正序进,倒序再次访问。 + 相当于每一层按压入后,每一层是按倒序逐个访问。 每一层childrens,使用vector2来小循环存入到stack。 + 最后val输入完vector1,再反转。 + stack类似于每一层的children全部正序压入。stack访问时,倒序访问每一个Node。来实现的。再反转vector。 +589 N叉树的前序遍历,使用迭代 + 跟589相似,主要是在对每一层的孩子在压入,使用倒序压入,为了先访问孩子。 + + + 通过本周学习,发现仅使用C语言还不够,快速应付所有的算法题,需要同步学习一下C++来解决问题。 +像老师说的,多看看其他语言的解决的方法。 +丰富自己的解决问题的能力与思路。 + + + + + diff --git a/Week_02/G20200343030453/LeetCode_429_453 b/Week_02/G20200343030453/LeetCode_429_453 new file mode 100644 index 00000000..bba3e6aa --- /dev/null +++ b/Week_02/G20200343030453/LeetCode_429_453 @@ -0,0 +1,44 @@ +// 429. N叉树的层序遍历 +/* +// Definition for a Node. +class Node { +public: + int val; + vector children; + + Node() {} + + Node(int _val) { + val = _val; + } + + Node(int _val, vector _children) { + val = _val; + children = _children; + } +}; +*/ +class Solution { +public: + vector> levelOrder(Node* root) { + if(root == NULL) { + return {}; + } + vector> ans; + queue qu; + qu.push(root); + while(!qu.empty()) { + vector v; + for(int i = qu.size(); i; i--) { + Node *curr = qu.front(); + qu.pop(); + v.push_back(curr -> val); + for(Node *it: curr -> children) { + qu.push(it); + } + } + ans.push_back(v); + } + return ans; + } +}; \ No newline at end of file diff --git a/Week_02/G20200343030453/LeetCode_589_453 b/Week_02/G20200343030453/LeetCode_589_453 new file mode 100644 index 00000000..7e03acb0 --- /dev/null +++ b/Week_02/G20200343030453/LeetCode_589_453 @@ -0,0 +1,42 @@ +// 589. N叉树的前序遍历 + +/* +// Definition for a Node. +class Node { +public: + int val; + vector children; + + Node() {} + + Node(int _val) { + val = _val; + } + + Node(int _val, vector _children) { + val = _val; + children = _children; + } +}; +*/ +class Solution { +private: + void helper(Node * root, vector &result) { + if(root == NULL) { + return; + } + // push当前节点值进容器 + result.push_back(root -> val); + // 循环递归当前节点的孩子节点 + for(Node * a : root -> children) { + helper(a, result); + a++; + } + } +public: + vector preorder(Node* root) { + vector result; + helper(root, result); + return result; + } +}; \ No newline at end of file diff --git a/Week_02/G20200343030453/LeetCode_590_453 b/Week_02/G20200343030453/LeetCode_590_453 new file mode 100644 index 00000000..a02b6827 --- /dev/null +++ b/Week_02/G20200343030453/LeetCode_590_453 @@ -0,0 +1,43 @@ +// 590. N叉树的后序遍历 + +/* +// Definition for a Node. +class Node { +public: + int val; + vector children; + + Node() {} + + Node(int _val) { + val = _val; + } + + Node(int _val, vector _children) { + val = _val; + children = _children; + } +}; +*/ +class Solution { +public: + vector postorder(Node* root) { + vector result; + stack st; + if(root == NULL) { + return {}; + } + st.push(root); + while(!st.empty()) { + Node *temp = st.top(); + st.pop(); + for(Node *next : temp -> children) { + st.push(next); + next++; + } + result.push_back(temp -> val); + } + reverse(result.begin(), result.end()); + return result; + } +}; \ No newline at end of file diff --git a/Week_02/G20200343030453/NOTE.md b/Week_02/G20200343030453/NOTE.md index 50de3041..5c528eb2 100644 --- a/Week_02/G20200343030453/NOTE.md +++ b/Week_02/G20200343030453/NOTE.md @@ -1 +1,7 @@ -学习笔记 \ No newline at end of file +学习笔记 + +马辉明 2020.2.23 + +1. C++ Vector容器 + +2. C++ stack && queue 使用 \ No newline at end of file diff --git a/Week_02/G20200343030457/postOrder.java b/Week_02/G20200343030457/postOrder.java new file mode 100644 index 00000000..e9b49003 --- /dev/null +++ b/Week_02/G20200343030457/postOrder.java @@ -0,0 +1,21 @@ +class Solution { + public List postorder(Node root) { + LinkedList stack = new LinkedList<>(); + LinkedList output = new LinkedList<>(); + if (root == null) { + return output; + } + + stack.add(root); + while (!stack.isEmpty()) { + Node node = stack.pollLast(); + output.addFirst(node.val); + for (Node item : node.children) { + if (item != null) { + stack.add(item); + } + } + } + return output; + } +} \ No newline at end of file diff --git a/Week_02/G20200343030457/preOrder.java b/Week_02/G20200343030457/preOrder.java new file mode 100644 index 00000000..42d55894 --- /dev/null +++ b/Week_02/G20200343030457/preOrder.java @@ -0,0 +1,20 @@ +class Solution { + public List preorder(Node root) { + LinkedList stack = new LinkedList<>(); + LinkedList output = new LinkedList<>(); + if (root == null) { + return output; + } + + stack.add(root); + while (!stack.isEmpty()) { + Node node = stack.pollLast(); + output.add(node.val); + Collections.reverse(node.children); + for (Node item : node.children) { + stack.add(item); + } + } + return output; + } +} \ No newline at end of file diff --git a/Week_02/G20200343030459/104.maximum-depth-of-binary-tree.py b/Week_02/G20200343030459/104.maximum-depth-of-binary-tree.py new file mode 100644 index 00000000..7cef0a26 --- /dev/null +++ b/Week_02/G20200343030459/104.maximum-depth-of-binary-tree.py @@ -0,0 +1,77 @@ +# +# @lc app=leetcode id=104 lang=python3 +# +# [104] Maximum Depth of Binary Tree +# +# https://leetcode.com/problems/maximum-depth-of-binary-tree/description/ +# +# algorithms +# Easy (63.95%) +# Likes: 2018 +# Dislikes: 66 +# Total Accepted: 706.9K +# Total Submissions: 1.1M +# Testcase Example: '[3,9,20,null,null,15,7]' +# +# Given a binary tree, find its maximum depth. +# +# The maximum depth is the number of nodes along the longest path from the root +# node down to the farthest leaf node. +# +# Note: A leaf is a node with no children. +# +# Example: +# +# Given binary tree [3,9,20,null,null,15,7], +# +# +# ⁠ 3 +# ⁠ / \ +# ⁠ 9 20 +# ⁠ / \ +# ⁠ 15 7 +# +# return its depth = 3. +# +# + +# @lc code=start +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +# divide & conquer +class Solution: + def maxDepth(self, root: TreeNode) -> int: + if not root: + return 0 + left_depth = self.maxDepth(root.left) + right_depth = self.maxDepth(root.right) + + return max(left_depth, right_depth) + 1 + +# BFS +from collections import deque +class Solution: + def maxDepth(self, root: TreeNode) -> int: + if not root: + return 0 + depth = 0 + queue = deque([root]) + while queue: + depth += 1 + size = len(queue) + for i in range(size): + node = queue.popleft() + if node.left: + queue.append(node.left) + if node.right: + queue.append(node.right) + + return depth + +# @lc code=end + diff --git a/Week_02/G20200343030459/110.balanced-binary-tree.py b/Week_02/G20200343030459/110.balanced-binary-tree.py new file mode 100644 index 00000000..bf399554 --- /dev/null +++ b/Week_02/G20200343030459/110.balanced-binary-tree.py @@ -0,0 +1,86 @@ +# +# @lc app=leetcode id=110 lang=python3 +# +# [110] Balanced Binary Tree +# +# https://leetcode.com/problems/balanced-binary-tree/description/ +# +# algorithms +# Easy (42.51%) +# Likes: 1798 +# Dislikes: 146 +# Total Accepted: 403.5K +# Total Submissions: 947.5K +# Testcase Example: '[3,9,20,null,null,15,7]' +# +# Given a binary tree, determine if it is height-balanced. +# +# For this problem, a height-balanced binary tree is defined as: +# +# +# a binary tree in which the left and right subtrees of every node differ in +# height by no more than 1. +# +# +# +# +# Example 1: +# +# Given the following tree [3,9,20,null,null,15,7]: +# +# +# ⁠ 3 +# ⁠ / \ +# ⁠ 9 20 +# ⁠ / \ +# ⁠ 15 7 +# +# Return true. +# +# Example 2: +# +# Given the following tree [1,2,2,3,3,null,null,4,4]: +# +# +# ⁠ 1 +# ⁠ / \ +# ⁠ 2 2 +# ⁠ / \ +# ⁠ 3 3 +# ⁠ / \ +# ⁠4 4 +# +# +# Return false. +# +# + +# @lc code=start +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution: + def isBalanced(self, root: TreeNode) -> bool: + is_valid, height = self.validate(root) + return is_valid + + def validate(self, node: TreeNode): + if not node: + return (True, 0) + left_valid, left_height = self.validate(node.left) + right_valid, right_height = self.validate(node.right) + + if not left_valid or not right_valid: + return (False, -1) + + if abs(left_height - right_height) > 1: + return (False, -1) + + return (True, max(left_height, right_height) + 1) + +# @lc code=end + diff --git a/Week_02/G20200343030459/114.flatten-binary-tree-to-linked-list.py b/Week_02/G20200343030459/114.flatten-binary-tree-to-linked-list.py new file mode 100644 index 00000000..f3edbe95 --- /dev/null +++ b/Week_02/G20200343030459/114.flatten-binary-tree-to-linked-list.py @@ -0,0 +1,102 @@ +# +# @lc app=leetcode id=114 lang=python3 +# +# [114] Flatten Binary Tree to Linked List +# +# https://leetcode.com/problems/flatten-binary-tree-to-linked-list/description/ +# +# algorithms +# Medium (46.32%) +# Likes: 2215 +# Dislikes: 275 +# Total Accepted: 303.7K +# Total Submissions: 652.5K +# Testcase Example: '[1,2,5,3,4,null,6]' +# +# Given a binary tree, flatten it to a linked list in-place. +# +# For example, given the following tree: +# +# +# ⁠ 1 +# ⁠ / \ +# ⁠ 2 5 +# ⁠/ \ \ +# 3 4 6 +# +# +# The flattened tree should look like: +# +# +# 1 +# ⁠\ +# ⁠ 2 +# ⁠ \ +# ⁠ 3 +# ⁠ \ +# ⁠ 4 +# ⁠ \ +# ⁠ 5 +# ⁠ \ +# ⁠ 6 +# +# +# + +# @lc code=start +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +# divide & conquer +class Solution: + def flatten(self, root: TreeNode) -> None: + """ + Do not return anything, modify root in-place instead. + """ + if not root: + return + self.flatten_subtree(root) + + def flatten_subtree(self, node: TreeNode) -> TreeNode: + if not node: + return None + + left_last = self.flatten_subtree(node.left) + right_last = self.flatten_subtree(node.right) + + if left_last: + left_last.right = node.right + node.right = node.left + node.left = None + + if right_last: + return right_last + if left_last: + return left_last + return node + +# traversal +class Solution: + last_node = None + def flatten(self, root: TreeNode) -> None: + """ + Do not return anything, modify root in-place instead. + """ + if not root: + return + + if self.last_node: + self.last_node.right = root + self.last_node.left = None + + self.last_node = root + right = root.right + self.flatten(root.left) + self.flatten(right) + +# @lc code=end + diff --git a/Week_02/G20200343030459/144.binary-tree-preorder-traversal.py b/Week_02/G20200343030459/144.binary-tree-preorder-traversal.py new file mode 100644 index 00000000..2843b347 --- /dev/null +++ b/Week_02/G20200343030459/144.binary-tree-preorder-traversal.py @@ -0,0 +1,79 @@ +# +# @lc app=leetcode id=144 lang=python3 +# +# [144] Binary Tree Preorder Traversal +# +# https://leetcode.com/problems/binary-tree-preorder-traversal/description/ +# +# algorithms +# Medium (53.91%) +# Likes: 1197 +# Dislikes: 51 +# Total Accepted: 436.7K +# Total Submissions: 808.3K +# Testcase Example: '[1,null,2,3]' +# +# Given a binary tree, return the preorder traversal of its nodes' values. +# +# Example: +# +# +# Input: [1,null,2,3] +# ⁠ 1 +# ⁠ \ +# ⁠ 2 +# ⁠ / +# ⁠ 3 +# +# Output: [1,2,3] +# +# +# Follow up: Recursive solution is trivial, could you do it iteratively? +# +# + +# @lc code=start +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +# recursion +class Solution: + def preorderTraversal(self, root: TreeNode) -> List[int]: + result = [] + if not root: + return result + self.dfs(root, result) + return result + + def dfs(self, node: TreeNode, result: List[int]): + if not node: + return + result.append(node.val) + self.dfs(node.left, result) + self.dfs(node.right, result) + +# stack “颜色标记法” +# https://leetcode-cn.com/problems/binary-tree-inorder-traversal/solution/yan-se-biao-ji-fa-yi-chong-tong-yong-qie-jian-ming/ +class Solution: + def preorderTraversal(self, root: TreeNode) -> List[int]: + result = [] + stack = [(root, False)] + + while stack: + node, visited = stack.pop() + if not node: + continue + if visited: + result.append(node.val) + else: + stack.append((node.right, False)) + stack.append((node.left, False)) + stack.append((node, True)) + return result + +# @lc code=end + diff --git a/Week_02/G20200343030459/145.binary-tree-postorder-traversal.py b/Week_02/G20200343030459/145.binary-tree-postorder-traversal.py new file mode 100644 index 00000000..e4d49b77 --- /dev/null +++ b/Week_02/G20200343030459/145.binary-tree-postorder-traversal.py @@ -0,0 +1,82 @@ +# +# @lc app=leetcode id=145 lang=python3 +# +# [145] Binary Tree Postorder Traversal +# +# https://leetcode.com/problems/binary-tree-postorder-traversal/description/ +# +# algorithms +# Hard (52.28%) +# Likes: 1391 +# Dislikes: 71 +# Total Accepted: 333.7K +# Total Submissions: 635.6K +# Testcase Example: '[1,null,2,3]' +# +# Given a binary tree, return the postorder traversal of its nodes' values. +# +# Example: +# +# +# Input: [1,null,2,3] +# ⁠ 1 +# ⁠ \ +# ⁠ 2 +# ⁠ / +# ⁠ 3 +# +# Output: [3,2,1] +# +# +# Follow up: Recursive solution is trivial, could you do it iteratively? +# +# + +# @lc code=start +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +# recursion +class Solution: + def postorderTraversal(self, root: TreeNode) -> List[int]: + result = [] + if not root: + return result + self.dfs(root, result) + return result + + def dfs(self, node: TreeNode, result: List[int]): + if not node: + return + self.dfs(node.left, result) + self.dfs(node.right, result) + result.append(node.val) + +# stack 颜色标记法 +# https://leetcode-cn.com/problems/binary-tree-inorder-traversal/solution/yan-se-biao-ji-fa-yi-chong-tong-yong-qie-jian-ming/ +class Solution: + def postorderTraversal(self, root: TreeNode) -> List[int]: + result = [] + if not root: + return result + + stack = [(root, False)] + while stack: + node, visited = stack.pop() + if not node: + continue + if visited: + result.append(node.val) + else: + stack.append((node, True)) + stack.append((node.right, False)) + stack.append((node.left, False)) + + return result + +# @lc code=end + diff --git a/Week_02/G20200343030459/236.lowest-common-ancestor-of-a-binary-tree.py b/Week_02/G20200343030459/236.lowest-common-ancestor-of-a-binary-tree.py new file mode 100644 index 00000000..8b47fea4 --- /dev/null +++ b/Week_02/G20200343030459/236.lowest-common-ancestor-of-a-binary-tree.py @@ -0,0 +1,80 @@ +# +# @lc app=leetcode id=236 lang=python3 +# +# [236] Lowest Common Ancestor of a Binary Tree +# +# https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-tree/description/ +# +# algorithms +# Medium (42.41%) +# Likes: 2969 +# Dislikes: 161 +# Total Accepted: 396.4K +# Total Submissions: 928.9K +# Testcase Example: '[3,5,1,6,2,0,8,null,null,7,4]\n5\n1' +# +# Given a binary tree, find the lowest common ancestor (LCA) of two given nodes +# in the tree. +# +# According to the definition of LCA on Wikipedia: “The lowest common ancestor +# is defined between two nodes p and q as the lowest node in T that has both p +# and q as descendants (where we allow a node to be a descendant of itself).” +# +# Given the following binary tree:  root = [3,5,1,6,2,0,8,null,null,7,4] +# +# +# +# Example 1: +# +# +# Input: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1 +# Output: 3 +# Explanation: The LCA of nodes 5 and 1 is 3. +# +# +# Example 2: +# +# +# Input: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4 +# Output: 5 +# Explanation: The LCA of nodes 5 and 4 is 5, since a node can be a descendant +# of itself according to the LCA definition. +# +# +# +# +# Note: +# +# +# All of the nodes' values will be unique. +# p and q are different and both values will exist in the binary tree. +# +# +# + +# @lc code=start +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution: + def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode': + if not root or root == p or root == q: + return root + + left = self.lowestCommonAncestor(root.left, p, q) + right = self.lowestCommonAncestor(root.right, p, q) + + if left and right: + return root + if left: + return left + if right: + return right + return None + +# @lc code=end + diff --git a/Week_02/G20200343030459/94.binary-tree-inorder-traversal.py b/Week_02/G20200343030459/94.binary-tree-inorder-traversal.py new file mode 100644 index 00000000..4b3fc283 --- /dev/null +++ b/Week_02/G20200343030459/94.binary-tree-inorder-traversal.py @@ -0,0 +1,81 @@ +# +# @lc app=leetcode id=94 lang=python3 +# +# [94] Binary Tree Inorder Traversal +# +# https://leetcode.com/problems/binary-tree-inorder-traversal/description/ +# +# algorithms +# Medium (60.71%) +# Likes: 2512 +# Dislikes: 105 +# Total Accepted: 634.4K +# Total Submissions: 1M +# Testcase Example: '[1,null,2,3]' +# +# Given a binary tree, return the inorder traversal of its nodes' values. +# +# Example: +# +# +# Input: [1,null,2,3] +# ⁠ 1 +# ⁠ \ +# ⁠ 2 +# ⁠ / +# ⁠ 3 +# +# Output: [1,3,2] +# +# Follow up: Recursive solution is trivial, could you do it iteratively? +# +# + +# @lc code=start +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +# recursion +class Solution: + def inorderTraversal(self, root: TreeNode) -> List[int]: + result = [] + if not root: + return result + self.dfs(root, result) + return result + + def dfs(self, node: TreeNode, result: List[int]): + if not node: + return + self.dfs(node.left, result) + result.append(node.val) + self.dfs(node.right, result) + +# stack 颜色标记法 +# https://leetcode-cn.com/problems/binary-tree-inorder-traversal/solution/yan-se-biao-ji-fa-yi-chong-tong-yong-qie-jian-ming/ +class Solution: + def inorderTraversal(self, root: TreeNode) -> List[int]: + result = [] + if not root: + return result + + stack = [(root, False)] + while stack: + node, visited = stack.pop() + if not node: + continue + if visited: + result.append(node.val) + else: + stack.append((node.right, False)) + stack.append((node, True)) + stack.append((node.left, False)) + + return result + +# @lc code=end + diff --git a/Week_02/G20200343030459/98.validate-binary-search-tree.py b/Week_02/G20200343030459/98.validate-binary-search-tree.py new file mode 100644 index 00000000..c6008c82 --- /dev/null +++ b/Week_02/G20200343030459/98.validate-binary-search-tree.py @@ -0,0 +1,106 @@ +# +# @lc app=leetcode id=98 lang=python3 +# +# [98] Validate Binary Search Tree +# +# https://leetcode.com/problems/validate-binary-search-tree/description/ +# +# algorithms +# Medium (27.06%) +# Likes: 3141 +# Dislikes: 447 +# Total Accepted: 589.1K +# Total Submissions: 2.2M +# Testcase Example: '[2,1,3]' +# +# Given a binary tree, determine if it is a valid binary search tree (BST). +# +# Assume a BST is defined as follows: +# +# +# The left subtree of a node contains only nodes with keys less than the node's +# key. +# The right subtree of a node contains only nodes with keys greater than the +# node's key. +# Both the left and right subtrees must also be binary search trees. +# +# +# +# +# Example 1: +# +# +# ⁠ 2 +# ⁠ / \ +# ⁠ 1 3 +# +# Input: [2,1,3] +# Output: true +# +# +# Example 2: +# +# +# ⁠ 5 +# ⁠ / \ +# ⁠ 1 4 +# / \ +# 3 6 +# +# Input: [5,1,4,null,null,3,6] +# Output: false +# Explanation: The root node's value is 5 but its right child's value is 4. +# +# +# + +# @lc code=start +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None +import sys +# divide & conquer +class Solution: + def isValidBST(self, root: TreeNode) -> bool: + valid, max_node, min_node = self.validate_bst(root) + return valid + def validate_bst(self, node: TreeNode): + if not node: + return (True, None, None) + + left_valid, left_max, left_min = self.validate_bst(node.left) + right_valid, right_max, right_min = self.validate_bst(node.right) + + if not left_valid or not right_valid: + return (False, None, None) + if left_max and left_max.val >= node.val: + return (False, None, None) + if right_max and right_min.val <= node.val: + return (False, None, None) + + min_node = left_min if left_min is not None else node + max_node = right_max if right_max is not None else node + + return (True, max_node, min_node) + +# inorder 上升序列 +class Solution: + last_val = -sys.maxsize + is_valid = True + def isValidBST(self, root: TreeNode) -> bool: + self.dfs(root) + return self.is_valid + def dfs(self, node: TreeNode): + if not node or not self.is_valid: + return + self.dfs(node.left) + if node.val <= self.last_val: + self.is_valid = False + self.last_val = node.val + self.dfs(node.right) + +# @lc code=end + diff --git a/Week_02/G20200343030463/463-Week 02/LeetCode_105_463.cpp b/Week_02/G20200343030463/463-Week 02/LeetCode_105_463.cpp new file mode 100644 index 00000000..9c2dc2c4 --- /dev/null +++ b/Week_02/G20200343030463/463-Week 02/LeetCode_105_463.cpp @@ -0,0 +1,31 @@ +题目:从前序与中序遍历序列构造二叉树 +解题思路: +官方题解https://leetcode-cn.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/solution/cong-qian-xu-he-zhong-xu-bian-li-xu-lie-gou-zao-er/ +代码入下: +class Solution { +public: + TreeNode* buildTree(vector& preorder, vector& inorder) { + + int preIndex =0; + return recurTree(preorder,preIndex,inorder,0,inorder.size()-1); + + } + + TreeNode *recurTree(vector& preorder,int &preIndex,vector& inorder,int left, int right){ + if (preIndex == preorder.size()) return 0; + int i = left; + for(i=left;i<=right;++i){ //从中序遍历中找到前序遍历的元素的索引 + if(inorder[i]==preorder[preIndex]) break; + } + + TreeNode *node = new TreeNode(preorder[preIndex]); + //将中序遍历以索引i一分为二 + //左子树就从中序遍历前半个数组中开始找 + //右子树就从中序遍历后半个数组中开始找 + if(left<=i-1) node->left = recurTree(preorder,++preIndex,inorder,left,i-1); + if(right>=i+1) node->right = recurTree(preorder,++preIndex,inorder,i+1,right); + return node; + } + + +}; diff --git a/Week_02/G20200343030463/463-Week 02/LeetCode_144_463.cpp b/Week_02/G20200343030463/463-Week 02/LeetCode_144_463.cpp new file mode 100644 index 00000000..b457fc54 --- /dev/null +++ b/Week_02/G20200343030463/463-Week 02/LeetCode_144_463.cpp @@ -0,0 +1,44 @@ +题目:二叉树的前序遍历 +解法1:递归 +递归的格式: +001 终止条件 +002 具体执行操作 +003 下一层执行的操作:层级增加,将相关元素带入 +004 清扫当前状态 + +class Solution { +public: + vector preorderTraversal(TreeNode* root) { + vector res; + dfs(res,root); + return res; + } + + void dfs(vector&res,TreeNode *root){ + if(!root) return; + res.push_back(root->val); + dfs(res,root->left); + dfs(res,root->right); + } +}; + +解法二:利用栈来管理递归调用 先放入右子树节点 再放左子树阶段 这样栈顶的元素就是左子树节点 出栈就是左子树先出来 + +class Solution { +public: + vector preorderTraversal(TreeNode* root) { + vector res; + if(!root) return res; + TreeNode *temp = root; + stacks; + s.push(root); + while(!s.empty()){ + temp = s.top(); + s.pop(); + res.push_back(temp->val); + if(temp->right) s.push(temp->right); + if(temp->left) s.push(temp->left); + } + return res; + } +}; diff --git a/Week_02/G20200343030463/463-Week 02/LeetCode_236_463.cpp b/Week_02/G20200343030463/463-Week 02/LeetCode_236_463.cpp new file mode 100644 index 00000000..10e8a346 --- /dev/null +++ b/Week_02/G20200343030463/463-Week 02/LeetCode_236_463.cpp @@ -0,0 +1,25 @@ +题目:二叉树的最近公共祖先 +解题思路: +001 如果root 就是p q 那么公告祖先 要么是p 要么是q +002 现在开始递归操作 从左子树开始递归 获得叶子节点l 从右子树找获得叶子节点r +003 如果l为空 那就看r那边 如果 r为空则看l那边 l 和 r都就看root;l r 都为空的话就返回NULL +参考链接:https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-tree/solution/c-jing-dian-di-gui-si-lu-fei-chang-hao-li-jie-shi-/ + + +解法: +class Solution { +public: + TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) { + + if(!root || root == p || root == q) return root; + TreeNode *l = lowestCommonAncestor(root->left,p,q); + TreeNode *r = lowestCommonAncestor(root->right,p,q); + + if(!l) + return r; + else if (!r) + return l; + else + return root; + } +}; diff --git a/Week_02/G20200343030463/463-Week 02/LeetCode_429_463.cpp b/Week_02/G20200343030463/463-Week 02/LeetCode_429_463.cpp new file mode 100644 index 00000000..1f0e6699 --- /dev/null +++ b/Week_02/G20200343030463/463-Week 02/LeetCode_429_463.cpp @@ -0,0 +1,33 @@ +题目: N叉树的层序遍历 +解题思路:利用队列 将每一层的节点放入队列中,依次出队列 将元素放入当前数组中 +参考资料L: +https://leetcode.com/problems/n-ary-tree-level-order-traversal/discuss/159086/Basic-C%2B%2B-iterative-solution-with-detailed-explanations.-Super-easy-for-beginners. +解法如下: +class Solution { +public: + vector> levelOrder(Node* root) { + if(!root) return {}; + vector> res; + Node *temp = root; + queue q; + q.push(root); + while(!q.empty()){ + vectorcurLevel; //当前层级数组 + int size = q.size(); //队列进行遍历 + for(int i =0; i< size;i++){ + temp = q.front(); //huoqu + q.pop(); + curLevel.push_back(temp->val); //遍历得到元素放入层级数组中 + for(auto n : temp->children){ //将每个节点的叶子节点放入队列中 + q.push(n); + } + } + res.push_back(curLevel); //将当前数组放入结果数组中 + } + return res; + } +}; + + + + diff --git a/Week_02/G20200343030463/463-Week 02/LeetCode_49_463.cpp b/Week_02/G20200343030463/463-Week 02/LeetCode_49_463.cpp new file mode 100644 index 00000000..0e3bbe36 --- /dev/null +++ b/Week_02/G20200343030463/463-Week 02/LeetCode_49_463.cpp @@ -0,0 +1,28 @@ +题目:字母异位词分组 +思路: +001 将数组内每个元素都进行排序 排序得到的结果作为Key +002 将相同的Key对应的元素放入map中 +003 然后将map元素遍历出来 + +解法: +class Solution { +public: + vector> groupAnagrams(vector& strs) { + + unordered_map > map; + + for (auto s : strs){ + string t = s; + sort(t.begin(),t.end()); + map[t].push_back(s); + } + + vector> ans; + for (auto c : map){ + ans.push_back(c.second); + } + + return ans; + + } +}; diff --git a/Week_02/G20200343030463/463-Week 02/LeetCode_589_463.cpp b/Week_02/G20200343030463/463-Week 02/LeetCode_589_463.cpp new file mode 100644 index 00000000..e14eb672 --- /dev/null +++ b/Week_02/G20200343030463/463-Week 02/LeetCode_589_463.cpp @@ -0,0 +1,67 @@ +题目: N叉树的前序遍历 +思路一:递归调用 +解法一: +class Solution { +public: + vector preorder(Node* root) { + + vector res; + recupreorder(res,root); + return res; + } + + void recupreorder( vector& res, Node*root){ + if(!root) return; + res.push_back(root->val); + for(int i =0;ichildren.size();i++){ + Node* item = root->children[i]; + if(!item) continue; + recupreorder(res,item); + } + } +}; + +解法二: 将解法一中的循环for(int i =0;ichildren.size();i++) 改为 for(Node* item : root->children) +class Solution { +public: + vector res; + vector preorder(Node* root) { + recupreorder(root); + return res; + } + + void recupreorder( Node*root){ + if(!root) return; + res.push_back(root->val); + for(Node* item : root->children){ + recupreorder(item); + } + } +}; +思路二:利用栈的特质进行模拟递归调用 +class Solution { +public: + + vector preorder(Node* root) { + vector result; + if (root == nullptr) { + return result; + } + + stack stk; + stk.push(root); + while (!stk.empty()) { + Node* cur = stk.top(); + stk.pop(); + result.push_back(cur -> val); + for (int i = cur -> children.size() - 1; i >= 0; i--) { + if (cur -> children[i] != nullptr) { + stk.push(cur -> children[i]); + } + } + } + return result; + } + +}; + diff --git a/Week_02/G20200343030463/463-Week 02/LeetCode_590_463.cpp b/Week_02/G20200343030463/463-Week 02/LeetCode_590_463.cpp new file mode 100644 index 00000000..39fc3cb7 --- /dev/null +++ b/Week_02/G20200343030463/463-Week 02/LeetCode_590_463.cpp @@ -0,0 +1,47 @@ +// +题目:N叉树的后序遍历 + +解法1:利用深度递归遍历的方式 + +class Solution { +public: + vector postorder(Node* root) { + + vectorres; + dfs(res,root); + return res; + } + + void dfs(vector&res,Node *root){ + if(!root) return; + for(int i=0; i < root->children.size();i++){ + Node *node = root->children[i]; + if(node) dfs(res,node); + } + res.push_back(root->val); + } + +}; +解法2:空间换时间的思路 通过栈模拟递归的调用 这里需要注意一段代码就是reverse(res.begin(), res.end()); + 递归存入vector中的元素是和后序遍历相反的顺序 所以需要翻转一下 + +class Solution { +public: + vector postorder(Node* root) { + + if(root==NULL) return {}; + vector res; + stack stk; + stk.push(root); + while(!stk.empty()) + { + Node* temp=stk.top(); + stk.pop(); + for(int i=0;ichildren.size();i++) stk.push(temp->children[i]); + res.push_back(temp->val); + } + reverse(res.begin(), res.end()); + return res; + } + +}; diff --git a/Week_02/G20200343030463/NOTE.md b/Week_02/G20200343030463/NOTE.md index 50de3041..71769ccb 100644 --- a/Week_02/G20200343030463/NOTE.md +++ b/Week_02/G20200343030463/NOTE.md @@ -1 +1,90 @@ -学习笔记 \ No newline at end of file +学习笔记 + +二叉树的中序遍历 后序遍历 前序遍历 +树的解法是通常使用递归:节点的定义和重复性 +一部电影<<盗梦空间>> +递归的特点: +001 向下进入不同的递归层,向上又回到原来一层 +002 通过声音同步到上一层,所谓同步就是用参数来进行函数不同层之间的传递变量 +003 每一层的环境和周围的人都是一份拷贝,主角等几个人(参数和全局变量)穿越不同层级的梦境(发生和携带变化) + +中序遍历: +/** +* Definition for a binary tree node. +* struct TreeNode { +* int val; +* TreeNode *left; +* TreeNode *right; +* TreeNode(int x) : val(x), left(NULL), right(NULL) {} +* }; +*/ +class Solution { +public: +vector inorderTraversal(TreeNode* root) { +vector res; +dfs(res,root); +return res; +} +void dfs(vector&res, TreeNode* root){ +if(root ==NULL) return; +dfs(res,root->left); +res.push_back(root->val); +dfs(res,root->right); +} +}; + +中序遍历: +class Solution { +public: +vector preorderTraversal(TreeNode* root) { +vector res; +dfs(res,root); +return res; +} +void dfs(vector&res,TreeNode *root){ +if(!root) return; +res.push_back(root->val); +dfs(res,root->left); +dfs(res,root->right); +} +}; +二叉树后序遍历: +class Solution { +public: +vector postorderTraversal(TreeNode* root) { +vector res; +dfs(res,root); +return res; +} +void dfs(vector&res,TreeNode *root){ +if(!root) return +dfs(res,root->left); +dfs(res,root->right); +res.push_back(root->val); +} +}; + +N叉树的后序遍历 +class Solution { +public: +vector postorder(Node* root) { + +if(root==NULL) return {}; +vector res; +stack stk; +stk.push(root); +while(!stk.empty()) +{ +Node* temp=stk.top(); +stk.pop(); +for(int i=0;ichildren.size();i++) stk.push(temp->children[i]); +res.push_back(temp->val); +} +reverse(res.begin(), res.end()); +return res; +} + +}; + + + diff --git a/Week_02/G20200343030465/leetcode_46_465.java b/Week_02/G20200343030465/leetcode_46_465.java new file mode 100644 index 00000000..a2a06a39 --- /dev/null +++ b/Week_02/G20200343030465/leetcode_46_465.java @@ -0,0 +1,26 @@ +public class Solution { + public List> permute(int[] nums) { + List> permutations = new ArrayList<>(); + if (nums.length == 0) { + return permutations; + } + + collectPermutations(nums, 0, new ArrayList<>(), permutations); + return permutations; + } + + private void collectPermutations(int[] nums, int start, List permutation, + List> permutations) { + + if (permutation.size() == nums.length) { + permutations.add(permutation); + return; + } + + for (int i = 0; i <= permutation.size(); i++) { + List newPermutation = new ArrayList<>(permutation); + newPermutation.add(i, nums[start]); + collectPermutations(nums, start + 1, newPermutation, permutations); + } + } +} \ No newline at end of file diff --git a/Week_02/G20200343030465/leetcode_77_465.java b/Week_02/G20200343030465/leetcode_77_465.java new file mode 100644 index 00000000..03167c3d --- /dev/null +++ b/Week_02/G20200343030465/leetcode_77_465.java @@ -0,0 +1,15 @@ +public class Solution { + public List> combine(int n, int k) { + if (k == n || k == 0) { + List row = new LinkedList<>(); + for (int i = 1; i <= k; ++i) { + row.add(i); + } + return new LinkedList<>(Arrays.asList(row)); + } + List> result = this.combine(n - 1, k - 1); + result.forEach(e -> e.add(n)); + result.addAll(this.combine(n - 1, k)); + return result; + } +} \ No newline at end of file diff --git a/Week_02/G20200343030485/LeetCode_105_485.cs b/Week_02/G20200343030485/LeetCode_105_485.cs new file mode 100644 index 00000000..3baad894 --- /dev/null +++ b/Week_02/G20200343030485/LeetCode_105_485.cs @@ -0,0 +1,42 @@ +/** + * Definition for a binary tree node. + * public class TreeNode { + * public int val; + * public TreeNode left; + * public TreeNode right; + * public TreeNode(int x) { val = x; } + * } + */ +public class Solution { + int preIndex = 0; + public int[] _preoder; + public int[] _inorder; + Dictionary indexDict = new Dictionary(); + + public TreeNode BuildTree(int[] preorder, int[] inorder) { + _preoder = preorder; + _inorder = inorder; + for (int i = 0; i < inorder.Length; i++) { + indexDict[inorder[i]] = i; + } + + TreeNode node = RecusiveTree(0, inorder.Length); + return node; + } + + public TreeNode RecusiveTree(int leftIndex, int rightIndex) { + if (leftIndex == rightIndex) { + return null; + } + + int val = _preoder[preIndex]; + preIndex++; + + TreeNode root = new TreeNode(val); + int index = indexDict[root.val]; + root.left = RecusiveTree(leftIndex, index); + root.right = RecusiveTree(index + 1, rightIndex); + + return root; + } +} \ No newline at end of file diff --git a/Week_02/G20200343030485/LeetCode_236_485.cs b/Week_02/G20200343030485/LeetCode_236_485.cs new file mode 100644 index 00000000..4913b249 --- /dev/null +++ b/Week_02/G20200343030485/LeetCode_236_485.cs @@ -0,0 +1,33 @@ +/** + * Definition for a binary tree node. + * public class TreeNode { + * public int val; + * public TreeNode left; + * public TreeNode right; + * public TreeNode(int x) { val = x; } + * } + */ +public class Solution { + public TreeNode targetNode; + + public TreeNode LowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { + TravelTree(root, p, q); + return targetNode; + } + + public bool TravelTree(TreeNode node, TreeNode p, TreeNode q) { + if (node == null) { + return false; + } + + int left = TravelTree(node.left, p, q) ? 1 : 0; + int right = TravelTree(node.right, p, q) ? 1 : 0; + int mid = (node == p || node == q) ? 1 : 0; + + if (left + right + mid >= 2) { + targetNode = node; + } + + return (left + right + mid > 0); + } +} \ No newline at end of file diff --git a/Week_02/G20200343030485/LeetCode_94_485.cs b/Week_02/G20200343030485/LeetCode_94_485.cs new file mode 100644 index 00000000..72f7cfd9 --- /dev/null +++ b/Week_02/G20200343030485/LeetCode_94_485.cs @@ -0,0 +1,28 @@ +/** + * Definition for a binary tree node. + * public class TreeNode { + * public int val; + * public TreeNode left; + * public TreeNode right; + * public TreeNode(int x) { val = x; } + * } + */ +public class Solution { + public IList InorderTraversal(TreeNode root) { + List list = new List(); + Stack stack = new Stack(); + TreeNode current = root; + while (current != null || stack.Count != 0) { + while (current != null) { + stack.Push(current); + current = current.left; + } + + current = stack.Pop(); + list.Add(current.val); + current = current.right; + } + + return list; + } +} \ No newline at end of file diff --git a/Week_02/G20200343030487/leetcode_144_487.js b/Week_02/G20200343030487/leetcode_144_487.js new file mode 100644 index 00000000..d8f34a50 --- /dev/null +++ b/Week_02/G20200343030487/leetcode_144_487.js @@ -0,0 +1,28 @@ +/** + * Definition for a binary tree node. + * function TreeNode(val) { + * this.val = val; + * this.left = this.right = null; + * } + */ +/** + * @param {TreeNode} root + * @return {number[]} + */ +var preorderTraversal = function(root) { + const stack = [] + const result = [] + if (!root) return [] + stack.push(root) + while (stack.length) { + const node = stack.pop() + result.push(node.val) + if (node.right) { + stack.push(node.right) + } + if (node.left) { + stack.push(node.left) + } + } + return result +}; \ No newline at end of file diff --git a/Week_02/G20200343030487/leetcode_236_487.js b/Week_02/G20200343030487/leetcode_236_487.js new file mode 100644 index 00000000..88ee2f46 --- /dev/null +++ b/Week_02/G20200343030487/leetcode_236_487.js @@ -0,0 +1,21 @@ +/** + * Definition for a binary tree node. + * function TreeNode(val) { + * this.val = val; + * this.left = this.right = null; + * } + */ +/** + * @param {TreeNode} root + * @param {TreeNode} p + * @param {TreeNode} q + * @return {TreeNode} + */ +var lowestCommonAncestor = function(root, p, q) { + if (!root || p === root || q === root) return root + const left = lowestCommonAncestor(root.left, p, q) + const right = lowestCommonAncestor(root.right, p, q) + if (left && right) return root + if (left) return left + if (right) return right +} diff --git a/Week_02/G20200343030487/leetcode_429_487.js b/Week_02/G20200343030487/leetcode_429_487.js new file mode 100644 index 00000000..5dbd9527 --- /dev/null +++ b/Week_02/G20200343030487/leetcode_429_487.js @@ -0,0 +1,28 @@ +/** + * // Definition for a Node. + * function Node(val,children) { + * this.val = val; + * this.children = children; + * }; + */ +/** + * @param {Node} root + * @return {number[][]} + */ +var levelOrder = function(root) { + if (!root) return [] + let queue = [] + const result = [] + queue.unshift(root) + while (queue.length) { + const arr = [] + const newArr = [] + queue.forEach(item => { + arr.push(item.val) + item.children.forEach(child => child && newArr.push(child)) + }) + result.push(arr) + queue = newArr.slice() + } + return result +} \ No newline at end of file diff --git a/Week_02/G20200343030487/leetcode_49_487.js b/Week_02/G20200343030487/leetcode_49_487.js new file mode 100644 index 00000000..7e4fe0f6 --- /dev/null +++ b/Week_02/G20200343030487/leetcode_49_487.js @@ -0,0 +1,27 @@ +/** + * @param {string[]} strs + * @return {string[][]} + */ +var groupAnagrams = function(strs) { + const obj = {} + const result = [] + for (let i = 0, len = strs.length; i < len; i++) { + const item = strs[i].split('').sort((a, b) => { + return a > b + }).join('') + if (!obj[item]) { + obj[item] = [] + } + obj[item].push(strs[i]) + } + console.log(obj) + for (const o in obj) { + if (obj.hasOwnProperty(o)) { + result.push(obj[o]) + } + } + return result +}; + +console.log(groupAnagrams(["eat", "tea", "tan", "ate", "nat", "bat"])) +// groupAnagrams([["eat", "tea", "tan", "ate", "nat", "bat"]]) \ No newline at end of file diff --git a/Week_02/G20200343030487/leetcode_589_487.js b/Week_02/G20200343030487/leetcode_589_487.js new file mode 100644 index 00000000..c927de70 --- /dev/null +++ b/Week_02/G20200343030487/leetcode_589_487.js @@ -0,0 +1,33 @@ +// 递归法 +var preorder1 = function(root) { + var list = []; + return preOrderNTree(root, list) +}; + +function preOrderNTree(root, list){ + if (!root) { + return list + } + list.push(root.val) + for (let i = 0, len = root.children.length; i < len; i++) { + preOrderNTree(root.children[i], list) + } + return list +} + +var preorder2 = function(root) { + let stack = [] + const result = [] + if (!root) return result + stack.push(root) + while (stack.length) { + const node = stack.pop() + result.push(node.val) + if (node.children) { + node.children.reverse().map((item) => { + stack.push(item) + }) + } + } + return result +} \ No newline at end of file diff --git a/Week_02/G20200343030487/leetcode_590_487.js b/Week_02/G20200343030487/leetcode_590_487.js new file mode 100644 index 00000000..18c696c5 --- /dev/null +++ b/Week_02/G20200343030487/leetcode_590_487.js @@ -0,0 +1,33 @@ +// 递归法 +var postorder1 = function(root) { + var list = []; + return preOrderNTree(root, list) +}; + +function preOrderNTree(root, list){ + if (!root) { + return list + } + for (let i = 0, len = root.children.length; i < len; i++) { + preOrderNTree(root.children[i], list) + } + list.push(root.val) + return list +} + +var postorder2 = function(root) { + let stack = [] + const result = [] + if (!root) return result + stack.push(root) + while (stack.length) { + const node = stack.pop() + result.push(node.val) + if (node.children) { + node.children.map((item) => { + stack.push(item) + }) + } + } + return result.reverse() +} \ No newline at end of file diff --git a/Week_02/G20200343030489/LeetCode_105_489.cpp b/Week_02/G20200343030489/LeetCode_105_489.cpp new file mode 100644 index 00000000..48bd4416 --- /dev/null +++ b/Week_02/G20200343030489/LeetCode_105_489.cpp @@ -0,0 +1,52 @@ +/* + * @lc app=leetcode.cn id=105 lang=cpp + * + * [105] 从前序与中序遍历序列构造二叉树 + */ + +// @lc code=start +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Solution +{ +public: + TreeNode *buildTree(vector &preorder, vector &inorder) + { + int pos = 0; + return buildTree(preorder, pos, inorder, 0, inorder.size() - 1); + } + TreeNode *buildTree(vector &preorder, int &pos, vector &inorder, int left, int right) + { + if (pos >= preorder.size()) + { + return 0; + } + int i = left; + for (; i <= right; i++) + { + if (inorder[i] == preorder[pos]) + { + break; + } + } + TreeNode* node=new TreeNode(preorder[pos]); + if (left<=i-1) + { + node->left=buildTree(preorder,++pos,inorder,left,i-1); + } + if (i+1<=right) + { + node->right=buildTree(preorder,++pos,inorder,i+1,right); + } + return node; + + } +}; +// @lc code=end diff --git a/Week_02/G20200343030489/LeetCode_144_489.cpp b/Week_02/G20200343030489/LeetCode_144_489.cpp new file mode 100644 index 00000000..b45d84bf --- /dev/null +++ b/Week_02/G20200343030489/LeetCode_144_489.cpp @@ -0,0 +1,39 @@ +/* + * @lc app=leetcode.cn id=144 lang=cpp + * + * [144] 二叉树的前序遍历 + */ + +// @lc code=start +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Solution { +public: + vector preorderTraversal(TreeNode* root) { + stack s; + vector v; + TreeNode* rt=root; + while (rt||s.size()) + { + /* code */while (rt) + { + /* code */s.push(rt->right); + v.push_back(rt->val); + rt=rt->left; + } + rt=s.top(); + s.pop(); + + } + return v; + } +}; +// @lc code=end + diff --git a/Week_02/G20200343030489/LeetCode_236_489.cpp b/Week_02/G20200343030489/LeetCode_236_489.cpp new file mode 100644 index 00000000..c8f9d9dd --- /dev/null +++ b/Week_02/G20200343030489/LeetCode_236_489.cpp @@ -0,0 +1,31 @@ +/* + * @lc app=leetcode.cn id=236 lang=cpp + * + * [236] 二叉树的最近公共祖先 + */ + +// @lc code=start +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Solution { +public: + TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) { + if (root==NULL||root==p||root==q) + { + /* code */return root; + } + TreeNode* left=lowestCommonAncestor(root->left,p,q); + TreeNode* right=lowestCommonAncestor(root->right,p,q); + return left==nullptr?right:(right==nullptr?left:root); + + } +}; +// @lc code=end + diff --git a/Week_02/G20200343030489/LeetCode_429_489.cpp b/Week_02/G20200343030489/LeetCode_429_489.cpp new file mode 100644 index 00000000..4abd2328 --- /dev/null +++ b/Week_02/G20200343030489/LeetCode_429_489.cpp @@ -0,0 +1,63 @@ +/* + * @lc app=leetcode.cn id=429 lang=cpp + * + * [429] N叉树的层序遍历 + */ + +// @lc code=start +/* +// Definition for a Node. +class Node { +public: + int val; + vector children; + + Node() {} + + Node(int _val) { + val = _val; + } + + Node(int _val, vector _children) { + val = _val; + children = _children; + } +}; +*/ +class Solution { +public: + vector> levelOrder(Node* root) { + if (!root) + { + /* code */return {}; + } + vector> res; + queue que; + que.push(root); + int count=1; + while (que.size()) + { + /* code */vector tmp; + int inner_count=0; + while (count>0) + { + /* code */Node* node=que.front(); + que.pop(); + tmp.push_back(node->val); + count-=1; + for (auto r : node->children) + { + /* code */que.push(r); + inner_count+=1; + } + + } + res.push_back(tmp); + count=inner_count; + } + return res; + + } +}; +// @lc code=end + diff --git a/Week_02/G20200343030489/LeetCode_46_489.cpp b/Week_02/G20200343030489/LeetCode_46_489.cpp new file mode 100644 index 00000000..ee6f5343 --- /dev/null +++ b/Week_02/G20200343030489/LeetCode_46_489.cpp @@ -0,0 +1,41 @@ +/* + * @lc app=leetcode.cn id=46 lang=cpp + * + * [46] 全排列 + */ + +// @lc code=start +class Solution +{ +public: + vector> permute(vector &nums) + { + vector> res; + backtrack(nums,res,0); + return res; + } + void backtrack(vector &nums, vector> &res, int i) + { + res.push_back(nums); + if (i == nums.size()) + { + return; + } + for (; i < nums.size() - 1; i++) + { + for (int j = i + 1; j < nums.size(); j++) + { + swap(nums[i], nums[j]); + backtrack(nums, res, i + 1); + swap(nums[i], nums[j]); + } + } + } + void swap(int &a,int &b){ + int tmp; + tmp=a; + a=b; + b=tmp; + } +}; +// @lc code=end diff --git a/Week_02/G20200343030489/LeetCode_47_489.cpp b/Week_02/G20200343030489/LeetCode_47_489.cpp new file mode 100644 index 00000000..80ce07fb --- /dev/null +++ b/Week_02/G20200343030489/LeetCode_47_489.cpp @@ -0,0 +1,43 @@ +/* + * @lc app=leetcode.cn id=47 lang=cpp + * + * [47] 全排列 II + */ + +// @lc code=start +class Solution +{ +public: + vector> permuteUnique(vector &nums) + { + map m; + for(auto x:nums) + ++m[x]; + vector> res; + vector v; + backtrace(m,0,nums.size(),v,res); + return res; + + } + void backtrace(map& m, int k, int n, vector &v, vector> &res) + { + if (k == n) + { + res.push_back(v); + return; + } + for (auto &p : m) + { + if (p.second == 0) + { + continue; + } + --p.second; + v.push_back(p.first); + backtrace(m, k + 1, n, v, res); + ++p.second; + v.pop_back(); + } + } +}; +// @lc code=end diff --git a/Week_02/G20200343030489/LeetCode_49_489.cpp b/Week_02/G20200343030489/LeetCode_49_489.cpp new file mode 100644 index 00000000..560202e2 --- /dev/null +++ b/Week_02/G20200343030489/LeetCode_49_489.cpp @@ -0,0 +1,36 @@ +/* + * @lc app=leetcode.cn id=49 lang=cpp + * + * [49] 字母异位词分组 + */ + +// @lc code=start +class Solution { +public: + vector> groupAnagrams(vector& strs) { + vector> res; + int line=0; + string tmp; + unordered_map work; + for (auto str:strs) + { + /* code */tmp=str; + sort(tmp.begin(),tmp.end()); + if (work.count(tmp)) + { + /* code */res[work[tmp]].push_back(str); + } + else + { + vector vec(1,str); + res.push_back(vec); + work[tmp]=line++; + } + + + } + return res; + } +}; +// @lc code=end + diff --git a/Week_02/G20200343030489/LeetCode_590_489.cpp b/Week_02/G20200343030489/LeetCode_590_489.cpp new file mode 100644 index 00000000..ce813a2c --- /dev/null +++ b/Week_02/G20200343030489/LeetCode_590_489.cpp @@ -0,0 +1,53 @@ +/* + * @lc app=leetcode.cn id=590 lang=cpp + * + * [590] N叉树的后序遍历 + */ + +// @lc code=start +/* +// Definition for a Node. +class Node { +public: + int val; + vector children; + + Node() {} + + Node(int _val) { + val = _val; + } + + Node(int _val, vector _children) { + val = _val; + children = _children; + } +}; +*/ +class Solution { +public: +vector v; + vector postorder(Node* root) { + if (!root) + { + /* code */return {}; + } + stack sta; + Node* tmp; + sta.push(root); + while (sta.size()) + { + /* code */tmp=sta.top(); + sta.pop(); + v.push_back(tmp->val); + for (Node* node : tmp->children) + { + /* code */sta.push(node); + } + } + reverse(v.begin(),v.end()); + return v; + } +}; +// @lc code=end + diff --git a/Week_02/G20200343030489/LeetCode_77_489.cpp b/Week_02/G20200343030489/LeetCode_77_489.cpp new file mode 100644 index 00000000..54657fe7 --- /dev/null +++ b/Week_02/G20200343030489/LeetCode_77_489.cpp @@ -0,0 +1,40 @@ +/* + * @lc app=leetcode.cn id=77 lang=cpp + * + * [77] 组合 + */ + +// @lc code=start +class Solution +{ +private: + vector> res; + + void dfs(int n, int k, int start, vector &path) + { + if (path.size() == k) + { + res.push_back(path); + return; + } + for (int i = start; i <= n - (k - path.size()) + 1; i++) + { + path.push_back(i); + dfs(n, k, i + 1, path); + path.pop_back(); + } + } + +public: + vector> combine(int n, int k) + { + if (n <= 0 || k <= 0 || k > n) + { + return res; + } + vector path; + dfs(n, k, 1, path); + return res; + } +}; +// @lc code=end diff --git a/Week_02/G20200343030489/LeetCode_94_489.cpp b/Week_02/G20200343030489/LeetCode_94_489.cpp new file mode 100644 index 00000000..b0010fd4 --- /dev/null +++ b/Week_02/G20200343030489/LeetCode_94_489.cpp @@ -0,0 +1,38 @@ +/* + * @lc app=leetcode.cn id=94 lang=cpp + * + * [94] 二叉树的中序遍历 + */ + +// @lc code=start +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Solution { +public: + vector inorderTraversal(TreeNode* root) { + stack s; + vector v; + TreeNode* rt=root; + while (rt||s.size()) + { + /* code */while (rt) + { + /* code */s.push(rt); + rt=rt->left; + } + rt=s.top(); + s.pop(); + v.push_back(rt->val); + rt=rt->right; + } + return v; + } +}; +// @lc code=end diff --git a/Week_02/G20200343030491/LeetCode_105_491.py b/Week_02/G20200343030491/LeetCode_105_491.py new file mode 100644 index 00000000..017c8237 --- /dev/null +++ b/Week_02/G20200343030491/LeetCode_105_491.py @@ -0,0 +1,16 @@ +class Solution: + def buildTree(self, preorder: List[int], inorder: List[int]) -> TreeNode: + + def rec(preorder,inorder): + if len(inorder)==0: + return None + + root = TreeNode(preorder[0]) + + mid = inorder.index(preorder[0]) + root.left = self.buildTree(preorder[1:mid+1],inorder[:mid]) + root.right = self.buildTree(preorder[mid+1:],inorder[mid+1:]) + + return root + + return rec(preorder,inorder) \ No newline at end of file diff --git a/Week_02/G20200343030491/LeetCode_144_491.py b/Week_02/G20200343030491/LeetCode_144_491.py new file mode 100644 index 00000000..6334b208 --- /dev/null +++ b/Week_02/G20200343030491/LeetCode_144_491.py @@ -0,0 +1,24 @@ +class Solution: + def preorderTraversal(self, root: TreeNode) -> List[int]: + res = [] + if not root: + return [] + res.append(root.val) + res += self.preorderTraversal(root.left) + res += self.preorderTraversal(root.right) + + return res + +class Solution: + def preorderTraversal(self, root: TreeNode) -> List[int]: + res = [] + if not root: + return [] + s = [root] + while s: + cur = s.pop() + if cur: + res.append(cur.val) + s.append(cur.right) + s.append(cur.left) + return res \ No newline at end of file diff --git a/Week_02/G20200343030491/LeetCode_236_491.py b/Week_02/G20200343030491/LeetCode_236_491.py new file mode 100644 index 00000000..64cf56a3 --- /dev/null +++ b/Week_02/G20200343030491/LeetCode_236_491.py @@ -0,0 +1,45 @@ +class Solution: + def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode': + def rec(node): + + if (not node.left) and (not node.right): + return [[node]] + if not node.left: + return [[node]+i for i in rec(node.right)]+[[node]] + if not node.right: + return [[node]+i for i in rec(node.left)]+[[node]] + return [[node]+i for i in rec(node.left) + rec(node.right)]+[[node]] + + path = rec(root) + temp = [] + for i in path: + if i[-1] == q or i[-1] == p: + temp.append(i) + + return [i for i in temp[0] if i in temp[1]][-1] + + +class Solution: + def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode': + if not root: + return None + if q is root or p is root: + return root + + left = self.lowestCommonAncestor(root.left,p,q) + right = self.lowestCommonAncestor(root.right,p,q) + + if left and not right: + return left + if right and not left: + return right + if left and right: + return root + +class Solution: + def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode': + if root in [None, p, q]: return root + + left, right = (self.lowestCommonAncestor(i,p,q) for i in [root.left, root.right]) + + return root if right and left else right or left diff --git a/Week_02/G20200343030491/LeetCode_429_491.py b/Week_02/G20200343030491/LeetCode_429_491.py new file mode 100644 index 00000000..e48f6fb9 --- /dev/null +++ b/Week_02/G20200343030491/LeetCode_429_491.py @@ -0,0 +1,49 @@ +class Solution: + def levelOrder(self, root: 'Node') -> List[List[int]]: + if not root: + return [] + res = {} + s, level = [root], 0 + while s: + level += 1 + res[level] = [] + ns = [] + for i in s: + res[level].append(i.val) + ns.extend(i.children) + s = ns + return res.values() + + +class Solution: + def levelOrder(self, root: 'Node') -> List[List[int]]: + if not root: + return [] + res = [] + s = [root] + while s: + l = [] + ns = [] + for i in s: + l += [i.val] + ns.extend(i.children) + res.append(l) + s = ns + return res + + +class Solution: + def levelOrder(self, root: 'Node') -> List[List[int]]: + lev, res = 0, {} + + def rec(node,level): + if not node: + return + + res[level] = res.get(level,[])+[node.val] + + for i in node.children: + rec(i,level+1) + + rec(root,lev) + return res.values() \ No newline at end of file diff --git a/Week_02/G20200343030491/LeetCode_46_491.py b/Week_02/G20200343030491/LeetCode_46_491.py new file mode 100644 index 00000000..d570face --- /dev/null +++ b/Week_02/G20200343030491/LeetCode_46_491.py @@ -0,0 +1,28 @@ +class Solution: + def permute(self, nums: List[int]) -> List[List[int]]: + if len(nums)==0: + return [[]] + return [[nums[i]]+temp for i in range(len(nums)) for temp in self.permute(nums[:i]+nums[i+1:])] + +class Solution: + def permute(self, nums: List[int]) -> List[List[int]]: + perms = [[]] + for num in nums: + temp_p = [] + for perm in perms: + for i in range(len(perm)+1): + temp_p.append((perm[:i] + [num] + perm[i:])) + perms=temp_p + return perms + +class Solution: + def permute(self, nums: List[int]) -> List[List[int]]: + res = [] + def backtrack(nums, temp): + if not nums: + res.append(temp) + return + for i in range(len(nums)): + backtrack(nums[:i]+nums[i+1:],temp+[nums[i]]) + backtrack(nums,[]) + return res \ No newline at end of file diff --git a/Week_02/G20200343030491/LeetCode_47_491.py b/Week_02/G20200343030491/LeetCode_47_491.py new file mode 100644 index 00000000..ec918c57 --- /dev/null +++ b/Week_02/G20200343030491/LeetCode_47_491.py @@ -0,0 +1,27 @@ +class Solution: + def permuteUnique(self, nums: List[int]) -> List[List[int]]: + res = [] + + if len(nums)==0: + return [[]] + + for i in range(len(nums)): + for temp in self.permuteUnique(nums[:i]+nums[i+1:]): + if [nums[i]] + temp not in res: + res.append([nums[i]] + temp) + + return res + + +class Solution: + def permuteUnique(self, nums: List[int]) -> List[List[int]]: + perms = [[]] + for num in nums: + temp = [] + for perm in perms: + for i in range(len(perm)+1): + temp.append(perm[:i]+[num]+perm[i:]) + if i List[List[str]]: + dic = {} + for s in strs: + if str(sorted(s)) in dic: + dic[str(sorted(s))].append(s) + else: + dic[str(sorted(s))] = [s] + return dic.values() \ No newline at end of file diff --git a/Week_02/G20200343030491/LeetCode_589_491.py b/Week_02/G20200343030491/LeetCode_589_491.py new file mode 100644 index 00000000..195b30fd --- /dev/null +++ b/Week_02/G20200343030491/LeetCode_589_491.py @@ -0,0 +1,25 @@ +class Solution: + def preorder(self, root: 'Node') -> List[int]: + if not root: + return [] + s = [root] + res = [] + while s: + cur = s.pop() + res.append(cur.val) + for child in cur.children[::-1]: + s.append(child) + return res + + +class Solution: + def preorder(self, root: 'Node') -> List[int]: + res = [] + if not root: + return [] + def rec(node): + res.append(node.val) + for i in node.children: + rec(i) + rec(root) + return res \ No newline at end of file diff --git a/Week_02/G20200343030491/LeetCode_590_491.py b/Week_02/G20200343030491/LeetCode_590_491.py new file mode 100644 index 00000000..98d96084 --- /dev/null +++ b/Week_02/G20200343030491/LeetCode_590_491.py @@ -0,0 +1,24 @@ +class Solution: + def postorder(self, root: 'Node') -> List[int]: + if not root: + return [] + s=[root] + l = [] + while s: + cur = s.pop() + if cur: + l.append(cur.val) + s.extend(cur.children) + return l[::-1] + + +class Solution: + def postorder(self, root: 'Node') -> List[int]: + res = [] + if not root: return [] + def rec(node): + for child in node.children: + rec(child) + res.append(node.val) + rec(root) + return res \ No newline at end of file diff --git a/Week_02/G20200343030491/LeetCode_77_491.py b/Week_02/G20200343030491/LeetCode_77_491.py new file mode 100644 index 00000000..845e0521 --- /dev/null +++ b/Week_02/G20200343030491/LeetCode_77_491.py @@ -0,0 +1,26 @@ +class Solution: + def combine(self, n: int, k: int) -> List[List[int]]: + a = [i+1 for i in range(n)] + + def rec(arr, k): + res = [] + if k==0: + return [[]] + for i in range(len(arr)-k+1): + for mid in rec(arr[i+1:], k-1): + res.append([arr[i]]+mid) + return res + + return rec(a,k) + + +class Solution: + def combine(self, n: int, k: int) -> List[List[int]]: + res = [] + if k == 0: + return [[]] + for i in range(k,n+1): + for temp in self.combine(i-1,k-1): + res.append(temp+[i]) + + return res \ No newline at end of file diff --git "a/Week_02/G20200343030493/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\347\232\204\346\234\200\350\277\221\345\205\254\345\205\261\347\245\226\345\205\210.java" "b/Week_02/G20200343030493/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\347\232\204\346\234\200\350\277\221\345\205\254\345\205\261\347\245\226\345\205\210.java" new file mode 100644 index 00000000..6adec63e --- /dev/null +++ "b/Week_02/G20200343030493/\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\347\232\204\346\234\200\350\277\221\345\205\254\345\205\261\347\245\226\345\205\210.java" @@ -0,0 +1,87 @@ +//给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。 +// +// 百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大( +//一个节点也可以是它自己的祖先)。” +// +// 例如,给定如下二叉搜索树: root = [6,2,8,0,4,7,9,null,null,3,5] +// +// +// +// +// +// 示例 1: +// +// 输入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 8 +//输出: 6 +//解释: 节点 2 和节点 8 的最近公共祖先是 6。 +// +// +// 示例 2: +// +// 输入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 4 +//输出: 2 +//解释: 节点 2 和节点 4 的最近公共祖先是 2, 因为根据定义最近公共祖先节点可以为节点本身。 +// +// +// +// 说明: +// +// +// 所有节点的值都是唯一的。 +// p、q 为不同节点且均存在于给定的二叉搜索树中。 +// +// Related Topics 树 + + +//leetcode submit region begin(Prohibit modification and deletion) +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; } + * } + */ +class Solution { + private TreeNode ans; + + public Solution() { + // Variable to store LCA node. + this.ans = null; + } + + + private boolean recurseTree(TreeNode currentNode, TreeNode p, TreeNode q) { + + // If reached the end of a branch, return false. + if (currentNode == null) { + return false; + } + + // Left Recursion. If left recursion returns true, set left = 1 else 0 + int left = this.recurseTree(currentNode.left, p, q) ? 1 : 0; + + // Right Recursion + int right = this.recurseTree(currentNode.right, p, q) ? 1 : 0; + + // If the current node is one of p or q + int mid = (currentNode == p || currentNode == q) ? 1 : 0; + + + // If any two of the flags left, right or mid become True + if (mid + left + right >= 2) { + this.ans = currentNode; + } + + // Return true if any one of the three bool values is True. + return (mid + left + right > 0); + } + + public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { + // Traverse the tree + this.recurseTree(root, p, q); + return this.ans; + } +} +//leetcode submit region end(Prohibit modification and deletion) diff --git "a/Week_02/G20200343030493/\344\272\214\345\217\211\346\240\221\347\232\204\344\270\255\345\272\217\351\201\215\345\216\206.java" "b/Week_02/G20200343030493/\344\272\214\345\217\211\346\240\221\347\232\204\344\270\255\345\272\217\351\201\215\345\216\206.java" new file mode 100644 index 00000000..5aad50d4 --- /dev/null +++ "b/Week_02/G20200343030493/\344\272\214\345\217\211\346\240\221\347\232\204\344\270\255\345\272\217\351\201\215\345\216\206.java" @@ -0,0 +1,48 @@ +//给定一个二叉树,返回它的中序 遍历。 +// +// 示例: +// +// 输入: [1,null,2,3] +// 1 +// \ +// 2 +// / +// 3 +// +//输出: [1,3,2] +// +// 进阶: 递归算法很简单,你可以通过迭代算法完成吗? +// Related Topics 栈 树 哈希表 + + +//leetcode submit region begin(Prohibit modification and deletion) +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; } + * } + */ +class Solution { + // 主方法 + public List inorderTraversal(TreeNode root) { + List res = new ArrayList<>(); + helper(root, res); + return res; + } + // 中序查找方法 + public void helper(TreeNode root, List < Integer > res) { + if (root != null) { + if (root.left != null) { + helper(root.left, res); + } + res.add(root.val); + if (root.right != null) { + helper(root.right, res); + } + } + } +} +//leetcode submit region end(Prohibit modification and deletion) diff --git "a/Week_02/G20200343030493/\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215\345\210\206\347\273\204.java" "b/Week_02/G20200343030493/\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215\345\210\206\347\273\204.java" new file mode 100644 index 00000000..71ccebfa --- /dev/null +++ "b/Week_02/G20200343030493/\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215\345\210\206\347\273\204.java" @@ -0,0 +1,49 @@ +//给定一个字符串数组,将字母异位词组合在一起。字母异位词指字母相同,但排列不同的字符串。 +// +// 示例: +// +// 输入: ["eat", "tea", "tan", "ate", "nat", "bat"], +//输出: +//[ +// ["ate","eat","tea"], +// ["nat","tan"], +// ["bat"] +//] +// +// 说明: +// +// +// 所有输入均为小写字母。 +// 不考虑答案输出的顺序。 +// +// Related Topics 哈希表 字符串 + + +//leetcode submit region begin(Prohibit modification and deletion) +class Solution { + public List> groupAnagrams(String[] strs) { + //其中每个键 K 是一个排序字符串,每个值是初始输入的字符串列表 + // 查看长度都是 .length + if (strs.length == 0) return new ArrayList(); + // 创建一个 key 是 String,value 是 List 的 hashmap + Map ans = new HashMap(); + for (String s: strs) { + // string 没有 sort 函数 转换成 array + char[] ca = s.toCharArray(); + Arrays.sort(ca); + // 再转换回 string calueOf 把分散的字符拼接成 string + String key = String.valueOf(ca); + // hashmap cintainsKey 方法:判断key是否在hashmap的key中 + if (!ans.containsKey(key)) { + // 如果不在 把key当做hashmap 的key hashmap.put + ans.put(key, new ArrayList()); + } + // 如果已经包含了 + // hashmap.get(key).add() array.add + ans.get(key).add(s); + } + // hashmap.values(); + return new ArrayList(ans.values()); + } +} +//leetcode submit region end(Prohibit modification and deletion) diff --git "a/Week_02/G20200343030493/\346\213\254\345\217\267\347\224\237\346\210\220.java" "b/Week_02/G20200343030493/\346\213\254\345\217\267\347\224\237\346\210\220.java" new file mode 100644 index 00000000..0ed11da0 --- /dev/null +++ "b/Week_02/G20200343030493/\346\213\254\345\217\267\347\224\237\346\210\220.java" @@ -0,0 +1,27 @@ +class Solution { + private List result; + + public List generateParenthesis(int n) { + result = new ArrayList(); + _generate(0, 0, n, ""); + return null; + } + + private void _generate(int left, int right, int n, String s) { + // terminator + if (level == n && right == n) { + // filter the invalid s + result.add(s); + return; + } + // process + + // drill down + if (left < n) + _generate(left + 1, right, n, s + "("); + if (left > right) + _generate(left, right + 1, n, s + ")"); + // reverse states + + } +} \ No newline at end of file diff --git "a/Week_02/G20200343030493/\346\234\211\346\225\210\347\232\204\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215.java" "b/Week_02/G20200343030493/\346\234\211\346\225\210\347\232\204\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215.java" new file mode 100644 index 00000000..eaa94170 --- /dev/null +++ "b/Week_02/G20200343030493/\346\234\211\346\225\210\347\232\204\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215.java" @@ -0,0 +1,42 @@ +class Solution { + public boolean isAnagram(String s, String t) { + // 解法一 把把两个字符串顺序排列 然后看是否相等 O(nlogn) + if (s.length() != t.length()) { + return false; + } + // char toCharArray 把字符串转换为字符数组 + char[] arr1 = s.toCharArray(); + char[] arr2 = t.toCharArray(); + // Arrays.sort() + Arrays.sort( arr1 ); + Arrarys.sort( arr2 ); + // 判断是否相等 Arrays.equals 相等就返回 true + return Arrays.equals(str1, str2); + + } + + class Solution { + public boolean isAnagram(String s, String t) { + // 解法二 哈希表 + if (s.length() != t.length()) { + return false; + } + int[] counter = new int[26]; + for ( int i = 0; i < s.length(); i++) { + // stirng.charAt() 通过索引查找某个字符在字符串中的位置 + // s 字符串相同的字符加1 + counter[s.charAt(i) - 'a']++; + // t 字符串相同的字符加1 + counter[t.charAt(i) - 'a'] --; + } + // 如果发现count里面有一个字符的计数不是0,代表这个数是多出来的 + for (int count:counter) { + if (count != 0) { + return false; + } + } + return true; + } + } + + diff --git "a/Week_02/G20200343030493/\347\210\254\346\245\274\346\242\257.java" "b/Week_02/G20200343030493/\347\210\254\346\245\274\346\242\257.java" new file mode 100644 index 00000000..b5059dd9 --- /dev/null +++ "b/Week_02/G20200343030493/\347\210\254\346\245\274\346\242\257.java" @@ -0,0 +1,42 @@ +//假设你正在爬楼梯。需要 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 动态规划 + + +//leetcode submit region begin(Prohibit modification and deletion) +class Solution { + public int climbStairs(int n) { + climb_Stairs(0,n); + } + public int climb_Stairs(int i, int n) { + if (i > n) { + return 0; + } + if (i == 1) { + return 1; + } + return climb_Stairs(i+1, n) + climb_Stairs(i+2,n); + } +} +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week_02/G20200343030497/LeetCode_144_497.cpp b/Week_02/G20200343030497/LeetCode_144_497.cpp new file mode 100644 index 00000000..4c6062b1 --- /dev/null +++ b/Week_02/G20200343030497/LeetCode_144_497.cpp @@ -0,0 +1,63 @@ +/** + * 144 二叉树的前序遍历 + * https://leetcode-cn.com/problems/binary-tree-preorder-traversal + */ + + +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Solution { +public: + // 使用迭代 + // 时间复杂度:O(n) + // 空间复杂度:O(n) + vector preorderTraversal(TreeNode* root) { + if(root == NULL){ + return vector(); + } + + vector res; + stack treeStack; + treeStack.push(root); //将根节点入栈 + + while(!treeStack.empty()){ + TreeNode *tmp = treeStack.top(); + res.push_back(tmp->val); + treeStack.pop(); + + // 先将右节点入栈 + if(tmp->right != NULL){ + treeStack.push(tmp->right); + } + // 将左节点入栈 + if(tmp->left != NULL){ + treeStack.push(tmp->left); + } + } + + return res; + } + + // 使用递归 + vector preorderTraversal1(TreeNode* root) { + vector res; + inorder(root, res); + return res; + } + + void inorder(TreeNode* root, vector& node){ + if(!root){ + return; + } + node.push_back(root->val); + inorder(root->left, node); + inorder(root->right, node); + } +}; \ No newline at end of file diff --git a/Week_02/G20200343030497/LeetCode_429_497.cpp b/Week_02/G20200343030497/LeetCode_429_497.cpp new file mode 100644 index 00000000..d90752f8 --- /dev/null +++ b/Week_02/G20200343030497/LeetCode_429_497.cpp @@ -0,0 +1,59 @@ +/** + * 429. N叉树的层序遍历 + * https://leetcode-cn.com/problems/n-ary-tree-level-order-traversal/ + */ + +/* +// Definition for a Node. +class Node { +public: + int val; + vector children; + + Node() {} + + Node(int _val) { + val = _val; + } + + Node(int _val, vector _children) { + val = _val; + children = _children; + } +}; +*/ +class Solution { +public: + // 广度优先遍历 + // 时间复杂度:O(n) + // 空间复杂度:O(n) + vector> levelOrder(Node* root) { + if(root == NULL){ + return vector>(); + } + + vector> res; + queue curLevel; + curLevel.push(root); + while(!curLevel.empty()){ + int levelSize = curLevel.size(); + vector tmpLevel; + + // 遍历当前层 + for(int i=0; ival); + curLevel.pop(); //将节点抛出 + + // 将子节点加入队列 + for(auto childNode:tmp->children){ + curLevel.push(childNode); + } + } + + res.push_back(tmpLevel); + } + + return res; + } +}; diff --git a/Week_02/G20200343030497/LeetCode_49_497.cpp b/Week_02/G20200343030497/LeetCode_49_497.cpp new file mode 100644 index 00000000..c5ab01d2 --- /dev/null +++ b/Week_02/G20200343030497/LeetCode_49_497.cpp @@ -0,0 +1,27 @@ +/** + * 49. 字母异位词分组 + * https://leetcode-cn.com/problems/group-anagrams/ + */ + + +class Solution { +public: + // 对每个元素按字母排序,然后当成键,存储在哈希表中,值为元素列表 + // 时间复杂度:O(nklogk) + // 空间复杂度:O(nk) + vector> groupAnagrams(vector& strs) { + unordered_map> mp; + for(auto str:strs){ + string tmp = str; + sort(tmp.begin(), tmp.end()); + mp[tmp].push_back(str); + } + + vector> res; + for(auto item:mp){ + res.push_back(item.second); + } + + return res; + } +}; \ No newline at end of file diff --git a/Week_02/G20200343030499/LeetCode_105_499.java b/Week_02/G20200343030499/LeetCode_105_499.java new file mode 100644 index 00000000..1b5cefef --- /dev/null +++ b/Week_02/G20200343030499/LeetCode_105_499.java @@ -0,0 +1,103 @@ +/* + * @lc app=leetcode id=105 lang=java + * + * [105] Construct Binary Tree from Preorder and Inorder Traversal + */ + +// @lc code=start +/** + * Definition for a binary tree node. public class TreeNode { int val; TreeNode + * left; TreeNode right; TreeNode(int x) { val = x; } } + */ +class Solution_1 { + public TreeNode buildTree(int[] preorder, int[] inorder) { + // assume preorder and inorder won't be null + if (preorder.length == 0) { + return null; + } + + int rootVal = preorder[0]; + TreeNode rootNode = new TreeNode(rootVal); + if (preorder.length == 1) { + return rootNode; + } + + int rootIndexInInorder = -1; + for (int i = 0; i < inorder.length; i++) { + if (rootVal == inorder[i]) { + rootIndexInInorder = i; + break; + } + } + int leftSize = rootIndexInInorder; + int rightSize = inorder.length - leftSize - 1; + + int[][] preorderPartitions = getPreorderPartitions(preorder, leftSize, rightSize); + int[][] inorderPartitions = getInorderPartitions(inorder, leftSize, rightSize); + rootNode.left = buildTree(preorderPartitions[0], inorderPartitions[0]); + rootNode.right = buildTree(preorderPartitions[1], inorderPartitions[1]); + + return rootNode; + + } + + private int[][] getPreorderPartitions(int[] array, int leftSize, int rightSize) { + // int[] root = new int[] { array[0] }; + int[] left = new int[leftSize]; + int[] right = new int[rightSize]; + for (int i = 0; i < leftSize; i++) { + left[i] = array[i + 1]; + } + for (int i = 0; i < rightSize; i++) { + right[i] = array[i + leftSize + 1]; + } + return new int[][] { left, right }; + } + + private int[][] getInorderPartitions(int[] array, int leftSize, int rightSize) { + // int[] root = new int[1]; + int[] left = new int[leftSize]; + int[] right = new int[rightSize]; + for (int i = 0; i < leftSize; i++) { + left[i] = array[i]; + } + for (int i = 0; i < rightSize; i++) { + right[i] = array[i + leftSize + 1]; + } + return new int[][] { left, right }; + } +} + +class Solution { + public TreeNode buildTree(int[] preorder, int[] inorder) { + return buildTree(preorder, inorder, 0, preorder.length, 0, inorder.length); + } + + private TreeNode buildTree(int[] preorder, int[] inorder, int preorderLeftEnd, int preorderRightEnd, + int inorderLeftEnd, int inorderRightEnd) { + if (preorderRightEnd - preorderLeftEnd == 0) { + return null; + } + TreeNode rootNode = new TreeNode(preorder[preorderLeftEnd]); + if (preorderRightEnd - preorderLeftEnd == 1) { + return rootNode; + } + + // find index of the root in inorder + int rootInInorder = -1; + for (int i = inorderLeftEnd; i < inorderRightEnd; i++) { + if (preorder[preorderLeftEnd] == inorder[i]) { + rootInInorder = i; + break; + } + } + int leftNodeSize = rootInInorder - inorderLeftEnd; + + rootNode.left = buildTree(preorder, inorder, preorderLeftEnd + 1, preorderLeftEnd + leftNodeSize + 1, + inorderLeftEnd, rootInInorder); + rootNode.right = buildTree(preorder, inorder, preorderLeftEnd + leftNodeSize + 1, preorderRightEnd, + rootInInorder + 1, inorderRightEnd); + return rootNode; + } +} +// @lc code=end diff --git a/Week_02/G20200343030499/LeetCode_144_499.java b/Week_02/G20200343030499/LeetCode_144_499.java new file mode 100644 index 00000000..8f89701c --- /dev/null +++ b/Week_02/G20200343030499/LeetCode_144_499.java @@ -0,0 +1,38 @@ +/* + * @lc app=leetcode id=144 lang=java + * + * [144] Binary Tree Preorder Traversal + */ + +// @lc code=start +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; } + * } + */ + +// 为什么这个题是中等难度?感觉比N-ary tree的难啊。 +import java.util.*; + +class Solution { + public List preorderTraversal(TreeNode root) { + List result = new ArrayList<>(); + traverse(result, root); + return result; + } + + private void traverse(List list, TreeNode root) { + if (root == null) { + return; + } + + list.add(root.val); + traverse(list, root.left); + traverse(list, root.right); + } +} +// @lc code=end diff --git a/Week_02/G20200343030499/LeetCode_236_499.java b/Week_02/G20200343030499/LeetCode_236_499.java new file mode 100644 index 00000000..0df46819 --- /dev/null +++ b/Week_02/G20200343030499/LeetCode_236_499.java @@ -0,0 +1,54 @@ +/* + * @lc app=leetcode id=236 lang=java + * + * [236] Lowest Common Ancestor of a Binary Tree + */ + +// @lc code=start +/** + * Definition for a binary tree node. public class TreeNode { int val; TreeNode + * left; TreeNode right; TreeNode(int x) { val = x; } } + */ +import java.util.*; + +class Solution_1 { + public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { + Set nodeVals = new HashSet(); + nodeVals.add(p.val); + nodeVals.add(q.val); + TreeNode[] resultPlaceholder = new TreeNode[1]; + findNodes(root, nodeVals, resultPlaceholder); + return resultPlaceholder[0]; + } + + private void findNodes(TreeNode root, Set nodeVals, TreeNode[] resultPlaceholder) { + if (root == null) { + return; + } + int initialSize = nodeVals.size(); + findNodes(root.left, nodeVals, resultPlaceholder); + findNodes(root.right, nodeVals, resultPlaceholder); + boolean case1 = initialSize == 2 && nodeVals.size() == 0; // 两个节点分别在左右子树的情况 + nodeVals.remove(root.val); + boolean case2 = initialSize == 2 && !case1 && nodeVals.size() == 0; // 其中一个节点就是子树根节点的情况 + + if ((case1 || case2) && resultPlaceholder[0] == null) { + resultPlaceholder[0] = root; + } + } +} + +class Solution { + public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { + if (root == null || root.val == p.val || root.val == q.val) { + return root; + } + TreeNode left = lowestCommonAncestor(root.left, p, q); + TreeNode right = lowestCommonAncestor(root.right, p, q); + if (left != null && right != null) { + return root; + } + return left == null ? right : left; + } +} +// @lc code=end diff --git a/Week_02/G20200343030499/LeetCode_429_499.java b/Week_02/G20200343030499/LeetCode_429_499.java new file mode 100644 index 00000000..59868fc1 --- /dev/null +++ b/Week_02/G20200343030499/LeetCode_429_499.java @@ -0,0 +1,53 @@ +/* +// Definition for a Node. +class Node { + public int val; + public List children; + + public Node() {} + + public Node(int _val) { + val = _val; + } + + public Node(int _val, List _children) { + val = _val; + children = _children; + } +}; +*/ +class Solution { + public List> levelOrder(Node root) { + List> result = new ArrayList>(); + if(root == null) { + return result; + } + Queue q = new LinkedList<>(); + q.offer(root); + traverse(result, q); + return result; + } + + private void traverse(List> result, Queue q) { + // Stop condition + if(q.size() == 0) { + return; + } + + // Process current level + int levelSize = q.size(); + + List level = new ArrayList<>(); + for(int i = 0; i < levelSize; i++) { + Node node = q.poll(); + level.add(node.val); + for(Node child : node.children) { + q.offer(child); + } + } + result.add(level); + + // Dig into deeper level + traverse(result, q); + } +} \ No newline at end of file diff --git a/Week_02/G20200343030499/LeetCode_46_499.java b/Week_02/G20200343030499/LeetCode_46_499.java new file mode 100644 index 00000000..9c5419d4 --- /dev/null +++ b/Week_02/G20200343030499/LeetCode_46_499.java @@ -0,0 +1,38 @@ +/* + * @lc app=leetcode id=46 lang=java + * + * [46] Permutations + */ + +// @lc code=start +class Solution { + public List> permute(int[] nums) { + List> results = new ArrayList<>(); + List resultIndices = new ArrayList<>(); + + recursor(nums, results, resultIndices, new HashSet()); + return results; + } + + private void recursor(int[] nums, List> results, List currResultIndices, Set skip) { + if (skip.size() == nums.length) { + List resultTemp = new ArrayList<>(); + for (int index : currResultIndices) { + resultTemp.add(nums[index]); + } + results.add(resultTemp); + return; + } + + for (int i = 0; i < nums.length; i++) { + if (!skip.contains(i)) { + currResultIndices.add(i); + skip.add(i); + recursor(nums, results, currResultIndices, skip); + currResultIndices.remove(currResultIndices.size() - 1); + skip.remove(i); + } + } + } +} +// @lc code=end diff --git a/Week_02/G20200343030499/LeetCode_49_499.java b/Week_02/G20200343030499/LeetCode_49_499.java new file mode 100644 index 00000000..61b693d8 --- /dev/null +++ b/Week_02/G20200343030499/LeetCode_49_499.java @@ -0,0 +1,78 @@ +/* + * @lc app=leetcode id=49 lang=java + * + * [49] Group Anagrams + */ + +// @lc code=start +import java.util.*; +import java.math.BigInteger; + +class Solution { + // 1. use sorted strings as keys + public List> groupAnagrams_1(String[] strs) { + Map> map = new HashMap<>(); + for (String str : strs) { + char[] strTemp = str.toCharArray(); + Arrays.sort(strTemp); + String sortedStr = new String(strTemp); + if (!map.containsKey(sortedStr)) { + map.put(sortedStr, new ArrayList()); + } + map.get(sortedStr).add(str); + } + return new ArrayList(map.values()); + } + + // 2. generate string from str:strs to get keys + public List> groupAnagrams2(String[] strs) { + Map> grouper = new HashMap<>(); + for (String str : strs) { + String strKey = getCharCounts(str); + if (!grouper.containsKey(strKey)) { + grouper.put(strKey, new ArrayList()); + } + grouper.get(strKey).add(str); + } + return new ArrayList(grouper.values()); + } + + private String getCharCounts(String s) { + int len = s.length(); + Map map = new HashMap<>(); + for (int i = 0; i < len; i++) { + if (!map.containsKey(s.charAt(i))) { + map.put(s.charAt(i), 0); + } + map.put(s.charAt(i), map.get(s.charAt(i)) + 1); + } + + StringBuilder sb = new StringBuilder(); + for (char c = 'a'; c <= 'z'; c++) { + if (map.containsKey(c)) { + sb.append(c); + sb.append(map.get(c)); + } + } + return sb.toString(); + } + + // 3. use prime numbers to get keys. + public List> groupAnagrams(String[] strs) { + String[] primeNumbers = new String[] { "2", "3", "5", "7", "11", "13", "17", "19", "23", "29", "31", "37", "41", + "43", "47", "53", "59", "61", "67", "71", "73", "79", "83", "89", "97", "101" }; + Map> grouper = new HashMap<>(); + for (String str : strs) { + BigInteger strInt = BigInteger.ONE; + for (int i = 0; i < str.length(); i++) { + strInt = strInt.multiply(new BigInteger(primeNumbers[str.charAt(i) - 'a'])); + } + if (!grouper.containsKey(strInt)) { + grouper.put(strInt, new ArrayList()); + } + grouper.get(strInt).add(str); + } + return new ArrayList(grouper.values()); + } +} +// @lc code=end diff --git a/Week_02/G20200343030499/LeetCode_589_499.java b/Week_02/G20200343030499/LeetCode_589_499.java new file mode 100644 index 00000000..180260f4 --- /dev/null +++ b/Week_02/G20200343030499/LeetCode_589_499.java @@ -0,0 +1,44 @@ +/* + * @lc app=leetcode id=589 lang=java + * + * [589] N-ary Tree Preorder Traversal + */ + +// @lc code=start +/* +// Definition for a Node. +class Node { + public int val; + public List children; + + public Node() {} + + public Node(int _val) { + val = _val; + } + + public Node(int _val, List _children) { + val = _val; + children = _children; + } +}; +*/ +class Solution { + public List preorder(Node root) { + List result = new ArrayList<>(); + traverse(result, root); + return result; + } + + private void traverse(List result, Node root) { + if (root == null) { + return; + } + + result.add(root.val); + for (Node child : root.children) { + traverse(result, child); + } + } +} +// @lc code=end diff --git a/Week_02/G20200343030499/LeetCode_590_499.java b/Week_02/G20200343030499/LeetCode_590_499.java new file mode 100644 index 00000000..f5dc4501 --- /dev/null +++ b/Week_02/G20200343030499/LeetCode_590_499.java @@ -0,0 +1,44 @@ +/* + * @lc app=leetcode id=590 lang=java + * + * [590] N-ary Tree Postorder Traversal + */ + +// @lc code=start +/* +// Definition for a Node. +class Node { + public int val; + public List children; + + public Node() {} + + public Node(int _val) { + val = _val; + } + + public Node(int _val, List _children) { + val = _val; + children = _children; + } +}; +*/ +class Solution { + public List postorder(Node root) { + List result = new ArrayList<>(); + traverse(result, root); + return result; + } + + private void traverse(List result, Node root) { + if (root == null) { + return; + } + + for (Node child : root.children) { + traverse(result, child); + } + result.add(root.val); + } +} +// @lc code=end diff --git a/Week_02/G20200343030499/LeetCode_77_499.java b/Week_02/G20200343030499/LeetCode_77_499.java new file mode 100644 index 00000000..720054b1 --- /dev/null +++ b/Week_02/G20200343030499/LeetCode_77_499.java @@ -0,0 +1,60 @@ + +/* + * @lc app=leetcode id=77 lang=java + * + * [77] Combinations + */ +// 利用level order traversal的思路,不同的是到最后一层直接返回该层。 +// 可以利用LinkedList是Queue和List的子类的特性,当成Queue处理,完后可以直接当List返回 +// @lc code=start +class Solution_1 { + public List> combine(int n, int k) { + LinkedList> current = new LinkedList<>(); + for (int i = 1; i <= n; i++) { + List initResult = new ArrayList<>(); + initResult.add(i); + current.offer(initResult); + } + return bfs(n, k, current, 1); + } + + private List> bfs(int n, int k, LinkedList> currentQueue, int depth) { + if (depth == k) { + return currentQueue; + } + + int currentSize = currentQueue.size(); + for (int i = 0; i < currentSize; i++) { + List temp = currentQueue.poll(); + for (int j = temp.get(temp.size() - 1) + 1; j <= n; j++) { + List currentList = new ArrayList<>(temp); + currentList.add(j); + currentQueue.offer(currentList); + } + } + return bfs(n, k, currentQueue, depth + 1); + } +} + +class Solution { + public List> combine(int n, int k) { + List> results = new ArrayList<>(); + List result = new ArrayList<>(); + recurser(n, k, results, result, 1); + return results; + } + + private void recurser(int n, int k, List> results, List currentResult, int startNum) { + if (currentResult.size() == k) { + results.add(currentResult); + return; + } + + for (int i = startNum; i <= n; i++) { + currentResult.add(i); + recurser(n, k, results, new ArrayList<>(currentResult), i + 1); + currentResult.remove(currentResult.size() - 1); + } + } +} +// @lc code=end diff --git a/Week_02/G20200343030501/LeetCode_589_501.java b/Week_02/G20200343030501/LeetCode_589_501.java new file mode 100644 index 00000000..87bc6c74 --- /dev/null +++ b/Week_02/G20200343030501/LeetCode_589_501.java @@ -0,0 +1,35 @@ +/* +// Definition for a Node. +class Node { + public int val; + public List children; + + public Node() {} + + public Node(int _val) { + val = _val; + } + + public Node(int _val, List _children) { + val = _val; + children = _children; + } +}; +*/ +class Solution { + public List preorder(Node root) { + List list = new LinkedList(); + traverse(root, list); + return list; + } + + private void traverse(Node node, List list) { + if (node == null) return; + list.add(node.val); + if (node.children != null) { + node.children.forEach(item -> { + traverse(item, list); + }); + } + } +} diff --git a/Week_02/G20200343030501/LeetCode_590_501.java b/Week_02/G20200343030501/LeetCode_590_501.java new file mode 100644 index 00000000..35956dbe --- /dev/null +++ b/Week_02/G20200343030501/LeetCode_590_501.java @@ -0,0 +1,35 @@ +/* +// Definition for a Node. +class Node { + public int val; + public List children; + + public Node() {} + + public Node(int _val) { + val = _val; + } + + public Node(int _val, List _children) { + val = _val; + children = _children; + } +}; +*/ +class Solution { + public List postorder(Node root) { + List list = new LinkedList(); + traverse(root, list); + return list; + } + + private void traverse(Node node, List list) { + if (node == null) return; + if (node.children != null) { + node.children.forEach(item -> { + traverse(item, list); + }); + } + list.add(node.val); + } +} \ No newline at end of file diff --git a/Week_02/G20200343030503/LeetCode_144_503.java b/Week_02/G20200343030503/LeetCode_144_503.java new file mode 100644 index 00000000..ac89760f --- /dev/null +++ b/Week_02/G20200343030503/LeetCode_144_503.java @@ -0,0 +1,70 @@ +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; } + * } + * + * 二叉树的前序遍历 + * 使用递归 从根节点开始遍历,如果是根节点直接添加到结果的集合中,如果是左节点继续递归,同理有节点一样 + * + * 借助栈 + * LinkedList 是一个双向链表。 + * 它也可以被当作堆栈、队列或双端队列进行操作。LinkedList随机访问效率低,但随机插入、随机删除效率低。 + * 总结: 本题中LinkedList比stack快 + * + */ +// class Solution { +// public List preorderTraversal(TreeNode root) { +// List result = new ArrayList(); +// helper(root,result); +// return result; +// } + +// public void helper(TreeNode root,List result) { +// if (root != null ) { +// result.add(root.val); +// if (root.left != null) { +// helper(root.left,result); +// } +// if (root.right != null) { +// helper(root.right,result); +// } +// } +// } +// } +class Solution { + public List preorderTraversal(TreeNode root) { + //Stack stack = new Stack(); + LinkedList stack = new LinkedList(); + List result = new ArrayList(); + if (root == null) { + return result; + } + //先序遍历 先把根节点入栈 + //stack.push(root); + stack.add(root); + while (!stack.isEmpty()) { //栈不为空的时候 + //根节点出栈 + //TreeNode treeNode = stack.pop(); + TreeNode treeNode = stack.pollLast(); + + result.add(treeNode.val); + //先入右节点 + //再入左节点 + if (treeNode.right != null) { + //stack.push(treeNode.right); + stack.add(treeNode.right); + } + if (treeNode.left != null) { + //stack.push(treeNode.left); + stack.add(treeNode.left); + } + } + + return result; + + } +} \ No newline at end of file diff --git a/Week_02/G20200343030503/LeetCode_242_503.java b/Week_02/G20200343030503/LeetCode_242_503.java new file mode 100644 index 00000000..32976a8e --- /dev/null +++ b/Week_02/G20200343030503/LeetCode_242_503.java @@ -0,0 +1,70 @@ +/** + * + * 是否是异位词 + * 方式1. 排序(借助字符数组进行排序) 判断内容是否相同 + * time complexity O(nlogn) + * space complexity O(n) + * 如果isAnagram中两个参数是字符数组,那么space complexity O(1) + * 方式2. 使用hash表来统计每个字符出现的次数 + * time complexity O(n) + * space complexity O(1) + * 总结: + * 第一种排序然后比较方便快捷,很容易想到 , 根据hash表统计字符出现的次数可以想到 , + * 第三种方式借助ASCII表统计字符出现的次数很难想到,看来官方题解和助教老师的帮助才理解来 + * 基础需要加强,仍然需要训练自己的思维能力 + * + */ +class Solution { + // public boolean isAnagram(String s, String t) { + // char[] sarr = s.toCharArray(); + // char[] tarr = t.toCharArray(); + // Arrays.sort(sarr); + // Arrays.sort(tarr); + // boolean flag = Arrays.equals(sarr,tarr); + // if (flag) { + // return true; + // } + // return false; + // } + //这种方式具慢 + // public boolean isAnagram(String s, String t) { + // Map counter = new HashMap(); + // for (int i = 0; i < s.length(); i++) { + // if (counter.containsKey(s.charAt(i))) { + // counter.put(s.charAt(i),counter.get(s.charAt(i))+1); + // } else { + // counter.put(s.charAt(i),1); + // } + // } + // for (int i = 0; i < t.length(); i++) { + // if (counter.containsKey(t.charAt(i))) { + // if (counter.get(t.charAt(i)) > 1) { //特别注意,如果只有个数只有1个 直接remove,如果是大于1需要减1 + // counter.put(t.charAt(i),counter.get(t.charAt(i))-1); + // }else { + // counter.remove(t.charAt(i)); + // } + // } else { + // return false; + // } + // } + // return counter.isEmpty(); + // } + + public boolean isAnagram(String s, String t) { + if (s.length() != t.length()) { + return false; + } + int[] counter = new int[26]; + for (int i = 0; i < s.length(); i++) { + //s.char[i]的个数加1 t.char[i]的个数减1, 最后遍历counter的值是否都为0即可 + counter[s.charAt(i) - 'a']++; + counter[t.charAt(i) - 'a']--; + } + for (int count: counter) { + if (count != 0) { + return false; + } + } + return true; + } +} \ No newline at end of file diff --git a/Week_02/G20200343030503/LeetCode_49_503.java b/Week_02/G20200343030503/LeetCode_49_503.java new file mode 100644 index 00000000..224f93e9 --- /dev/null +++ b/Week_02/G20200343030503/LeetCode_49_503.java @@ -0,0 +1,27 @@ + +/** + * 1. 方式一、借助hash表,将字符数组中的元素排序之后当作key入map,值为未排序的元素的集合 + * time complexity O(nklogk) n表示的是Strs字符串数组的所有元素,每个元素的排序klogk + * space complexity O(nk) O(NK),排序存储在 ls 中的全部信息内容。 + * + */ +class Solution { + public List> groupAnagrams(String[] strs) { + Map> map = new HashMap>(); + + for (String str: strs) { + char[] chars = str.toCharArray(); + Arrays.sort(chars); + String charStr = String.valueOf(chars); + if (map.containsKey(charStr)) { + map.get(charStr).add(str); + }else { + List ls = new ArrayList<>(); + ls.add(str); + map.put(charStr,ls); + } + } + + return new ArrayList<>(map.values()); + } +} \ No newline at end of file diff --git a/Week_02/G20200343030503/LeetCode_589_503.java b/Week_02/G20200343030503/LeetCode_589_503.java new file mode 100644 index 00000000..f584520d --- /dev/null +++ b/Week_02/G20200343030503/LeetCode_589_503.java @@ -0,0 +1,28 @@ +/* +* +* 递归实现N叉树的前序遍历 +* +* +* +* +*/ +class Solution { + public List preorder(Node root) { + List result = new ArrayList(); + helper(root,result); + return result; + } + + public void helper(Node root,List result){ + if (root != null) { + result.add(root.val); + if(root.children != null) { + for (Node node: root.children) { + helper(node,result); + } + } + + } + + } +} \ No newline at end of file diff --git a/Week_02/G20200343030503/LeetCode_590_503.java b/Week_02/G20200343030503/LeetCode_590_503.java new file mode 100644 index 00000000..784e7c10 --- /dev/null +++ b/Week_02/G20200343030503/LeetCode_590_503.java @@ -0,0 +1,43 @@ +/* +// Definition for a Node. +class Node { + public int val; + public List children; + + public Node() {} + + public Node(int _val) { + val = _val; + } + + public Node(int _val, List _children) { + val = _val; + children = _children; + } +}; +* +* 递归实现N叉树的遍历 +*/ +class Solution { + List result = new ArrayList(); + //递归实现 + public List postorder(Node root) { + + if (root == null) { + return null; + } + for (Node node: root.children) { + + postorder(node); + + } + result.add(root.val); + + return result; + } + + //迭代实现 + // public List postorder(Node root) { + + // } +} \ No newline at end of file diff --git a/Week_02/G20200343030503/LeetCode_94_503.java b/Week_02/G20200343030503/LeetCode_94_503.java new file mode 100644 index 00000000..e66fca76 --- /dev/null +++ b/Week_02/G20200343030503/LeetCode_94_503.java @@ -0,0 +1,37 @@ +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; } + * } + * + * + * https://leetcode-cn.com/problems/binary-tree-inorder-traversal/ + * 方式一、使用递归 + * + * + * + */ +class Solution { + public List inorderTraversal(TreeNode root) { + List result = new ArrayList(); + helper(root,result); + return result; + } + + public void helper(TreeNode root,List result) { + if (root != null) { + //递归所有左节点 + if (root.left != null) { + helper(root.left,result); + } + result.add(root.val); + //递归所有右节点 + if(root.right != null) { + helper(root.right,result); + } + } + } +} \ No newline at end of file diff --git a/Week_02/G20200343030503/NOTE.md b/Week_02/G20200343030503/NOTE.md index 50de3041..024b7035 100644 --- a/Week_02/G20200343030503/NOTE.md +++ b/Week_02/G20200343030503/NOTE.md @@ -1 +1,77 @@ -学习笔记 \ No newline at end of file +学习笔记 + +知识点总结: + + 1. hash表定义: + + 散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通 过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散表。 + +2. 顺序存储、链式存储、树存储对比 + + 1) 数组存储方式的分析 + + ​ 优点:通过下标方式访问元素,速度快。对于有序数组,还可使用二分查找提高检索速度。 + + ​ 缺点:如果要检索具体某个值,或者插入值**(**按一定顺序**)**会整体移动,效率较低 + + 2) 链式存储方式的分析 + + ​ 优点:在一定程度上对数组存储方式有优化(比如:插入一个数值节点,只需要将插入节点,链接到链表中即可,删除 + + ​ 效率也很好)。 + + ​ 缺点:在进行检索时,效率仍然较低,比如(检索某个值,需要从头节点开始遍历) + + 3) 树存储方式的分析 + + ​ 能提高数据存储,读取的效率, 比如利用 二叉排序树(Binary Sort Tree),既可以保证数据的检索速度,同时也可以 保证数据的插入,删除,修改的速度。 + +3. 二叉树 + + 定义: 树有很多种,每个节点最多只能有两个子节点的一种形式称为二叉树。 + +4. 树的遍历 + + 前序遍历: 先输出父节点,再遍历左子树和右子树 + + 中序遍历: 先遍历左子树,再输出父节点,再遍历右子树 + + 后序遍历: 先遍历左子树,再遍历右子树,最后输出父节点 + + 总结: 看输出父节点的顺序,就确定是前序,中序还是后序 + +5. 递归需要遵守的重要规则 + + a. terminator 终止条件 + + b. process 处理程序 + + c. drill down 向下递归 + + d. reverse states 状态还原 + +homework总结: + + 1. 异位词分组 + + 借助hash表,将字符串数组中的元素按照字符数组(toCharArray)排序之后当作key入map,值为未排序的元素的集合 + + 2. 是否是异位词 + + 方式1. 排序(借助字符数组进行排序) 判断内容是否相同 + + 方式2. 使用hash表来统计每个字符出现的次数 + + 第一种排序然后比较方便快捷,很容易想到 , 根据hash表统计字符出现的次数可以想到 ,第三种方式借助ASCII表统计字符出现的次数很难想到,看来官方题解和助教老师的帮助才理解来 + + 结论: 基础需要加强,仍然需要训练自己的思维能力 + + 3. 树的前、中、后序遍历 + + 方式1. 使用递归使用递归遍历套路都差不多,主要考虑的就是根节点的顺序 + + 方式2. 使用栈实现 + + ​ LinkedList 是一个双向链表。它也可以被当作堆栈、队列或双端队列进行操作。 + + 总结: 向leetcode提交作业的时候,使用LinkedList比使用stack快 \ No newline at end of file diff --git a/Week_02/G20200343030505/LeetCode_105_505.java b/Week_02/G20200343030505/LeetCode_105_505.java new file mode 100644 index 00000000..81fcdc27 --- /dev/null +++ b/Week_02/G20200343030505/LeetCode_105_505.java @@ -0,0 +1,25 @@ +class LeetCode_105_505 { + private Map map = new HashMap(); + public TreeNode buildTree(int[] preorder, int[] inorder) { + for (int i=0;i p_right) { + return null; + } + + TreeNode root = new TreeNode(preorder[p_left]); + int i_index = map.get(preorder[p_left]); + int leftNum = i_index - i_left; + root.left = buildTree(preorder, p_left + 1, p_left + leftNum, inorder, i_left, i_index - 1); + root.right = buildTree(preorder, p_left + leftNum + 1, p_right, inorder, i_index+1, i_right); + + return root; + } +} \ No newline at end of file diff --git a/Week_02/G20200343030505/LeetCode_144_505.java b/Week_02/G20200343030505/LeetCode_144_505.java new file mode 100644 index 00000000..2917574e --- /dev/null +++ b/Week_02/G20200343030505/LeetCode_144_505.java @@ -0,0 +1,54 @@ +/** + * 使用栈 + * @author huangwen05 + * + * @date: 2020年2月23日 下午7:53:59 + */ +class LeetCode_144_505 { + private List result = new ArrayList(); + public List preorderTraversal(TreeNode root) { + if(root == null) { + return result; + } + + Stack stacks = new Stack(); + stacks.add(root); + TreeNode curr = null; + while (!stacks.isEmpty()) { + curr = stacks.pop(); + result.add(curr.val); + if(curr.right != null) { + stacks.add(curr.right); + } + if(curr.left != null) { + stacks.add(curr.left); + } + } + + return result; + } +} + +/** + * 递归方法 + * @author huangwen05 + * + * @date: 2020年2月23日 下午7:53:48 + */ +class LeetCode_144_505_digui { + private List result = new ArrayList(); + public List preorderTraversal(TreeNode root) { + preorderTree(root); + return result; + } + + public void preorderTree(TreeNode root) { + if(root == null) { + return; + } + + result.add(root.val); + preorderTree(root.left); + preorderTree(root.right); + } +} \ No newline at end of file diff --git a/Week_02/G20200343030505/LeetCode_236_505.java b/Week_02/G20200343030505/LeetCode_236_505.java new file mode 100644 index 00000000..56500a90 --- /dev/null +++ b/Week_02/G20200343030505/LeetCode_236_505.java @@ -0,0 +1,18 @@ +class LeetCode_429_505 { + public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { + + //递归终止条件 + if (root == null || root == p || root == q) { + return root; + } + + TreeNode p1 = lowestCommonAncestor(root.left, p, q); + TreeNode p2 = lowestCommonAncestor(root.right, p, q); + + if (p1 != null && p2 != null) { + return root; + } + + return p1 == null ?p2:p1; + } +} \ No newline at end of file diff --git a/Week_02/G20200343030505/LeetCode_429_505.java b/Week_02/G20200343030505/LeetCode_429_505.java new file mode 100644 index 00000000..1b6ffdde --- /dev/null +++ b/Week_02/G20200343030505/LeetCode_429_505.java @@ -0,0 +1,28 @@ +class LeetCode_429_505 { + private List> result = new ArrayList(); + public List> levelOrder(Node root) { + if (root == null) { + return result; + } + + Deque queue = new ArrayDeque(); + queue.addLast(root); + while (!queue.isEmpty()) { + int count = queue.size(); + List level = new ArrayList(); + while (count-- > 0) { + Node node = queue.pollFirst(); + level.add(node.val); + if (node.children != null) { + for (Node node1:node.children) { + queue.addLast(node1); + } + } + } + + result.add(level); + } + + return result; + } +} \ No newline at end of file diff --git a/Week_02/G20200343030505/LeetCode_46_505.java b/Week_02/G20200343030505/LeetCode_46_505.java new file mode 100644 index 00000000..e962c3e8 --- /dev/null +++ b/Week_02/G20200343030505/LeetCode_46_505.java @@ -0,0 +1,34 @@ +class Solution_46_505 { + private List> result = new ArrayList(); + public List> permute(int[] nums) { + + if (nums == null || nums.length == 0) { + return result; + } + + int depth = 0; + LinkedList path = new LinkedList(); + boolean[] used = new boolean[nums.length]; + permute(nums, depth, path, used); + return result; + } + + public void permute(int[] nums, int depth, LinkedList path, boolean[] used) { + if (depth == nums.length) { + result.add(new ArrayList(path)); + return; + } + + for (int i=0;i> result = new ArrayList(); + public List> permuteUnique(int[] nums) { + + if (nums == null || nums.length == 0) { + return result; + } + + int depth = 0; + LinkedList path = new LinkedList(); + boolean[] used = new boolean[nums.length]; + Arrays.sort(nums); + permute(nums, depth, path, used); + return result; + } + + public void permute(int[] nums, int depth, LinkedList path, boolean[] used) { + if (depth == nums.length) { + result.add(new ArrayList(path)); + return; + } + + for (int i=0;i 0 && nums[i - 1] == nums[i] && !used[i-1]) { + continue; + } + + used[i] = true; + path.addLast(nums[i]); + //下一层递归处理 + permute(nums, depth + 1, path, used); + path.removeLast(); + used[i] = false; + } + } + } + + } \ No newline at end of file diff --git a/Week_02/G20200343030505/LeetCode_49_505.java b/Week_02/G20200343030505/LeetCode_49_505.java new file mode 100644 index 00000000..866d6c18 --- /dev/null +++ b/Week_02/G20200343030505/LeetCode_49_505.java @@ -0,0 +1,24 @@ +class Solution_49_505 { + public List> groupAnagrams(String[] strs) { + List> result = new ArrayList(); + if (strs == null || strs.length == 0) { + return result; + } + + Map> map = new HashMap(); + for (String str:strs) { + char[] arr = str.toCharArray(); + Arrays.sort(arr); + String t = String.valueOf(arr); + if (map.containsKey(t)) { + map.get(t).add(str); + } else { + List tList = new ArrayList(); + tList.add(str); + map.put(t, tList); + } + } + + return new ArrayList(map.values()); + } +} \ No newline at end of file diff --git a/Week_02/G20200343030505/LeetCode_589_505.java b/Week_02/G20200343030505/LeetCode_589_505.java new file mode 100644 index 00000000..908a4ee7 --- /dev/null +++ b/Week_02/G20200343030505/LeetCode_589_505.java @@ -0,0 +1,59 @@ +/** + * 使用栈 + * @author huangwen05 + * + * @date: 2020年2月23日 下午7:57:29 + */ +class Solution_589_505 { + private List result = new ArrayList(); + public List preorder(Node root) { + if (root == null) { + return result; + } + + Stack stacks = new Stack(); + stacks.add(root); + Node curr = null; + while (!stacks.isEmpty()) { + curr = stacks.pop(); + result.add(curr.val); + if (curr.children != null) { + for (int i=curr.children.size() - 1;i>=0;--i) { + stacks.add(curr.children.get(i)); + } + } + } + + return result; + } +} + +/** + * 递归 + * @author huangwen05 + * + * @date: 2020年2月23日 下午7:57:48 + */ +class Solution_589_505_2 { + private List result = new ArrayList(); + public List preorder(Node root) { + if (root == null) { + return result; + } + preorderTree(root); + return result; + } + + public void preorderTree(Node root) { + if (root == null) { + return; + } + + result.add(root.val); + if (root.children != null) { + for (Node node:root.children) { + preorderTree(node); + } + } + } +} \ No newline at end of file diff --git a/Week_02/G20200343030505/LeetCode_590_505.java b/Week_02/G20200343030505/LeetCode_590_505.java new file mode 100644 index 00000000..d58e3fcc --- /dev/null +++ b/Week_02/G20200343030505/LeetCode_590_505.java @@ -0,0 +1,55 @@ +/** + * 递归 + * @author huangwen05 + * + * @date: 2020年2月23日 下午7:58:26 + */ +class Solution_590_505 { + private List result = new ArrayList(); + public List postorder(Node root) { + if(root == null) { + return result; + } + + postorderTree(root); + return result; + } + + public void postorderTree(Node root) { + if(root == null) { + return; + } + + if (root.children != null) { + for (Node node:root.children) { + postorder(node); + } + } + + result.add(root.val); + } +} + +class Solution_590_505_2 { + private LinkedList result = new LinkedList(); + public List postorder(Node root) { + if(root == null) { + return result; + } + + Stack stacks = new Stack(); + stacks.add(root); + Node curr = null; + while (!stacks.isEmpty()) { + curr = stacks.pop(); + result.addFirst(curr.val); + if (curr.children != null) { + for(Node node:curr.children) { + stacks.add(node); + } + } + } + + return result; + } +} diff --git a/Week_02/G20200343030505/LeetCode_77_505.java b/Week_02/G20200343030505/LeetCode_77_505.java new file mode 100644 index 00000000..06c1aab9 --- /dev/null +++ b/Week_02/G20200343030505/LeetCode_77_505.java @@ -0,0 +1,25 @@ +class Solution_77_505 { + private List> result = new ArrayList(); + public List> combine(int n, int k) { + if (n <= 0 || k <= 0 || n < k) { + return result; + } + + LinkedList path = new LinkedList(); + combine(n, 0, 1, k, path); + return result; + } + + public void combine(int n, int depth, int begin, int k, LinkedList path) { + if (depth == k) { + result.add(new ArrayList(path)); + return; + } + + for (int i=begin;i<=n-k+path.size()+1;++i) { + path.addLast(i); + combine(n, depth + 1, i + 1, k, path); + path.removeLast(); + } + } + } \ No newline at end of file diff --git a/Week_02/G20200343030507/507-Week 02/LeetCode_105_507.py b/Week_02/G20200343030507/507-Week 02/LeetCode_105_507.py new file mode 100644 index 00000000..a31f284d --- /dev/null +++ b/Week_02/G20200343030507/507-Week 02/LeetCode_105_507.py @@ -0,0 +1,27 @@ +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution(object): + def buildTree(self, preorder, inorder): + """ + :type preorder: List[int] + :type inorder: List[int] + :rtype: TreeNode + """ + if len(inorder) == 0: + return None + # 前序遍历第一个值为根节点 + root = TreeNode(preorder[0]) + # 因为没有重复元素,所以可以直接根据值来查找根节点在中序遍历中的位置 + mid = inorder.index(preorder[0]) + # 构建左子树 + root.left = self.buildTree(preorder[1:mid+1], inorder[:mid]) + # 构建右子树 + root.right = self.buildTree(preorder[mid+1:], inorder[mid+1:]) + + return root + diff --git a/Week_02/G20200343030507/507-Week 02/LeetCode_144_507.py b/Week_02/G20200343030507/507-Week 02/LeetCode_144_507.py new file mode 100644 index 00000000..f90c35c2 --- /dev/null +++ b/Week_02/G20200343030507/507-Week 02/LeetCode_144_507.py @@ -0,0 +1,19 @@ +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution: + def preorderTraversal(self, root: TreeNode) -> List[int]: + res = [] + p = root + stack = [] + while p or stack: + while p: + res.append(p.val) + stack.append(p) + p = p.left + p = stack.pop().right + return res \ No newline at end of file diff --git a/Week_02/G20200343030507/507-Week 02/LeetCode_236_507.py b/Week_02/G20200343030507/507-Week 02/LeetCode_236_507.py new file mode 100644 index 00000000..a3161fbd --- /dev/null +++ b/Week_02/G20200343030507/507-Week 02/LeetCode_236_507.py @@ -0,0 +1,19 @@ +class Solution: + def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode': + stack = [root] + parent = {root: None} + while p not in parent or q not in parent: + node = stack.pop() + if node.left: + parent[node.left] = node + stack.append(node.left) + if node.right: + parent[node.right] = node + stack.append(node.right) + ancestors = set() + while p: + ancestors.add(p) + p = parent[p] + while q not in ancestors: + q = parent[q] + return q \ No newline at end of file diff --git a/Week_02/G20200343030507/507-Week 02/LeetCode_429_507.py b/Week_02/G20200343030507/507-Week 02/LeetCode_429_507.py new file mode 100644 index 00000000..df15d7ee --- /dev/null +++ b/Week_02/G20200343030507/507-Week 02/LeetCode_429_507.py @@ -0,0 +1,21 @@ +""" +# Definition for a Node. +class Node: + def __init__(self, val=None, children=None): + self.val = val + self.children = children +""" +class Solution: + def levelOrder(self, root: 'Node') -> List[List[int]]: + if root is None: + return [] + result = [] + queue = collections.deque([root]) + while queue: + level = [] + for _ in range(len(queue)): + node = queue.popleft() + level.append(node.val) + queue.extend(node.children) + result.append(level) + return result \ No newline at end of file diff --git a/Week_02/G20200343030507/507-Week 02/LeetCode_46_507.py b/Week_02/G20200343030507/507-Week 02/LeetCode_46_507.py new file mode 100644 index 00000000..1669755e --- /dev/null +++ b/Week_02/G20200343030507/507-Week 02/LeetCode_46_507.py @@ -0,0 +1,11 @@ +class Solution: + def permute(self, nums: List[int]) -> List[List[int]]: + res = [] + def backtrack(nums, tmp): + if not nums: + res.append(tmp) + return + for i in range(len(nums)): + backtrack(nums[:i] + nums[i+1:], tmp + [nums[i]]) + backtrack(nums, []) + return res diff --git a/Week_02/G20200343030507/507-Week 02/LeetCode_47_507.py b/Week_02/G20200343030507/507-Week 02/LeetCode_47_507.py new file mode 100644 index 00000000..460bec7c --- /dev/null +++ b/Week_02/G20200343030507/507-Week 02/LeetCode_47_507.py @@ -0,0 +1,26 @@ +class Solution: + def permuteUnique(self, nums: List[int]) -> List[List[int]]: + def dfs(nums, size, depth, path, used, res): + if depth == size: + res.append(path.copy()) + return + for i in range(size): + if not used[i]: + if i > 0 and nums[i] == nums[i - 1] and not used[i - 1]: + continue + used[i] = True + path.append(nums[i]) + dfs(nums, size, depth + 1, path, used, res) + used[i] = False + path.pop() + + size = len(nums) + if size == 0: + return [] + + nums.sort() + + used = [False] * len(nums) + res = [] + dfs(nums, size, 0, [], used, res) + return res diff --git a/Week_02/G20200343030507/507-Week 02/LeetCode_49_507.py b/Week_02/G20200343030507/507-Week 02/LeetCode_49_507.py new file mode 100644 index 00000000..951ba2fd --- /dev/null +++ b/Week_02/G20200343030507/507-Week 02/LeetCode_49_507.py @@ -0,0 +1,7 @@ +class Solution: + def groupAnagrams(self, strs: List[str]) -> List[List[str]]: + d = {} + for w in sorted(strs): + key = tuple(sorted(w)) + d[key] = d.get(key, []) + [w] + return d.values() \ No newline at end of file diff --git a/Week_02/G20200343030507/507-Week 02/LeetCode_77_507.py b/Week_02/G20200343030507/507-Week 02/LeetCode_77_507.py new file mode 100644 index 00000000..b924cc74 --- /dev/null +++ b/Week_02/G20200343030507/507-Week 02/LeetCode_77_507.py @@ -0,0 +1,26 @@ +from typing import List + + +class Solution: + def combine(self, n: int, k: int) -> List[List[int]]: + # 先把不符合条件的情况去掉 + if n <= 0 or k <= 0 or k > n: + return [] + res = [] + self.__dfs(1, k, n, [], res) + return res + + def __dfs(self, start, k, n, pre, res): + # 当前已经找到的组合存储在 pre 中,需要从 start 开始搜索新的元素 + # 在第 k 层结算 + if len(pre) == k: + res.append(pre[:]) + return + + for i in range(start, n + 1): + pre.append(i) + # 因为已经把 i 加入到 pre 中,下一轮就从 i + 1 开始 + # 注意和全排列问题的区别,因为按顺序选择,因此无须使用 used 数组 + self.__dfs(i + 1, k, n, pre, res) + # 回溯的时候,状态重置 + pre.pop() diff --git a/Week_02/G20200343030509/046_509.java b/Week_02/G20200343030509/046_509.java new file mode 100644 index 00000000..4e68bf70 --- /dev/null +++ b/Week_02/G20200343030509/046_509.java @@ -0,0 +1,38 @@ +/* + * @lc app=leetcode.cn id=46 lang=java + * + * [46] 全排列 + */ + +class Solution { + public List> permute(int[] nums) { + List> list = new ArrayList<>(); + + backtrack(list, new ArrayList<>(), new HashSet<>(), nums); + + return list; + } + + private void backtrack(List> list, List tempList, Set tempSet, int[] nums) { + if(tempSet.size() == nums.length) { + list.add( new ArrayList<>(tempList)); + } + + for (int i=0; i < nums.length; i++ ) { + if (tempSet.contains(nums[i])) continue; + + tempList.add(nums[i]); + tempSet.add(nums[i]); + + backtrack(list, tempList, tempSet, nums); + + tempSet.remove(tempList.get(tempList.size() -1)); + tempList.remove(tempList.size() - 1); + } + } + + public static void main(String[] args) { + Solution sol = new Solution(); + System.out.println(sol.permute("")); + } +} \ No newline at end of file diff --git a/Week_02/G20200343030509/049_509.java b/Week_02/G20200343030509/049_509.java new file mode 100644 index 00000000..ce61bf79 --- /dev/null +++ b/Week_02/G20200343030509/049_509.java @@ -0,0 +1,31 @@ +/* + * @lc app=leetcode.cn id=49 lang=java + * + * [49] 字母异位词分组 + */ + +class Solution { + public List> groupAnagrams(String[] strs) { + if (strs == null || strs.length == 0) { + return new ArrayList>(); + } + + HashMap> map = new HashMap>(); + for (String str : strs) { + char[] charArray = str.toCharArray(); + Arrays.sort(charArray); + String key = String.valueOf(charArray); + if (!map.containsKey(key)) { + map.put(key, new ArrayList()); + } + map.get(key).add(str); + } + return new ArrayList>(map.values()); + } + + public static void main(String[] args) { + Solution sol = new Solution(); + System.out.println(sol.groupAnagrams(new String[]{"eat","tea","tan","ate","nat","bat"})); + } +} + diff --git a/Week_02/G20200343030509/105_509.java b/Week_02/G20200343030509/105_509.java new file mode 100644 index 00000000..caab0994 --- /dev/null +++ b/Week_02/G20200343030509/105_509.java @@ -0,0 +1,46 @@ +import java.util.HashMap; +import java.util.Map; + +/* + * @lc app=leetcode.cn id=105 lang=java + * + * [105] 从前序与中序遍历序列构造二叉树 + */ + +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; } + * } + */ +class Solution { + public TreeNode buildTree(int[] preorder, int[] inorder) { + Map inMap = new HashMap<>(); + + for (int i = 0; i < inorder.length; i++) { + inMap.put(inorder[i], i); + } + + return makeTreeNode(preorder, 0, preorder.length -1 , inorder, 0, inorder.length -1, inMap); + } + + public TreeNode makeTreeNode(int[] preorder, int preStart, int preEnd, int[] inorder, int inStart, int inEnd, Map inMap) { + // terminator + if (preStart > preEnd || inStart > inEnd) return null; + + // process current process + TreeNode root = new TreeNode(preorder[preStart]); + int inRoot = inMap.get(root.val); + int moveLeft = inRoot - inStart; + + // drill down + root.left = makeTreeNode( preorder, preStart + 1, preStart + moveLeft, inorder, inStart, inRoot -1, inMap); + root.right = makeTreeNode( preorder, preStart + moveLeft + 1, preEnd, inorder, inRoot + 1, inEnd, inMap); + + return root; + } +} + diff --git a/Week_02/G20200343030509/144_509.java b/Week_02/G20200343030509/144_509.java new file mode 100644 index 00000000..5e0f5340 --- /dev/null +++ b/Week_02/G20200343030509/144_509.java @@ -0,0 +1,55 @@ +/* + * @lc app=leetcode.cn id=144 lang=java + * + * [144] 二叉树的前序遍历 + */ + +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; } + * } + */ +class Solution { + // 递归 + public List preorderTraversal(TreeNode root) { + List list = new ArrayList<>(); + preorder( root, list); + return list; + } + + private void preorder(TreeNode root, List list) { + if (root == null) return; + list.add(root.val); + if (root.left != null) preorder(root.left, list); + if (root.right != null) preorder(root.right, list); + } + + // 迭代 + public List preorderTraversal1(TreeNode root) { + List list = new ArrayList<>(); + + if (root == null) return list; + + Stack stack = new Stack<>(); + stack.add(root); + + while (!stack.isEmpty()) { + TreeNode node = stack.pop(); + list.add(node.val); + if (node.right != null) stack.add(node.right); + if (node.left != null) stack.add(node.left); + } + + return list; + } + + public static void main(String[] args) { + Solution sol = new Solution(); + System.out.println(sol.preorderTraversal("")); + } +} + diff --git a/Week_02/G20200343030509/589_509.java b/Week_02/G20200343030509/589_509.java new file mode 100644 index 00000000..4ca610c3 --- /dev/null +++ b/Week_02/G20200343030509/589_509.java @@ -0,0 +1,65 @@ +/* + * @lc app=leetcode.cn id=589 lang=java + * + * [589] N叉树的前序遍历 + */ + +/* +// Definition for a Node. +class Node { + public int val; + public List children; + + public Node() {} + + public Node(int _val) { + val = _val; + } + + public Node(int _val, List _children) { + val = _val; + children = _children; + } +}; +*/ +class Solution { + List list = new ArrayList<>(); + + public List preorder(Node root) { + if (root == null) return list; + + list.add(root.val); + + for (Node child: root.children) { + preorder(child); + } + + return list; + } + + public List preorder2(Node root) { + List list = new ArrayList<>(); + + if (root == null) return list; + + Stack stack = new Stack<>(); + stack.push(root); + + while (!stack.isEmpty()) { + Node node = stack.pop(); + list.add(node.val); + List nodeList = node.children; + for (int i = nodeList.size() -1; i >=0; i-- ) { + stack.push(nodeList.get(i)); + } + } + + return list; + } + + public static void main(String[] args) { + Solution sol = new Solution(); + System.out.println(sol.preorder("")); + } +} + diff --git a/Week_02/G20200343030509/590_509.java b/Week_02/G20200343030509/590_509.java new file mode 100644 index 00000000..e2870d4f --- /dev/null +++ b/Week_02/G20200343030509/590_509.java @@ -0,0 +1,78 @@ +import java.util.LinkedList; +import java.util.Stack; + +import com.sun.corba.se.impl.orbutil.graph.Node; + +/* + * @lc app=leetcode.cn id=590 lang=java + * + * [590] N叉树的后序遍历 + */ + +/* +// Definition for a Node. +class Node { + public int val; + public List children; + + public Node() {} + + public Node(int _val) { + val = _val; + } + + public Node(int _val, List _children) { + val = _val; + children = _children; + } +}; +*/ +class Solution { + // 递归 + List list = new ArrayList<>(); + public List postorder (Node root) { + // terminator + if(root == null) { + return list; + } + + // drill down + for( Node node: root.children) { + postorder(node); + } + + // process current logic + list.add(root.val); + + return list; + } + + //迭代 + public List postorder2 (Node root) { + LinkedList l = new LinkedList<>(); + + if (root == null) return l; + + Stack stack = new Stack<>(); + stack.push(root); + + while (!stack.isEmpty()) { + Node node = stack.pop(); + l.addFirst(node.val); + for (Node child : node.children) { + stack.push(child); + } + } + + return l; + } + + + + + public static void main(String[] args) { + Solution sol = new Solution(); + System.out.println(sol.postorder("")); + } +} + diff --git a/Week_02/G20200343030511/LeetCode_105_511.java b/Week_02/G20200343030511/LeetCode_105_511.java new file mode 100644 index 00000000..2cae5feb --- /dev/null +++ b/Week_02/G20200343030511/LeetCode_105_511.java @@ -0,0 +1,37 @@ +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; } + * } + */ +class Solution { + public TreeNode buildTree(int[] preorder, int[] inorder) { + if (preorder == null || inorder == null || preorder.length != inorder.length) + return null; + return help(preorder, 0, preorder.length, inorder, 0, inorder.length); + } + + private TreeNode help(int[] preorder, int pre_start, int pre_end, int[] inorder, int in_start, int in_end) { + // ֹ + if (pre_start == pre_end) + return null; + // ǰ + TreeNode node = new TreeNode(preorder[pre_start]); + int index; + for (index = in_start; index <= in_end; index++) + if (preorder[pre_start] == inorder[index]) + break; + + + // 仰 + int leftNum = index - in_start; + // ݹ + node.left = help(preorder, pre_start + 1, pre_start+leftNum+1, inorder, in_start, index); + node.right = help(preorder, pre_start + leftNum + 1, pre_end, inorder, index + 1, in_end); + // ״̬ + return node; + } +} diff --git a/Week_02/G20200343030511/LeetCode_144_511.java b/Week_02/G20200343030511/LeetCode_144_511.java new file mode 100644 index 00000000..ab30adf2 --- /dev/null +++ b/Week_02/G20200343030511/LeetCode_144_511.java @@ -0,0 +1,38 @@ +class Solution { + // ǰݹ + public List preorderTraversal(TreeNode root) { + List list = new ArrayList(); + if (root == null) + return list; + preorderTraversal_h(root, list); + return list; + } + + private void preorderTraversal_h(TreeNode node, List list) { + if (node == null) + return; + list.add(node.val); + preorderTraversal_h(node.left, list); + preorderTraversal_h(node.right, list); + } + + // ǰstack + public List preorderTraversal1(TreeNode root) { + List list = new ArrayList(); + if (root == null) + return list; + TreeNode node = root; + Stack stack = new Stack(); + while (node != null || !stack.isEmpty()) { + while (node != null) { + list.add(node.val); + if (node.right != null) + stack.push(node.right); + node = node.left; + } + if (!stack.isEmpty()) + node = stack.pop(); + } + return list; + } +} \ No newline at end of file diff --git a/Week_02/G20200343030511/LeetCode_145_511.java b/Week_02/G20200343030511/LeetCode_145_511.java new file mode 100644 index 00000000..65ca49b8 --- /dev/null +++ b/Week_02/G20200343030511/LeetCode_145_511.java @@ -0,0 +1,52 @@ +class Solution { + //,ʵϾDz,ÿһͺ + public List postorderTraversal(TreeNode root) { + //ʱջ룬ʱlist + LinkedList list = new LinkedList<>(); + if(root==null) return list; + Stack stack = new Stack<>(); + stack.push(root); + while(!stack.isEmpty()){ + root =stack.pop(); + list.addFirst(root.val); + if(root.left!=null) stack.push(root.left); + if(root.right!=null) stack.push(root.right); + } + return list; + } + + // + + public List postorderTraversal2(TreeNode root) { + List list = new ArrayList<>(); + Stack stack = new Stack<>(); + TreeNode cur = root; + TreeNode last = null; + while (cur != null || !stack.isEmpty()) { + if (cur != null) { + stack.push(cur); + cur = cur.left; + } else { + TreeNode temp = stack.peek(); + //Ϊգ temp.right != last(˵,ڵ㲻Ǵ.) + //Ҫ䵽. + if (temp.right != null && temp.right != last) { + cur = temp.right; + } else { + /*ڵ϶ΪգΪգ˵Ҷӽڵ㣬 + * ϴηʵĽڵ㣬˵ѾǸҪˡ + * */ + list.add(temp.val); + last = temp; + /*Ϊʲôֻ¶lastиֵأ + * Ϊǰڵ϶ûֻ + * һαڵͿ϶Ҷӽڵ㡣 + * ӡʵûá + * ҺӣζҺӺ󣬻Ҫص׽ڵ㡣 +*/ stack.pop(); + } + } + } + return list; + } +} \ No newline at end of file diff --git a/Week_02/G20200343030511/LeetCode_236_511.java b/Week_02/G20200343030511/LeetCode_236_511.java new file mode 100644 index 00000000..9ab5e89f --- /dev/null +++ b/Week_02/G20200343030511/LeetCode_236_511.java @@ -0,0 +1,70 @@ +class Solution { + // ҵPȣҵqȣPqһ + public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { + + if (root == null || p == null || q == null) + return null; + + ArrayList pList = new ArrayList<>(); + boolean pfound =search(root, p,pList); + ArrayList qList = new ArrayList<>(); + boolean qfound =search(root, q,qList); + + if (!pfound && !qfound) { + return null; + } + + // ҵڵһͬĽڵ + int psize = pList.size() - 1; + int qsize = qList.size() - 1; + for (int i = psize; i >= 0; i--) { + for (int j = qsize; j >= 0; j--) { + if (pList.get(i).val == qList.get(j).val) { + return pList.get(i); + } + } + } + return null; + } + + private boolean search(TreeNode root, TreeNode node, ArrayList list) { + // ݹֹ + if (root.val == node.val){ + list.add(root); + return true; + } + // ǰ + list.add(root); + boolean found =false; + // ݹ + if(root.left!=null) found=search(root.left, node, list); + if(!found&&root.right!=null) found=search(root.right, node, list); + // ״̬ + if(!found) list.remove(list.size()-1); + return found; + } + + //򻯰 + public TreeNode lowestCommonAncestor1(TreeNode root, TreeNode p, TreeNode q) { + if (root == null || p == null || q == null) + return null; + return help(root, p, q); + } + + private TreeNode help(TreeNode root, TreeNode p, TreeNode q) { + // ֹ + if (root == null || root == q || root == p) + return root; + // ǰ + // ݹ + TreeNode l = help(root.left, p, q); + if (l != null && l != p && l != q) + return l; + TreeNode r = help(root.right, p, q); + if (l != null && r != null) + return root; + else { + return l == null ? r : l; + } + } +} \ No newline at end of file diff --git a/Week_02/G20200343030511/LeetCode_242_511.java b/Week_02/G20200343030511/LeetCode_242_511.java new file mode 100644 index 00000000..2f6fdfa1 --- /dev/null +++ b/Week_02/G20200343030511/LeetCode_242_511.java @@ -0,0 +1,27 @@ +public class IsAnagram { + + //⡣ĸλ һͬ + public boolean isAnagram(String s, String t) { + if(s.length()!=t.length()) return false; + char[] ss = s.toCharArray(); + char[] tt =t.toCharArray(); + Arrays.sort(ss); + Arrays.sort(tt); + return Arrays.equals(ss, tt); + } + + + public boolean isAnagram1(String s, String t) { + if(s.length()!=t.length()) return false; + char[] ss = s.toCharArray(); + char[] tt = t.toCharArray(); + int[] array = new int[26]; + for (int i = 0; i < ss.length; i++) { + array[ss[i]-'a']++; + array[tt[i]-'a']--; + } + for (int i = 0; i < array.length; i++) { + if(array[i]!=0) return false; + } + return true; + } \ No newline at end of file diff --git a/Week_02/G20200343030511/LeetCode_429_511.java b/Week_02/G20200343030511/LeetCode_429_511.java new file mode 100644 index 00000000..c563eae6 --- /dev/null +++ b/Week_02/G20200343030511/LeetCode_429_511.java @@ -0,0 +1,60 @@ +class Solution { + public List> levelOrder(Node root) { + List> list = new ArrayList<>(); + if (root == null) + return list; + LinkedList queue = new LinkedList<>(); + queue.add(root); + while(!queue.isEmpty()){ + List per = new ArrayList(); + //这里通过固定的size判断层级 + int size =queue.size(); + for (int i = 0; i < size ; i++) { + Node tmp = queue.poll(); + per.add(tmp.val); + queue.addAll(tmp.children); + } + list.add(per); + } + return list; + } + + + + public List> levelOrder1(Node root) { + List> list = new ArrayList<>(); + if (root == null) + return list; + List pre = Arrays.asList(root); + while(pre!=null&&pre.size()!=0){ + List level = new ArrayList<>(); + List current =new ArrayList<>(); + for (Node tmp:pre) { + level.add(tmp.val); + current.addAll(tmp.children); + } + list.add(level); + pre = current; + } + return list; + } + + //递归 + public List> levelOrder3(Node root) { + List> list = new ArrayList<>(); + if (root == null) + return list; + traverseNode(root, 0,list); + return list; + } + + private void traverseNode(Node node, int level,List> result) { + if (result.size() <= level) { + result.add(new ArrayList<>()); + } + result.get(level).add(node.val); + for (Node child : node.children) { + traverseNode(child, level + 1,result); + } + } +} \ No newline at end of file diff --git a/Week_02/G20200343030511/LeetCode_46_511.java b/Week_02/G20200343030511/LeetCode_46_511.java new file mode 100644 index 00000000..d1c14480 --- /dev/null +++ b/Week_02/G20200343030511/LeetCode_46_511.java @@ -0,0 +1,24 @@ +class Solution { + List> result = new ArrayList<>(); + public List> permute(int[] nums) { + if(nums.length==0||nums ==null) return result; + List list = new ArrayList<>(); + help(nums,list); + return result; + } + private void help(int[] nums, List list) { + //жϷ,ʾеѡѾѡ + if(nums.length==list.size()){ + result.add(new ArrayList(list)); + return; + } + for (int i = 0; i < nums.length; i++) { + //ʾѾѡˡΪظ + if(list.contains(nums[i])) continue; + list.add(nums[i]); + help(nums,list); + //ѡ + list.remove(list.size()-1); + } + } +} \ No newline at end of file diff --git a/Week_02/G20200343030511/LeetCode_47_511.java b/Week_02/G20200343030511/LeetCode_47_511.java new file mode 100644 index 00000000..a8563f2b --- /dev/null +++ b/Week_02/G20200343030511/LeetCode_47_511.java @@ -0,0 +1,32 @@ +class Solution { + List> result = new ArrayList<>(); + + public List> permuteUnique(int[] nums) { + if (nums.length == 0 || nums == null) + return result; + List list = new ArrayList<>(); + boolean[] visited = new boolean[nums.length]; + Arrays.sort(nums); + help(nums, list,visited); + return result; + } + + private void help(int[] nums, List list,boolean[] visited) { + // жϷ,ʾеѡѾѡ,һµlist + if (nums.length == list.size()) { + result.add(new ArrayList<>(list)); + return; + } + for (int i = 0; i < nums.length; i++) { + //ȥϵ + if(i>0&&nums[i]==nums[i-1]&&!visited[i-1]) continue; + if(visited[i]) continue; + list.add(nums[i]); + visited[i]=true; + help(nums, list,visited); + // ѡ + list.remove(list.size() - 1); + visited[i]=false; + } + } +} \ No newline at end of file diff --git a/Week_02/G20200343030511/LeetCode_49_511.java b/Week_02/G20200343030511/LeetCode_49_511.java new file mode 100644 index 00000000..3dbf9d32 --- /dev/null +++ b/Week_02/G20200343030511/LeetCode_49_511.java @@ -0,0 +1,46 @@ +class Solution { + public List> groupAnagrams(String[] strs) { + Map> map = new HashMap(); + for (int i = 0; i < strs.length; i++) { + char[] temp =strs[i].toCharArray(); + Arrays.sort(temp); + String key = new String(temp); + if(!map.containsKey(key)){ + List l = new ArrayList<>(); + l.add(strs[i]); + map.put(key, l); + }else{ + map.get(key).add(strs[i]); + } + } + return new ArrayList(map.values()); + } + + + //ʱ O(NK) ռO(NK) + public List> groupAnagrams1(String[] strs) { + Map> map = new HashMap(); + int[] count =new int[26]; + for (int i = 0; i < strs.length; i++) { + char[] temp = strs[i].toCharArray(); + Arrays.fill(count, 0); + for (int j = 0; j < temp.length; j++) { + count[temp[j]-'a']++; + } + StringBuilder sb = new StringBuilder(); + for (int j = 0; j < count.length; j++) { + sb.append("#"); + sb.append(count[j]); + } + String key = sb.toString(); + if(!map.containsKey(key)){ + List l = new ArrayList(); + l.add(strs[i]); + map.put(key, l); + }else{ + map.get(key).add(strs[i]); + } + } + return new ArrayList(map.values()); + } +} \ No newline at end of file diff --git a/Week_02/G20200343030511/LeetCode_589_511.java b/Week_02/G20200343030511/LeetCode_589_511.java new file mode 100644 index 00000000..9425d145 --- /dev/null +++ b/Week_02/G20200343030511/LeetCode_589_511.java @@ -0,0 +1,32 @@ +class Solution { + public List preorder(Node root) { + List list = new ArrayList(); + if(root ==null) return list; + preorder_h(root,list); + return list; + } + + private void preorder_h(Node node, List list) { + if(node ==null) return; + list.add(node.val); + for(Node tmp:node.children){ + preorder_h(tmp,list); + } + } + //迭代 + public List preorder1(Node root) { + Stack stack = new Stack<>(); + List list = new ArrayList<>(); + if (root == null) { + return list; + } + stack.push(root); + while(!stack.empty()){ + Node node =stack.pop(); + list.add(node.val); + Collections.reverse(node.children); + for(Node temp:node.children) stack.push(temp); + } + return list; + } +} \ No newline at end of file diff --git a/Week_02/G20200343030511/LeetCode_590_511.java b/Week_02/G20200343030511/LeetCode_590_511.java new file mode 100644 index 00000000..5efb9bf8 --- /dev/null +++ b/Week_02/G20200343030511/LeetCode_590_511.java @@ -0,0 +1,38 @@ +class Solution { + public List postorder(Node root) { + List list = new ArrayList(); + if (root == null) + return list; + postorder_h(root, list); + return list; + } + + private void postorder_h(Node node, List list) { + if (node == null) + return; + for (Node tmp : node.children) { + postorder_h(tmp, list); + } + list.add(node.val); + } + + public List postorder1(Node root) { + Stack stack = new Stack<>(); + LinkedList output = new LinkedList<>(); + if (root == null) { + return output; + } + + stack.add(root); + while (!stack.isEmpty()) { + Node node = stack.pop(); + output.addFirst(node.val); + for (Node item : node.children) { + if (item != null) { + stack.add(item); + } + } + } + return output; + } +} \ No newline at end of file diff --git a/Week_02/G20200343030511/LeetCode_77_511.java b/Week_02/G20200343030511/LeetCode_77_511.java new file mode 100644 index 00000000..a15294fe --- /dev/null +++ b/Week_02/G20200343030511/LeetCode_77_511.java @@ -0,0 +1,23 @@ +class Solution { + List> result = new ArrayList<>(); + public List> combine(int n, int k) { + if(n==0||k==0) return result; + List list = new ArrayList<>(); + help(n,k,list); + return result; + } + + private void help(int n, int k, List list) { + //ֹ + if(k==list.size()) { + result.add(new ArrayList(list)); + return; + } + for (int i = 1; i <= n; i++) { + if(list.contains(i)) continue; + list.add(i); + help(i,k,list); + list.remove(list.size()-1); + } + } +} \ No newline at end of file diff --git a/Week_02/G20200343030511/LeetCode_94_511.java b/Week_02/G20200343030511/LeetCode_94_511.java new file mode 100644 index 00000000..3dbf9d32 --- /dev/null +++ b/Week_02/G20200343030511/LeetCode_94_511.java @@ -0,0 +1,46 @@ +class Solution { + public List> groupAnagrams(String[] strs) { + Map> map = new HashMap(); + for (int i = 0; i < strs.length; i++) { + char[] temp =strs[i].toCharArray(); + Arrays.sort(temp); + String key = new String(temp); + if(!map.containsKey(key)){ + List l = new ArrayList<>(); + l.add(strs[i]); + map.put(key, l); + }else{ + map.get(key).add(strs[i]); + } + } + return new ArrayList(map.values()); + } + + + //ʱ O(NK) ռO(NK) + public List> groupAnagrams1(String[] strs) { + Map> map = new HashMap(); + int[] count =new int[26]; + for (int i = 0; i < strs.length; i++) { + char[] temp = strs[i].toCharArray(); + Arrays.fill(count, 0); + for (int j = 0; j < temp.length; j++) { + count[temp[j]-'a']++; + } + StringBuilder sb = new StringBuilder(); + for (int j = 0; j < count.length; j++) { + sb.append("#"); + sb.append(count[j]); + } + String key = sb.toString(); + if(!map.containsKey(key)){ + List l = new ArrayList(); + l.add(strs[i]); + map.put(key, l); + }else{ + map.get(key).add(strs[i]); + } + } + return new ArrayList(map.values()); + } +} \ No newline at end of file diff --git a/Week_02/G20200343030513/LeetCode_144_513.java b/Week_02/G20200343030513/LeetCode_144_513.java new file mode 100644 index 00000000..7d345a2e --- /dev/null +++ b/Week_02/G20200343030513/LeetCode_144_513.java @@ -0,0 +1,51 @@ +//给定一个二叉树,返回它的 前序 遍历。 +// +// 示例: +// +// 输入: [1,null,2,3] +// 1 +// \ +// 2 +// / +// 3 +// +//输出: [1,2,3] +// +// +// 进阶: 递归算法很简单,你可以通过迭代算法完成吗? +// Related Topics 栈 树 + + +//leetcode submit region begin(Prohibit modification and deletion) + +import java.util.LinkedList; + +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; } + * } + */ +class Solution { + public List preorderTraversal(TreeNode root) { + LinkedList stack = new LinkedList(); + LinkedList res = new LinkedList<>(); + if ( root == null) return res; + stack.add(root); + while (!stack.isEmpty()) { + TreeNode node = stack.pollLast(); + res.add(node.val); + if (node.right != null) { + stack.add(node.right); + } + if (node.left != null) { + stack.add(node.left); + } + } + return res; + } +} +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week_02/G20200343030513/LeetCode_49_513.java b/Week_02/G20200343030513/LeetCode_49_513.java new file mode 100644 index 00000000..149c3de5 --- /dev/null +++ b/Week_02/G20200343030513/LeetCode_49_513.java @@ -0,0 +1,43 @@ +//给定一个字符串数组,将字母异位词组合在一起。字母异位词指字母相同,但排列不同的字符串。 +// +// 示例: +// +// 输入: ["eat", "tea", "tan", "ate", "nat", "bat"], +//输出: +//[ +// ["ate","eat","tea"], +// ["nat","tan"], +// ["bat"] +//] +// +// 说明: +// +// +// 所有输入均为小写字母。 +// 不考虑答案输出的顺序。 +// +// Related Topics 哈希表 字符串 + + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; + +//leetcode submit region begin(Prohibit modification and deletion) +class Solution { + public List> groupAnagrams(String[] strs) { + //map + if (strs.length == 0) return new ArrayList(); + HashMap resMap = new HashMap<>(); + for (String str: strs) { + char[] chars = str.toCharArray(); + Arrays.sort(chars); + String key = String.valueOf(chars); + if (!resMap.containsKey(key)) resMap.put(key, new ArrayList()); + resMap.get(key).add(str); + } + return new ArrayList(resMap.values()); + } +} +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week_02/G20200343030513/LeetCode_589_513.java b/Week_02/G20200343030513/LeetCode_589_513.java new file mode 100644 index 00000000..1d22bdb9 --- /dev/null +++ b/Week_02/G20200343030513/LeetCode_589_513.java @@ -0,0 +1,54 @@ +//给定一个 N 叉树,返回其节点值的前序遍历。 +// +// 例如,给定一个 3叉树 : +// +// +// +// +// +// +// +// 返回其前序遍历: [1,3,5,6,2,4]。 +// +// +// +// 说明: 递归法很简单,你可以使用迭代法完成此题吗? Related Topics 树 + + +import java.util.ArrayList; + +//leetcode submit region begin(Prohibit modification and deletion) +/* +// Definition for a Node. +class Node { + public int val; + public List children; + + public Node() {} + + public Node(int _val) { + val = _val; + } + + public Node(int _val, List _children) { + val = _val; + children = _children; + } +}; +*/ +class Solution { + List res = new ArrayList<>(); + public List preorder(Node root) { + traversal(root); + return res; + } + private void traversal (Node root) { + if (root == null) return; + res.add(root.val); + for (int i = 0; i < root.children.size(); i++) { + traversal(root.children.get(i)); + } + + } +} +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week_02/G20200343030513/LeetCode_590_513.java b/Week_02/G20200343030513/LeetCode_590_513.java new file mode 100644 index 00000000..b38c78f3 --- /dev/null +++ b/Week_02/G20200343030513/LeetCode_590_513.java @@ -0,0 +1,55 @@ +//给定一个 N 叉树,返回其节点值的后序遍历。 +// +// 例如,给定一个 3叉树 : +// +// +// +// +// +// +// +// 返回其后序遍历: [5,6,3,2,4,1]. +// +// +// +// 说明: 递归法很简单,你可以使用迭代法完成此题吗? Related Topics 树 + + +import java.util.ArrayList; + +//leetcode submit region begin(Prohibit modification and deletion) +/* +// Definition for a Node. +class Node { + public int val; + public List children; + + public Node() {} + + public Node(int _val) { + val = _val; + } + + public Node(int _val, List _children) { + val = _val; + children = _children; + } +}; +*/ +class Solution { + public List postorder(Node root) { + List res = new ArrayList<>(); + if (root == null) return res; + traversal(root, res); + return res; + } + + private void traversal (Node root, List res) { + if (root == null) return; + for (Node node: root.children) { + traversal(node, res); + } + res.add(root.val); + } +} +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week_02/G20200343030519/Week 02/LeetCode_105_519.js b/Week_02/G20200343030519/Week 02/LeetCode_105_519.js new file mode 100644 index 00000000..fd90fa98 --- /dev/null +++ b/Week_02/G20200343030519/Week 02/LeetCode_105_519.js @@ -0,0 +1,26 @@ +// https://leetcode-cn.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/ + +var buildTree = function(preOrder, inOrder) { + + if(inOrder.length == 0 && preOrder.length == 0) { + return null; + }; + + let root = {}; + root.val = preOrder[0]; + + let rootIdxInOrder = inOrder.indexOf(root.val); + + let leftTreeInOrder = inOrder.slice(0, rootIdxInOrder); + let leftTreePreOrder = preOrder.slice(1, leftTreeInOrder.length + 1); + + root.left = buildTree(leftTreePreOrder, leftTreeInOrder); + + + let rightTreeInOrder = inOrder.slice(rootIdxInOrder + 1); + let rightTreePreOrder = preOrder.slice(rootIdxInOrder + 1); + + root.right = buildTree(rightTreePreOrder, rightTreeInOrder); + + return root; +}; \ No newline at end of file diff --git a/Week_02/G20200343030519/Week 02/LeetCode_144_519.js b/Week_02/G20200343030519/Week 02/LeetCode_144_519.js new file mode 100644 index 00000000..92283f50 --- /dev/null +++ b/Week_02/G20200343030519/Week 02/LeetCode_144_519.js @@ -0,0 +1,18 @@ +// https://leetcode-cn.com/problems/binary-tree-preorder-traversal/ + +var preorderTraversal = function(root) { + var result = []; + function pushRoot(node) { + if (node != null) { + result.push(node.val); + if (node.left != null) { + pushRoot(node.left); + } + if (node.right != null) { + pushRoot(node.right); + } + } + } + pushRoot(root); + return result; +}; \ No newline at end of file diff --git a/Week_02/G20200343030519/Week 02/LeetCode_1_519.js b/Week_02/G20200343030519/Week 02/LeetCode_1_519.js new file mode 100644 index 00000000..360fb9ae --- /dev/null +++ b/Week_02/G20200343030519/Week 02/LeetCode_1_519.js @@ -0,0 +1,19 @@ +// https://leetcode-cn.com/problems/two-sum/ + +var twoSum = function(nums, target) { + var result = new Map(); + var len = nums.length; + var diff = 0; + var out = []; + for(var i=0;i { + if (tmpPath.length == n) { + res.push(tmpPath); + return; + } + for (let i = 0; i < n; i++) { + if (!tmpPath.includes(nums[i])) { + tmpPath.push(nums[i]); + backtrack(tmpPath.slice()); + tmpPath.pop(); + } + } + } + backtrack(tmpPath); + return res; +}; \ No newline at end of file diff --git a/Week_02/G20200343030519/Week 02/LeetCode_47_519.js b/Week_02/G20200343030519/Week 02/LeetCode_47_519.js new file mode 100644 index 00000000..665e7477 --- /dev/null +++ b/Week_02/G20200343030519/Week 02/LeetCode_47_519.js @@ -0,0 +1,25 @@ +// https://leetcode-cn.com/problems/permutations-ii/ + +var permuteUnique = function(nums) { + let n = nums.length; + nums = nums.sort((a,b) => {return a - b}); + let res = []; + let tmpPath = []; + let hash = {}; + let backtrack = (tmpPath) => { + if(tmpPath.length == n){ + res.push(tmpPath); + return; + } + for(let i = 0;i < n;i++){ + if(hash[i] || (i > 0 && !hash[i-1] && nums[i-1] == nums[i])) continue; + hash[i] = true; + tmpPath.push(nums[i]); + backtrack(tmpPath.slice()); + hash[i] = false; + tmpPath.pop(); + } + } + backtrack(tmpPath); + return res; +}; \ No newline at end of file diff --git a/Week_02/G20200343030519/Week 02/LeetCode_49_519.js b/Week_02/G20200343030519/Week 02/LeetCode_49_519.js new file mode 100644 index 00000000..dd958176 --- /dev/null +++ b/Week_02/G20200343030519/Week 02/LeetCode_49_519.js @@ -0,0 +1,16 @@ +// https://leetcode-cn.com/problems/group-anagrams/ + +var groupAnagrams = function(strs) { + let hash = new Map(); + for (let i = 0; i < strs.length; i++) { + let str = strs[i].split('').sort().join(); + if (hash.has(str)) { + let temp = hash.get(str); + temp.push(strs[i]); + hash.set(str, temp) + } else { + hash.set(str, [strs[i]]); + } + } + return [...hash.values()] +}; \ No newline at end of file diff --git a/Week_02/G20200343030519/Week 02/LeetCode_589_519.js b/Week_02/G20200343030519/Week 02/LeetCode_589_519.js new file mode 100644 index 00000000..cc1c4db8 --- /dev/null +++ b/Week_02/G20200343030519/Week 02/LeetCode_589_519.js @@ -0,0 +1,18 @@ +// https://leetcode-cn.com/problems/n-ary-tree-preorder-traversal/ + +var preorder = function(root) { + if (!root) return []; + + var res = []; + recusion(root); + return res; + + function recusion(root) { + if (!root) return; + + res.push(root.val); + for (var i = 0; i < root.children.length; i++) { + recusion(root.children[i]); + } + } +}; \ No newline at end of file diff --git a/Week_02/G20200343030519/Week 02/LeetCode_590_519.js b/Week_02/G20200343030519/Week 02/LeetCode_590_519.js new file mode 100644 index 00000000..718c6fe3 --- /dev/null +++ b/Week_02/G20200343030519/Week 02/LeetCode_590_519.js @@ -0,0 +1,18 @@ +// https://leetcode-cn.com/problems/n-ary-tree-postorder-traversal/ + +var postorder = function(root) { + if (!root) return []; + + var res = []; + recusion(root); + return res; + + function recusion(root){ + if (!root) return; + + for (var i = 0; i < root.children.length; i++){ + recusion(root.children[i]); + } + res.push(root.val) + } +}; \ No newline at end of file diff --git a/Week_02/G20200343030519/Week 02/LeetCode_77_519.js b/Week_02/G20200343030519/Week 02/LeetCode_77_519.js new file mode 100644 index 00000000..b4dd6fbd --- /dev/null +++ b/Week_02/G20200343030519/Week 02/LeetCode_77_519.js @@ -0,0 +1,19 @@ +// https://leetcode-cn.com/problems/combinations/ + +var combine = function(n, k) { + var result = []; + var subresult = []; + if (n == k || k == 0) { + var tmp = []; + for (var i = 1; i <= k; i++) { + subresult.push(i); + } + tmp.push(subresult); + return tmp; + } + var result = combine(n-1, k-1); + result.map((arr) => arr.push(n)); + var tmp = combine(n-1, k); + tmp.map((arr) => result.push(arr)); + return result; +}; \ No newline at end of file diff --git a/Week_02/G20200343030519/Week 02/LeetCode_94_519.js b/Week_02/G20200343030519/Week 02/LeetCode_94_519.js new file mode 100644 index 00000000..8900a270 --- /dev/null +++ b/Week_02/G20200343030519/Week 02/LeetCode_94_519.js @@ -0,0 +1,18 @@ +// https://leetcode-cn.com/problems/binary-tree-inorder-traversal/ + +var inorderTraversal = function(root) { + var result = []; + function pushRoot(root){ + if(root != null){ + if(root.left != null){ + pushRoot(root.left); + } + result.push(root.val); + if(root.right !=null){ + pushRoot(root.right); + } + } + } + pushRoot(root); + return result; +}; \ No newline at end of file diff --git a/Week_02/G20200343030523/id_523/LeetCode_105_523.java b/Week_02/G20200343030523/id_523/LeetCode_105_523.java new file mode 100644 index 00000000..db3f8a4a --- /dev/null +++ b/Week_02/G20200343030523/id_523/LeetCode_105_523.java @@ -0,0 +1,49 @@ +package tree; + +public class ConstructBinaryTreeFromPreorderAndInorderTraversal01 { + + public TreeNode buildTree(int[] preorder, int[] inorder) { + return buildTreeHeler(preorder, 0, preorder.length, inorder, 0, inorder.length); + } + + private TreeNode buildTreeHeler(int[] preorder, int pStart, int pEnd, + int[] inorder, int iStart, int iEnd) { + if (pStart >= pEnd) { + return null; + } + + if (iStart >= iEnd) { + return null; + } + + int value = preorder[pStart]; + int index = find(inorder, iStart, iEnd, value); + + int leftIndex = index - iStart; + + TreeNode node = new TreeNode(value); + node.left = buildTreeHeler(preorder, pStart + 1, pStart + leftIndex + 1, inorder, iStart, index); + node.right = buildTreeHeler(preorder, pStart + leftIndex + 1, pEnd, inorder, index + 1, iEnd); + return node; + } + + private int find(int[] inorder, int start, int end, int value) { + int index = -1; + for (int i = start; i < end; i++) { + if (inorder[i] == value) { + index = i; + break; + } + } + return index; + } + + public static void main(String[] args) { + int[] preorder = new int[]{1, 2, 3}; + int[] inorder = new int[]{2, 3, 1}; + + ConstructBinaryTreeFromPreorderAndInorderTraversal01 tree = new ConstructBinaryTreeFromPreorderAndInorderTraversal01(); + TreeNode root = tree.buildTree(preorder, inorder); + } + +} diff --git a/Week_02/G20200343030523/id_523/LeetCode_144_523.java b/Week_02/G20200343030523/id_523/LeetCode_144_523.java new file mode 100644 index 00000000..ca301152 --- /dev/null +++ b/Week_02/G20200343030523/id_523/LeetCode_144_523.java @@ -0,0 +1,35 @@ +package tree; + +import java.util.ArrayList; +import java.util.List; + +public class BinaryTreePreorderTraversal { + + public List preorderTraversal(TreeNode root) { + List result = new ArrayList<>(); + preorder(root, result); + return result; + } + + private void preorder(TreeNode node, List result) { + if (node == null) { + return; + } + result.add(node.val); + preorder(node.left, result); + preorder(node.right, result); + } + + public static void main(String[] args) { + TreeNode root = new TreeNode(1); + TreeNode node1 = new TreeNode(2); + TreeNode node2 = new TreeNode(3); + root.right = node1; + node1.left = node2; + + BinaryTreePreorderTraversal preorderTraversal = new BinaryTreePreorderTraversal(); + List result = preorderTraversal.preorderTraversal(root); + System.out.println(result); + } + +} diff --git a/Week_02/G20200343030523/id_523/LeetCode_236_523.java b/Week_02/G20200343030523/id_523/LeetCode_236_523.java new file mode 100644 index 00000000..97fc90d0 --- /dev/null +++ b/Week_02/G20200343030523/id_523/LeetCode_236_523.java @@ -0,0 +1,22 @@ +package tree; + +public class LowestCommonAncestorOfABinaryTree { + + public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { + if (root == null || root == p || root == q) { + return root; + } + + TreeNode left = lowestCommonAncestor(root.left, p, q); + TreeNode right = lowestCommonAncestor(root.right, p, q); + + if (left == null) { + return right; + } else if (right == null) { + return left; + } else { + return root; + } + } + +} diff --git a/Week_02/G20200343030523/id_523/LeetCode_429_523.java b/Week_02/G20200343030523/id_523/LeetCode_429_523.java new file mode 100644 index 00000000..236ea57f --- /dev/null +++ b/Week_02/G20200343030523/id_523/LeetCode_429_523.java @@ -0,0 +1,75 @@ +package tree; + +import java.util.*; + +/** + * https://leetcode-cn.com/problems/n-ary-tree-level-order-traversal/ + */ +public class NAryTreeLevelOrderTraversal01 { + + public List> levelOrder(Node root) { + List> result = new ArrayList<>(); + if (root == null) { + return result; + } + + Queue queue = new LinkedList<>(); + queue.add(root); + while (!queue.isEmpty()) { + List level = new ArrayList<>(); + int size = queue.size(); + for (int i = 0; i < size; i++) { + Node node = queue.poll(); + level.add(node.val); + if (node.children != null) { + queue.addAll(node.children); + } + } + result.add(level); + } + + return result; + } + + public static void main(String[] args) { + Node root = new Node(1); + Node n1 = new Node(3); + Node n2 = new Node(2); + Node n3 = new Node(4); + Node n4 = new Node(5); + Node n5 = new Node(6); + + List c1 = new ArrayList<>(); + c1.add(n1); + c1.add(n2); + c1.add(n3); + root.children = c1; + + List c2 = new ArrayList<>(); + c2.add(n4); + c2.add(n5); + n1.children = c2; + + NAryTreeLevelOrderTraversal01 orderTraversal = new NAryTreeLevelOrderTraversal01(); + System.out.println(orderTraversal.levelOrder(root)); + } + + + static class Node { + public int val; + public List children; + + public Node() { + } + + public Node(int _val) { + val = _val; + } + + public Node(int _val, List _children) { + val = _val; + children = _children; + } + } + +} diff --git a/Week_02/G20200343030523/id_523/LeetCode_46_523.java b/Week_02/G20200343030523/id_523/LeetCode_46_523.java new file mode 100644 index 00000000..4bc0a40c --- /dev/null +++ b/Week_02/G20200343030523/id_523/LeetCode_46_523.java @@ -0,0 +1,57 @@ +package recursion; + +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Deque; +import java.util.List; + +public class Permutations { + + public List> permute(int[] nums) { + + if (nums == null || nums.length == 0) { + return new ArrayList<>(); + } + + int length = nums.length; + List> result = new ArrayList<>(factorial(length)); + boolean[] used = new boolean[length]; + + Deque path = new ArrayDeque<>(); + dfs(nums, length, 0, used, path, result); + return result; + } + + private int factorial(int n) { + int res = 1; + for (int i = 2; i < n; i++) { + res *= i; + } + return res; + } + + private void dfs(int[] nums, int length, int depth, boolean[] used, Deque path, List> result) { + if (depth == length) { + result.add(new ArrayList<>(path)); + return; + } + + for (int i = 0; i < length; i++) { + if (!used[i]) { + path.addLast(nums[i]); + used[i] = true; + dfs(nums, length, depth + 1, used, path, result); + used[i] = false; + path.removeLast(); + } + } + } + + + public static void main(String[] args) { + Permutations permutations = new Permutations(); + int[] nums = new int[]{1, 1, 2}; + System.out.println(permutations.permute(nums)); + } + +} diff --git a/Week_02/G20200343030523/id_523/LeetCode_47_523.java b/Week_02/G20200343030523/id_523/LeetCode_47_523.java new file mode 100644 index 00000000..c87958fd --- /dev/null +++ b/Week_02/G20200343030523/id_523/LeetCode_47_523.java @@ -0,0 +1,59 @@ +package recursion; + +import java.util.*; + +public class PermutationsII { + + public List> permuteUnique(int[] nums) { + + if (nums == null || nums.length == 0) { + return new ArrayList<>(); + } + + Arrays.sort(nums); + + int length = nums.length; + List> result = new ArrayList<>(factorial(length)); + + boolean[] used = new boolean[length]; + Deque path = new ArrayDeque<>(); + dfs(nums, length, 0, used, path, result); + return result; + + } + + private int factorial(int n) { + int res = 1; + for (int i = 2; i < n; i++) { + res *= i; + } + return res; + } + + private void dfs(int[] nums, int length, int depth, boolean[] used, Deque path, List> result) { + if (depth == length) { + result.add(new ArrayList<>(path)); + return; + } + + for (int i = 0; i < length; i++) { + if (i > 0 && nums[i] == nums[i - 1] && !used[i - 1]) { + continue; + } + if (!used[i]) { + path.addLast(nums[i]); + used[i] = true; + dfs(nums, length, depth + 1, used, path, result); + used[i] = false; + path.removeLast(); + } + } + } + + public static void main(String[] args) { + PermutationsII permutations = new PermutationsII(); + int[] nums = new int[]{1, 2, 1}; + System.out.println(permutations.permuteUnique(nums)); + } + +} diff --git a/Week_02/G20200343030523/id_523/LeetCode_49_523.java b/Week_02/G20200343030523/id_523/LeetCode_49_523.java new file mode 100644 index 00000000..3001b9d3 --- /dev/null +++ b/Week_02/G20200343030523/id_523/LeetCode_49_523.java @@ -0,0 +1,31 @@ +package hashmap; + +import java.util.*; + +/** + * https://leetcode-cn.com/problems/group-anagrams + */ +public class GroupAnagrams { + public List> groupAnagrams(String[] strs) { + Map> ans = new HashMap<>(16); + for (String str : strs) { + char[] arr = str.toCharArray(); + Arrays.sort(arr); + String key = String.valueOf(arr); + if (!ans.containsKey(key)) { + ans.put(key, new ArrayList<>()); + } + ans.get(key).add(str); + } + return new ArrayList<>(ans.values()); + } + + public static void main(String[] args) { + String[] strs = new String[]{"eat", "tea", "tan", "ate", "nat", "bat"}; + GroupAnagrams groupAnagrams = new GroupAnagrams(); + List> result = groupAnagrams.groupAnagrams(strs); + System.out.println(result); + } + + +} diff --git a/Week_02/G20200343030523/id_523/LeetCode_589_523.java b/Week_02/G20200343030523/id_523/LeetCode_589_523.java new file mode 100644 index 00000000..d88fdf80 --- /dev/null +++ b/Week_02/G20200343030523/id_523/LeetCode_589_523.java @@ -0,0 +1,71 @@ +package tree; + +import java.util.ArrayList; +import java.util.List; + +/** + * https://leetcode-cn.com/problems/n-ary-tree-preorder-traversal/description/ + */ +public class NAryTreePreorderTraversal { + + public List preorder(Node root) { + List result = new ArrayList<>(); + helper(root, result); + return result; + } + + private void helper(Node node, List result) { + if (node == null) { + return; + } + result.add(node.val); + if (node.children != null) { + for (Node child : node.children) { + helper(child, result); + } + } + } + + public static void main(String[] args) { + Node root = new Node(1); + Node n1 = new Node(3); + Node n2 = new Node(2); + Node n3 = new Node(4); + Node n4 = new Node(5); + Node n5 = new Node(6); + + List c1 = new ArrayList<>(); + c1.add(n1); + c1.add(n2); + c1.add(n3); + root.children = c1; + + List c2 = new ArrayList<>(); + c2.add(n4); + c2.add(n5); + n1.children = c2; + + NAryTreePreorderTraversal traversal = new NAryTreePreorderTraversal(); + System.out.println(traversal.preorder(root)); + } + + static class Node { + public int val; + public List children; + + public Node() { + } + + public Node(int _val) { + val = _val; + } + + public Node(int _val, List _children) { + val = _val; + children = _children; + } + } + + ; + +} diff --git a/Week_02/G20200343030523/id_523/LeetCode_590_523.java b/Week_02/G20200343030523/id_523/LeetCode_590_523.java new file mode 100644 index 00000000..9b33cffb --- /dev/null +++ b/Week_02/G20200343030523/id_523/LeetCode_590_523.java @@ -0,0 +1,73 @@ +package tree; + +import java.util.ArrayList; +import java.util.List; + +/** + * https://leetcode-cn.com/problems/n-ary-tree-postorder-traversal + */ +public class NAryTreePostorderTraversal { + + public List postorder(Node root) { + List result = new ArrayList<>(); + heler(root, result); + return result; + } + + private void heler(Node node, List result) { + if (node == null) { + return; + } + if (node.children != null) { + List children = node.children; + for (Node child : children) { + heler(child, result); + } + } + result.add(node.val); + } + + public static void main(String[] args) { + + Node root = new Node(1); + Node n1 = new Node(3); + Node n2 = new Node(2); + Node n3 = new Node(4); + Node n4 = new Node(5); + Node n5 = new Node(6); + + List c1 = new ArrayList<>(); + c1.add(n1); + c1.add(n2); + c1.add(n3); + root.children = c1; + + List c2 = new ArrayList<>(); + c2.add(n4); + c2.add(n5); + n1.children = c2; + + NAryTreePostorderTraversal traversal = new NAryTreePostorderTraversal(); + System.out.println(traversal.postorder(root)); + } + + static class Node { + public int val; + public List children; + + public Node() { + } + + public Node(int _val) { + val = _val; + } + + public Node(int _val, List _children) { + val = _val; + children = _children; + } + } + + ; + +} diff --git a/Week_02/G20200343030523/id_523/LeetCode_77_523.java b/Week_02/G20200343030523/id_523/LeetCode_77_523.java new file mode 100644 index 00000000..fd37367b --- /dev/null +++ b/Week_02/G20200343030523/id_523/LeetCode_77_523.java @@ -0,0 +1,39 @@ +package recursion; + +import java.util.ArrayList; +import java.util.List; + +/** + * https://leetcode-cn.com/problems/combinations/ + */ +public class Combinations01 { + + public List> combine(int n, int k) { + List> result = new ArrayList<>(); + + if (k > n || k < 0) { + return result; + } + + if (k == 0) { + result.add(new ArrayList<>()); + return result; + } + + result = combine(n - 1, k - 1); + for (List list : result) { + list.add(n); + } + result.addAll(combine(n - 1, k)); + + return result; + } + + + public static void main(String[] args) { + Combinations01 combinations = new Combinations01(); + List> result = combinations.combine(4, 2); + System.out.println(result); + } + +} diff --git a/Week_02/G20200343030527/LeetCode_49_527.java b/Week_02/G20200343030527/LeetCode_49_527.java new file mode 100644 index 00000000..d2af06f9 --- /dev/null +++ b/Week_02/G20200343030527/LeetCode_49_527.java @@ -0,0 +1,36 @@ +class ValidAnagram { + public boolean isAnagram(String s, String t) { + if (s == null || t == null || s.length() != t.length()) { + return false; + } + + char[] str1 = s.toCharArray(); + char[] str2 = t.toCharArray(); + Arrays.sort(str1); + Arrays.sort(str2); + + return Arrays.equals(str1,str2); + } + + public boolean isAnagram_2(String s, String t) { + if (s == null || t == null || s.length() != t.length()) { + return false; + } + + Map map = new HashMap<>(); + for (char ch : s.toCharArray()) { + map.put(ch, map.getOrDefault(ch, 0) + 1); + } + for (char ch : t.toCharArray()) { + Integer count = map.get(ch); + if (count == null) { + return false; + } else if (count > 1) { + map.put(ch, count -1); + } else { + map.remove(ch); + } + } + return map.isEmpty() + } +} \ No newline at end of file diff --git a/Week_02/G20200343030527/LeetCode_94_527.java b/Week_02/G20200343030527/LeetCode_94_527.java new file mode 100644 index 00000000..55eb9fe7 --- /dev/null +++ b/Week_02/G20200343030527/LeetCode_94_527.java @@ -0,0 +1,16 @@ +class InorderTraversal { + public List inorderTraversal(TreeNode root) { + List res = new ArrayList(); + dfs(res,root); + return res; + } + + void dfs(List res, TreeNode root) { + if(root==null) { + return; + } + dfs(res,root.left); + res.add(root.val); + dfs(res,root.right); + } +} \ No newline at end of file diff --git a/Week_02/G20200343030529/LeetCode_105_529.java b/Week_02/G20200343030529/LeetCode_105_529.java new file mode 100644 index 00000000..00478bd4 --- /dev/null +++ b/Week_02/G20200343030529/LeetCode_105_529.java @@ -0,0 +1,51 @@ +package com.leetcode.practices; + +import java.util.Arrays; + +public class Solution { + + public class TreeNode { + int val; + TreeNode left; + TreeNode right; + TreeNode(int x) { val = x; } + } + + /** + * 例如:前序数组preorder = [3,9,20,15,7], 中序数组inorder = [9,3,15,20,7] + * 由二叉树定义可知,二叉树由根节点+左子树+右子树组成。通过前序遍历可知preorder[0]为根节点 + * 通过inorder可知inorder[0:1]为左子树,inorder[2:]为右子树。 + * 可通过递归算法求解, + * 1、先从前序数组中取得子树根节点,然后从中序数组中,确定根节点数组位置 + * 2、递归构建左子树(需要确定左子树的前序数组及其中序数组) + * 3、递归构建右子树(需要确定右子树的前序数组及其中序数组) + * @param preorder 前序数组 + * @param inorder 中序数组 + * @return 二叉树根节点 + */ + public TreeNode buildTree(int[] preorder, int[] inorder) { + if (preorder.length == 0 || inorder.length == 0) { + return null; + } + int rootVal = preorder[0]; + TreeNode root = new TreeNode(rootVal); + int mid = 0; + for (int i = 0; i < inorder.length; i++) { + if (inorder[i] == rootVal) { + mid = i; + break; + } + } + root.left = buildTree(Arrays.copyOfRange(preorder, 1, mid + 1), Arrays.copyOfRange(inorder, 0, mid)); + root.right = buildTree(Arrays.copyOfRange(preorder, mid + 1, preorder.length), Arrays.copyOfRange(inorder, mid + 1, inorder.length)); + return root; + + } + + public static void main(String[] args) { + BuildTree buildTree = new BuildTree(); + int[] preorder = new int[]{3,9,20,15,7}; + int[] inorder = new int[]{9,3,15,20,7}; + buildTree.buildTree(preorder, inorder); + } +} diff --git a/Week_02/G20200343030529/LeetCode_492_529.java b/Week_02/G20200343030529/LeetCode_492_529.java new file mode 100644 index 00000000..9eef9de0 --- /dev/null +++ b/Week_02/G20200343030529/LeetCode_492_529.java @@ -0,0 +1,85 @@ +package com.leetcode.practices; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; + +/** + * leetcode.429.N叉树的层序遍历 + * https://leetcode-cn.com/problems/n-ary-tree-level-order-traversal/ + */ +public class NAryTreeLevelOrderTraversal { + + class Node { + public int val; + public List children; + + public Node() {} + + public Node(int _val) { + val = _val; + } + + public Node(int _val, List _children) { + val = _val; + children = _children; + } + }; + + /** + * 层级遍历二叉树,采用队列queue + * 1、根节点入队列 + * 2、判断队列是否为空 + * 3、获取队列大小为n + * 4、遍历队列前n个元素 + * 4.1、每个元素依次出队列,元素节点值添加到集合中 + * 4.2、每个元素中所有子元素加入队列 + * 5、把集合中结果加入到结果中 + * 6、回到步骤2 + * @param root + * @return + */ + public List> levelOrder(Node root) { + List> result = new ArrayList<>(); + if (root == null) { + return result; + } + Queue queue = new LinkedList<>();//广度搜索二叉树,采用queue + queue.add(root); + while (!queue.isEmpty()) { + List level = new ArrayList<>(); + int size = queue.size(); + for (int i = 0; i < size; i++) { + Node node = queue.poll(); + level.add(node.val); //加入当前层级节点值 + queue.addAll(node.children); //加入当前层级节点所有子节点 + } + result.add(level); + } + return result; + } + + + // public List> levelOrder(Node root) { + // List> result = new ArrayList<>(); + // if (root == null) { + // return result; + // } + // helper(root, 0, result); + // return result; + // } + // //深度搜索中,建立层级关系,在遍历树的同时,先对应层级添加当前节点的值 + // private void helper(Node node, int level, List> result) { + // if (result.size() <= level) { + // List list = new ArrayList<>(); + // list.add(node.val); + // result.add(list); + // } else { + // result.get(level).add(node.val); + // } + // for (Node child : node.children) { + // helper(child, level + 1, result); + // } + // } +} diff --git a/Week_02/G20200343030529/LeetCode_49_529.java b/Week_02/G20200343030529/LeetCode_49_529.java new file mode 100644 index 00000000..91ded14c --- /dev/null +++ b/Week_02/G20200343030529/LeetCode_49_529.java @@ -0,0 +1,62 @@ +package com.leetcode.practices; + +import java.util.*; + +/** + * leetcode.49.字母异位词分组 + * https://leetcode-cn.com/problems/group-anagrams/ + */ +public class Solution { + +// public List> groupAnagrams(String[] strs) { +// Map> map = new HashMap<>(); +// for (String str: strs) { +// char[] chars = str.toCharArray(); +// Arrays.sort(chars); +// String key = String.valueOf(chars); +// if (map.containsKey(key)) { +// map.get(key).add(str); +// } else { +// List list = new ArrayList<>(); +// list.add(str); +// map.put(key, list); +// } +// } +// return new ArrayList<>(map.values()); +// } + + public List> groupAnagrams(String[] strs) { + Map> map = new HashMap<>(); + for (String str: strs) { + String key = generateKey(str); + if (map.containsKey(key)) { + map.get(key).add(str); + } else { + List list = new ArrayList<>(); + list.add(str); + map.put(key, list); + } + + } + return new ArrayList<>(map.values()); + } + + /** + * 将输入的str进行编码。 + * 编码方法:先建立一个大小为26的数组,字母a-z分别对应数组0-25位置, + * 然后按字母出现次数进行累加,并更新字母对应数组位置的值。 + * 最后返回字符数组int->String + * @param str + * @return + */ + public String generateKey(String str) { + int[] count = new int[26]; + for (char c : str.toCharArray()) { + count[(byte)c - 97] += 1; + } + StringBuilder sb = new StringBuilder(); + + return Arrays.toString(count); + } + +} diff --git a/Week_02/G20200343030529/LeetCode_77_529.java b/Week_02/G20200343030529/LeetCode_77_529.java new file mode 100644 index 00000000..5587eb22 --- /dev/null +++ b/Week_02/G20200343030529/LeetCode_77_529.java @@ -0,0 +1,55 @@ +package com.leetcode.practices; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * leetcode.77.组合 + * https://leetcode-cn.com/problems/combinations/ + */ +public class Solution { + + private List> result = new ArrayList<>(); + + /** + * 此题属于组合问题,即C(n, k)。n为总数,k为组合数目。 + * 解决方案,采取递归方案,先确定位置一的数字,然后再递归确定下一位置的数字。 + * 当list中大小==k时,把结果添加支result中 + * @param n + * @param k + * @return + */ + public List> combine(int n, int k) { + helper(0, k, 1, n, new ArrayList<>()); + return result; + } + + /** + * 套用递归模版 + * @param level 递归层深度 + * @param max 组合数目 + * @param begin 起始位置(begin...n) + * @param n 总数 + * @param list 产生的组合结果暂时缓存区 + */ + private void helper(int level, int max, int begin, int n, List list) { + //terminator + if (list.size() == max) { + result.add(new ArrayList<>(list)); + return; + } + + //process current logic + for (int i = begin; i <= n; i++) { + list.add(i);//每个位置只能够是begin..n的数字 + helper(level + 1, max, i + 1, n, list);//下一位置的数字 + //drill down + list.remove(list.size() - 1);//因为当前list.size == max, 所以要删除最后一个元素(回溯,撤销前一状态) + } + + //reverse states; + + } + +} diff --git a/Week_02/G20200343030531/LeetCode_49_531.go b/Week_02/G20200343030531/LeetCode_49_531.go new file mode 100644 index 00000000..4eb1bfe1 --- /dev/null +++ b/Week_02/G20200343030531/LeetCode_49_531.go @@ -0,0 +1,120 @@ +package main + +import ( + "fmt" + "sort" +) + +func main() { + strs := []string{"eat", "tea", "tan", "ate", "nat", "bat"} + t := groupAnagrams(strs) + fmt.Println("t == ", t) +} + +// 暴力法 +/* + 一个个去遍历,去比对 + 结果:失败,自己写懵逼了,按照覃超老师说的,不去纠结,看题解,向正确答案靠齐。 +*/ +/* +func groupAnagrams(strs []string) [][]string { + // 1.建立临时变量 + temp := make([][]string, len(strs)) + for i := range temp { + temp[i] = make([]string, 5) + } + // 2.循环 + // 2.1 第一层循环,取出比较变量 + for i := 0; i < len(strs); i++ { + str := strs[i] + temp[i][0] = str + //fmt.Println("i = ", i, "str = ", str) + // 2.2 第二层循环,取出被比较变量 + for j := i+1; j < len(strs)-1;j++ { + secd := strs[j] + //fmt.Println("j = ", j, "secd = ", secd) + // 2.3 第三层循环,一个个字符串比较 + equal := false + for k := 0; k < len(secd); k++ { + // 2.4 第四层循环 + for m := 0; m < len(secd); m++ { + fmt.Println("str[k] = ", str[k], "k = ", k, "secd[m] = ", secd[m], "m = ", m) + if str[k] == secd[m] { + fmt.Println("break") + equal = true + } + if m == len(secd) { + temp[i][len(temp[i])] = secd + } + } + if equal == false { + break + } + } + } + } + return temp +} +*/ + +// 排序数组分类 +/* + 反思:1.字符串排序这一块太繁琐,多了很多步骤,转来转去的 + 2. []byte可以通过string([]byte)强转 + 3. 加入最后的切片中,可以通过map判断然后一步到位,不需要最后另外判断在append +*/ +/* +func groupAnagrams(strs []string) [][]string { + // 1.初始化 + s := make(map[string][]string, len(strs)) + // 2.循环遍历 + for i := 0; i < len(strs); i++ { + // 2.1字符串排序 + cha := []byte(strs[i]) + len := len(cha) + temp := make([]string, len) + for index, value := range cha { + temp[index] = string(value) + } + sort.Strings(temp) + arrstring := strings.Join(temp, "") + // 2.2判断字典有没有,有的话加入数组,没有排序后就作为key + s[arrstring] = append(s[arrstring], strs[i]) + } + slice := make([][]string, 0) + for _, value := range s { + slice = append(slice, value) + } + return slice +} +*/ + +// leetcode 28ms范例 +/* + 反思:1、学会使用sort.slice进行排序 + 2、通过map判断有无,存储中间变量map的长度,联系返回值二维数组 + 3、二维数组拼接要注意 +*/ +func groupAnagrams(strs []string) [][]string { + // 1.初始化 + res := make([][]string, 0) + m := make(map[string]int, 0) + l := len(strs) + for i := 0; i < l; i++ { + // 2.排序 + // 2.1字符串转byte + temp := []byte(strs[i]) + // 2.2排序 + sort.Slice(temp, func(i, j int) bool { + return temp[i] < temp[j] + }) + // 2.3判断 + if v, ok := m[string(temp)]; ok == true { + res[v] = append(res[v], strs[i]) + } else { + m[string(temp)] = len(m) + res = append(res, []string{strs[i]}) + } + } + return res +} diff --git a/Week_02/G20200343030533/LeetCode_001_533.cpp b/Week_02/G20200343030533/LeetCode_001_533.cpp new file mode 100644 index 00000000..c040b5de --- /dev/null +++ b/Week_02/G20200343030533/LeetCode_001_533.cpp @@ -0,0 +1,22 @@ +// 两数之和: https://leetcode-cn.com/problems/two-sum/submissions/ +#include +#include +#include + +class Solution { +public: + vector twoSum(vector& nums, int target) { + unordered_map idx_map; + vector result = {0,0}; + for ( int i = 0; i < nums.size(); i++){ + if (idx_map.count(target - nums[i]) > 0){ + result[0] = i; + result[1] = idx_map[target-nums[i]]; + break; + } else{ + idx_map[nums[i]] = i; + } + } + return result; + } +}; \ No newline at end of file diff --git a/Week_02/G20200343030533/LeetCode_022_533.c b/Week_02/G20200343030533/LeetCode_022_533.c new file mode 100644 index 00000000..39a58ce5 --- /dev/null +++ b/Week_02/G20200343030533/LeetCode_022_533.c @@ -0,0 +1,38 @@ + +//C语言做法,整体逻辑和Cpp一样,就是内存需要手动分配 +void generate(int n, int left, int right, char** ret, char *s, int*returnSize){ + if (left == n && right == n){ + s[left+right] = '\0'; + ret[*returnSize] = strdup(s); + *returnSize = *returnSize + 1; + return ; + } + if (left < n){ + s[left+right] = '('; + generate(n, left+1, right, ret, s, returnSize); + } + if (right < left){ + s[left+right] = ')'; + generate(n, left, right+1, ret, s, returnSize); + } + return ; + +} + +int comb(int n){ + int ret = 1; + for (int i = 1; i <= n; i++){ + ret *= i; + } + return ret; +} + +char ** generateParenthesis(int n, int* returnSize){ + char *s = malloc(sizeof(char) * n * 2 +1); + *returnSize = 0; //默认是0 + int initSize = comb(n); + char **ret = malloc(sizeof(char*) * initSize); + generate(n, 0, 0, ret, s, returnSize); + return ret; + +} diff --git a/Week_02/G20200343030533/LeetCode_022_533.cpp b/Week_02/G20200343030533/LeetCode_022_533.cpp new file mode 100644 index 00000000..9e7872f1 --- /dev/null +++ b/Week_02/G20200343030533/LeetCode_022_533.cpp @@ -0,0 +1,27 @@ +// 22. 括号生成 +// https://leetcode-cn.com/problems/generate-parentheses/ +public: + vector strings; + vector generateParenthesis(int n) { + _generate(0, 0, n, ""); + return strings; + } + void _generate(int left, int right, int n, string s){ + // terminate + if ( left == n && right == n){ + strings.push_back(s); + } + //process logical + // dirll down + if (left < n){ + _generate(left+1, right, n, s+"("); + } + if (left > right){ + _generate(left, right + 1, n, s+")"); + } + + // reverse + return ; + + } +}; \ No newline at end of file diff --git a/Week_02/G20200343030533/LeetCode_046_533.cpp b/Week_02/G20200343030533/LeetCode_046_533.cpp new file mode 100644 index 00000000..fe275e7a --- /dev/null +++ b/Week_02/G20200343030533/LeetCode_046_533.cpp @@ -0,0 +1,48 @@ +// 46. 全排列 ii +// https://leetcode-cn.com/problems/permutations-i/ + +class Solution { +public: + int idx = 0; + vector> permute(vector& nums) { + int perm_nums = 1; + for (int i = 1; i <= nums.size(); i++) perm_nums *= i; + //预先分配内存 + vector> ret(perm_nums, vector(nums.size(), 0)); + //表示使用状态 + vector used(nums.size(), false); + //当前的组合 + vector perm(nums.size()); + + generate(0, perm, nums, used, ret); + return ret; + + } + /* 参数说明: + * depth: 表示当前的深度 + * num: 当前的组合 + * nums: 给定的数组 + * used: 使用情况 + * idx : + */ + void generate(int depth, vector&perm, vector& nums, vector& used, vector>& ret){ + if ( depth == nums.size() ) { + ret[idx] = perm; + idx+=1; + return ; + } + // 做选择 + for(int i = 0; i < nums.size(); i++){ + // 当前数字没有被使用, 没有用过是false + if ( ! used[i] ) { + used[i] = true; + perm[depth] = nums[i]; + generate(depth+1, perm, nums, used, ret); + //重置状态 + used[i] = false; + } + + } + + } +}; \ No newline at end of file diff --git a/Week_02/G20200343030533/LeetCode_047_533.cpp b/Week_02/G20200343030533/LeetCode_047_533.cpp new file mode 100644 index 00000000..efc5666f --- /dev/null +++ b/Week_02/G20200343030533/LeetCode_047_533.cpp @@ -0,0 +1,47 @@ +// 47. 全排列 II +//https://leetcode-cn.com/problems/permutations-ii/ + +class Solution { +public: + vector> permuteUnique(vector& nums) { + + sort(nums.begin(), nums.end()); + //输出结果 + vector> ret; + //表示使用状态 + vector used(nums.size(), false); + //当前的组合 + vector perm(nums.size()); + generate(0, perm, nums, used, ret); + + return ret; + + } + /* 参数说明: + * depth: 表示当前的深度 + * perm: 当前的组合 + * nums: 给定的数组 + * used: 使用情况 + */ + void generate(int depth, vector&perm, vector& nums, vector& used, vector>& ret){ + if ( depth == nums.size() ) { + ret.push_back( perm ); + return ; + } + // 做选择 + for(int i = 0; i < nums.size(); i++){ + // 当前数字没有被使用, 没有用过是false + if ( used[i] ) continue; + if ( i> 0 && nums[i] == nums[i-1] && ! used[i-1] ) continue; + + used[i] = true; + perm[depth] = nums[i]; + generate(depth+1, perm, nums, used, ret); + //重置状态 + used[i] = false; + + + } + + } +}; \ No newline at end of file diff --git a/Week_02/G20200343030533/LeetCode_049_533.cpp b/Week_02/G20200343030533/LeetCode_049_533.cpp new file mode 100644 index 00000000..33cc0512 --- /dev/null +++ b/Week_02/G20200343030533/LeetCode_049_533.cpp @@ -0,0 +1,111 @@ +#include + +//49. 字母异位词分组 +// https://leetcode-cn.com/problems/group-anagrams/ + +//方法1: 排序字符表 +// key为排序的字符串,值为字符串数组,对字符串进行排序,然后查找 +// 时间复杂度 K(nlog n) +class Solution { +public: + vector> groupAnagrams(vector& strs) { + vector> res; //输出结果 + unordered_map word_tbl; //记录word对应位置 + int word_pos = 0 ; //word在结果中的位置 + string tmp_str; //临时存放字符 + for( auto str : strs){ + tmp_str = str; + sort(tmp_str.begin(), tmp_str.end()); + if ( word_tbl.count(tmp_str) ){ //如果匹配到已有词 + int temp_pos = word_tbl[tmp_str]; + res[temp_pos].push_back(str) ; //加入结果 + } else{ + vector vec(1, str); + res.push_back(vec); + word_tbl[tmp_str] = word_pos++; + } + } + return res; + } +}; + +//方法2: 字母频数表 +//统计每个字符串中,26个字母出现的次数, +//比如说a=3,b=4,c=5, 那么就是#3#4#4#0#0... 这就是哈希表的key +class Solution { +public: + string encodeStr(string str){ + string res; + int freq_arr[26] = {0}; + for ( auto ch : str){ + freq_arr[ch - 'a']++; + } + for( int i = 0; i < 26; i++){ + res += "#"; + res += to_string(freq_arr[i]); + } + return res; + } + vector> groupAnagrams(vector& strs) { + + vector> res; + unordered_map word_tbl; //key为字符频数, value为位置 + int index = 0; //数组下标 + + string freq_key; + + for (auto str : strs){ + freq_key = encodeStr(str); + + if ( word_tbl.count(freq_key) ){ + res[ word_tbl[freq_key] ].push_back(str); + } else{ + vector vec(1, str); + res.push_back(vec); + word_tbl[freq_key] = index++; + } + + } + return res; + + } +}; + +//方法3: 方法2优化哈希函数 +//按理说这道题中,方法2应该快一点,但实际上速度却慢了 +//估计是字符串的哈希函数不好使。可以借助 算术基本定理,又称为正整数的唯一分解定理, +//即:每个大于1的自然数,要么本身就是质数,要么可以写为2个以上的质数的积, +//而且这些质因子按大小排列之后,写法仅有一种方式。 +class Solution { +public: + vector> groupAnagrams(vector& strs) { + //26个字母的质数对应表 + int char_hash[26] = { + 2, 3, 5, 7, 11, + 13, 17, 19, 23, 29, + 31, 37, 41, 43, 47, + 53, 59, 61, 67, 71, + 73, 79, 83, 89, 97, + 101 + } ; + vector> res; + unordered_map word_table; + int index = 0; //对应res的二维下标 + + for (auto str : strs){ + unsigned long hash_key = 1; + for (auto ch : str){ + hash_key *= char_hash[ch-'a']; + } + if ( word_table.count(hash_key) > 0 ) { + res[word_table[hash_key]].push_back(str); + } else{ + vector temp(1, str); + res.push_back(temp); + word_table[hash_key] = index++; + } + } + return res; + + } +}; \ No newline at end of file diff --git a/Week_02/G20200343030533/LeetCode_077_533.cpp b/Week_02/G20200343030533/LeetCode_077_533.cpp new file mode 100644 index 00000000..7e10827b --- /dev/null +++ b/Week_02/G20200343030533/LeetCode_077_533.cpp @@ -0,0 +1,27 @@ +// 77. 组合 +// https://leetcode-cn.com/problems/combinations/ + +class Solution { +public: + vector> combine(int n, int k) { + vector> ret; + vector comb; + generate(0, 1, n, k, comb, ret ); + return ret; + } + //千万不要忘记&符号,表示右值引用 + void generate(int depth, int start, int n, int k, vector& comb, vector>& ret){ + if ( depth == k){ + ret.push_back(comb); + } + for (int i = start; i <= n; i++){ + comb.push_back(i); + //新的start为当前位置的后一位 + generate(depth+1, i+1, n, k, comb, ret); + //reverse + comb.pop_bakc(); + } + + + } +}; \ No newline at end of file diff --git a/Week_02/G20200343030533/LeetCode_094_533.cpp b/Week_02/G20200343030533/LeetCode_094_533.cpp new file mode 100644 index 00000000..66453af5 --- /dev/null +++ b/Week_02/G20200343030533/LeetCode_094_533.cpp @@ -0,0 +1,19 @@ +// 94.中序树的遍历 https://leetcode-cn.com/problems/binary-tree-inorder-traversal/ + +//递归的方法 +class Solution { +public: + vector res; + void inOrder(TreeNode *root){ + if (root == nullptr) return; + inOrder(root->left); + res.push_back(root->val); + inOrder(root->right); + } + vector inorderTraversal(TreeNode* root) { + + inOrder(root); + return res; + + } +}; \ No newline at end of file diff --git a/Week_02/G20200343030533/LeetCode_098_533.cpp b/Week_02/G20200343030533/LeetCode_098_533.cpp new file mode 100644 index 00000000..5d50410c --- /dev/null +++ b/Week_02/G20200343030533/LeetCode_098_533.cpp @@ -0,0 +1,24 @@ +// 98. 验证二叉搜索树 +//https://leetcode-cn.com/problems/validate-binary-search-tree/ + +//分别遍历左子树和右子树 +// 保证左节点都小于根节点,右节点都大于根节点 +// 注意点:一定要注意边界检查 +class Solution { +public: + bool isValidBST(TreeNode* root) { + + long long low = (long long)INT_MIN - 1; + long long high= (long long)INT_MAX + 1; + + return DFS(root, low, high); + + } + bool DFS(TreeNode* root, long long low, long long high){ + if ( root == nullptr) return true; + if ( root->val <= low || root->val >= high) return false; + + //左树更新上界,右树更新下界 + return DFS(root->left, low, root->val) && DFS(root->right,root->val, high); + } +}; \ No newline at end of file diff --git a/Week_02/G20200343030533/LeetCode_104_533.cpp b/Week_02/G20200343030533/LeetCode_104_533.cpp new file mode 100644 index 00000000..1ca3a830 --- /dev/null +++ b/Week_02/G20200343030533/LeetCode_104_533.cpp @@ -0,0 +1,60 @@ +// 104. 二叉树的最大深度 +// https://leetcode-cn.com/problems/maximum-depth-of-binary-tree/ +// 递归 二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。 + +// 用辅助函数,用全局变量 +class Solution { +public: + int max = 0; + int maxDepth(TreeNode* root) { + + findMax(root, 0); + return max; + } + void findMax(TreeNode* root, int n){ + if (root == nullptr) { + if ( n > max ) max = n; + return; + } + findMax(root->left, n+1); + findMax(root->right, n+1); + + return; + } +}; + +//用辅助函数,不用全局变量 +class Solution { +public: + + int maxDepth(TreeNode* root) { + + int max = findMax(root, 0); + return max; + } + int findMax(TreeNode* root, int n){ + if (root == nullptr) { + return n; + } + int left = findMax(root->left, n+1); + int right =findMax(root->right, n+1); + + return max(left, right); + } +}; + +//不用辅助函数,不用全局变量 +class Solution { +public: + + int maxDepth(TreeNode* root) { + if ( root == nullptr){ + return 0; + } + int left = maxDepth(root->left); + int right = maxDepth(root->right); + + return max(left, right) + 1; + } + +}; \ No newline at end of file diff --git a/Week_02/G20200343030533/LeetCode_105_533.c b/Week_02/G20200343030533/LeetCode_105_533.c new file mode 100644 index 00000000..297db98f --- /dev/null +++ b/Week_02/G20200343030533/LeetCode_105_533.c @@ -0,0 +1,80 @@ +#include + +struct TreeNode { + int val; + struct TreeNode *left; + struct TreeNode *right; +}; + +typedef struct TreeNode Node; + +Node* createNode(int val){ + Node *node = malloc(sizeof(Node)); + node->left = NULL; + node->right = NULL; + node->val = val; + return node; +} + +//寻找索引的函数,一定要注意,是一个等号 +//因为最小区间起始和结果同一个位置 +int findRoot(int val, int *inorder, int ib, int ie){ + for (int i = ib; i <= ie; i++){ + if ( inorder[i] == val){ + return i; + } + } + return NULL; + +} + +//算法思想是分治, 难点是如何拆分数组 +//先利用先序拆中序,然后用中旬拆前序 +Node* DC(int* preorder, int pb, int pe, int* inorder, int ib, int ie){ + // 终止条件: 数组为空 + if (pb > pe ) return NULL; + //利用preorder区间的第一个确定root + Node *root = createNode(preorder[pb]); + //利用root拆分inorder + int rootIndex = findRoot(root->val, inorder, ib, ie); + //确定左右子树大小 + int leftSize = rootIndex - ib; + int rightSize = ie - rootIndex; + + root->left = DC(preorder, pb+1, pb+leftSize, inorder, ib, rootIndex-1); + root->right = DC(preorder, pb+leftSize+1, pe, inorder, rootIndex+1, ie ); + + return root; + +} + + +struct TreeNode* buildTree(int* preorder, int preorderSize, int* inorder, int inorderSize){ + + Node *root = DC(preorder, 0, preorderSize-1, inorder, 0, inorderSize); + return root; +} + + +//优秀的代码 +struct TreeNode* buildTree(int* preorder, int preorderSize, int* inorder, int inorderSize){ + // 终止条件: 数组大小不同,或者前序为0 + if(preorderSize != inorderSize || preorderSize == 0) + return NULL; + + struct TreeNode *root = (struct TreeNode *)malloc(sizeof(struct TreeNode)); + root->val = preorder[0]; + //遍历中序数组,找到分割点 + for(int i=0; ileft = buildTree(preorder+1, i, inorder, i); + //对于右子树, 开始为+1+i, 结束就是-1-i + root->right = buildTree(preorder+1+i, preorderSize-1-i, inorder+i+1, + preorderSize-1-i); + } + } + return root; +} \ No newline at end of file diff --git a/Week_02/G20200343030533/LeetCode_105_533.cpp b/Week_02/G20200343030533/LeetCode_105_533.cpp new file mode 100644 index 00000000..e446ce15 --- /dev/null +++ b/Week_02/G20200343030533/LeetCode_105_533.cpp @@ -0,0 +1,40 @@ +// 105. 从前序与中序遍历序列构造二叉树 +//https://leetcode-cn.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/ + + struct TreeNode { + int val; + TreeNode *left; + TreeNode *right; + TreeNode(int x) : val(x), left(NULL), right(NULL) {} + }; + +class Solution { +public: + unordered_map mp; + TreeNode* buildTree(vector& preorder, vector& inorder) { + //记录inorder的值的位置,方便后续拆分 + for(int i = 0; i < inorder.size(); i++){ + mp[inorder[i]] = i; + } + return dc(preorder, 0, preorder.size()-1, inorder, 0, inorder.size()-1); + } + /* 参数说明 + * pb, preorder begin + * pe, preorder end + * ib, inorder begin + * ie, inorder end + */ + TreeNode *dc(vector& preorder, int pb, int pe, vector& inorder, int ib, int ie){ + if( pb > pe ) return nullptr; + + TreeNode *root = new TreeNode(preorder[pb]); + int rootIndex = mp[root->val]; //获取中序的位置 + int leftSize = rootIndex - ib; //左子树大小 + int rightSize = ie - rootIndex; //右子树大小 + root->left = dc(preorder,pb+1,pb+leftSize, inorder,ib, rootIndex-1); //新的左子树问题 + root->right = dc(preorder,pb+leftSize+1, pe, inorder, rootIndex+1, ie); //新的右子树问题 + + return root; + + } +}; diff --git a/Week_02/G20200343030533/LeetCode_111_533.c b/Week_02/G20200343030533/LeetCode_111_533.c new file mode 100644 index 00000000..334260e5 --- /dev/null +++ b/Week_02/G20200343030533/LeetCode_111_533.c @@ -0,0 +1,20 @@ +//C的方法 +int minDepth(struct TreeNode* root){ + + if(root == NULL ) return 0; + + int left = minDepth(root->left); + int right = minDepth(root->right); + + //左子树为空,left=0,当前高度为右子树+1 + //右子树为空,right=0,当前高度为左子树+1 + //两者都为空,left,right都为0, 那就是0+1 + if (root->left == NULL || root->right == NULL){ + return left > right ? left+1 : right +1; + } else{ + //都不为空,就返回比较小的+1 + return left > right ? right + 1 : left + 1; + } + + +} diff --git a/Week_02/G20200343030533/LeetCode_111_533.cpp b/Week_02/G20200343030533/LeetCode_111_533.cpp new file mode 100644 index 00000000..fb0054b4 --- /dev/null +++ b/Week_02/G20200343030533/LeetCode_111_533.cpp @@ -0,0 +1,64 @@ +// 111. 二叉树的最小深度 +// https://leetcode-cn.com/problems/minimum-depth-of-binary-tree/ + +//错误示范, 在碰到[0],[1,2]的时候直接错 +class Solution { +public: + int min = INT_MAX; + void findMin(TreeNode *root, int n){ + if (root == nullptr) { + if (n < min) min = n; + return; + } + findMin(root->left, n+1); + findMin(root->right, n+1); + return; + + } + int minDepth(TreeNode* root) { + findMin(root, 0); + return min; + + } +}; + +// 为了能够通过[0]和[1,2], 就直接在主函数修改,发现依旧出错 +class Solution { + + int minDepth(TreeNode* root) { + if (root == nullptr) return 0; + if (root->left == nullptr && root->right == nullptr ) return 1; + findMin(root, 0); + + return min == 1 ? 2 : min; + + } +} + +/* 上面的代码想当然了,直接套用找最大深度的方法,没有认真思考过叶子节点的 + +叶子节点的定义是左孩子和右孩子都为 null 时叫做叶子节点 +- 当 root 节点左右孩子都为空时,返回 1 +- 当 root 节点左右孩子有一个为空时,返回不为空的孩子节点的深度 +- 当 root 节点左右孩子都不为空时,返回左右孩子较小深度的节点值 +*/ + +//重新理清思路后 +class Solution { +public: + int minDepth(TreeNode* root) { + if (root == nullptr) return 0; + //找左边最低深度 + int left = minDepth(root->left); + //找右边最低深度 + int right = minDepth(root->right); + // 如果左右子树有一个为空,说明当前不是叶子节点 + // 当前的深度就是左右节点中不为空(返回0)的节点深度+1 + if ( root->left == nullptr || root->right == nullptr){ + return left == 0 ? right + 1 : left + 1; + } + // 否则返回的是其中最小的+1 + return min(left, right) + 1; + + } +}; \ No newline at end of file diff --git a/Week_02/G20200343030533/LeetCode_144_533.cpp b/Week_02/G20200343030533/LeetCode_144_533.cpp new file mode 100644 index 00000000..72694877 --- /dev/null +++ b/Week_02/G20200343030533/LeetCode_144_533.cpp @@ -0,0 +1,18 @@ +// 44. 二叉树的前序遍历 +// https://leetcode-cn.com/problems/binary-tree-preorder-traversal +class Solution { +public: + vector res; + void preOrder(TreeNode* root){ + if (root == nullptr) return; + res.push_back(root->val); + preOrder(root->left); + preOrder(root->right); + } + vector preorderTraversal(TreeNode* root) { + + preOrder(root); + return res; + + } +}; \ No newline at end of file diff --git a/Week_02/G20200343030533/LeetCode_226_533.cpp b/Week_02/G20200343030533/LeetCode_226_533.cpp new file mode 100644 index 00000000..9e7aa3b3 --- /dev/null +++ b/Week_02/G20200343030533/LeetCode_226_533.cpp @@ -0,0 +1,33 @@ +// 226. 翻转二叉树 +//https://leetcode-cn.com/problems/invert-binary-tree/submissions/ +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +//一开始好无头绪,后来想到老师说的重复子问题,拒绝人肉暴力递归 +//于是就发现问题变得简单起来,也就是每一层就是反转当前的两个子节点,然后分别对这两个子节点对后代进行反转 +class Solution { +public: + TreeNode* invertTree(TreeNode* root) { + _invertTree(root); + return root; + } + void _invertTree(TreeNode *root){ + //terminator + if (root == nullptr) return; + // process logical + TreeNode *temp; + temp = root->left; + root->left = root->right; + root->right =temp; + //drill down + _invertTree(root->left); + _invertTree(root->right); + return ; + } +}; \ No newline at end of file diff --git a/Week_02/G20200343030533/LeetCode_236_533.c b/Week_02/G20200343030533/LeetCode_236_533.c new file mode 100644 index 00000000..cd578b09 --- /dev/null +++ b/Week_02/G20200343030533/LeetCode_236_533.c @@ -0,0 +1,16 @@ +// C版本的解决方法 +typedef struct TreeNode node; +struct TreeNode* lowestCommonAncestor(struct TreeNode* root, struct TreeNode* p, struct TreeNode* q) { + if ( root == NULL || root == p || root == q ){ + return root; + } + node *left = lowestCommonAncestor(root->left, p, q); + node *right = lowestCommonAncestor(root->right, p, q); + + if ( left != NULL && right != NULL) { + return root; + } + + return left != NULL ? left : right; + +} \ No newline at end of file diff --git a/Week_02/G20200343030533/LeetCode_236_533.cpp b/Week_02/G20200343030533/LeetCode_236_533.cpp new file mode 100644 index 00000000..3953ae76 --- /dev/null +++ b/Week_02/G20200343030533/LeetCode_236_533.cpp @@ -0,0 +1,21 @@ +// 236. 二叉树的最近公共祖先 +// https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-tree/ + +class Solution { +public: + TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) { + //如果当前节点为空, 或者是p,q的一个,返回该节点 + if( root == nullptr|| root == p || root == q){ + return root; + } + TreeNode *left = lowestCommonAncestor(root->left, p, q); + TreeNode *right = lowestCommonAncestor(root->right, p, q); + //在左右分别找到了p和q, 那么当前节点就是LCA + if ( left != nullptr && right != nullptr) { + return root; + } + // 否则说明,在一边上找到了p和q + return left != nullptr ? left : right; + + } +}; \ No newline at end of file diff --git a/Week_02/G20200343030533/LeetCode_242_533.cpp b/Week_02/G20200343030533/LeetCode_242_533.cpp new file mode 100644 index 00000000..f90254ab --- /dev/null +++ b/Week_02/G20200343030533/LeetCode_242_533.cpp @@ -0,0 +1,58 @@ +//方法1: 基于排序 +// 36ms +class Solution { +public: + bool isAnagram(string s, string t) { + if (s.size() != t.size()) return false; + sort(s.begin(), s.end()); //排序s + sort(t.begin(), t.end()); //排序t + + return s.compare(t) == 0; //如果完全相同,返回0 + + } +}; + +//方法2: 使用内置的unordered_map +// 16ms +class Solution { +public: + bool isAnagram(string s, string t) { + if (s.size() != t.size()) return false; + unordered_map hash_table; + for (int i = 0; i < s.size(); i++){ + hash_table[s[i]] += 1; + } + for (int i = 0; i < t.size(); i++){ + hash_table[t[i]] -= 1; + } + //遍历哈希表 + for(auto it = hash_table.begin(); it != hash_table.end(); ++it){ + if (it->second != 0 ) return false; + } + return true; + + + } +}; + + +//方法3: 根据map原理,利用数组实现 +// < 12ms, 最快是8ms +class Solution { +public: + bool isAnagram(string s, string t) { + if (s.size() != t.size()) return false; + char mytable[26] = {0}; + for ( int i = 0; i < s.size(); i++){ + mytable[ s[i] - 'a' ] += 1; + } + for ( int i = 0;i < t.size(); i++){ + mytable[ t[i] - 'a' ] -= 1; + } + for ( int i = 0; i< 26; i++){ + if (mytable[i] != 0) return false; + } + return true; + + } +}; diff --git a/Week_02/G20200343030533/LeetCode_589_533.cpp b/Week_02/G20200343030533/LeetCode_589_533.cpp new file mode 100644 index 00000000..d2a463cb --- /dev/null +++ b/Week_02/G20200343030533/LeetCode_589_533.cpp @@ -0,0 +1,18 @@ +// 589. N叉树的前序遍历 +// https://leetcode-cn.com/problems/n-ary-tree-preorder-traversal/submissions/ +class Solution { +public: + vector res; + void helper(Node *root){ + if (root == nullptr) return; + res.push_back(root->val); + vector children = root->children; + for( auto child : children){ + helper(child); + } + } + vector preorder(Node* root) { + helper(root); + return res; + } +}; \ No newline at end of file diff --git a/Week_02/G20200343030533/LeetCode_590_533.cpp b/Week_02/G20200343030533/LeetCode_590_533.cpp new file mode 100644 index 00000000..efda300e --- /dev/null +++ b/Week_02/G20200343030533/LeetCode_590_533.cpp @@ -0,0 +1,21 @@ +// 590. N叉树的后序遍历 +// https://leetcode-cn.com/problems/n-ary-tree-postorder-traversal/submissions/ + +// 方法1: 递归 +// 把原来的两行代码改成循环就行了 +class Solution { +public: + vector res; + void helper(Node *root){ + if (root == nullptr) return ; + vector children = root->children; + for( auto child : children){ + helper(child); + } + res.push_back(root->val); + } + vector postorder(Node* root) { + helper(root); + return res; + } +}; \ No newline at end of file diff --git a/Week_02/G20200343030533/NOTE.md b/Week_02/G20200343030533/NOTE.md index 50de3041..14867c2f 100644 --- a/Week_02/G20200343030533/NOTE.md +++ b/Week_02/G20200343030533/NOTE.md @@ -1 +1,184 @@ -学习笔记 \ No newline at end of file +# 学习笔记 + +## 哈希map和set + +map和set都分成两种,一种是有顺序,一种没有顺序。 + +对于有序map,内部元素通过key进行排序(a specific strict weak ordering criterion). 内部实现,**二叉搜索树** + +对于无序map(`unordered_map`),访问速度快于有序map. 内部元素根据他们的哈希值组织成buckets(桶),可以直接根据key进行访问。 + +map容器重载了操作符`[]`和`=`, 使得键值对的设置更加符合直觉,也更加方便。 + +set和map类似,只不过只存放key,不存放value。 + +调用例子 + +```cpp +std::unordered_map hash_table; //定义 +hash_table["张三"] = "年轻司机"; //设置key-value +hash_table["李四"] = "老司机"; //设置key-value +hash_table["张三"] ; //访问已有的结果 +hash_table["王五"] ; //访问不存在的元素,会新建一个元素,内容为空 +hash_table.count("张三"); //计数key +hash_table.find("张三") ;// 查找,如果找不到则返回hash_table.end() +``` + +### 242:有效的字母异位词 + +注意审题,例如这道题目 + +- 什么异位词 +- 是否大小写敏感 + +可能的解题方法 + +1. 暴力求解1,排序,判断是否相同 +1. 暴力求解2,哈希表,比较每个字母出现频次 + +类似的题目:49题 + +### 1:两数之和 + +最大误区: 题目只做一遍 + +好习惯: 收藏比较好的代码,整理成代码库 + +## 树 + +树的结构用于满足人类需求,例如递归树,状态树,决策树 + +二叉树的遍历,前序,中序,后序,相对于根的位置 + +树的循环比较麻烦,递归是更好的实现。 + +二叉搜索树,空树也是 + +- 左子树的所有节点都小于根 +- 右子树的所有节点都大于根 +- 依次类推,也就是重复性来源 + +二叉搜索树 Demo, + +常见操作 + +- 查询: O(log n) +- 插入: O(log n) +- 删除: O(log n): 如果是叶子节点,直接删除,如果不是,则找第一个大于待删除节点来替换掉要删除的节点。 + +最差的情况,退换成单链表 + +必须记住的代码 + +```python +def preOrder(self, root): + if root: + self.traverse_path.append(root.val) + self.preOrder(root.left) + self.preOrder(root.right) + +def inOrder(self, root): + if root: + self.inOrder(root.left) + self.traverse_path(root.val) + self.inOrder(root.right) + +def postOrder(self, root): + if root: + self.postOrder(root.left) + self.postOrder(root.right) + self.traverse_path(root.val) +``` + +### 题目 + +**一个误区**: 递归本身不存在效率低,效率差的问题,只要你的程序本身没有写残。递归相对于非递归,就在于递归需要额外开栈,因此在深度非常高的情况下,可能会差一些。但是目前编译器存在尾递归优化,可以认为递归和循环一样的效率。 + +题目用遍历做都不难,只要理解中序,前序,和后续的含义,也就是前中后是相对于根节点。 + +## 递归 + +递归本质就是循环,通过函数体来循环。 + +根本原因是 **汇编没有循环嵌套一说**, 比较常见的情况,就是不断跳到之前写的函数命令,循环汇编之后会递归其实差不多。 + +一层一层下降落,然后一层一层回来 + +函数参数和全局参数会在递归过程中会发生变化 + +代码模版 + +```java +public void recur(int level, int param) { + + // terminator + if (level > MAX_LEVEL) { + // process result + return; + } + + // process current logic + process(level, param); + + // drill down + recur( level: level + 1, newParam); + + // restore current status + ``` + +核心部分 + +- 终止条件 +- 当前层逻辑 +- 下探下一层 +- (可选)清理当前环境 + +思维要点: + +1. 不要人肉递归, 不要尝试绘制递归树 +1. 找到最近最简的方法,将其拆解成可重复解决的问题(最近子问题) +1. 数学归纳法思维 + +### 爬楼梯 + +在第三层的时候,不再是从头思考,而是从已有的结果出发,也就是从第二层和第三层出发 + +### 括号的生成 + +先思考参数应该如何设置,自顶向下编程 + +然后无脑写模版 + +第一种思路,先把所有可能都输出了,然后在return的时候,过滤结果 + +第二种思路,在中间过程中就把不合法的删除,规则是右括号小于等于左括号 + +为什么7行代码可以解决复杂的问题,因为人脑老是习惯暴力递归,而没有思考重复性。 + +### 验证二叉搜索树 + +方法1: 根据二叉搜索树定义 + +方法2: 中序遍历,输出有序数组 + +### 二叉树最大深度和最小深度 + +关键是叶子节点定义,最大深度肯定是探到底,因此最后的节点必然是叶子结点。但是对于最小深度,并不是最前面的节点就算是最小深度的节点了。比如下面这颗树,虽然9和20都算出来是2,但是20不符合要求,9才是需要的节点。 + +```bash + 3 + / \ + 9 20 + / + 15 +```` + +因此都为空,返回+1,一个为空一个不为空,发挥不为空节点后续+1; + +## 其他 + +Cpp的新的for循环: `for( auto str:strs )`. + +新建容器vector的一种方法`vect or vec(1, str)`, 结果是长度为1,默认为str的vector + +**算术基本定理**,又称为正整数的唯一分解定理,即:每个大于1的自然数,要么本身就是质数,要么可以写为2个以上的质数的积, diff --git a/Week_02/G20200343030535/LeetCode_589_535.java b/Week_02/G20200343030535/LeetCode_589_535.java new file mode 100644 index 00000000..91a85677 --- /dev/null +++ b/Week_02/G20200343030535/LeetCode_589_535.java @@ -0,0 +1,38 @@ +package G20200343030535; + +import java.util.ArrayList; +import java.util.List; + +public class LeetCode_589_535 { + + class Node { + public int val; + public List children; + + public Node() {} + + public Node(int _val) { + val = _val; + } + + public Node(int _val, List _children) { + val = _val; + children = _children; + } + } + + List res=new ArrayList(); + public List preorder(Node root) { + helper(root); + return res; + } + public void helper(Node root){ + if (root == null) return; + res.add(root.val); + for (int i = 0; i children; + + public Node() {} + + public Node(int _val) { + val = _val; + } + + public Node(int _val, List _children) { + val = _val; + children = _children; + } + } + + //递归: + public List postorder(LeetCode_589_535.Node root) { + List res = new ArrayList(); + if(root == null) return res; + helper(root,res); + return res; + } + + private void helper(LeetCode_589_535.Node root, List res) { + if(root == null) return; + for(LeetCode_589_535.Node node : root.children){ + helper(node,res); + } + res.add(root.val); + } + + +} diff --git a/Week_02/G20200343030537/LeetCode_144_537.py b/Week_02/G20200343030537/LeetCode_144_537.py new file mode 100644 index 00000000..6f10d568 --- /dev/null +++ b/Week_02/G20200343030537/LeetCode_144_537.py @@ -0,0 +1,45 @@ +# 给定一个二叉树,返回它的 前序 遍历。 +# +# 示例: +# +# 输入: [1,null,2,3] +# 1 +# \ +# 2 +# / +# 3 +# +# 输出: [1,2,3] +# +# +# 进阶: 递归算法很简单,你可以通过迭代算法完成吗? +# Related Topics 栈 树 + + +# leetcode submit region begin(Prohibit modification and deletion) +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution: + def preorderTraversal(self, root: TreeNode) -> List[int]: + if root is None: + return [] + + stack, output = [root, ], [] + + while stack: + root = stack.pop() + if root is not None: + output.append(root.val) + if root.right is not None: + stack.append(root.right) + if root.left is not None: + stack.append(root.left) + + return output + +# leetcode submit region end(Prohibit modification and deletion) diff --git a/Week_02/G20200343030537/LeetCode_49_537.py b/Week_02/G20200343030537/LeetCode_49_537.py new file mode 100644 index 00000000..1c1e0671 --- /dev/null +++ b/Week_02/G20200343030537/LeetCode_49_537.py @@ -0,0 +1,30 @@ +# 给定一个字符串数组,将字母异位词组合在一起。字母异位词指字母相同,但排列不同的字符串。 +# +# 示例: +# +# 输入: ["eat", "tea", "tan", "ate", "nat", "bat"], +# 输出: +# [ +# ["ate","eat","tea"], +# ["nat","tan"], +# ["bat"] +# ] +# +# 说明: +# +# +# 所有输入均为小写字母。 +# 不考虑答案输出的顺序。 +# +# Related Topics 哈希表 字符串 + + +# leetcode submit region begin(Prohibit modification and deletion) +class Solution: + def groupAnagrams(self, strs: List[str]) -> List[List[str]]: + res = collections.defaultdict(list) + for s in str s: + res[tuple(sorted(s))].append(s) + return res.values() + +# leetcode submit region end(Prohibit modification and deletion) diff --git a/Week_02/G20200343030537/LeetCode_77_537.py b/Week_02/G20200343030537/LeetCode_77_537.py new file mode 100644 index 00000000..60010f49 --- /dev/null +++ b/Week_02/G20200343030537/LeetCode_77_537.py @@ -0,0 +1,38 @@ +# 给定两个整数 n 和 k,返回 1 ... n 中所有可能的 k 个数的组合。 +# +# 示例: +# +# 输入: n = 4, k = 2 +# 输出: +# [ +# [2,4], +# [3,4], +# [2,3], +# [1,2], +# [1,3], +# [1,4], +# ] +# Related Topics 回溯算法 +from typing import List +# leetcode submit region begin(Prohibit modification and deletion) +class Solution: + def combine(self, n: int, k: int) -> List[List[int]]: + # 特判 + if n <= 0 or k <= 0 or k > n: + return [] + res = [] + self.__dfs(1, k, n, [], res) + return res + + def __dfs(self, start, k, n, pre, res): + if len(pre) == k: + res.append(pre[:]) + return + + # 注意:这里 i 的上限是归纳得到的 + for i in range(start, n - (k - len(pre)) + 2): + pre.append(i) + self.__dfs(i + 1, k, n, pre, res) + pre.pop() + +# leetcode submit region end(Prohibit modification and deletion) diff --git a/Week_02/G20200343030541/LeetCode_22_541.java b/Week_02/G20200343030541/LeetCode_22_541.java new file mode 100644 index 00000000..3251b471 --- /dev/null +++ b/Week_02/G20200343030541/LeetCode_22_541.java @@ -0,0 +1,29 @@ +import java.util.ArrayList; +import java.util.List; + +public class LeetCode_22_541 { + + public List generateParenthesis(int n) { + List resultList = new ArrayList<>(); + dfs(resultList, "", n, n); + return resultList; + } + + + public void dfs(List resultList, String str, int left, int right) { + //深度优先搜索,在末尾设置一个返回或者弹出的临界值,然后回溯。 + if (left == 0 && right == 0) { + resultList.add(str); + } + //考虑放入左括号,可以随意放入 + if (left > 0) { + dfs(resultList, str + '(', left - 1, right); + } + //不满足情况的例子都是因为右括号早于左括号放入,因此right必须在left之后放入 + if (right > left) { + dfs(resultList, str + ')', left, right - 1); + } + } + + +} diff --git a/Week_02/G20200343030541/LeetCode_98_541.java b/Week_02/G20200343030541/LeetCode_98_541.java new file mode 100644 index 00000000..db1b5f84 --- /dev/null +++ b/Week_02/G20200343030541/LeetCode_98_541.java @@ -0,0 +1,30 @@ +public class LeetCode_98_541 { + public boolean helper(TreeNode node, Integer lower, Integer upper) { + if (node == null) return true; + + int val = node.val; + if (lower != null && val <= lower) return false; + if (upper != null && val >= upper) return false; + + if (! helper(node.right, val, upper)) return false; + if (! helper(node.left, lower, val)) return false; + return true; + } + + public boolean isValidBST(TreeNode root) { + return helper(root, null, null); + } + + +} + + +class TreeNode { + int val; + TreeNode left; + TreeNode right; + + TreeNode(int x) { + val = x; + } +} \ No newline at end of file diff --git a/Week_02/G20200343030541/NOTE.md b/Week_02/G20200343030541/NOTE.md index 50de3041..5afa12ca 100644 --- a/Week_02/G20200343030541/NOTE.md +++ b/Week_02/G20200343030541/NOTE.md @@ -1 +1,26 @@ -学习笔记 \ No newline at end of file +## 【541-week 03】第三周总结 + +| S/N | Add Time | Leet Code Number | Name of questions | Link | Data Structure | Solution/Question Type | Hardness | Player1 Finish Date | Player2 Finish Date | Player1 Comment | Player2 Comment | Player1 Revised Date | Player2 Revised Date | +| ---- | -------- | ---------------- | ----------------------------------- | ------------------------------------------------------------ | ----------------------------------- | ---------------------- | -------- | ------------------- | ------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | -------------------- | -------------------- | +| 1 | 20200219 | 11 | Container With Most Water | [Container With Most Water](https://leetcode.com/problems/container-with-most-water/) | Array/List | Traversal | Medium | 20200219 | 20200219 | 思路:一维数组遍历 S1: 快慢双指针双重遍历 + 枚举 S2: 头指针+尾指针左右夹逼 | | | | +| 2 | 20200219 | 283 | Move Zeroes | [Move Zeroes](https://leetcode.com/problems/move-zeroes/) | Array/List | Traversal | Easy | 20200219 | 20200220 | "思路:一维数组遍历 S1: 两次遍历 S2: Pivod分成左右两边 | | | | +| 3 | 20200219 | 15 | 3Sum | [3Sum](https://leetcode.com/problems/3sum/) | Array/List | Traversal | Medium | 20200220 | | 思路:一维数组遍历 S1: 【禁忌】奥义之3重for循环 S2: HashMap保存重复结果 S3: 头指针+尾指针夹逼 | | | | +| 4 | 20200219 | 26 | Remove Duplicates From Sorted Array | [Remove Duplicates From Sorted Array](https://leetcode.com/problems/remove-duplicates-from-sorted-array/) | Array/List | Traversal | Easy | 20200220 | | 思路:一维数组遍历 S1: 快慢双指针将不重复元素移到数组左边 | | | | +| 5 | 20200219 | 189 | Rotate Array | [Rotate Array](https://leetcode.com/problems/rotate-array/) | Array/List | Traversal | Easy | 20200220 | 20200219 | | 1. Cyclic replacement 2. Reverse array | | | +| 6 | 20200219 | 21 | Merge Two Sorted Lists | [Merge Two Sorted Lists](https://leetcode.com/problems/merge-two-sorted-lists/) | LinkedList | Recursion | Easy | 20200220 | | | | | | +| 7 | 20200219 | 1 | Two Sum | [Two Sum](https://leetcode.com/problems/two-sum/) | Array/List | Traversal | Easy | 20200219 | | 思路:一维数组遍历 S1: 快慢双指针双重遍历 + 枚举 S2: HashMap | | | | +| 8 | 20200219 | 66 | Plus One | [Plus One](https://leetcode.com/problems/plus-one/) | Array/List | Traversal | Easy | | 20200219 | | | | | +| 9 | 20200219 | 22 | Generate Parenthese | [Generate Parenthese](https://leetcode.com/problems/generate-parentheses/) | Array/List | Traversal | Medium | | | | | | | +| 10 | 20200219 | 70 | Climbing Stairs | [Climbing Stairs](https://leetcode.com/problems/climbing-stairs/) | Array/List | Recursion | Easy | 20200219 | | 思路:找最近重复子问题 S1: 暴力Fibonacci递归 S2: 只保存3个值递归 | | | | +| 11 | 20200219 | 206 | Reverse Linked List | [Reverse Linked List](https://leetcode.com/problems/reverse-linked-list/) | LinkedList | Traversal | Easy | | | | | | | +| 12 | 20200219 | 24 | Swap Nodes in Pairs | [Swap Nodes in Pairs](https://leetcode.com/problems/swap-nodes-in-pairs/) | LinkedList | Traversal | Medium | | | | | | | +| 13 | 20200219 | 141 | Linked List Cycle | [Linked List Cycle](https://leetcode.com/problems/linked-list-cycle/) | LinkedList | Traversal | Easy | | | | | | | +| 14 | 20200219 | 142 | Linked List Cycle II | [Linked List Cycle II](https://leetcode.com/problems/linked-list-cycle-ii/) | LinkedList | Traversal | Medium | | | | | | | +| 15 | 20200219 | 25 | Reverse Nodes in k-Group | [Reverse Nodes in k-Group](https://leetcode.com/problems/reverse-nodes-in-k-group/) | LinkedList | Traversal | Hard | | | | | | | +| 16 | 20200219 | 20 | Valid Parentheses | [Valid Parentheses](https://leetcode.com/problems/valid-parentheses/) | Stack/Queue | Traversal | Easy | | | | | | | +| 17 | 20200219 | 155 | Min Stack | [Min Stack](https://leetcode.com/problems/min-stack/) | Stack/Queue | Traversal | Easy | | | | | | | +| 18 | 20200219 | 641 | Design Circular Deque | [Design Circular Deque](https://leetcode.com/problems/design-circular-deque/) | Stack/Queue | Traversal | Medium | | | | | | | +| 19 | 20200219 | 42 | Trapping Rain Water | [Trapping Rain Water](https://leetcode.com/problems/trapping-rain-water/) | Stack/Queue | Traversal | Hard | | 20200220 | | 1. 维护从左到右、从右到左的acceding队列,得到第i个位置左右两边最高的数值 2. 左右夹逼 | | | +| 20 | 20200220 | 560 | Subarray Sum Equals K | [Subarray Sum Equals K](https://leetcode.com/problems/subarray-sum-equals-k/) | Array/List | Traversal | Medium | | | | | | | +| 21 | 20200220 | 134 | Gas Station | [Gas Station](https://leetcode.com/problems/gas-station/) | Array/List | Traversal | Medium | | 20200220 | | time complexity O(n),遍历一遍数组 | | | +| 22 | 20200219 | 98 | Validate Binary Search Tree | [Validate Binary Search Tree](https://leetcode.com/problems/validate-binary-search-tree/) | Tree/Binary Tree/Binary Search Tree | Recursion | Medium | 20200223 | | | | | | \ No newline at end of file diff --git "a/Week_02/G20200343030543/HashMap\346\200\273\347\273\223" "b/Week_02/G20200343030543/HashMap\346\200\273\347\273\223" new file mode 100644 index 00000000..af69233b --- /dev/null +++ "b/Week_02/G20200343030543/HashMap\346\200\273\347\273\223" @@ -0,0 +1,28 @@ + JDK1.8 HashMap + + JDK1.8HashMap底层是由数组加链表以及红黑树实现的 + + 数组默认长度为16,扩容因子0.75f + + 当数组存储发生hash碰撞,碰撞的元素用链表存储 + + 链表长度为8时,添加第九个元素时,链表转为红黑树 + + 只有当数组长度大于64的时候才会进行转换,否则,就算链表长度大于8也不会转换 + + 当红黑节点数小于6的时候转换为链表形式 + HashMap添加方法: + 1.首先判断插入的key值是否为空,如果为空,因为HashMap允许存入空值,但是只能存储一个key为空的值,这个key-value存储到下标为0的位置 + 2.如果key不为空,就放到数组中,用hash值寻找下标,如果该位置为空,则在该位置添加该key-value + 3.如果该位置有值了,则发生了hash碰撞,需要先去红黑树中寻找,遍历,看是否为红黑树中的节点,如果存在,并且key也相等,则覆盖值 + 4.如果红黑树中也没有,则去链表中遍历寻找,找到了与之相等的节点以及key相等,则覆盖 + 5.如果没有找到,则在链表后面添加该key-value值 + + HashMap查找方法: + 如果key为空,则看看数组下标为0的key是否为空,如果为空就返回下标为0位置的value,如果不为零就返回null + 如果key不为空,先去数组里面遍历查找,如果存在就返回value + 如果数组里没有,就去红黑树里查找,判断该节点是否属于红黑树,如果有就返回value + 如果红黑树里也没有,就去链表中遍历查询,如果有就返回value + 如果链表中也没有,就返回null + + diff --git a/Week_02/G20200343030543/LeetCode_105_543.java b/Week_02/G20200343030543/LeetCode_105_543.java new file mode 100644 index 00000000..bf4e9a4f --- /dev/null +++ b/Week_02/G20200343030543/LeetCode_105_543.java @@ -0,0 +1,53 @@ +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; } + * } + */ +class Solution { + //前序遍历结果遍历指针 + int pre_idx = 0; + //左子树 + int[] preorder; + //右子树 + int[] inorder; + //存储中序遍历 + HashMap idx_map = new HashMap(); + + public TreeNode helper(int in_left,int in_right){ + if(in_left == in_right){ + return null; + } + //取出前序遍历的第一个元素(必为根) + int root_val = preorder[pre_idx]; + + TreeNode root = new TreeNode(root_val); + int index = idx_map.get(root_val); + //递归 + pre_idx++; + + //中序遍历分割左右子树 + root.left = helper(in_left,index); + root.right = helper(index + 1,in_right); + + + return root; + + + } + + + public TreeNode buildTree(int[] preorder, int[] inorder) { + this.preorder = preorder; + this.inorder = inorder; + + int index = 0; + for(Integer val : inorder){ + idx_map.put(val,index++); + } + return helper(0,preorder.length); + } +} \ No newline at end of file diff --git a/Week_02/G20200343030543/LeetCode_49_543.java b/Week_02/G20200343030543/LeetCode_49_543.java new file mode 100644 index 00000000..fc244fc1 --- /dev/null +++ b/Week_02/G20200343030543/LeetCode_49_543.java @@ -0,0 +1,18 @@ +class Solution { + public List> groupAnagrams(String[] strs) { + if(strs == null){ + return new ArrayList<>(); + } + Map> map = new HashMap<>(); + for(String str : strs){ + char[] ca = str.toCharArray(); + Arrays.sort(ca); + String key = String.valueOf(ca); + if(!map.containsKey(key)){ + map.put(key,new ArrayList<>()); + } + map.get(key).add(str); + } + return new ArrayList<>(map.values()); + } +} \ No newline at end of file diff --git a/Week_02/G20200343030543/NOTE.md b/Week_02/G20200343030543/NOTE.md index 50de3041..cc8b5a9c 100644 --- a/Week_02/G20200343030543/NOTE.md +++ b/Week_02/G20200343030543/NOTE.md @@ -1 +1,5 @@ -学习笔记 \ No newline at end of file +学习笔记 +经过第二周的学习,发现了自己好多以为知道,但实际不知道的地方。 +而且发现自己把知道当作了会,其实离掌握还有很远的距离。 +不能怂 希望自己能一个个攻破 +控制自己的畏难情绪 \ No newline at end of file diff --git a/Week_02/G20200343030545/LeetCode_105_545.py b/Week_02/G20200343030545/LeetCode_105_545.py new file mode 100644 index 00000000..9ef0f7ce --- /dev/null +++ b/Week_02/G20200343030545/LeetCode_105_545.py @@ -0,0 +1,49 @@ +""" + 根据一棵树的前序遍历与中序遍历构造二叉树。 + 注意: + 你可以假设树中没有重复的元素。 + + 例如,给出 + 前序遍历 preorder = [3,9,20,15,7] + 中序遍历 inorder = [9,3,15,20,7] + 返回如下的二叉树: + + 3 + / \ + 9 20 + / \ + 15 7 +""" +from typing import List + + +class TreeNode: + def __init__(self, x): + self.val = x + self.left = None + self.right = None + + +class Solution: + def buildTree(self, preorder: List[int], inorder: List[int]) -> TreeNode: + """ + 先序遍历 根左右 + 中序遍历 左根右 + """ + return self.recursive(preorder, inorder) + + @classmethod + def recursive(cls, preorder: List[int], inorder: List[int]) -> TreeNode: + """ + 时间复杂度:O(n),空间复杂度:O(n) + + """ + if len(inorder): + root = TreeNode(preorder[0]) + + mid = inorder.index(preorder[0]) + + root.left = cls.recursive(preorder[1:mid + 1], inorder[:mid]) + root.right = cls.recursive(preorder[mid + 1:], inorder[mid + 1:]) + + return root diff --git a/Week_02/G20200343030545/LeetCode_144_545.py b/Week_02/G20200343030545/LeetCode_144_545.py new file mode 100644 index 00000000..8a7a417c --- /dev/null +++ b/Week_02/G20200343030545/LeetCode_144_545.py @@ -0,0 +1,58 @@ +""" + 给定一个二叉树,返回它的 前序 遍历。 + 示例: + 输入: [1,null,2,3] + 1 + \ + 2 + / + 3 + 输出: [1,2,3] + 进阶: 递归算法很简单,你可以通过迭代算法完成吗? +""" +from typing import List + + +class TreeNode: + def __init__(self, x): + self.val = x + self.left = None + self.right = None + + +class Solution: + def preorderTraversal(self, root: TreeNode) -> List[int]: + """ + 前序遍历 根左右 + """ + res = [] + self.recursive(root, res) + return res + + @classmethod + def recursive(cls, root: TreeNode, res: List) -> None: + if root: + res.append(root.val) + cls.recursive(root.left, res) + cls.recursive(root.right, res) + + @classmethod + def use_stack(cls, root: TreeNode) -> List[int]: + """ + 使用栈 + 时间复杂度:O(n),空间复杂度:O(n) + """ + res = [] + + if root: + stack = [root] + + while stack: + cur = stack.pop() + res.append(cur.val) + if cur.right: # 先入栈 后弹出 + stack.append(cur.right) + + if cur.left: + stack.append(cur.left) + return res diff --git a/Week_02/G20200343030545/LeetCode_22_545.py b/Week_02/G20200343030545/LeetCode_22_545.py new file mode 100644 index 00000000..bf2d6269 --- /dev/null +++ b/Week_02/G20200343030545/LeetCode_22_545.py @@ -0,0 +1,49 @@ +""" + 给出 n 代表生成括号的对数,请你写出一个函数,使其能够生成所有可能的并且有效的括号组合。 + 例如,给出 n = 3,生成结果为: + [ + "((()))", + "(()())", + "(())()", + "()(())", + "()()()" + ] +""" +from typing import List + + +class Solution: + def generateParenthesis(self, n: int) -> List[str]: + res = [] + self.recursive(0, 0, n, "", res) + return res + + @classmethod + def recursive(cls, left: int, right: int, n: int, s: str, res: List): + """ + 写递归时, + 1。先写递归终止条件 + 2。 处理逻辑 + 3。 递归下沉 + 4。 处理临时状态 + + """ + # 1. terminator + if left == n and right == n: + res.append(s) + return + + # process current logic left right + # drill down + if left < n: + cls.recursive(left + 1, right, n, s + "(", res) + + if left > right: + cls.recursive(left, right + 1, n, s + ")", res) + + # reverse state + + +if __name__ == "__main__": + info = Solution().generateParenthesis(3) + print(info) diff --git a/Week_02/G20200343030545/LeetCode_236_545.py b/Week_02/G20200343030545/LeetCode_236_545.py new file mode 100644 index 00000000..bf916e2d --- /dev/null +++ b/Week_02/G20200343030545/LeetCode_236_545.py @@ -0,0 +1,95 @@ +""" + 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。 + 百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x, + 满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。” + + 例如,给定如下二叉树:  root = [3,5,1,6,2,0,8,null,null,7,4] + 示例 1: + 输入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1 + 输出: 3 + 解释: 节点 5 和节点 1 的最近公共祖先是节点 3。 + + 示例 2: + 输入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4 + 输出: 5 + 解释: 节点 5 和节点 4 的最近公共祖先是节点 5。因为根据定义最近公共祖先节点可以为节点本身。 + 说明: + + 所有节点的值都是唯一的。 + p、q 为不同节点且均存在于给定的二叉树中。 +""" + + +class TreeNode: + def __init__(self, x): + self.val = x + self.left = None + self.right = None + + +class Solution: + def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode': + return self.recursive(root, p, q) + + @classmethod + def use_hash(cls, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode': + """ + 使用哈希保存遍历过的节点 key是子节点,value是父节点 + 循环遍历只到p 和 q节点都出现在哈希表中。 + + 然后构建一个set(元素唯一), + 将p的祖宗这条线都加到set里 + + 然后遍历q,找到q的祖先在set中第一次出现的节点 + 就是最先公共祖先。 + 时间复杂度:O(n) 空间复杂度:O(n) + """ + hash_map = {root: None} + stack = [root] + + while p not in hash_map or q not in hash_map: + node = stack.pop() + + if node.left: + hash_map[node.left] = node + stack.append(node.left) + if node.right: + hash_map[node.right] = node + stack.append(node.right) + + set_ = set() + + while p: + set_.add(p) + p = hash_map[p] + + while q not in set_: + q = hash_map[q] + + return q + + @classmethod + def recursive(cls, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode': + """ + 时间复杂度:O(n),空间复杂度:O(n) + 如果root 或者root等于p或者q,直接返回root就行 + 然后递归下去, + 如果left为空,那只能在right上找 + 如果right为空,那只能在left上咋后 + 如果left right都为空,那直接返回空 + """ + + if not root or (root == p or root == q): + return root + + left = cls.recursive(root.left, p, q) + right = cls.recursive(root.right, p, q) + + if not left: + return right + + if not right: + return left + + if left and right: + return root diff --git a/Week_02/G20200343030545/LeetCode_242_545.py b/Week_02/G20200343030545/LeetCode_242_545.py new file mode 100644 index 00000000..de7ee9aa --- /dev/null +++ b/Week_02/G20200343030545/LeetCode_242_545.py @@ -0,0 +1,100 @@ +""" +给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。 + +示例 1: + +输入: s = "anagram", t = "nagaram" +输出: true +示例 2: + +输入: s = "rat", t = "car" +输出: false +说明: +你可以假设字符串只包含小写字母。 + +进阶: +如果输入字符串包含 unicode 字符怎么办?你能否调整你的解法来应对这种情况? +""" +import string + + +class Solution: + def isAnagram(self, s: str, t: str) -> bool: + pass + + @classmethod + def directly(cls, s: str, t: str) -> bool: + """ + 暴力求解法: + 对两个字符串分别进行排序,然后做等值判断。如果相等则说明是字母异位词。 + 时间复杂度:O(nlogn),空间复杂度:O(1) + 这个方法也适合unicode字符 + """ + return sorted(s) == sorted(t) + + @classmethod + def use_array(cls, s: str, t: str) -> bool: + """ + 使用列表,初始化一个有26个元素的且,每个元素的值都为0的列表。 + 1) + 1.1 循环遍历s,获取s中的元素。 + 1.2 计算出元素对应的ascii值,并且减去字母a的ascii码值。 + 1.3 得到的结果就是这个元素在初始化列表中的下标位置,然后该下标位置的值+1。 + 2) 和1)基本一样,只不过不同于1.3步,最后要对相应下标的值-1。 + 3) 遍历列表,如果列表中有元素的值大于1,直接返回False,否则返回True。 + + 时间复杂度:O(n),空间复杂度:O(1) + TODO:这中解法只适用于两个输入都是小写字母。 + """ + nums = [0] * 26 + # Step 1 + for s_one in s: + nums[ord(s_one) - ord('a')] += 1 + + # Step 2 + for t_one in t: + nums[ord(t_one) - ord('a')] -= 1 + + # Step 3 + for num in nums: + if num: + return False + return True + + @classmethod + def use_hash_1(cls, s: str, t: str) -> bool: + """ + 使用哈希表,3步遍历。 + 1)遍历s,输出s的每个元素到哈希表中。 + 如果该元素不存在,将该元素赋到哈希表中,并且赋予该元素在哈希表中的初始值为1。 + 如果该元素存在,更新该元素在哈希表中的值+1。 + 2)遍历t, 输出m的每个元素到哈希表中。 + 如果该元素不存在,将该元素赋到哈希表中,并且赋予该元素在哈希表中的初始值为1。 + 如果该元素存在,更新该元素在哈希表中的值-1。 + 3)遍历哈希表,如果哈希表中有元素对应的值大于1,直接返回False。循环遍历完后返回True。 + + 时间复杂度:O(n),空间复杂度:O(n) + + 这个方法也适合unicode字符 + """ + hash_map = {} + + # Step 1 + for s_one in s: + if s_one in hash_map: + hash_map[s_one] += 1 + else: + hash_map[s_one] = 1 + + # Step 2 + for t_one in t: + if t_one in hash_map: + hash_map[t_one] -= 1 + else: + hash_map[t_one] = 1 + + # Step 3 + for k, v in hash_map.items(): + if v: + return False + return True diff --git a/Week_02/G20200343030545/LeetCode_429_545.py b/Week_02/G20200343030545/LeetCode_429_545.py new file mode 100644 index 00000000..c52ede72 --- /dev/null +++ b/Week_02/G20200343030545/LeetCode_429_545.py @@ -0,0 +1,71 @@ +""" + 给定一个 N 叉树,返回其节点值的层序遍历。 (即从左到右,逐层遍历)。 + + 返回其层序遍历: + [ + [1], + [3,2,4], + [5,6] + ] +  + 说明: + 树的深度不会超过 1000。 + 树的节点总数不会超过 5000。 +""" + +from typing import List + + +class Node: + def __init__(self, val=None, children=None): + self.val = val + self.children = children + + +class Solution: + def levelOrder(self, root: Node) -> List[List[int]]: + return self.use_queue(root) + + @classmethod + def recursive(cls, root: Node) -> List[List[int]]: + """ + 递归 + 时间复杂度 O(n) + 空间复杂度 O(n) + """ + + def hand(node: Node, level) -> None: + if len(res) == level: + res.append([]) + res[level].append(node.val) + + for child in node.children: + hand(child, level + 1) + + res = [] + if root: + hand(root, 0) + + return res + + @classmethod + def use_queue(cls, root: Node) -> List[List[int]]: + """ + 使用queue保存当前层的节点。 + 时间复杂度是 O(nk) k为节点最多一层的数目,因为extend的时间复杂度是O(k) + 空间复杂度是 O(n) + """ + res = [] + if root: + queue = [root] + while queue: + tmp_queue = [] + tmp_res = [] + + for node in queue: # 每一次的循环都是一层 + if node: + tmp_res.append(node.val) + tmp_queue.extend(node.children) + queue = tmp_queue + res.append(tmp_res) + return res diff --git a/Week_02/G20200343030545/LeetCode_46_545.py b/Week_02/G20200343030545/LeetCode_46_545.py new file mode 100644 index 00000000..d2eb1389 --- /dev/null +++ b/Week_02/G20200343030545/LeetCode_46_545.py @@ -0,0 +1,42 @@ +""" + 给定一个没有重复数字的序列,返回其所有可能的全排列。 + 示例: + 输入: [1,2,3] + 输出: + [ + [1,2,3], + [1,3,2], + [2,1,3], + [2,3,1], + [3,1,2], + [3,2,1] + ] +""" +from typing import List + + +class Solution: + def permute(self, nums: List[int]) -> List[List[int]]: + """ + TODO: 背吧,没理解清楚,多练习几遍 + 时间复杂度: + 空间复杂度:O(N!) + """ + res = [] + if nums: + self.recursive(nums, res) + return res + + @classmethod + def recursive(cls, nums: List[int], res: List[List[int]], start: int = 0): + + # 递归的终止条件 + nums_len = len(nums) + if nums_len == start: + res.append(nums[:]) + + # 业务逻辑 + for index in range(start, nums_len): + nums[start], nums[index] = nums[start], nums[index] + cls.recursive(nums, res, start + 1) + nums[start], nums[index] = nums[start], nums[index] diff --git a/Week_02/G20200343030545/LeetCode_47_545.py b/Week_02/G20200343030545/LeetCode_47_545.py new file mode 100644 index 00000000..5f954ed8 --- /dev/null +++ b/Week_02/G20200343030545/LeetCode_47_545.py @@ -0,0 +1,52 @@ +""" + 给定一个可包含重复数字的序列,返回所有不重复的全排列。 + 示例: + 输入: + [1,1,2] + 输出: + [ + [1,1,2], + [1,2,1], + [2,1,1] + ] +""" +from typing import List + + +class Solution: + def permuteUnique(self, nums: List[int]) -> List[List[int]]: + # nums.sort() + res = [] + # self.recursive(nums, [], res) + # return res + res = [] + self.recursive_2(0, nums, res) + return res + + @classmethod + def recursive(cls, nums: List[int], tmp: List[int], res: List[List[int]]): + if not nums: + res.append(tmp) + return + + for i in range(len(nums)): + if i > 0 and nums[i] == nums[i - 1]: + continue + cls.recursive(nums[:i] + nums[i + 1:], tmp + [nums[i]], res) + + @classmethod + def recursive_2(cls, k: int, nums: List[int], res: List[List[int]]): + if k == len(nums): + res.append(nums[:]) + return + + for i in range(k, len(nums)): + if i != k and nums[i] == nums[k]: + continue + nums[i], nums[k] = nums[k], nums[i] + cls.recursive_2(k + 1, nums, res) + nums[i], nums[k] = nums[k], nums[i] + + +if __name__ == '__main__': + print(Solution().permuteUnique([1, 1, 2, 2])) diff --git a/Week_02/G20200343030545/LeetCode_49_545.py b/Week_02/G20200343030545/LeetCode_49_545.py new file mode 100644 index 00000000..a5e8ec96 --- /dev/null +++ b/Week_02/G20200343030545/LeetCode_49_545.py @@ -0,0 +1,74 @@ +""" + 给定一个字符串数组,将字母异位词组合在一起。字母异位词指字母相同,但排列不同的字符串。 + + 示例: + 输入: + ["eat", "tea", "tan", "ate", "nat", "bat"], + 输出: + [ + ["ate","eat","tea"], + ["nat","tan"], + ["bat"] + ] + 说明: + 所有输入均为小写字母。 + 不考虑答案输出的顺序。 +""" +from typing import List + + +class Solution: + def groupAnagrams(self, strs: List[str]) -> List[List[str]]: + return self.count_and_group(strs) + + @classmethod + def count_and_group(cls, strs: List[str]) -> List[List[str]]: + """ + 计数分类 两层循环 + 第一层循环: + 遍历输入列表 + 生成一个里面包含26个0的列表 + 执行完第二层循环后更新的列表,将其转为元祖,当成hash表的key + 如果key存在就更新对应的value,不存在就初始化一个列表,将value添加到列表中。 + 第二层循环: + 再遍历对应的元素: + 通过ord函数计算出字母对应的ascii码值, + 并且减去a的ascii码值,得到结果就是第一层循环里面列表中的下标,然后将下标的值+1。 + 时间复杂度:O(nk),空间复杂度:O(nk) + """ + hash_map = {} + for s in strs: + nums = [0] * 24 + for i in s: + nums[ord(i) - ord("a")] += 1 + nums_tuple = tuple(nums) + + if nums_tuple not in hash_map: + hash_map[nums_tuple] = [s] + else: + hash_map[nums_tuple].append(s) + return list(hash_map.values()) + + @classmethod + def sort_and_group(cls, strs: List[str]) -> List[List[str]]: + """ + 排序分组处理: + 1)遍历给定列表中的每一个字符串 + 2)将每个字符串排序得到一个有序列表,再将列表转换为元组。 + 3)判断元组是不是在哈希表中, + 3.1 如果不在将hash表中,则将元祖传入到哈希表中,并且给元祖对应的值初始化一个列表,将遍历得到的字符串插入到列表中。 + 3.2 如果在hash表中,将该字符串追加到对应的列表中。 + 4)输出哈希表中的所有值。 + 时间复杂度:O(nklogk) k为元素中最长字符串的长度 + 空间复杂度:O(nk) + """ + + hash_map = {} + + for s in strs: + sort_s = tuple(sorted(s)) + if sort_s not in hash_map: + hash_map[sort_s] = [s] + else: + hash_map[sort_s].append(s) + return list(hash_map.values()) diff --git a/Week_02/G20200343030545/LeetCode_589_454.py b/Week_02/G20200343030545/LeetCode_589_454.py new file mode 100644 index 00000000..9c79427a --- /dev/null +++ b/Week_02/G20200343030545/LeetCode_589_454.py @@ -0,0 +1,46 @@ +""" +给定一个 N 叉树,返回其节点值的前序遍历。 +""" +from typing import List + + +class Node: + def __init__(self, val=None, children=None): + self.val = val + self.children = children + + +class Solution: + def preorder(self, root: Node) -> List[int]: + res = [] + self.recursive(root, res) + return res + + @classmethod + def loop(cls, root: Node) -> List[int]: + """ + 前序遍历 根左右 + 迭代写法 + 时间复杂度:O(n),空间复杂度:O(n) + """ + res = [] + if root: + stack = [root] + while stack: + node = stack.pop() + res.append(node.val) + for node in reversed(node.children): # 反转 + stack.append(node) + + return res + + @classmethod + def recursive(cls, root: Node, res: List[int]): + """ + 递归写法 + 时间复杂度: O(n),空间复杂度:O(n) + """ + if root: + res.append(root.val) + for child in root.children: + cls.recursive(child, res) diff --git a/Week_02/G20200343030545/LeetCode_590_545.py b/Week_02/G20200343030545/LeetCode_590_545.py new file mode 100644 index 00000000..83f2bb2d --- /dev/null +++ b/Week_02/G20200343030545/LeetCode_590_545.py @@ -0,0 +1,51 @@ +""" + 给定一个 N 叉树,返回其节点值的后序遍历。 + 说明: 递归法很简单,你可以使用迭代法完成此题吗? +""" + +from typing import List + + +class Node: + def __init__(self, val=None, children=None): + self.val = val + self.children = children + + +class Solution: + def postorder(self, root: Node) -> List[int]: + """左右根""" + # return self.use_stack_and_reverse(root) + res = [] + self.recursive(root, res) + return res + + @classmethod + def recursive(cls, root: Node, res: List[int]): + """ + 递归的写法 + """ + if root: + for child in root.children: + cls.recursive(child, res) + res.append(root.val) + + @classmethod + def use_stack_and_reverse(cls, root: Node) -> List[int]: + """ + 循环实现。 + 后序遍历是左右根,可以先输入为根右左 然后反转一下就是左右根 + 时间复杂度O(n),空间复杂度O(n) + """ + + res = [] + if root: + + stack = [root] + while stack: + cur = stack.pop() + res.append(cur.val) + + for child in cur.children: + stack.append(child) + return res[::-1] diff --git a/Week_02/G20200343030545/LeetCode_77_545.py b/Week_02/G20200343030545/LeetCode_77_545.py new file mode 100644 index 00000000..8f301f91 --- /dev/null +++ b/Week_02/G20200343030545/LeetCode_77_545.py @@ -0,0 +1,69 @@ +""" + 给定两个整数 n 和 k,返回 1 ... n 中所有可能的 k 个数的组合。 + + 示例: + + 输入: n = 4, k = 2 + 输出: + [ + [2,4], + [3,4], + [2,3], + [1,2], + [1,3], + [1,4], + ] +""" + +from typing import List + + +class Solution: + def combine(self, n: int, k: int) -> List[List[int]]: + res = [] + if n > 0 and k <= n: + self.recursive(1, k, n, [], res) + + return res + + @classmethod + def recursive(cls, start: int, k: int, n: int, pre: List[int], res: List[List[int]]): + """ + 时间复杂度: O(kC k/n) 空间复杂度:O(C) + + """ + # 递归的终止条件 + if len(pre) == k: + res.append(pre[:]) + return + for i in range(start, n + 1): + # 业务逻辑 + pre.append(i) + + # 递归下沉 + cls.recursive(i + 1, k, n, pre, res) + + # 处理业务状态 FIXME 这里不太理解为什么要pop + pre.pop() + + @classmethod + def loop(cls, n, k): + """不理解 多练习几遍""" + # init first combination + nums = list(range(1, k + 1)) + [n + 1] + output, j = [], 0 + while j < k: + # add current combination + output.append(nums[:k]) + # increase first nums[j] by one + # if nums[j] + 1 != nums[j + 1] + j = 0 + while j < k and nums[j + 1] == nums[j] + 1: + nums[j] = j + 1 + j += 1 + nums[j] += 1 + return output + + +if __name__ == '__main__': + print(Solution.loop(4, 2)) diff --git a/Week_02/G20200343030545/LeetCode_94_545.py b/Week_02/G20200343030545/LeetCode_94_545.py new file mode 100644 index 00000000..793ebb89 --- /dev/null +++ b/Week_02/G20200343030545/LeetCode_94_545.py @@ -0,0 +1,64 @@ +""" + 给定一个二叉树,返回它的中序 遍历。 + 示例: + 输入: [1,null,2,3] + 1 + \ + 2 + / + 3 + + 输出: [1,3,2] + 进阶: 递归算法很简单,你可以通过迭代算法完成吗? +""" +from typing import List + + +# Definition for a binary tree node. +class TreeNode: + def __init__(self, x): + self.val = x + self.left = None + self.right = None + + +class Solution: + def inorderTraversal(self, root: TreeNode) -> List[int]: + """中序遍历左根右""" + res = [] + self.recursive(root, res) + return res + + @classmethod + def recursive(cls, root: TreeNode, res: List) -> None: + """ + 递归解法 固定套路 记住就行 + 时间复杂度:O(n),空间复杂度:O(logn) + + """ + if root: + cls.recursive(root.left, res) + res.append(root.val) + cls.recursive(root.right, res) + + @classmethod + def use_stack(cls, root: TreeNode, res: List) -> List[int]: + """ + 使用栈 + 遍历树,判断树是否有左子树,如果有,就依次压入栈中。 + 没有就从栈顶弹出节点,并且把节点的值输出到结果集里面。然后判断这个节点是否有右子树。 + 时间复杂度:O(n),空间复杂度:O(n) + """ + stack = [] + res = [] + + cur = root + + while cur or stack: + while cur: + stack.append(cur) + cur = cur.left + cur = stack.pop() + res.append(cur.val) + cur = cur.right + return res diff --git a/Week_02/G20200343030545/LeetCode_98_545.py b/Week_02/G20200343030545/LeetCode_98_545.py new file mode 100644 index 00000000..07de3f5d --- /dev/null +++ b/Week_02/G20200343030545/LeetCode_98_545.py @@ -0,0 +1,57 @@ +""" + 给定一个二叉树,判断其是否是一个有效的二叉搜索树。 + + 假设一个二叉搜索树具有如下特征: + + 节点的左子树只包含小于当前节点的数。 + 节点的右子树只包含大于当前节点的数。 + 所有左子树和右子树自身必须也是二叉搜索树。 +""" + + +class TreeNode: + def __init__(self, x): + self.val = x + self.left = None + self.right = None + + +class Solution: + def isValidBST(self, root: TreeNode) -> bool: + return self.recursive(root) + + @classmethod + def in_order_check(cls, root: TreeNode) -> bool: + stack = [] + check_value = float("-inf") + + while stack or root: + while root: + stack.append(root) + root = root.left + + node = root.pop() + + if node.val <= check_value: + return False + + check_value = root.val + root = root.right + + @classmethod + def recursive(cls, root: TreeNode, lower=float("-inf"), upper=float("inf")): + # 递归的终止条件 + if not root: + return True + + if not (lower < root.val < upper): + return False + + # 递归下沉 + if not cls.recursive(root.left, lower, root.val): + return False + + if not cls.recursive(root.right, root.val, upper): + return False + # 处理临时状态 + return True diff --git a/Week_02/G20200343030545/NOTE.md b/Week_02/G20200343030545/NOTE.md index 50de3041..67ba3ff2 100644 --- a/Week_02/G20200343030545/NOTE.md +++ b/Week_02/G20200343030545/NOTE.md @@ -1 +1,39 @@ -学习笔记 \ No newline at end of file +#学习笔记 + +##哈希表 +- 含义:```哈希表,也成散列表,是根据关键码值(Key Value)而直接访问的数据结构。``` + +- 详细:```通过把关键码值映射到表中的一个位置,以加快查找的速度。 +这个映射的函数称为哈希函数。存放记录的数组叫哈希表(散列表)。``` + +- 应用:```LRUCache、Redis``` + +- 哈希冲突:```当两个不同的输入值通过哈希函数计算出来了相同的关键码值的这种情况称为哈希冲突。``` + +- 哈希冲突解决: + 1. 链地址法:```链地址法的基本思想是,为每个 Hash 值建立一个单链表,当发生冲突时,将记录插入到链表中。``` + 2. 开放寻地法:```插入一个元素的时候,先通过哈希函数进行判断,若是发生哈希冲突,就以当前地址为基准,根据再寻址的方法(探查序列),去寻找下一个地址,若发生冲突再去寻找,直至找到一个为空的地址为止。``` + +- 算法题: + 1. 字母异位词分组:```循环遍历给定的字符串数组,取出的字母按照一定的规律(可以是排序,可以是根据字符串再循环计算出Key)生成一个固定的key,存放到哈希表中,最后输出结果。 ``` + +##树 +###二叉树 +- 遍历: + 1. 前序(Pre-Order):根左右 + 2. 中序(In-Order):左根右 + 3. 后序(Post-Order):左右根 + +###二叉搜索树 +- 定义:又称有序二叉树、排序二叉树,是指一个空的二叉树或者二叉树满足一下特性: + 1. 左子树上所有节点的值均小于它的根节点的值。 + 2. 右子树上所有节点的值均大于它的跟节点的值。 + 3. 左右子树分别为二叉搜索树。 + 中序遍历:升序遍历 + 时间复杂度:O(logn),最坏时间复杂度O(n) + +- 树的面试题解法一般都是递归,为什么? + ```递归和树很相似,递归就是不断生成下一个递归,树的话也是不断的扩展自己。``` + +##递归 +- 解释:递归本身就是一个循环体,只不过是循环调用本身。 \ No newline at end of file diff --git a/Week_02/G20200343030553/LeetCode_236_553.java b/Week_02/G20200343030553/LeetCode_236_553.java new file mode 100644 index 00000000..b3b418e5 --- /dev/null +++ b/Week_02/G20200343030553/LeetCode_236_553.java @@ -0,0 +1,33 @@ +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; } + * } + */ +class Solution { + TreeNode f; + public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { + help(root, p, q); + return f; + } + public boolean help(TreeNode root, TreeNode p, TreeNode q){ + if(root == null) + return false; + + int left = help(root.left, p, q) ? 1:0; + int right = help(root.right, p, q) ? 1:0; + + int mid = 0; + if(root == p || root ==q){ + mid = 1; + } + + if((mid+left+right)>=2) + f = root; + + return (mid + left + right)>0; + } +} \ No newline at end of file diff --git a/Week_02/G20200343030553/LeetCode_589_553.java b/Week_02/G20200343030553/LeetCode_589_553.java new file mode 100644 index 00000000..bc0cb1df --- /dev/null +++ b/Week_02/G20200343030553/LeetCode_589_553.java @@ -0,0 +1,33 @@ +/* +// Definition for a Node. +class Node { + public int val; + public List children; + + public Node() {} + + public Node(int _val) { + val = _val; + } + + public Node(int _val, List _children) { + val = _val; + children = _children; + } +}; +*/ +class Solution { + public List preorder(Node root) { + List list = new ArrayList<>(); + helper(root, list); + return list; + } + public void helper(Node root, List list){ + if(root!=null){ + list.add(root.val); + for(Node node:root.children){ + helper(node, list); + } + } + } +} \ No newline at end of file diff --git a/Week_02/G20200343030553/NOTE.md b/Week_02/G20200343030553/NOTE.md index 50de3041..2f8bfcf2 100644 --- a/Week_02/G20200343030553/NOTE.md +++ b/Week_02/G20200343030553/NOTE.md @@ -1 +1,49 @@ -学习笔记 \ No newline at end of file +学习笔记 + +###哈希表:利用数组下标随机访问的特性,通过哈希函数将数据映射到数组对应的下标。 + +哈希函数:hash(key),对应key值通过哈希函数计算得到散列值,mod数组长度,得到对应数组下标。 + +​ 哈希函数三点要求:1、得到散列值要为一个非负整数 2、当key1=key2是,对应hash值相同 3、当key1!=key2时,hash值不一定不同 + +装载因子:保证数组中有一定比例的空闲槽位 + +哈希冲突解决方法: + +1、开放寻址法:如果出现hash冲突则重新探测一个空闲位置 + +​ 线性探测、二次探测、双重散列 + +2、拉链法:利用链表,对于哈希冲突的数据,形成链表 + +###栈、队列:操作受限的线性结构 + +栈:先进后出 + +​ 实现:顺序栈(数组)、链式栈(链表) + +队列:先进先出 + +​ 实现:顺序队列(数组)、链式队列(链表) + +​ 循环队列 + +​ 阻塞队列:在队列基础上增加阻塞操作(生产者消费者模型) + +### 树 + +二叉树:只有左右两个节点的树 + +完全二叉树:叶子节点都在最低下两层,且最底叶子节点从左往右。 这样通过数组实现最省内存 + +满二叉树:叶子节点都在最底层,除了叶子节点,每个节点都有左右两个子节点。 + +二叉搜索树:树中的任意节点,其左子树的节点值都小于这个节点值,右子树节点值都大于这个节点值。 + +可以支持快速地查找最大节点和最小节点,中序遍历,可以有序的输出数据 + +平衡二叉搜索树:频繁的插入删除节点,可能导致左右子树不平衡,导致查询时间复杂度O(Logn)下降。通过平衡操作,实现二叉树左右子树节点平衡。 + +存储:数组和链表 + +二叉树的遍历:前序遍历,中序遍历,后序遍历 (根节点) \ No newline at end of file diff --git a/Week_02/G20200343030559/LeetCode_589_559.java b/Week_02/G20200343030559/LeetCode_589_559.java new file mode 100644 index 00000000..7110a920 --- /dev/null +++ b/Week_02/G20200343030559/LeetCode_589_559.java @@ -0,0 +1,38 @@ +package jc.demo.LeetCode; + +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; +class Node { + public int val; + public List children; + + public Node() {} + + public Node(int _val) { + val = _val; + } + + public Node(int _val, List _children) { + val = _val; + children = _children; + } +}; +public class LeetCode_589_559 { + public List preorder(Node root) { + List list = new ArrayList(); + Stack stack = new Stack(); + if (root==null){ + return list; + } + stack.push(root); + while (!stack.isEmpty()){ + Node node = stack.pop(); + list.add(node.val); + for(int i = node.children.size()-1;i>=0;i--){ + stack.add(node.children.get(i)); + } + } + return list; + } +} diff --git a/Week_02/G20200343030559/LeetCode_590_559.java b/Week_02/G20200343030559/LeetCode_590_559.java new file mode 100644 index 00000000..9381a582 --- /dev/null +++ b/Week_02/G20200343030559/LeetCode_590_559.java @@ -0,0 +1,40 @@ +package jc.demo.LeetCode; +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; + + +class Node { + public int val; + public List children; + + public Node() {} + + public Node(int _val) { + val = _val; + } + + public Node(int _val, List _children) { + val = _val; + children = _children; + } +}; +public class LeetCode_590_559 { + public List postorder(Node root) { + List list = new ArrayList(); + Stack stack = new Stack(); + if (root==null){ + return list; + } + stack.push(root); + while (!stack.isEmpty()){ + Node node = stack.pop(); + list.add(node.val); + for(int i = 0;i 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 new int[0]; + } +} */ +// @lc code=start +// 一遍哈希表 +// @data Feb 19 2020 +class Solution { + public int[] twoSum(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[] {i, map.get(complement)}; + map.put(nums[i], i); + } + return new int[0]; + } +} +// @lc code=end + diff --git a/Week_02/G20200343030561/Leetcode_046_561.java b/Week_02/G20200343030561/Leetcode_046_561.java new file mode 100644 index 00000000..aef064e6 --- /dev/null +++ b/Week_02/G20200343030561/Leetcode_046_561.java @@ -0,0 +1,37 @@ +import java.util.*; + +/* + * @lc app=leetcode.cn id=46 lang=java + * + * [46] 全排列 + */ + +// @lc code=start +class Solution { + List> res = new ArrayList<>(); + int l; + public List> permute(int[] nums) { + l = nums.length; + backtrace(0, new ArrayList() {{ for (int i : nums) add(i); }}); + return res; + } + + private void backtrace(int i, ArrayList nums) { + if (i == l) { + res.add(new ArrayList(nums)); + } + for (int j = i; j < l; j ++) { + backtrace(i+1, swap(nums, i, j)); + } + } + + public ArrayList swap (ArrayList arr, int i, int j) { + ArrayList newArr = new ArrayList(arr); + int tmp = newArr.get(i); + newArr.set(i, newArr.get(j)); + newArr.set(j, tmp); + return newArr; + } +} +// @lc code=end + diff --git a/Week_02/G20200343030561/Leetcode_047_561.java b/Week_02/G20200343030561/Leetcode_047_561.java new file mode 100644 index 00000000..e1d7e44e --- /dev/null +++ b/Week_02/G20200343030561/Leetcode_047_561.java @@ -0,0 +1,72 @@ +import java.util.*; +/* + * @lc app=leetcode.cn id=47 lang=java + * + * [47] 全排列 II + */ + +// @lc code=start +// swap backtrace +// 需去重 +// @date Feb 21 2020 +/* class Solution { + int l; + List> res = new ArrayList<>(); + public List> permuteUnique(int[] nums) { + l = nums.length; + backtrace(new ArrayList(){{for(int n:nums) add(n);}}, 0); + return res; + } + private void backtrace(ArrayList nums, int i) { + if (i == l && !used(nums)) + res.add(new ArrayList(nums)); + + for(int j = i; j < l; j ++) + backtrace(swap(nums, i, j), i + 1); + } + + private ArrayList swap(ArrayList arr, int i, int j) { + ArrayList newArr = new ArrayList<>(arr); + int temp = arr.get(i); + newArr.set(i, arr.get(j)); + newArr.set(j, temp); + return newArr; + } + + private boolean used(ArrayList arr) { + for(List a : res) + if(a.equals(arr)) return true; + return false; + } +} */ +// list add backtrace +// 需排序 +// @date Feb 22 2020 +class Solution { + List> res = new ArrayList<>(); + int l; + public List> permuteUnique(int[] nums) { + l = nums.length; + Arrays.sort(nums); + backtrace(nums, new ArrayList(), new boolean[l]); + return res; + } + private void backtrace(int[] nums, ArrayList list, boolean[] used){ + if (list.size() == l) { + res.add(new ArrayList(list)); + return; + } + for(int i = 0; i < l; i++) { + if (used[i]) continue; + if (i > 0 && nums[i] == nums[i -1] && !used[i - 1]) continue; + + used[i] = true; + list.add(nums[i]); + backtrace(nums, list, used); + used[i] = false; + list.remove(list.size() - 1); + } + } +} +// @lc code=end + diff --git a/Week_02/G20200343030561/Leetcode_049_561.java b/Week_02/G20200343030561/Leetcode_049_561.java new file mode 100644 index 00000000..5310667d --- /dev/null +++ b/Week_02/G20200343030561/Leetcode_049_561.java @@ -0,0 +1,24 @@ +import java.util.*; + +/* + * @lc app=leetcode.cn id=49 lang=java + * + * [49] 字母异位词分组 + */ + +// @lc code=start +class Solution { + public List> groupAnagrams(String[] strs) { + Map ans = new HashMap(); + for (String s: strs) { + char[] ch = s.toCharArray(); + Arrays.sort(ch); + String key = String.valueOf(ch); + if(!ans.containsKey(key)) ans.put(key, new ArrayList()); + ans.get(key).add(s); + } + return new ArrayList(ans.values()); + } +} +// @lc code=end + diff --git a/Week_02/G20200343030561/Leetcode_077_561.java b/Week_02/G20200343030561/Leetcode_077_561.java new file mode 100644 index 00000000..7debce4b --- /dev/null +++ b/Week_02/G20200343030561/Leetcode_077_561.java @@ -0,0 +1,34 @@ +import java.util.*; + +/* + * @lc app=leetcode.cn id=77 lang=java + * + * [77] 组合 + */ + +// @lc code=start +class Solution { + List> res; + public List> combine(int n, int k) { + res = new ArrayList<>(); + helper(new ArrayList(), n, k, 1); + return res; + } + private void helper(ArrayList kList, int n, int k, int i) { + if (kList.size() == k) { + ArrayList tmp = new ArrayList(); + for(int v: kList) + tmp.add(v); + res.add(tmp); + return; + } + + for(int j = i; j <= n; j++) { + kList.add(j); + helper(kList, n, k, j+1); + kList.remove(kList.size() - 1); + } + } +} +// @lc code=end + diff --git a/Week_02/G20200343030561/Leetcode_094_561.java b/Week_02/G20200343030561/Leetcode_094_561.java new file mode 100644 index 00000000..d352b0da --- /dev/null +++ b/Week_02/G20200343030561/Leetcode_094_561.java @@ -0,0 +1,33 @@ +/* + * @lc app=leetcode.cn id=94 lang=java + * + * [94] 二叉树的中序遍历 + */ + +// @lc code=start +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; } + * } + */ +class Solution { + public List inorderTraversal(TreeNode root) { + List ans = new ArrayList<>(); + inOrder(root, ans); + return ans; + } + + public void inOrder(TreeNode root, List ans) { + if (root == null) return; + if (root.left != null) inOrder(root.left, ans); + ans.add(root.val); + if (root.right != null) inOrder(root.right, ans); + + } +} +// @lc code=end + diff --git a/Week_02/G20200343030561/Leetcode_105_561.java b/Week_02/G20200343030561/Leetcode_105_561.java new file mode 100644 index 00000000..d821983e --- /dev/null +++ b/Week_02/G20200343030561/Leetcode_105_561.java @@ -0,0 +1,42 @@ +/* + * @lc app=leetcode.cn id=105 lang=java + * + * [105] 从前序与中序遍历序列构造二叉树 + */ + +// @lc code=start +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; } + * } + */ +class Solution { + public TreeNode buildTree(int[] preorder, int[] inorder) { + if(preorder.length == 0) return null; + TreeNode root = new TreeNode(preorder[0]); + int i = 0; + for(int val: inorder) { + if (val == preorder[0]) break; + i ++; + } + root.left = buildTree(buildArr(preorder, 1, i+1), buildArr(inorder, 0, i)); + root.right = buildTree(buildArr(preorder, i+1, preorder.length), buildArr(inorder, i+1, inorder.length)); + return root; + } + + public int[] buildArr(int[] arr, int fromIdx, int toIdx){ + if (toIdx - fromIdx <= 0) return new int[0]; + int[] ints = new int[toIdx - fromIdx]; + for (int i = fromIdx; i < toIdx; i++) { + ints[i - fromIdx] = arr[i]; + } + return ints; + } + +} +// @lc code=end + diff --git a/Week_02/G20200343030561/Leetcode_144_561.java b/Week_02/G20200343030561/Leetcode_144_561.java new file mode 100644 index 00000000..379e4f16 --- /dev/null +++ b/Week_02/G20200343030561/Leetcode_144_561.java @@ -0,0 +1,32 @@ +/* + * @lc app=leetcode.cn id=144 lang=java + * + * [144] 二叉树的前序遍历 + */ + +// @lc code=start +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; } + * } + */ +class Solution { + public List preorderTraversal(TreeNode root) { + List ans = new ArrayList<>(); + preOrder(root, ans); + return ans; + } + + public void preOrder(TreeNode root, List ans) { + if (root == null) return ; + ans.add(root.val); + if (root.left != null) preOrder(root.left, ans); + if (root.right != null) preOrder(root.right, ans); + } +} +// @lc code=end + diff --git a/Week_02/G20200343030561/Leetcode_145_561.java b/Week_02/G20200343030561/Leetcode_145_561.java new file mode 100644 index 00000000..b7904fed --- /dev/null +++ b/Week_02/G20200343030561/Leetcode_145_561.java @@ -0,0 +1,34 @@ +import java.util.ArrayList; + +/* + * @lc app=leetcode.cn id=145 lang=java + * + * [145] 二叉树的后序遍历 + */ + +// @lc code=start +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; } + * } + */ +class Solution { + public List postorderTraversal(TreeNode root) { + List ans = new ArrayList<>(); + postOrder(root, ans); + return ans; + } + + public void postOrder(TreeNode root, List ans) { + if (root == null) return; + if (root.left != null) postOrder(root.left, ans); + if (root.right != null) postOrder(root.right, ans); + ans.add(root.val); + } +} +// @lc code=end + diff --git a/Week_02/G20200343030561/Leetcode_236_561.java b/Week_02/G20200343030561/Leetcode_236_561.java new file mode 100644 index 00000000..7c0b6fb2 --- /dev/null +++ b/Week_02/G20200343030561/Leetcode_236_561.java @@ -0,0 +1,36 @@ +/* + * @lc app=leetcode.cn id=236 lang=java + * + * [236] 二叉树的最近公共祖先 + */ + +// @lc code=start +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; } + * } + */ +// @date Feb 21 2020 +class Solution { + public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { + //recursion + if (root == null) return null; + if (root == q) return q; + if (root == p) return p; + //process logic + //drill down + TreeNode left = lowestCommonAncestor(root.left, p, q); + TreeNode right = lowestCommonAncestor(root.right, p, q); + + if (left == null) return right; + if (right == null) return left; + return root; + //reverse status + } +} +// @lc code=end + diff --git a/Week_02/G20200343030561/Leetcode_242_561.java b/Week_02/G20200343030561/Leetcode_242_561.java new file mode 100644 index 00000000..c217f981 --- /dev/null +++ b/Week_02/G20200343030561/Leetcode_242_561.java @@ -0,0 +1,25 @@ +/* + * @lc app=leetcode.cn id=242 lang=java + * + * [242] 有效的字母异位词 + */ + +// @lc code=start +class Solution { + public boolean isAnagram(String s, String t) { + if (s.length() != t.length()) return false; + int [] counter = new int[26]; + for (int i = 0; i < s.length(); i ++) { + counter[s.charAt(i) - 'a'] ++; + counter[t.charAt(i) - 'a'] --; + } + + for(int ch : counter) { + if (ch != 0) + return false; + } + return true; + } +} +// @lc code=end + diff --git a/Week_02/G20200343030561/Leetcode_429_561.java b/Week_02/G20200343030561/Leetcode_429_561.java new file mode 100644 index 00000000..1d3fbe83 --- /dev/null +++ b/Week_02/G20200343030561/Leetcode_429_561.java @@ -0,0 +1,47 @@ +/* + * @lc app=leetcode.cn id=429 lang=java + * + * [429] N叉树的层序遍历 + */ + +// @lc code=start +/* +// Definition for a Node. +class Node { + public int val; + public List children; + + public Node() {} + + public Node(int _val) { + val = _val; + } + + public Node(int _val, List _children) { + val = _val; + children = _children; + } +}; +*/ +// @date Feb 20 2020 +class Solution { + public List> levelOrder(Node root) { + List> ans = new ArrayList<>(); + if (root == null) return ans; + Queue q = new LinkedList<>(); + q.add(root); + while(!q.isEmpty()) { + List l = new ArrayList<>(); + int size = q.size(); + for (int i = 0; i < size; i ++) { + Node n = q.poll(); + l.add(n.val); + q.addAll(n.children); + } + ans.add(l); + } + return ans; + } +} +// @lc code=end + diff --git a/Week_02/G20200343030561/Leetcode_589_561.java b/Week_02/G20200343030561/Leetcode_589_561.java new file mode 100644 index 00000000..510c0918 --- /dev/null +++ b/Week_02/G20200343030561/Leetcode_589_561.java @@ -0,0 +1,46 @@ +import java.util.List; + +import org.w3c.dom.Node; + +/* + * @lc app=leetcode.cn id=589 lang=java + * + * [589] N叉树的前序遍历 + */ + +// @lc code=start +/* +// Definition for a Node. +class Node { + public int val; + public List children; + + public Node() {} + + public Node(int _val) { + val = _val; + } + + public Node(int _val, List _children) { + val = _val; + children = _children; + } +}; +*/ +class Solution { + public List preorder(Node root) { + List ans = new ArrayList (); + preOrder(root, ans); + return ans; + } + + public void preOrder(Node root, List ans) { + if (root == null) return; + ans.add(root.val); + if (root.children.size() == 0) return; + for (Node child : root.children) + preOrder(child, ans); + } +} +// @lc code=end + diff --git a/Week_02/G20200343030561/Leetcode_590_561.java b/Week_02/G20200343030561/Leetcode_590_561.java new file mode 100644 index 00000000..b67dfb1b --- /dev/null +++ b/Week_02/G20200343030561/Leetcode_590_561.java @@ -0,0 +1,43 @@ +/* + * @lc app=leetcode.cn id=590 lang=java + * + * [590] N叉树的后序遍历 + */ + +// @lc code=start +/* +// Definition for a Node. +class Node { + public int val; + public List children; + + public Node() {} + + public Node(int _val) { + val = _val; + } + + public Node(int _val, List _children) { + val = _val; + children = _children; + } +}; +*/ +class Solution { + public List postorder(Node root) { + List ans = new ArrayList<> (); + postOrder(root, ans); + return ans; + } + public void postOrder (Node root, List ans) { + if (root == null) return; + if (root.children.size() !=0 ) { + for (Node child : root.children) { + postOrder(child, ans); + } + } + ans.add(root.val); + } +} +// @lc code=end + diff --git a/Week_02/G20200343030561/NOTE.md b/Week_02/G20200343030561/NOTE.md deleted file mode 100644 index 50de3041..00000000 --- a/Week_02/G20200343030561/NOTE.md +++ /dev/null @@ -1 +0,0 @@ -学习笔记 \ No newline at end of file diff --git a/Week_02/G20200343030561/NOTE.org b/Week_02/G20200343030561/NOTE.org new file mode 100644 index 00000000..a60df060 --- /dev/null +++ b/Week_02/G20200343030561/NOTE.org @@ -0,0 +1,52 @@ +* 源码分析 +** HashMap +*** 构造函数 +*DEFAULT_LOAD_FACTOR* 默认的最大装载因子 0.75 +*table* Node[] 存储方式为 *数组* ,涉及数组的容量 +*DEFAULT_INITIAL_CAPACITY* 数组的初始容量 +*MAXIMUM_CAPACITY* 数组的最大容量 +*putMapEntries* 当参数是map的时候调用该函数,函数内设定capacity与loadFactor,循环调用putVal存储数据 +*** 增&改 +*put* 调用hash方法并做为参数传入putVal +*hash* 返回key的hashCode高16位异或低16位(h >>> 16) +*putVal* (n-1)&hash为数组下标,p为数组中当前元素。 +如果p为空,将Node赋值给p +如果p不为空,且p.key与key相同,返回旧值 +如果p不为空,且p.key与key不同,且p为TreeNode,则在TreeNode上增加p +如果p不为空,且p.key与key不同,且p不为TreeNode,则在链表上增加p +当增加后链表的长度大于8,调用treeifyBin +*n-1 bitwise hash* 保证小于n,且与hash低位相同(hash低位 & 111111111),且效率远小于找最小hash再求差的方法,也小于模n取余的方法。 +*resize* 将数组大小翻倍,保证恒为2的幂(也保证了上述中n-1的低位都是1),并将数组拷贝 +*treeifyBin* 先判断是否是table太小,太小则直接resize()。循环调用replacementTreeNode将bin替换为TreeNode结构 +*replacementTreeNode* new TreeNode +*** 删 +*remove* 调用removeNode,返回 Node.value +*removeNode* 将table中的值(table[(n-1)&hash])赋给p +如果p的值就是目标,将p的值赋给node +如果p的值不是目标,但p.next不为空,且p为TreeNode,将getTreeNode赋给node +如果p的值不是目标,但p.next不为空,且p不为TreeNode,遍历链表将值赋给node,此时p的值为链表上一节点的值 +如果node是TreeNode,调用node.removeTreeNode +如果node等于p,将node.next赋给table的值(table[(n-1)&hash]) +如果不满足上述两个条件,将node.next赋给p.next(此时p的值为链表上一节点的值) +返回 node +其它情况返回 null +*** 查 +*get* 调用getNode,返回 Node.value +*getNode* 将table中的值(table[(n-1)&hash])赋给first +如果first的值就是目标,返回first +如果first.next不为空,且first为TreeNode,调用getTreeNode并返回 +如果first.next不为空,且first不为TreeNode,循环链表找到后返回 +上述条件都不满足,返回空 +*** 遍历 +*entrySet* new EntrySet +*Entry.iterator* new EntryIterator +*EntryIterator.next* HashIterator.nextNode +*HashIterator* next=current=null,从i=0开始遍历table直到找到第一个不为空的值并赋给next +*HashIterator.nextNode* e=next,current=e,next=current.next +如果next为空,继续从i遍历table直到找到下一个不为空的值并赋给next +返回e +* 学习总结 +- Java基本功还是差,也是Java这门语言太繁琐了,在ArrayList与int[]上浪费好多时间。 +- 递归(包括回溯)是有套路的,还是熟能生巧的问题。 +- 递归(包括回溯)本身就是以tree的方式思考。 +- 越底层的代码越需要位运算,(n - 1) & hash 真涨见识,我自愧写不出来。 diff --git a/Week_02/G20200343030567/LeetCode_589_567.java b/Week_02/G20200343030567/LeetCode_589_567.java new file mode 100644 index 00000000..af9816d0 --- /dev/null +++ b/Week_02/G20200343030567/LeetCode_589_567.java @@ -0,0 +1,41 @@ +public class Preorder { + + /** + * 解题思路: + * 1、递归实现前续遍历 + * 2、迭代法完成此题 + * + * 前序遍历:根左右 + * 中序遍历:左根右 + * 后序遍历:左右根 + * ps: 前中后指的是根的遍历位置,这样就好记了 + * + * @param root + * @return + */ + public List preorder(Node root) { + LinkedList ret = new LinkedList<>(); + + // 1 recursion terminator + if (Objects.isNull(root)) { + return ret; + } + if (Objects.isNull(root.children) || root.children.isEmpty()) { + ret.add(root.val); + return ret; + } + + // 2 process logic in current level + + // 3 drill down + // 根左右 + ret.add(root.val); + for (Node node : root.children) { + ret.addAll(preorder(node)); + } + + // 4 reverse the current level status if needed + return ret; + } + +} diff --git a/Week_02/G20200343030567/LeetCode_590_567.java b/Week_02/G20200343030567/LeetCode_590_567.java new file mode 100644 index 00000000..724310ab --- /dev/null +++ b/Week_02/G20200343030567/LeetCode_590_567.java @@ -0,0 +1,73 @@ +public class Postorder { + + /** + * 解题思路: + * 1、递归实现后续遍历 + * 2、迭代法完成此题 + * + * 前序遍历:根左右 + * 中序遍历:左根右 + * 后序遍历:左右根 + * ps: 前中后指的是根的遍历位置,这样就好记了 + * + * @param root + * @return + */ + public List postorder(Node root) { + LinkedList ret = new LinkedList<>(); + + // 1 recursion terminator + if (Objects.isNull(root)) { + return ret; + } + if (Objects.isNull(root.children) || root.children.isEmpty()) { + ret.add(root.val); + return ret; + } + + // 2 process logic in current level + + // 3 drill down + // 左右根 + for (Node node : root.children) { + ret.addAll(postorder(node)); + } + ret.add(root.val); + + // 4 reverse the current level status if needed + return ret; + } + + /** + * 迭代法常见套路,反向顺序处理 + * + * @param root + * @return + */ + public List postorderLoop(Node root) { + LinkedList ret = new LinkedList<>(); + + // 1 recursion terminator + if (Objects.isNull(root)) { + return ret; + } + if (Objects.isNull(root.children) || root.children.isEmpty()) { + ret.add(root.val); + return ret; + } + + LinkedList deque = new LinkedList<>(); + // 左右根 --> 根右左 + deque.push(root); + while (!deque.isEmpty()) { + Node current = deque.pollFirst(); + ret.push(current.val); + for (Node node : current.children) { + deque.push(node); + } + } + + return ret; + } + +} \ No newline at end of file diff --git a/Week_02/G20200343030567/NOTE.md b/Week_02/G20200343030567/NOTE.md index 50de3041..8ea27026 100644 --- a/Week_02/G20200343030567/NOTE.md +++ b/Week_02/G20200343030567/NOTE.md @@ -1 +1,68 @@ -学习笔记 \ No newline at end of file +学习笔记 + +## 笔记 + +复杂的问题都会归结为找重复性 + +1、优化的思想 +升维 +空间换时间 +2、解题最大误区 +只做一遍 +3、懵逼的时候: +3.1 能不能暴力 +3.2 基本情况罗列 递推,数学归纳法 +3.3 找最近重复子问题 +代码本质就三部分 +if else switch +while loop +递归 +4、什么时候可以用栈来解决 +最近相关性,最外层是一对、最内层是一对,类似洋葱的结构 +先来后到 +5、四件套 +沟通清楚题目 +列举所有可能性 +编码 +测试代码 +6、数和图的最大差别就是有没有环 +链表是特殊化的树、树是特殊化的图 +7、二叉搜索树 +查询到的位置,就是需要插入的位置 +8、递归结构模板 +8.1 递归终结条件 recursion terminator +8.2 处理当前层逻辑 process logic in current level +8.3 下探到下一层 drill down +8.4 清理当前层 reverse the current level status if needed +9、递归要点 +9.1 不要人肉进行递归(最大误区) +9.2 找最近重复子问题 +9.3 数学归纳法 +mutual exclusive, complete exhaustive + + +## 散列表 + +散列表: +1、散列表用的是数组支持按照下标随机访问数据的特性,所以散列表其实就是数组的一种扩展,由数组演化而来。可以说,如果没有数组,就没有散列表。 +参赛编号转化为数组下标的映射方法就叫作散列函数(或“Hash 函数”“哈希函数”),而散列函数计算得到的值就叫作散列值(或“Hash 值”“哈希值”) +2、三点散列函数设计的基本要求: +2.1 散列函数计算得到的散列值是一个非负整数; +2.2 如果 key1 = key2,那 hash(key1) == hash(key2); +2.3 如果 key1 ≠ key2,那 hash(key1) ≠ hash(key2)。 +3、哈希算法 +MD5、SHA、CRC +4、散列冲突 +开放寻址法(open addressing)和链表法(chaining) +5、开放寻址法 +核心思想是,如果出现了散列冲突,我们就重新探测一个空闲位置,将其插入 +线性探测(Linear Probing)二次探测(Quadratic probing)和双重散列(Double hashing) +散列表的装载因子=填入表中的元素个数/散列表的长度 +装载因子越大,说明空闲位置越少,冲突越多,散列表的性能会下降。 +6、链表法 +每个“桶(bucket)”或者“槽(slot)”会对应一条链表,所有散列值相同的元素我们都放到相同槽位对应的链表中 +7、Word 文档中单词拼写检查功能是如何实现的? +常用的英文单词有 20 万个左右,假设单词的平均长度是 10 个字母,平均一个单词占用 10 个字节的内存空间,那 20 万英文单词大约占 2MB 的存储空间,就算放大 10 倍也就是 20MB。对于现在的计算机来说,这个大小完全可以放在内存里面。所以我们可以用散列表来存储整个英文单词词典。 +当用户输入某个英文单词时,我们拿用户输入的单词去散列表中查找。如果查到,则说明拼写正确;如果没有查到,则说明拼写可能有误,给予提示。借助散列表这种数据结构,我们就可以轻松实现快速判断是否存在拼写错误。 + + diff --git a/Week_02/G20200343030569/LeetCode_105_569.java b/Week_02/G20200343030569/LeetCode_105_569.java new file mode 100644 index 00000000..de6cbd81 --- /dev/null +++ b/Week_02/G20200343030569/LeetCode_105_569.java @@ -0,0 +1,50 @@ +public class LeetCode_105_569 { + + public static void main(String[] args) { + int[] preorder = {3,9,20,15,7}; + int[] inorder = {9,3,15,20,7}; + TreeNode root = new LeetCode_105_569().new Solution().buildTree(preorder, inorder); + System.out.println( root.val ); + } + + public class TreeNode { + int val; + TreeNode left; + TreeNode right; + TreeNode(int x) { val = x; } + } + + class Solution { + public TreeNode buildTree(int[] preorder, int[] inorder) { + return recurseBuildTree(preorder, inorder); + } + + TreeNode recurseBuildTree(int[] preorder, int[] inorder ) + { + if( preorder.length == 0 ) + return null; + TreeNode root = new TreeNode(preorder[0]); + int idx = arraySearch(inorder, preorder[0]); + root.left = recurseBuildTree(subArray(preorder,1,idx),subArray(inorder,0,idx)); + root.right = recurseBuildTree(subArray(preorder,idx+1,preorder.length-idx-1),subArray(inorder,idx+1,inorder.length-idx-1)); + return root; + } + + int[] subArray( int[] a, int begin, int length ) + { + if( a.length < length+begin ) + return new int[0]; + int[] sub = new int[length]; + System.arraycopy(a, begin, sub, 0, length); + return sub; + } + + int arraySearch( int[] a, int key ) { + for ( int i = 0; i < a.length; i++ ) { + if ( a[i] == key ) + return i; + } + return -1; + } + } +} diff --git a/Week_02/G20200343030569/LeetCode_144_569.java b/Week_02/G20200343030569/LeetCode_144_569.java new file mode 100644 index 00000000..b12ff87f --- /dev/null +++ b/Week_02/G20200343030569/LeetCode_144_569.java @@ -0,0 +1,65 @@ +import java.util.LinkedList; +import java.util.List; +import java.util.Stack; + +/* + * 144. Binary Tree Preorder Traversal + * 二叉树的前序遍历 + */ +public class LeetCode_144_569 { + int index; + + TreeNode buildTreeNode(Integer data[]){ + if( index >= data.length ) + return null; + Integer value = data[index++]; + TreeNode node = null; + if ( value != null ) { + node = new TreeNode(value); + node.left = buildTreeNode(data); + node.right = buildTreeNode(data); + } + return node; + } + + public static void main(String[] args) { + // TODO Auto-generated method stub + //输入: [1,null,2,3] + Integer[] treeData = { 1, null, 2, 3 }; + LeetCode_144_569 main = new LeetCode_144_569(); + TreeNode node = main.buildTreeNode(treeData); + + List result = main.new Solution().preorderTraversal(node); + for(Integer v: result) + System.out.println(v); + } + + + + public class TreeNode { + int val; + TreeNode left; + TreeNode right; + TreeNode(int x) { val = x; } + } + + class Solution { + public List preorderTraversal(TreeNode root) { + List result = new LinkedList(); + Stack stack = new Stack(); + if ( root == null ) + return result; + stack.push(root); + while ( !stack.isEmpty() ) { + TreeNode node = stack.pop(); + result.add( node.val ); + if ( node.right != null ) + stack.push( node.right ); + if ( node.left != null ) + stack.push( node.left ); + } + + return result; + } + } +} diff --git a/Week_02/G20200343030569/LeetCode_145_569.java b/Week_02/G20200343030569/LeetCode_145_569.java new file mode 100644 index 00000000..75384291 --- /dev/null +++ b/Week_02/G20200343030569/LeetCode_145_569.java @@ -0,0 +1,67 @@ +import java.util.LinkedList; +import java.util.List; +import java.util.Stack; + + + +/* + * 145. Binary Tree Postorder Traversal + * 二叉树的后序遍历 + */ +public class LeetCode_145_569 { + int index; + + TreeNode buildTreeNode(Integer data[]){ + if( index >= data.length ) + return null; + Integer value = data[index++]; + TreeNode node = null; + if ( value != null ) { + node = new TreeNode(value); + node.left = buildTreeNode(data); + node.right = buildTreeNode(data); + } + return node; + } + + public static void main(String[] args) { + // TODO Auto-generated method stub + //输入: [1,null,2,3] + Integer[] treeData = { 1, null, 2, 3 }; + LeetCode_145_569 main = new LeetCode_145_569(); + TreeNode node = main.buildTreeNode(treeData); + + List result = main.new Solution().postorderTraversal(node); + for(Integer v: result) + System.out.println(v); + } + + + + public class TreeNode { + int val; + TreeNode left; + TreeNode right; + TreeNode(int x) { val = x; } + } + + class Solution { + public List postorderTraversal(TreeNode root) { + LinkedList result = new LinkedList(); + Stack stack = new Stack(); + if ( root == null ) + return result; + while ( !stack.isEmpty() || root != null ) { + if ( root != null ) { + result.addFirst(root.val); + stack.push(root); + root = root.right; + } else { + TreeNode node = stack.pop(); + root = node.left; + } + } + return result; + } + } +} diff --git a/Week_02/G20200343030569/LeetCode_236_569.java b/Week_02/G20200343030569/LeetCode_236_569.java new file mode 100644 index 00000000..faecb33a --- /dev/null +++ b/Week_02/G20200343030569/LeetCode_236_569.java @@ -0,0 +1,47 @@ +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + + +public class LeetCode_236_569 { + + public static void main(String[] args) { + // TODO Auto-generated method stub + LeetCode_236_569 main = new LeetCode_236_569(); + + TreeNode result = main.new Solution().lowestCommonAncestor(null, null, null); + } + + + public class TreeNode { + int val; + TreeNode left; + TreeNode right; + TreeNode(int x) { val = x; } + } + + class Solution { + TreeNode ancestor; + + public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { + recurseFind(root, p, q); + return ancestor; + } + + int recurseFind(TreeNode node, TreeNode p, TreeNode q) { + if ( node == null ) + return 0; + if ( ancestor != null ) + return 0; + + int leftFlag = recurseFind(node.left, p, q); + int rightFlag = recurseFind(node.right, p, q); + int pFlag = (node == p || node==q) ? 1 : 0; + + if( leftFlag + rightFlag + pFlag >=2 ) + ancestor = node; + + return (leftFlag + rightFlag + pFlag)>0 ? 1 : 0; + } + } +} diff --git a/Week_02/G20200343030569/LeetCode_429_569.java b/Week_02/G20200343030569/LeetCode_429_569.java new file mode 100644 index 00000000..daab3838 --- /dev/null +++ b/Week_02/G20200343030569/LeetCode_429_569.java @@ -0,0 +1,74 @@ +import java.util.ArrayList; +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; + + +public class LeetCode_429_569 { + + public static void main(String[] args) { + LeetCode_429_569 main = new LeetCode_429_569(); + Node node1 = main.new Node(1); + Node node3 = main.new Node(3); + Node node2 = main.new Node(2); + Node node4 = main.new Node(4); + Node node5 = main.new Node(5); + Node node6 = main.new Node(6); + node1.children = new ArrayList(); + node1.children.add(node3); + node1.children.add(node2); + node1.children.add(node4); + node3.children = new ArrayList(); + node3.children.add(node5); + node3.children.add(node6); + + node2.children = new ArrayList(); + node4.children = new ArrayList(); + node5.children = new ArrayList(); + node6.children = new ArrayList(); + + List> result = main.new Solution().levelOrder(node1); + for(List v: result) + System.out.println(Arrays.toString(v.toArray())); + } + + + class Node { + public int val; + public List children; + + public Node() {} + + public Node(int _val) { + val = _val; + } + + public Node(int _val, List _children) { + val = _val; + children = _children; + } + }; + + class Solution { + public List> levelOrder(Node root) { + List> result = new ArrayList<>(); + if (root == null) + return result; + List levelNodes = new LinkedList(); + levelNodes.add(root); + while( levelNodes.size() > 0 ) { + List nextLevelNodes = new LinkedList(); + List levelValues = new LinkedList(); + result.add(levelValues); + for( Node n : levelNodes ) { + levelValues.add(n.val); + for ( Node c : n.children ) { + nextLevelNodes.add(c); + } + } + levelNodes = nextLevelNodes; + } + return result; + } + } +} diff --git a/Week_02/G20200343030569/LeetCode_49_569.java b/Week_02/G20200343030569/LeetCode_49_569.java new file mode 100644 index 00000000..db12eb3c --- /dev/null +++ b/Week_02/G20200343030569/LeetCode_49_569.java @@ -0,0 +1,39 @@ +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/* + * 49. Group Anagrams + * 字母异位词分组 + */ +public class LeetCode_49_569 { + + public static void main(String[] args) { + // TODO Auto-generated method stub + String[] strs = { "eat", "tea", "tan", "ate", "nat", "bat" }; + LeetCode_49_569 main = new LeetCode_49_569(); + List> result = main.new Solution().groupAnagrams(strs); + for ( List group: result ) { + System.out.println(Arrays.toString(group.toArray())); + } + } + + class Solution { + public List> groupAnagrams(String[] strs) { + Map anaMap = new HashMap(); + for ( String s: strs ) { + char[] t = s.toCharArray(); + Arrays.sort(t); + String key = new String(t); + if ( !anaMap.containsKey(key) ) { + anaMap.put(key, new ArrayList() ); + } + anaMap.get(key).add(s); + } + + return new ArrayList( anaMap.values() ); + } + } +} diff --git a/Week_02/G20200343030569/LeetCode_589_569.java b/Week_02/G20200343030569/LeetCode_589_569.java new file mode 100644 index 00000000..5386e924 --- /dev/null +++ b/Week_02/G20200343030569/LeetCode_589_569.java @@ -0,0 +1,73 @@ +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; + +/* + * 589. N-ary Tree Preorder Traversal + * N叉树的前序遍历 + */ + +public class LeetCode_589_569 { + + public static void main(String[] args) { + // TODO Auto-generated method stub + LeetCode_589_569 main = new LeetCode_589_569(); + Node node1 = main.new Node(1); + Node node3 = main.new Node(3); + Node node2 = main.new Node(2); + Node node4 = main.new Node(4); + Node node5 = main.new Node(5); + Node node6 = main.new Node(6); + node1.children = new ArrayList(); + node1.children.add(node3); + node1.children.add(node2); + node1.children.add(node4); + node3.children = new ArrayList(); + node3.children.add(node5); + node3.children.add(node6); + + node2.children = new ArrayList(); + node4.children = new ArrayList(); + node5.children = new ArrayList(); + node6.children = new ArrayList(); + + List result = main.new Solution().preorder(node1); + for(Integer v: result) + System.out.println(v); + } + public class Node { + public int val; + public List children; + + public Node() {} + + public Node(int _val) { + val = _val; + } + + public Node(int _val, List _children) { + val = _val; + children = _children; + } + }; + + class Solution { + public List preorder(Node root) { + LinkedList result = new LinkedList(); + LinkedList stack = new LinkedList(); + if ( root == null ) + return result; + stack.push(root); + while ( !stack.isEmpty() ) { + Node node = stack.pop(); + result.add(node.val); + for ( int i = node.children.size()-1; i >= 0; i-- ) { + Node n = node.children.get(i); + if ( n != null ) + stack.push(n); + } + } + return result; + } + } +} diff --git a/Week_02/G20200343030569/LeetCode_590_569.java b/Week_02/G20200343030569/LeetCode_590_569.java new file mode 100644 index 00000000..1563adca --- /dev/null +++ b/Week_02/G20200343030569/LeetCode_590_569.java @@ -0,0 +1,75 @@ +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; + + +/* + * N-ary Tree Postorder Traversal + * N叉树的后序遍历 + */ +public class LeetCode_590_569 { + + public static void main(String[] args) { + // TODO Auto-generated method stub + LeetCode_590_569 main = new LeetCode_590_569(); + Node node1 = main.new Node(1); + Node node3 = main.new Node(3); + Node node2 = main.new Node(2); + Node node4 = main.new Node(4); + Node node5 = main.new Node(5); + Node node6 = main.new Node(6); + node1.children = new ArrayList(); + node1.children.add(node3); + node1.children.add(node2); + node1.children.add(node4); + node3.children = new ArrayList(); + node3.children.add(node5); + node3.children.add(node6); + + node2.children = new ArrayList(); + node4.children = new ArrayList(); + node5.children = new ArrayList(); + node6.children = new ArrayList(); + + List result = main.new Solution().postorder(node1); + for(Integer v: result) + System.out.println(v); + } + + + + public class Node { + public int val; + public List children; + + public Node() {} + + public Node(int _val) { + val = _val; + } + + public Node(int _val, List _children) { + val = _val; + children = _children; + } + }; + + class Solution { + public List postorder(Node root) { + LinkedList result = new LinkedList(); + LinkedList stack = new LinkedList(); + if ( root == null ) + return result; + stack.push(root); + while ( !stack.isEmpty() ) { + Node node = stack.pollLast(); + result.addFirst(node.val); + for ( Node n : node.children ) { + if ( n != null ) + stack.add(n); + } + } + return result; + } + } +} diff --git a/Week_02/G20200343030569/LeetCode_94_569.java b/Week_02/G20200343030569/LeetCode_94_569.java new file mode 100644 index 00000000..7cdaaf6f --- /dev/null +++ b/Week_02/G20200343030569/LeetCode_94_569.java @@ -0,0 +1,61 @@ +import java.util.LinkedList; +import java.util.List; +import java.util.Stack; + +/* + * 94. Binary Tree Inorder Traversal + * 二叉树的中序遍历 + */ +public class LeetCode_94_569 { + + int index; + + TreeNode buildTreeNode(Integer data[]){ + if( index >= data.length ) + return null; + Integer value = data[index++]; + TreeNode node = null; + if ( value != null ) { + node = new TreeNode(value); + node.left = buildTreeNode(data); + node.right = buildTreeNode(data); + } + return node; + } + + public static void main(String[] args) { + // TODO Auto-generated method stub + //输入: [1,null,2,3] + Integer[] treeData = { 1, null, 2, 3 }; + LeetCode_94_569 main = new LeetCode_94_569(); + TreeNode node = main.buildTreeNode(treeData); + + List result = main.new Solution().inorderTraversal(node); + for(Integer v: result) + System.out.println(v); + } + public class TreeNode { + int val; + TreeNode left; + TreeNode right; + TreeNode(int x) { val = x; } + } + + class Solution { + public List inorderTraversal(TreeNode root) { + List result = new LinkedList(); + Stack stack = new Stack(); + while ( !stack.isEmpty() || root != null ) { + if ( root != null ) { + stack.push(root); + root = root.left; + } else { + TreeNode node = stack.pop(); + result.add(node.val); + root = node.right; + } + } + return result; + } + } +} diff --git a/Week_02/G20200343030571/main/binary-tree-preorder-traversal.go b/Week_02/G20200343030571/main/binary-tree-preorder-traversal.go new file mode 100644 index 00000000..cdc36b3a --- /dev/null +++ b/Week_02/G20200343030571/main/binary-tree-preorder-traversal.go @@ -0,0 +1,136 @@ +package main + +import ( + "fmt" + ) + +/* + 二叉树的前序遍历 + 给定一个二叉树,返回它的 前序 遍历。 + 示例: + + 输入: [1,null,2,3] + 1 + \ + 2 + / + 3 + + 输出: [1,2,3] +*/ + +/* + 递归法 + 1.终止条件 + 2.处理这一层 + 3.进入下一层 + 4.回收资源 + + 自己写了递归的算法,开始时出了一个比较低级的错误,直接传了slice的值 + 这是因为自己记错了切片的底层实现,切片中含有指向底层数组的指针,但那个不等于指向切片的指针。 + golang的函数传参只有值传递,所以要传进指向res切片的指针才行。 + + !!! 但是因为我印象中一直是记得golang虽然是值传递,但是会自动对slice做一些处理,导致会造成似乎是传引用的幻觉。 + 查了一些博客,自己写了test.go的测试用例,发现更迷糊了。测试用例的结果似乎是与这次代码的结果相冲突? + 求解答 +*/ + +/*type TreeNode struct { + Val int + Left *TreeNode + Right *TreeNode +}*/ + +func traversal(node *TreeNode, res []int) { + if node == nil { + return + } + res = append(res, node.Val) + fmt.Println(res) + traversal(node.Left, res) + traversal(node.Right, res) +} + +func preorderTraversal1(root *TreeNode) []int { + if root == nil {return nil} + res := make([]int, 0, 0) + traversal(root, res) + return res +} + +/* + 通过看别人的题解,明白了迭代法,但是需要栈,golang没有栈 + 我自己试着实现一下 + 通过了,感觉通过自己实现了个栈,对golang的空接口又熟练了一点 + 说实话,自己用golang写了一年半的业务代码都没怎么接触空接口 + + 写完去国际站看了下,也有用golang写迭代法的,思路和我基本一致。只不过是没有额外单独将stack这个 + 类型实现。 +*/ + +type stack []interface {} + +func (s *stack) len() int { + return len(*s) +} + +func (s *stack) pop() interface{} { + if s.isEmpty() {return nil} + tempStack := *s + res := tempStack[len(*s)-1] + *s = tempStack[:len(*s)-1] + return res +} + +func (s *stack) push(i interface{}) { + *s = append(*s, i) +} + +func (s *stack) isEmpty() bool { + if len(*s) == 0 { + return true + } + return false +} + +func preorderTraversal(root *TreeNode) []int { + if root == nil {return nil} //一开始又忘了判空了 + + stack := make(stack, 0, 0) + res := make([]int, 0, 0) + stack.push(root) + for !stack.isEmpty() { + tempNode := stack.pop().(*TreeNode) + res = append(res, tempNode.Val) + //一开始这里忘判空了,和递归不一样,因为递归会在每层开头判空 + if tempNode.Right != nil { + stack.push(tempNode.Right) + } + if tempNode.Left != nil { + stack.push(tempNode.Left) + } + } + return res +} + +/*func main() { + Node3 := TreeNode { + Val: int(3), + Left: nil, + Right: nil, + } + Node2 := TreeNode { + Val: int(2), + Left: &Node3, + Right: nil, + } + Node1 := TreeNode { + Val: int(1), + Left: nil, + Right: &Node2, + } + + res := preorderTraversal(&Node1) + fmt.Println(res) + return +}*/ \ No newline at end of file diff --git a/Week_02/G20200343030571/main/group-anagrams.go b/Week_02/G20200343030571/main/group-anagrams.go new file mode 100644 index 00000000..8fb4557c --- /dev/null +++ b/Week_02/G20200343030571/main/group-anagrams.go @@ -0,0 +1,89 @@ +package main + +import "sort" + +/* +字母异位词分组 + + 给定一个字符串数组,将字母异位词组合在一起。字母异位词指字母相同,但排列不同的字符串。 + + 示例: + + 输入: ["eat", "tea", "tan", "ate", "nat", "bat"], + 输出: + [ + ["ate","eat","tea"], + ["nat","tan"], + ["bat"] + ] + 说明: + + 所有输入均为小写字母。 + 不考虑答案输出的顺序。 +*/ +/* + map[sorted str][old str...] + 这个由于老师课上讲了几句,所以大体思路是有的。 + 但是写代码的时候还是苦难重重,估计是因为自己工作中写的代码太简单了。 + 导致我并不知道在golang里怎么对字符串本身进行排序,找了半天中终于在国际站中找到了答案。 + 由于对这块go语言的不熟悉,导致代码写的很不顺畅,而且go语言在这块是真的麻烦。。。 + 写完如下代码,提交完成,击败了59% + 时间复杂度:O(NKlogK),其中 N 是 strs 的长度,而 K 是 strs 中字符串的长度。 +*/ +func groupAnagrams1(strs []string) [][]string { + if len(strs) == 0 {return nil} + mapSorted := make(map[string][]string) + for _, str := range strs { + b := []byte(str) + sort.Slice(b, func(i, j int) bool{ + return b[i] < b[j] + }) + key := string(b) + mapSorted[key] = append(mapSorted[key], str) + } + ret := make([][]string, 0, len(mapSorted)) + for _, strs := range mapSorted { + ret = append(ret, strs) + } + + return ret +} +/* + 因为上面的解法写了两层循环,我在想能不能“顺便”(顺便这个想法是我在第一周自己想出的 + 一个规律,也写在了第一周的学习总结中了),即第一个循环就把第二个循环的事情给做了。 + 然后想了下,收之前双指针题目的启发,因为第二个指针其实记录的也是一个位置。那么其实我把 + 第一个map改下,不放string了,也放一个表示“位置”的元素,然后就可以利用这个位置直接在ret中 + 存数据了。 + 但是提交后发现性能上并没有改善,还是59% + 比较奇怪的是在看别人的solution的时候,发现一个人用C++写了类似思路的代码, + 但是他却能击败99%的C++解决方案 +*/ +func groupAnagrams(strs []string) [][]string { + if len(strs) == 0 {return nil} + mapIndex := make(map[string]int) + ret := make([][]string, 0, len(strs)) + index := int(0) + for _, str := range strs { + b := []byte(str) + sort.Slice(b, func(i, j int) bool{ + return b[i] < b[j] + }) + key := string(b) + idx, ok := mapIndex[key] + if !ok { + mapIndex[key] = index + ret = append(ret, []string{str}) + index++ + } else { + ret[idx] = append(ret[idx], str) + } + } + return ret +} + +func main() { + strs := []string{"eat","tea","tan","ate","nat","bat"} + ret := groupAnagrams(strs) + print(ret) + return +} diff --git a/Week_02/G20200343030571/main/lowest-common-ancestor-of-a-binary-tree.go b/Week_02/G20200343030571/main/lowest-common-ancestor-of-a-binary-tree.go new file mode 100644 index 00000000..e2c80f9e --- /dev/null +++ b/Week_02/G20200343030571/main/lowest-common-ancestor-of-a-binary-tree.go @@ -0,0 +1,174 @@ +package main + +import "fmt" + +/* +二叉树的最近公共祖先: +给定一个二叉树,找到该树中两个指定节点的最近公共祖先。 + +百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x, +满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。” +*/ + +/* + 递归法:自己想不到,看了题解 + 按照老师说的四步: + 1.终止条件:如果此节点为nil,返回false + 如果此节点为p或q,返回true + 2.将到这层为止,这个节点与p,q的关系返回上一层(或直接得出结果),关系一共有以下几种: + 1.这个节点是其中节点之一的祖先 + 2.这个节点不是任意一个节点的祖先 + 3.这个节点是两个节点的公告祖先(即得出结果,因为一旦判定即返回,所以一定是最近祖先) + ps:自己本身算是自己的祖先 + 3.去下探下一层,左与右 + 4.无资源需要清理 + + 上面的false 与 true是为方便表达,表示的是找到与最终没找到两个结果。实际上因为要设计判断是否是 + 公共祖先,所以替换成返回0和1,这样是否是公共祖先可以用是否等于2来判断 +*/ + +/* + 自己写完,发现犯了3个错误,123都用注释标记了。 + 1. 这个错误应该算是递归的整体思路的错误。其实就是上面写的四步其实是有问题的。如果当前节点是p或q的话, + 也不应该是立即返回,因为如果这样的话,如果另一个节点是在它的叶子树中,由于已经提前返回了,所以就差不到了。 + 2. res := &TreeNode{}; + 这条语句并不是定义一个指向该类型的空指针。而是先定义出一个这个类型的结构,其成员都是零值,然后返回指向他的指针 + 3. golang是值传递,所以传入函数的不应该是指针,而是指针的指针 + + 另外,我做完这个题,有个困惑就是:要么是覃老师关于递归的四步说的不太精准,要么就是我自己领悟错了。 + 按照老师讲的第2步是处理这一层,他的下一步才是去到下一层。但按照这个题,我觉得处理处理这一层和去到下一层是混着的。 + 因为对于每个节点,你要想判断他与p,q的关系,必然是已经把下面的层都探查完了。 +*/ + +type TreeNode struct { + Val int + Left *TreeNode + Right *TreeNode +} + +func recursiveTree1(root, p, q *TreeNode, res **TreeNode) int { //3. + if root == nil { + return 0 + } + /*if root == p || root == q { // 1. + return 1 + }*/ + leftHave := recursiveTree1(root.Left, p, q, res) + rightHave := recursiveTree1(root.Right, p, q, res) + thisIs := int(0) + if root == p || root == q { + thisIs = 1 + } + if thisIs + leftHave + rightHave >= 2 && *res == nil{ + *res = root + } + if thisIs + leftHave + rightHave >= 1 { + return 1 + } + return 0 +} + +func lowestCommonAncestor1(root, p, q *TreeNode) *TreeNode { + //res := &TreeNode{} // 2. + var res *TreeNode = nil + recursiveTree1(root, p, q, &res) + return res +} + +/* + 看了另一个人写的递归,更加简洁。 + 他用一种更加简洁的方法,使得当这个节点为p或q的时候,可以直接返回而不做判断。 + 但是前提是,p q 两个节点必须是存在于给出的树中的 + 如果是面试的时候,那么第一步就可以确定一下这个问题 + + 这种递归的思路: + 如果当前节点是p或q就直接返回当前节点 + 对于下层,如果下层都是空则返回空,这个很简单,就是pq都不在这个节点的子树里 + 如果两层都不为空,那么说明找到了,这个节点就是答案。 + 如果有一层不为空,则直接把他的结果往上层反还(注意是结果,而不是左儿子节点) + 如果两次都为空,那么返回空 + 为什么这样就可以省去第一种递归那么多的步骤呢? + 首先明确之所以第一种递归比较麻烦,就麻烦在于要考虑p,q本身即为答案的情况 + 这个思路,他首先基于p,q节点必然存在于给出的树中这个条件。 + 那么基于这个条件如果p,q节点本身为答案,我们直接把他往上一层层的返。在这个情况中,肯定会一直讲这个节点网上返直到根节点。因为不可能再 + 找到另一个节点了。到了根节点,如果发现左右遍历,有一个的答案为空,那么直接返回另一个,就是答案。 + 相当于,我们基于p,q节点必然存在于给出的树中这个条件,逆推出答案。 +*/ +func recursiveTree(root, p, q *TreeNode) *TreeNode { + if root == nil { + return nil + } + if root == p || root == q { + return root + } + + left := recursiveTree(root.Left, p, q) + right := recursiveTree(root.Right, p, q) + + if left != nil && right != nil { + return root + } + if left == nil && right != nil { + return right + } + if left != nil && right == nil { + return left + } + + return nil +} + +func lowestCommonAncestor(root, p, q *TreeNode) *TreeNode { + return recursiveTree(root, p, q) +} + +func main() { + node1 := TreeNode{ + Left:nil, + Right:nil, + Val:7, + } + node2 := TreeNode{ + Left:nil, + Right:nil, + Val:4, + } + node3 := TreeNode{ + Left:&node1, + Right:&node2, + Val:2, + } + node4 := TreeNode{ + Left:nil, + Right:nil, + Val:6, + } + node5 := TreeNode{ + Left:&node4, + Right:&node3, + Val:5, + } + node6 := TreeNode{ + Left:nil, + Right:nil, + Val:0, + } + node7 := TreeNode{ + Left:nil, + Right:nil, + Val:8, + } + node8 := TreeNode{ + Left:&node6, + Right:&node7, + Val:1, + } + node9 := TreeNode{ + Left:&node5, + Right:&node8, + Val:3, + } + res := lowestCommonAncestor(&node9, &node5, &node8) + fmt.Println(res) + return +} \ No newline at end of file diff --git a/Week_02/G20200343030571/main/test.go b/Week_02/G20200343030571/main/test.go new file mode 100644 index 00000000..09616872 --- /dev/null +++ b/Week_02/G20200343030571/main/test.go @@ -0,0 +1,15 @@ +package main + +import "fmt" + +func main() { + ages:=[]int{6,6,6} + fmt.Printf("原始slice的内存地址是%p\n",ages) + modify(ages) + fmt.Println(ages) +} + +func modify(ages []int){ + fmt.Printf("函数里接收到slice的内存地址是%p\n",ages) + ages[0]=1 +} diff --git a/Week_02/G20200343030573/LeetCode_105_573.py b/Week_02/G20200343030573/LeetCode_105_573.py new file mode 100644 index 00000000..517c6d75 --- /dev/null +++ b/Week_02/G20200343030573/LeetCode_105_573.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- + +import sys + +__author__ = "Onceabu" +__version__ = "v2.0" + +""" + Time + describe + copyright (c) 2019 by Abu +""" + +reload(sys) +sys.setdefaultencoding('utf-8') + + +# Definition for a binary tree node. +class TreeNode(object): + def __init__(self, x): + self.val = x + self.left = None + self.right = None + + +class Solution(object): + # 递归实现 主要借助前序总会先遍历根节点的原理 对中序遍历结果进行分割递归 + def buildTree(self, preorder, inorder): + """ + :type preorder: List[int] + :type inorder: List[int] + :rtype: TreeNode + """ + if inorder: + ind = inorder.index(preorder.pop(0)) + root = TreeNode(inorder[ind]) + root.left = self.buildTree(preorder, inorder[0:ind]) + root.right = self.buildTree(preorder, inorder[ind + 1:]) + return root diff --git a/Week_02/G20200343030573/LeetCode_144_573.py b/Week_02/G20200343030573/LeetCode_144_573.py new file mode 100644 index 00000000..f43b0993 --- /dev/null +++ b/Week_02/G20200343030573/LeetCode_144_573.py @@ -0,0 +1,65 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- + +import sys + +__author__ = "Onceabu" +__version__ = "v2.0" + +""" + Time + describe + copyright (c) 2019 by Abu +""" + +reload(sys) +sys.setdefaultencoding('utf-8') + + +# Definition for a binary tree node. +# class TreeNode(object): +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution(object): + # 方法一 递归 不再多述 + def preorderTraversal(self, root): + """ + :type root: TreeNode + :rtype: List[int] + """ + res = [] + if root is None: + return res + + def recursive(root): + res.append(root.val) + if root.left: + recursive(root.left) + if root.right: + recursive(root.right) + + recursive(root) + return res + + # 方法二 迭代算法 也是利用栈 同589 + def _preorderTraversal(self, root): + """ + :type root: TreeNode + :rtype: List[int] + """ + res = [] + if root is None: + return res + stack = [root] + while stack: + cur = stack.pop() + if cur: + res.append(cur.val) + if cur.right: + stack.append(cur.right) + if cur.left: + stack.append(cur.left) + return res diff --git a/Week_02/G20200343030573/LeetCode_236_573.py b/Week_02/G20200343030573/LeetCode_236_573.py new file mode 100644 index 00000000..e6c53e8b --- /dev/null +++ b/Week_02/G20200343030573/LeetCode_236_573.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- + +import sys + +__author__ = "Onceabu" +__version__ = "v2.0" + +""" + Time + describe + copyright (c) 2019 by Abu +""" + +reload(sys) +sys.setdefaultencoding('utf-8') + + +# Definition for a binary tree node. +# class TreeNode(object): +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution(object): + BOTH_PENDING = 2 + LEFT_DONE = 1 + BOTH_DONE = 0 + + # 借助栈实现的无父指针的迭代方法 其他方法待研究 + def lowestCommonAncestor(self, root, p, q): + """ + :type root: TreeNode + :type p: TreeNode + :type q: TreeNode + :rtype: TreeNode + """ + stack = [(root, Solution.BOTH_PENDING)] + one_node_found = False + LCA_index = -1 + while stack: + parent_node, parent_state = stack[-1] + if parent_state != Solution.BOTH_DONE: + if parent_state == Solution.BOTH_PENDING: + if parent_node == p or parent_node == q: + if one_node_found: + return stack[LCA_index][0] + else: + one_node_found = True + LCA_index = len(stack) - 1 + child_node = parent_node.left + else: + child_node = parent_node.right + stack.pop() + stack.append((parent_node, parent_state - 1)) + if child_node: + stack.append((child_node, Solution.BOTH_PENDING)) + else: + if one_node_found and LCA_index == len(stack) - 1: + LCA_index -= 1 + stack.pop() + return None diff --git a/Week_02/G20200343030573/LeetCode_429_573.py b/Week_02/G20200343030573/LeetCode_429_573.py new file mode 100644 index 00000000..6035347f --- /dev/null +++ b/Week_02/G20200343030573/LeetCode_429_573.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- + +import sys + +__author__ = "Onceabu" +__version__ = "v2.0" + +""" + Time + describe + copyright (c) 2019 by Abu +""" + +reload(sys) +sys.setdefaultencoding('utf-8') + +""" +# Definition for a Node. +class Node(object): + def __init__(self, val=None, children=None): + self.val = val + self.children = children +""" + + +class Solution(object): + # 方法一:正常思路 遍历每一层的同时记录每个节点的子节点 循环 + def levelOrder(self, root): + """ + :type root: Node + :rtype: List[List[int]] + """ + res = [] + if root is None: + return res + + nodes = [root] + while nodes: + childrens = [] + res.append([]) + for n in nodes: + res[-1].append(n.val) + if n.children: + childrens.extend(n.children) + nodes = childrens + return res + + # 方法二 递归 待研究 diff --git a/Week_02/G20200343030573/LeetCode_46_573.py b/Week_02/G20200343030573/LeetCode_46_573.py new file mode 100644 index 00000000..0e539dfc --- /dev/null +++ b/Week_02/G20200343030573/LeetCode_46_573.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- + +import sys + +__author__ = "Onceabu" +__version__ = "v2.0" + +""" + Time + describe + copyright (c) 2019 by Abu +""" + +reload(sys) +sys.setdefaultencoding('utf-8') + + +class Solution(object): + # 递归-深度优先 + def permute(self, nums): + res = [] + self.dfs(nums, [], res) + return res + + def dfs(self, nums, path, res): + if not nums: + res.append(path) + for i in xrange(len(nums)): + self.dfs(nums[:i] + nums[i + 1:], path + [nums[i]], res) diff --git a/Week_02/G20200343030573/LeetCode_47_573.py b/Week_02/G20200343030573/LeetCode_47_573.py new file mode 100644 index 00000000..7af924d1 --- /dev/null +++ b/Week_02/G20200343030573/LeetCode_47_573.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- + +import sys + +__author__ = "Onceabu" +__version__ = "v2.0" + +""" + Time + describe + copyright (c) 2019 by Abu +""" + +reload(sys) +sys.setdefaultencoding('utf-8') + + +class Solution(object): + def permuteUnique(self, nums): + ans = [[]] + for n in nums: + new_ans = [] + for l in ans: + for i in xrange(len(l) + 1): + new_ans.append(l[:i] + [n] + l[i:]) + if i < len(l) and l[i] == n: + break + ans = new_ans + return ans diff --git a/Week_02/G20200343030573/LeetCode_49_573.py b/Week_02/G20200343030573/LeetCode_49_573.py new file mode 100644 index 00000000..fc5e33ed --- /dev/null +++ b/Week_02/G20200343030573/LeetCode_49_573.py @@ -0,0 +1,31 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- + +import sys + +__author__ = "Onceabu" +__version__ = "v2.0" + +""" + Time + describe + copyright (c) 2019 by Abu +""" + +reload(sys) +sys.setdefaultencoding('utf-8') + + +class Solution(object): + # 主要是借助dict 即哈希表 + def groupAnagrams(self, strs): + """ + :type strs: List[str] + :rtype: List[List[str]] + """ + res = {} + for s in strs: + k = ''.join(sorted(s)) + res[k] = res.get(k, []) + [s] # pythonic + # return res.values() + return list(res.values()) # python3的话需要转一下 diff --git a/Week_02/G20200343030573/LeetCode_589_573.py b/Week_02/G20200343030573/LeetCode_589_573.py new file mode 100644 index 00000000..24b260d1 --- /dev/null +++ b/Week_02/G20200343030573/LeetCode_589_573.py @@ -0,0 +1,62 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- + +import sys + +__author__ = "Onceabu" +__version__ = "v2.0" + +""" + Time + describe + copyright (c) 2019 by Abu +""" + +reload(sys) +sys.setdefaultencoding('utf-8') + +""" +# Definition for a Node. +class Node(object): + def __init__(self, val=None, children=None): + self.val = val + self.children = children +""" + + +class Solution(object): + # 方法一:同590 把res.append放到for循环之前即可 + def preorder(self, root): + """ + :type root: Node + :rtype: List[int] + """ + res = [] + if root is None: + return res + + def recursive(root, res): + res.append(root.val) + for c in root.children: + recursive(c, res) + + recursive(root, res) + return res + + # 方法二:同590一样也是用栈 只是这里要注意后序是刚好顺序相反可以直接反转 + # 但是前序的话root顺序是对的,children顺序是反的,所以只需要反转children即可 + def _preorder(self, root): + """ + :type root: Node + :rtype: List[int] + """ + res = [] + if root is None: + return res + + stack = [root] + while stack: + cur = stack.pop() + res.append(cur.val) + stack.extend(cur.children[::-1]) + return res diff --git a/Week_02/G20200343030573/LeetCode_590_573.py b/Week_02/G20200343030573/LeetCode_590_573.py new file mode 100644 index 00000000..ecc54aa6 --- /dev/null +++ b/Week_02/G20200343030573/LeetCode_590_573.py @@ -0,0 +1,58 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- + +import sys + +__author__ = "Onceabu" +__version__ = "v2.0" + +""" + Time + describe + copyright (c) 2019 by Abu +""" + +reload(sys) +sys.setdefaultencoding('utf-8') + +""" +# Definition for a Node. +class Node(object): + def __init__(self, val=None, children=None): + self.val = val + self.children = children +""" + + +class Solution(object): + + # 方法一 递归遍历所有的子节点 最后再添加当前根节点的值 + # 当然如果是前序遍历就先添加当前根节点的值再遍历子节点 + def postorder(self, root): + """ + :type root: Node + :rtype: List[int] + """ + res = [] + if root is None: + return res + + def recursive(root, res): + for c in root.children: + recursive(c, res) + res.append(root.val) # 如果是前序遍历就放到for循环上面 + + recursive(root, res) + return res + + # 方法二 利用栈,以后序遍历的顺序将各个节点入栈,然后逐个出栈记录val,最后倒序 时间复杂度应该是O(1) + def _postorder(self, root): + res = [] + if root is None: + return res + stack = [root] + while stack: + cur = stack.pop() + res.append(cur.val) + stack.extend(cur.children) + return res[::-1] diff --git a/Week_02/G20200343030573/LeetCode_77_573.py b/Week_02/G20200343030573/LeetCode_77_573.py new file mode 100644 index 00000000..2c2efc22 --- /dev/null +++ b/Week_02/G20200343030573/LeetCode_77_573.py @@ -0,0 +1,37 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- + +import sys + +__author__ = "Onceabu" +__version__ = "v2.0" + +""" + Time + describe + copyright (c) 2019 by Abu +""" + +reload(sys) +sys.setdefaultencoding('utf-8') + + +class Solution(object): + def combine(self, n, k): + """ + :type n: int + :type k: int + :rtype: List[List[int]] + """ + nums = list(range(1, k + 1)) + [n + 1] + + output, j = [], 0 + while j < k: + output.append(nums[:k]) + j = 0 + while j < k and nums[j + 1] == nums[j] + 1: + nums[j] = j + 1 + j += 1 + nums[j] += 1 + + return output diff --git a/Week_02/G20200343030575/LeetCode_144_575.swift b/Week_02/G20200343030575/LeetCode_144_575.swift new file mode 100644 index 00000000..7dd3f710 --- /dev/null +++ b/Week_02/G20200343030575/LeetCode_144_575.swift @@ -0,0 +1,49 @@ +/* + * @lc app=leetcode.cn id=144 lang=swift + * + * [144] 二叉树的前序遍历 + */ + +// @lc code=start +/** + * Definition for a binary tree node. + * public class TreeNode { + * public var val: Int + * public var left: TreeNode? + * public var right: TreeNode? + * public init(_ val: Int) { + * self.val = val + * self.left = nil + * self.right = nil + * } + * } + */ +class Solution { + func preorderTraversal(_ root: TreeNode?) -> [Int] { + guard let root = root else{ + return [Int](); + } + var stack = Array() + + var result = [Int]() + stack.append(root) + while(stack.count > 0){ + let node = stack.removeLast() + result.append(node.val) + + if let right = node.right{ + stack.append(right) + } + + if let left = node.left{ + stack.append(left) + } + + + } + + return result + } +} +// @lc code=end + diff --git a/Week_02/G20200343030575/LeetCode_145_575.swift b/Week_02/G20200343030575/LeetCode_145_575.swift new file mode 100644 index 00000000..4113e9c3 --- /dev/null +++ b/Week_02/G20200343030575/LeetCode_145_575.swift @@ -0,0 +1,53 @@ +/* + * @lc app=leetcode.cn id=145 lang=swift + * + * [145] 二叉树的后序遍历 + */ + +// @lc code=start +/** + * Definition for a binary tree node. + * public class TreeNode { + * public var val: Int + * public var left: TreeNode? + * public var right: TreeNode? + * public init(_ val: Int) { + * self.val = val + * self.left = nil + * self.right = nil + * } + * } + */ +class Solution { + func postorderTraversal(_ root: TreeNode?) -> [Int] { + guard let root = root else{ + return [Int](); + } + var stack = Array() + var visitedSet = Set() + + var result = [Int]() + stack.append(root) + while(stack.count > 0){ + let node = stack.last! + if (node.left == nil && node.right == nil) || visitedSet.contains(node){ + result.append(node.val) + stack.removeLast() + }else{ + visitedSet.insert(node) + if let right = node.right{ + stack.append(right) + } + + if let left = node.left{ + stack.append(left) + } + } + + + } + return result + } +} +// @lc code=end + diff --git a/Week_02/G20200343030575/LeetCode_1_575.swift b/Week_02/G20200343030575/LeetCode_1_575.swift new file mode 100644 index 00000000..f37d7229 --- /dev/null +++ b/Week_02/G20200343030575/LeetCode_1_575.swift @@ -0,0 +1,23 @@ +/* + * @lc app=leetcode.cn id=1 lang=swift + * + * [1] 两数之和 + */ + +// @lc code=start +class Solution { + func twoSum(_ nums: [Int], _ target: Int) -> [Int] { + var map = [Int:Int]() + map[nums[0]] = 0 + for i in 1.. ListNode? { + if l1 == nil { + return l2 + } + + if l2 == nil { + return l1 + } + + + let result: ListNode? + var current : ListNode? + + var left = l1, right = l2 + if l1!.val <= l2!.val { + result = l1 + current = l1 + left = l1?.next + }else{ + result = l2 + current = l2 + right = l2?.next + } + + while left != nil || right != nil { + + if left == nil { + current!.next = right + break + }else if right == nil { + current!.next = left + break + }else{ + if left!.val < right!.val { + current!.next = left + left = left?.next + }else{ + current!.next = right + right = right?.next + } + current = current!.next + } + } + + + return result + + } +} +// @lc code=end + diff --git a/Week_02/G20200343030575/LeetCode_242_575.swift b/Week_02/G20200343030575/LeetCode_242_575.swift new file mode 100644 index 00000000..a7f48683 --- /dev/null +++ b/Week_02/G20200343030575/LeetCode_242_575.swift @@ -0,0 +1,37 @@ +/* + * @lc app=leetcode.cn id=242 lang=swift + * + * [242] 有效的字母异位词 + */ + +// @lc code=start +class Solution { + func isAnagram(_ s: String, _ t: String) -> Bool { + guard s.count == t.count else { + return false + } + var map = [Character:Int]() + for i in s.indices { + if let value = map[s[i]] { + map[s[i]] = value + 1 + }else{ + map[s[i]] = 1 + } + } + + for i in t.indices { + if let value = map[t[i]] { + if value == 1 { + map.removeValue(forKey: t[i]) + }else{ + map[t[i]] = value - 1 + } + }else{ + return false + } + } + return map.count == 0 + } +} +// @lc code=end + diff --git a/Week_02/G20200343030575/LeetCode_49_575.swift b/Week_02/G20200343030575/LeetCode_49_575.swift new file mode 100644 index 00000000..50f1cd54 --- /dev/null +++ b/Week_02/G20200343030575/LeetCode_49_575.swift @@ -0,0 +1,33 @@ +/* + * @lc app=leetcode.cn id=49 lang=swift + * + * [49] 字母异位词分组 + */ + +// @lc code=start +class Item{ + var array = [String]() +} +class Solution { + func groupAnagrams(_ strs: [String]) -> [[String]] { + var map = [String: Item]() + for string in strs { + let key = String.init(string.sorted()) + if let value = map[key] { + value.array.append(string) + }else{ + let item = Item() + item.array.append(string) + map[key] = item + } + } + + var result = [[String]]() + for (_, value) in map { + result.append(value.array) + } + return result + } +} +// @lc code=end + diff --git a/Week_02/G20200343030575/LeetCode_589_575.java b/Week_02/G20200343030575/LeetCode_589_575.java new file mode 100644 index 00000000..273f8db8 --- /dev/null +++ b/Week_02/G20200343030575/LeetCode_589_575.java @@ -0,0 +1,49 @@ +/* + * @lc app=leetcode.cn id=589 lang=java + * + * [589] N叉树的前序遍历 + */ + +// @lc code=start +/* +// Definition for a Node. +class Node { + public int val; + public List children; + + public Node() {} + + public Node(int _val) { + val = _val; + } + + public Node(int _val, List _children) { + val = _val; + children = _children; + } +}; +*/ +class Solution { + public List preorder(Node root) { + List result = new ArrayList<>(); + if(root == null){ + return result; + } + + Stack stack = new Stack<>(); + stack.add(root); + while(stack.isEmpty() == false){ + Node node = stack.pop(); + result.add(node.val); + + for(int i = node.children.size() - 1; i >= 0; i--){ + stack.push(node.children.get(i)); + } + + } + return result; + } + +} +// @lc code=end + diff --git a/Week_02/G20200343030575/LeetCode_590_575.java b/Week_02/G20200343030575/LeetCode_590_575.java new file mode 100644 index 00000000..f9fc6ec0 --- /dev/null +++ b/Week_02/G20200343030575/LeetCode_590_575.java @@ -0,0 +1,53 @@ +/* + * @lc app=leetcode.cn id=590 lang=java + * + * [590] N叉树的后序遍历 + */ + +// @lc code=start +/* +// Definition for a Node. +class Node { + public int val; + public List children; + + public Node() {} + + public Node(int _val) { + val = _val; + } + + public Node(int _val, List _children) { + val = _val; + children = _children; + } +}; +*/ +class Solution { + public List postorder(Node root) { + List result = new ArrayList<>(); + Set visitedNode = new HashSet<>(); + if(root == null){ + return result; + } + + Stack stack = new Stack<>(); + stack.add(root); + while(stack.isEmpty() == false){ + Node node = stack.peek(); + if(node.children.size() == 0 || visitedNode.contains(node)){ + result.add(node.val); + stack.pop(); + }else{ + visitedNode.add(node); + for(int i = node.children.size() - 1; i >= 0; i--){ + stack.push(node.children.get(i)); + } + } + } + return result; + } + +} +// @lc code=end + diff --git a/Week_02/G20200343030575/LeetCode_88_575.swift b/Week_02/G20200343030575/LeetCode_88_575.swift new file mode 100644 index 00000000..5b2c6449 --- /dev/null +++ b/Week_02/G20200343030575/LeetCode_88_575.swift @@ -0,0 +1,34 @@ +/* + * @lc app=leetcode.cn id=88 lang=swift + * + * [88] 合并两个有序数组 + */ + +// @lc code=start +class Solution { + func merge(_ nums1: inout [Int], _ m: Int, _ nums2: [Int], _ n: Int) { + var firstIndex = m - 1, secondIndex = n - 1 + var index = m + n - 1 + while firstIndex >= 0 && secondIndex >= 0 { + if nums1[firstIndex] >= nums2[secondIndex] { + nums1[index] = nums1[firstIndex] + firstIndex -= 1 + }else{ + nums1[index] = nums2[secondIndex] + secondIndex -= 1 + } + index -= 1 + } + + while secondIndex >= 0 { + nums1[index] = nums2[secondIndex] + secondIndex -= 1 + index -= 1 + + } + } +} + + +// @lc code=end + diff --git a/Week_02/G20200343030577/LeetCode_144_577.go b/Week_02/G20200343030577/LeetCode_144_577.go new file mode 100644 index 00000000..025b5e13 --- /dev/null +++ b/Week_02/G20200343030577/LeetCode_144_577.go @@ -0,0 +1,106 @@ +/* + * @lc app=leetcode.cn id=144 lang=golang + * + * [144] 二叉树的前序遍历 + * + * https://leetcode-cn.com/problems/binary-tree-preorder-traversal/description/ + * + * algorithms + * Medium (63.91%) + * Likes: 208 + * Dislikes: 0 + * Total Accepted: 69.6K + * Total Submissions: 108.4K + * Testcase Example: '[1,null,2,3]' + * + * 给定一个二叉树,返回它的 前序 遍历。 + * + * 示例: + * + * 输入: [1,null,2,3] + * ⁠ 1 + * ⁠ \ + * ⁠ 2 + * ⁠ / + * ⁠ 3 + * + * 输出: [1,2,3] + * + * + * 进阶: 递归算法很简单,你可以通过迭代算法完成吗? + * + */ +package leetcode + +// create time: 2020-02-23 20:01 + +type TreeNode struct { + Val int + Left *TreeNode + Right *TreeNode +} + +// @lc code=start +/** + * Definition for a binary tree node. + * type TreeNode struct { + * Val int + * Left *TreeNode + * Right *TreeNode + * } + */ +func preorderTraversal(root *TreeNode) []int { + // return preorderTraversalUseRecurse(root) + return preorderTraversalUseIter(root) +} + +func preorderTraversalUseRecurse(root *TreeNode) []int { + if root == nil { + return nil + } + var res []int + var traversal func(*TreeNode) + traversal = func(node *TreeNode) { + // 递归终止条件 + if node == nil { + return + } + // 处理当前节点 + res = append(res, node.Val) + // 递归左节点 + traversal(node.Left) + // 递归右节点 + traversal(node.Right) + } + traversal(root) + return res +} + +func preorderTraversalUseIter(root *TreeNode) []int { + if root == nil { + return nil + } + + var res []int + stack := make([]*TreeNode, 0) + stack = append(stack, root) + var node *TreeNode + // 前序遍历 根左右 + for len(stack) > 0 { + // 当前节点出栈并处理 + node = stack[len(stack)-1] + stack = stack[:len(stack)-1] + res = append(res, node.Val) + // 加入右节点(先加入后处理) + if node.Right != nil { + stack = append(stack, node.Right) + } + // 加入左节点(后加入先处理) + if node.Left != nil { + stack = append(stack, node.Left) + } + } + return res +} + +// @lc code=end diff --git a/Week_02/G20200343030577/LeetCode_49_577.go b/Week_02/G20200343030577/LeetCode_49_577.go new file mode 100644 index 00000000..fd5c82dc --- /dev/null +++ b/Week_02/G20200343030577/LeetCode_49_577.go @@ -0,0 +1,108 @@ +/* + * @lc app=leetcode.cn id=49 lang=golang + * + * [49] 字母异位词分组 + * + * https://leetcode-cn.com/problems/group-anagrams/description/ + * + * algorithms + * Medium (60.53%) + * Likes: 271 + * Dislikes: 0 + * Total Accepted: 51.4K + * Total Submissions: 84.4K + * Testcase Example: '["eat","tea","tan","ate","nat","bat"]' + * + * 给定一个字符串数组,将字母异位词组合在一起。字母异位词指字母相同,但排列不同的字符串。 + * + * 示例: + * + * 输入: ["eat", "tea", "tan", "ate", "nat", "bat"], + * 输出: + * [ + * ⁠ ["ate","eat","tea"], + * ⁠ ["nat","tan"], + * ⁠ ["bat"] + * ] + * + * 说明: + * + * + * 所有输入均为小写字母。 + * 不考虑答案输出的顺序。 + * + * + */ +package leetcode + +import "sort" + +// @lc code=start +// create time:2020-02-23 19:37 +func groupAnagrams(strs []string) [][]string { + return groupAnagramsUseSortAndHash(strs) + // return groupAnagramsUseCountAndHash(strs) +} + +func groupAnagramsUseSortAndHash(strs []string) [][]string { + if len(strs) == 0 { + return nil + } + // 将子集存放于hash表中 + ans := make(map[string][]int) + for i := range strs { + // 排序 + b := []byte(strs[i]) + sort.Slice(b, func(i, j int) bool { + return b[i] <= b[j] + }) + if _, ok := ans[string(b)]; ok { + ans[string(b)] = append(ans[string(b)], i) + } else { + ans[string(b)] = append(make([]int, 0, 1), i) + } + + } + // 从hash表中获取结果 + res, count := make([][]string, len(ans)), 0 + for _, index := range ans { + child := make([]string, 0, len(index)) + for _, i := range index { + child = append(child, strs[i]) + } + res[count] = child + count++ + } + return res +} + +func groupAnagramsUseCountAndHash(strs []string) [][]string { + if len(strs) == 0 { + return nil + } + + ans := make(map[[26]int][]int) + for i := range strs { + var s [26]int + for j := range strs[i] { + s[strs[i][j]-'a']++ + } + if _, ok := ans[s]; ok { + ans[s] = append(ans[s], i) + } else { + ans[s] = append(make([]int, 0, 1), i) + } + } + res, count := make([][]string, len(ans)), 0 + for _, index := range ans { + child := make([]string, 0, len(index)) + for _, i := range index { + child = append(child, strs[i]) + } + res[count] = child + count++ + } + return res +} + +// @lc code=end diff --git a/Week_02/G20200343030577/NOTE.md b/Week_02/G20200343030577/NOTE.md index 50de3041..336153f8 100644 --- a/Week_02/G20200343030577/NOTE.md +++ b/Week_02/G20200343030577/NOTE.md @@ -1 +1,145 @@ -学习笔记 \ No newline at end of file +# 第2周学习心得 +### 创建时间:2020-02-23 20:43 +## Hash表 +1. ### Hash 原理 +- 利用数组的随机访问特性,通过 index = hash(key) mod 数组容量,将kv对象存放于arr[index]下,实现O(1)的随机访问特性 +2. ### Hash 函数 +- 常见hash函数入MD5,SHA,CRC +- hash函数特性:敏感性,稳定性,不可逆,冲突概率小 +- hash表选择hash函数因数:相对简单性(hash计算需要消耗大量计算资源,量力而为),均匀性(避免hash攻击,hash随机访问降至O(n),造成服务不可用) +3. ### Hash 碰撞(散列冲突) +- 原理:hash函数总是最多产出有限max个hash串,当数据容量大于max时,必定至少存在一对相同的hash串,这就是hash碰撞 +- 解决方式1:开放寻址(一维结构,找到下一个空槽,有一次线性探测,二次探测,双重散列方式,适合装载因子较小的场景) +- 解决方式2:链表法(二维结构,一维数组二维链表或者树,数据存放在二维结构上,装载因子较大时也适合) +4. ### Hash 应用 +- 安全加密 (不可逆性) +- 唯一标志,数字证书,数据校验(敏感性,稳定性) +- 散列函数,hash表 (敏感性,冲突概率小) +- 负载均衡(稳定性) +- 数据分片,分布式存储 (稳定性) +5. ### Hash表 设计 +- 要求: 支持快速的增删改查,内存占用合理,稳定 +- 设计参考因数:散列函数,散列冲突,初始容量,装载因子阀值,动态扩缩容策略, +## 二叉树 +1. ### 二叉树结构 +- 每个节点有两个叉,分别左子节点和右子节点 +2. ### 二叉树类型 +- 按照节点存储方式:链式存储的二叉树(节点通过指针关联),顺序存储的二叉树(数组,节点通过公式关联) +- 按照节点状态:满二叉树(所有节点均有左右子节点),完全二叉树(最后一层以外的所有节点均有左右子节点),普通二叉树 +3. ### 遍历方式 +- 前序遍历 根左右(根右左) +- 中序遍历 左根右(右根左),排序 +- 后续遍历 左右根 (右左根) +- 遍历时间复杂度O(n),每个节点访问2次(一进一出),共访问2n次 +- 递归遍历模版 +```golang +/** +type ListNode struct { + Val int + Left,Right *ListNode +} +**/ +// 必须包含 递归终止条件 递归左节点 递归右节点 处理当前节点 + +// 前序遍历模版 +func preOrderTravel(root *ListNode) { + // 递归终止条件 + if root == nil { + return + } + // 处理当前节点 + print(node.Val) + // 递归左节点 + preOrderTravel(root.Left) + // 递归右节点 + preOrderTravel(root.Right) +} + +// 中序遍历模版 +func inOrderTravel(root *ListNode) { + // 递归终止条件 + if root == nil { + return + } + // 递归左节点 + inOrderTravel(root.Left) + // 处理当前节点 + print(node.Val) + // 递归右节点 + inOrderTravel(root.Right) +} + +// 后序遍历模版 +func postOrderTravel(root *ListNode) { + // 递归终止条件 + if root == nil { + return + } + // 递归左节点 + postOrderTravel(root.Left) + // 递归右节点 + postOrderTravel(root.Right) + // 处理当前节点 + print(node.Val) +} +``` +4. ### 二叉树平衡算法 +- 红黑树 +- ALV +5. ### 二叉树应用 +- 二叉搜索树 +- 大小项堆 +- 优先队列 +## 递归 +1. ### 递归特点 +- 具有终止条件 +- 可以分解为重复子问题,子问题之间存在迭代递推公式 +- 子问题逻辑保持一致规模不同 +2. ### 递归模版 +```golang + func recur(level int,params int) { + // 终止条件 + if level > MAX_LEVEL { + return + } + // 处理当前层级逻辑 + process(params) + // 递归至下一层 + recur(level+1,params) + // 清理当前层级状态 + clean(params) + } +``` +3. ### 递归注意因数 +- 堆栈溢出(递归深度大可考虑迭代和自建堆栈) +- 重复计算(可以使用换缓存来记忆已计算的结果) +4. ### 递归与循环 +- 递归需要借助栈来实现,会比循环多消耗一下资源,可能会出现堆栈溢出或者重复计算问题 +- 递归相对循环往往是代码更凝练简洁和便于理解,代码实现往往比循环简单 +- 尾递归优化可以减少常用栈空间的占用 +5. ### 尾递归 +- 原理:在递归的基础上,使用上一次调用返回状态作为新的状态作为下一次递归的状态参数,即存在F(x),F(n) = F(F(n-1)) +- 本质是递归转换为循环,总的来说,一般没有什么特别大的用处 +- 尾递归举例(斐波那次) +```golang +// 原始递归版 +func fibUseRecur(n int) int { + if n <= 2 { + return n + } + return fibUseRecur(n-1) + fibUseRecur(n-2) +} + +// 尾递归版本 +func fibUseTailRecur(target,fv, sv int) int { + if target <= 1 { + return fv + } + if target == 2 { + return sv + } + return fibUseTailRecur(target-1, sv, fv+sv) +} +// fibUseRecur(6) == fibUseTailRecur(6,1,2) +``` + diff --git a/Week_02/G20200343030581/LeetCode_105_581.js b/Week_02/G20200343030581/LeetCode_105_581.js new file mode 100644 index 00000000..61d9e895 --- /dev/null +++ b/Week_02/G20200343030581/LeetCode_105_581.js @@ -0,0 +1,41 @@ +/* + * @lc app=leetcode.cn id=105 lang=javascript + * + * [105] 从前序与中序遍历序列构造二叉树 + */ + +// @lc code=start +/** + * Definition for a binary tree node. + * function TreeNode(val) { + * this.val = val; + * this.left = this.right = null; + * } + */ +/** + * @param {number[]} preorder + * @param {number[]} inorder + * @return {TreeNode} + */ +var buildTree = function(preorder, inorder) { + let p = 0; + let inorderDic = {} + for (let i = 0; i < inorder.length; i++) { + inorderDic[inorder[i]] = i; + } + function helper(s, e) { + if (s >= e) + return null; + let val = preorder[p++]; + let node = new TreeNode(val); + let index = inorderDic[val]; + node.left = helper(s, index); + node.right = helper(index + 1, e); + return node; + } + + return helper(0, inorder.length); +}; +// @lc code=end + + diff --git a/Week_02/G20200343030581/LeetCode_144_581.js b/Week_02/G20200343030581/LeetCode_144_581.js new file mode 100644 index 00000000..427cfb2e --- /dev/null +++ b/Week_02/G20200343030581/LeetCode_144_581.js @@ -0,0 +1,53 @@ +/* + * @lc app=leetcode.cn id=144 lang=javascript + * + * [144] 二叉树的前序遍历 + */ + +// @lc code=start +/** + * Definition for a binary tree node. + * function TreeNode(val) { + * this.val = val; + * this.left = this.right = null; + * } + */ +/** + * @param {TreeNode} root + * @return {number[]} + */ +// 1.递归 O(n) +var preorderTraversal = function(root) { + let res = []; + function helper(root) { + if (root) { + res.push(root.val); + helper(root.left); + helper(root.right); + } + } + + helper(root); + return res; +}; + +// 2.迭代 O(n) +var preorderTraversal = function(root) { + let res = []; + if (!root) + return res; + let stack = [root]; + while (stack.length) { + let tmp = stack.pop(); + res.push(tmp.val); + if (tmp.right) + stack.push(tmp.right); + if (tmp.left) + stack.push(tmp.left); + } + + return res; +} +// @lc code=end + + diff --git a/Week_02/G20200343030581/LeetCode_145_581.js b/Week_02/G20200343030581/LeetCode_145_581.js new file mode 100644 index 00000000..4bccae75 --- /dev/null +++ b/Week_02/G20200343030581/LeetCode_145_581.js @@ -0,0 +1,54 @@ +/* + * @lc app=leetcode.cn id=145 lang=javascript + * + * [145] 二叉树的后序遍历 + */ + +// @lc code=start +/** + * Definition for a binary tree node. + * function TreeNode(val) { + * this.val = val; + * this.left = this.right = null; + * } + */ +/** + * @param {TreeNode} root + * @return {number[]} + */ +// 1.递归 O(n) +var postorderTraversal = function(root) { + let res = []; + function helper(root) { + if (root) { + helper(root.left); + helper(root.right); + res.push(root.val); + } + } + + helper(root); + return res; +}; + +// 2.迭代 O(n) +var postorderTraversal = function(root) { + let res = []; + if (!root) + return res; + let stack = [root]; + while (stack.length) { + let tmp = stack.pop(); + res.push(tmp.val); + if (tmp.left) + stack.push(tmp.left); + if (tmp.right) + stack.push(tmp.right); + } + + return res.reverse(); +} + +// @lc code=end + + diff --git a/Week_02/G20200343030581/LeetCode_1_581.js b/Week_02/G20200343030581/LeetCode_1_581.js new file mode 100644 index 00000000..ef2e6d5c --- /dev/null +++ b/Week_02/G20200343030581/LeetCode_1_581.js @@ -0,0 +1,20 @@ +// 1. 暴力 O(n^2) +var twoSum = function(nums, target) { + for (let i = 0; i < nums.length - 1; i++) { + for (let j = i + 1; j < nums.length; j++) { + if (nums[i] + nums[j] == target) + return [i, j]; + } + } +}; + +// 2.Hash O(n) +var twoSum = function (nums, target) { + let dic = {}; + for (let i = 0; i < nums.length; i++) { + if (dic[nums[i]] != undefined) { + return [dic[nums[i]], i]; + } + dic[target - nums[i]] = i; + } +} diff --git a/Week_02/G20200343030581/LeetCode_236_581.js b/Week_02/G20200343030581/LeetCode_236_581.js new file mode 100644 index 00000000..68dc8e24 --- /dev/null +++ b/Week_02/G20200343030581/LeetCode_236_581.js @@ -0,0 +1,72 @@ +/* + * @lc app=leetcode.cn id=236 lang=javascript + * + * [236] 二叉树的最近公共祖先 + */ + +// @lc code=start +/** + * Definition for a binary tree node. + * function TreeNode(val) { + * this.val = val; + * this.left = this.right = null; + * } + */ +/** + * @param {TreeNode} root + * @param {TreeNode} p + * @param {TreeNode} q + * @return {TreeNode} + */ +// 1.递归 +var lowestCommonAncestor = function(root, p, q) { + let res; + function helper(root) { + if (!root) + return false; + let mid = root == p || root == q; + let l = helper(root.left, p, q); + let r = helper(root.right, p, q); + if (l + r + mid >= 2) { + res = root; + return true; + } + + return mid || l || r; + } + helper(root); + return res; +}; + +// 2.迭代 +var lowestCommonAncestor = function(root, p, q) { + let map = new Map(); + let stack = [root]; + map.set(root, null); + while (!map.has(p) || !map.has(q)) { + let tmp = stack.pop(); + if (tmp.right) { + stack.push(tmp.right); + map.set(tmp.right, tmp); + } + if (tmp.left) { + stack.push(tmp.left); + map.set(tmp.left, tmp); + } + } + + let set = new Set(); + while (p) { + set.add(p); + p = map.get(p); + } + + while (!set.has(q)) { + q = map.get(q); + } + + return q; +} +// @lc code=end + + diff --git a/Week_02/G20200343030581/LeetCode_242_581.js b/Week_02/G20200343030581/LeetCode_242_581.js new file mode 100644 index 00000000..f7e9cc3c --- /dev/null +++ b/Week_02/G20200343030581/LeetCode_242_581.js @@ -0,0 +1,41 @@ +/** + * @param {string} s + * @param {string} t + * @return {boolean} + */ +// 1.排序 +var isAnagram = function(s, t) { + return s.split('').sort().join('') == t.split('').sort().join(''); +}; + +// 2.HashMap O(n) +var isAnagram = function(s, t) { + if (s.length != t.length) + return false; + let a = 'a'.charCodeAt(0); + let map = Array(26).fill(0); + for (let i = 0; i < s.length; i++) { + map[s.charCodeAt(i) - a]++; + map[t.charCodeAt(i) - a]--; + } + return map.every(e => e == 0); +} + +// 3.HashMap优化,发现一个字符不符合条件就返回False +var isAnagram = function(s, t) { + if (s.length != t.length) + return false; + let a = 'a'.charCodeAt(0); + let map = Array(26).fill(0); + for (let i = 0; i < s.length; i++) { + map[s.charCodeAt(i) - a]++; + } + for (let i = 0; i < t.length; i++) { + let tmp = t.charCodeAt(i) - a; + if (map[tmp] <= 0) + return false; + map[tmp]--; + } + + return true; +} diff --git a/Week_02/G20200343030581/LeetCode_429_581.js b/Week_02/G20200343030581/LeetCode_429_581.js new file mode 100644 index 00000000..cba82fe5 --- /dev/null +++ b/Week_02/G20200343030581/LeetCode_429_581.js @@ -0,0 +1,61 @@ +/* + * @lc app=leetcode.cn id=429 lang=javascript + * + * [429] N叉树的层序遍历 + */ + +// @lc code=start +/** + * // Definition for a Node. + * function Node(val,children) { + * this.val = val; + * this.children = children; + * }; + */ +/** + * @param {Node} root + * @return {number[][]} + */ +// 1.递归 先序遍历,记录层级 +var levelOrder = function(root) { + let res = []; + function helper(level, root) { + if (root) { + let l; + if (!(l = res[level])) + res[level] = l = []; + l.push(root.val); + if (root.children) { + for (let child of root.children) { + helper(level + 1, child); + } + } + } + } + helper(0, root); + return res; +}; + +// 2.BFS +var levelOrder = function(root) { + let res = []; + if (!root) + return res; + let queue = [root]; + while (queue.length) { + let la = []; + for (let i = 0, l = queue.length; i < l; i++) { + let tmp = queue.shift(); + la.push(tmp.val); + if (tmp.children) { + for (let child of tmp.children) + queue.push(child); + } + } + res.push(la); + } + return res; +} +// @lc code=end + + diff --git a/Week_02/G20200343030581/LeetCode_46_581.js b/Week_02/G20200343030581/LeetCode_46_581.js new file mode 100644 index 00000000..38d05743 --- /dev/null +++ b/Week_02/G20200343030581/LeetCode_46_581.js @@ -0,0 +1,40 @@ +/* + * @lc app=leetcode.cn id=46 lang=javascript + * + * [46] 全排列 + */ + +// @lc code=start +/** + * @param {number[]} nums + * @return {number[][]} + */ +var permute = function(nums) { + let res = []; + function helper(s) { + if (s == nums.length - 1) { + res.push(nums.slice()); + return; + } + + for (let i = s; i < nums.length; i++) { + swap(nums, s, i); + helper(s + 1); + swap(nums, s, i); + } + } + + helper(0); + return res; +}; + +function swap(nums, i, j) { + if (i == j) + return; + let tmp = nums[i]; + nums[i] = nums[j]; + nums[j] = tmp; +} +// @lc code=end + + diff --git a/Week_02/G20200343030581/LeetCode_47_581.js b/Week_02/G20200343030581/LeetCode_47_581.js new file mode 100644 index 00000000..ac20381c --- /dev/null +++ b/Week_02/G20200343030581/LeetCode_47_581.js @@ -0,0 +1,43 @@ +/* + * @lc app=leetcode.cn id=47 lang=javascript + * + * [47] 全排列 II + */ + +// @lc code=start +/** + * @param {number[]} nums + * @return {number[][]} + */ +var permuteUnique = function(nums) { + let res = []; + function helper(s) { + if (s == nums.length - 1) { + res.push(nums.slice()) + return; + } + + let dic = {}; + for (let i = s; i < nums.length; i++) { + if (!dic[nums[i]]) { + dic[nums[i]] = 1; + swap(nums, s, i); + helper(s + 1); + swap(nums, s, i); + } + } + } + + helper(0); + return res; +}; + +function swap(nums, i, j) { + if (i == j) return; + let tmp = nums[i]; + nums[i] = nums[j]; + nums[j] = tmp; +} +// @lc code=end + + diff --git a/Week_02/G20200343030581/LeetCode_49_581.js b/Week_02/G20200343030581/LeetCode_49_581.js new file mode 100644 index 00000000..65bc409a --- /dev/null +++ b/Week_02/G20200343030581/LeetCode_49_581.js @@ -0,0 +1,37 @@ +/** + * @param {string[]} strs + * @return {string[][]} + */ +// 1. HashMap 排序后的字符串作为健值 +var groupAnagrams = function(strs) { + let map = new Map(); + for (let s of strs) { + let sortedStr = s.split('').sort().join(''); + if (map.has(sortedStr)) { + map.get(sortedStr).push(s); + } else { + map.set(sortedStr, [s]); + } + } + return [...map.values()]; +}; + +// 2.HasMap 统计字符出现次数作为健值 +var groupAnagrams = function(strs) { + let map = new Map(); + let a = 'a'.charCodeAt(0); + for (let s of strs) { + + let arr = Array(26).fill(0); + for (let i = 0; i < s.length; i++) + arr[s.charCodeAt(i) - a]++; + + let keyStr = arr.join(','); + if (map.has(keyStr)) + map.get(keyStr).push(s); + else + map.set(keyStr, [s]); + } + + return [...map.values()]; +} diff --git a/Week_02/G20200343030581/LeetCode_589_581.js b/Week_02/G20200343030581/LeetCode_589_581.js new file mode 100644 index 00000000..6a3ad8e9 --- /dev/null +++ b/Week_02/G20200343030581/LeetCode_589_581.js @@ -0,0 +1,54 @@ +/* + * @lc app=leetcode.cn id=589 lang=javascript + * + * [589] N叉树的前序遍历 + */ + +// @lc code=start +/** + * // Definition for a Node. + * function Node(val, children) { + * this.val = val; + * this.children = children; + * }; + */ +/** + * @param {Node} root + * @return {number[]} + */ +// 1.递归 +var preorder = function(root) { + let res = []; + function helper(root) { + if (root) { + res.push(root.val); + if (root.children) { + for (let child of root.children) + helper(child); + } + } + } + helper(root); + return res; +}; + +// 1.迭代 +var preorder = function(root) { + let res = []; + if (!root) + return res; + let stack = [root]; + while (stack.length) { + let tmp = stack.pop(); + res.push(tmp.val); + if (tmp.children) { + let children = tmp.children; + for (let i = children.length - 1; i >= 0; --i) + stack.push(children[i]); + } + } + return res; +} +// @lc code=end + + diff --git a/Week_02/G20200343030581/LeetCode_590_581.js b/Week_02/G20200343030581/LeetCode_590_581.js new file mode 100644 index 00000000..5b7e811f --- /dev/null +++ b/Week_02/G20200343030581/LeetCode_590_581.js @@ -0,0 +1,56 @@ +/* + * @lc app=leetcode.cn id=590 lang=javascript + * + * [590] N叉树的后序遍历 + */ + +// @lc code=start +/** + * // Definition for a Node. + * function Node(val,children) { + * this.val = val; + * this.children = children; + * }; + */ +/** + * @param {Node} root + * @return {number[]} + */ +// 1.递归 +var postorder = function(root) { + let res = []; + function helper(root) { + if (root) { + if (root.children) { + for (let child of root.children) + helper(child); + } + + res.push(root.val); + } + } + + helper(root); + return res; +}; + +// 2.非递归 +var postorder = function(root) { + let res = []; + if (!root) + return res; + let stack = [root]; + while (stack.length) { + let tmp = stack.pop(); + res.push(tmp.val); + if (tmp.children) { + for (let child of tmp.children) + stack.push(child); + } + } + + return res.reverse(); +} +// @lc code=end + + diff --git a/Week_02/G20200343030581/LeetCode_77_581.js b/Week_02/G20200343030581/LeetCode_77_581.js new file mode 100644 index 00000000..32735bd1 --- /dev/null +++ b/Week_02/G20200343030581/LeetCode_77_581.js @@ -0,0 +1,34 @@ +/* + * @lc app=leetcode.cn id=77 lang=javascript + * + * [77] 组合 + */ + +// @lc code=start +/** + * @param {number} n + * @param {number} k + * @return {number[][]} + */ +var combine = function(n, k) { + let res = []; + let com = []; + function helper(level, s) { + if (level == k) { + res.push(com.slice()); + return; + } + + for (let i = s; i <= n; i++) { + com.push(i); + helper(level + 1, i + 1); + com.pop(); + } + } + + helper(0, 1); + return res; +}; +// @lc code=end + + diff --git a/Week_02/G20200343030581/LeetCode_94_581.js b/Week_02/G20200343030581/LeetCode_94_581.js new file mode 100644 index 00000000..32ec73c6 --- /dev/null +++ b/Week_02/G20200343030581/LeetCode_94_581.js @@ -0,0 +1,94 @@ +/* + * @lc app=leetcode.cn id=94 lang=javascript + * + * [94] 二叉树的中序遍历 + */ + +// @lc code=start +/** + * Definition for a binary tree node. + * function TreeNode(val) { + * this.val = val; + * this.left = this.right = null; + * } + */ +/** + * @param {TreeNode} root + * @return {number[]} + */ +// 1.递归 O(n) +var inorderTraversal = function(root) { + let res = []; + function helper(root) { + if (root) { + helper(root.left); + res.push(root.val); + helper(root.right); + } + } + + helper(root); + return res; +}; + +// 2.用栈去迭代 O(n) O(n) +var inorderTraversal = function(root) { + let res = []; + let stack = []; + let cur = root; + while (cur || stack.length) { + while (cur) { + stack.push(cur); + cur = cur.left; + } + + cur = stack.pop(); + res.push(cur.val); + cur = cur.right; + } + + return res; +} + +var inorderTraversal = function(root) { + let res = []; + let stack = []; + let cur = root; + while (cur || stack.length) { + if (cur) { + stack.push(cur); + cur = cur.left; + } else { + cur = stack.pop(); + res.push(cur.val); + cur = cur.right; + } + } + + return res; +} + +// 3. 莫里斯遍历 O(n) O(1) +var inorderTraversal = function (root) { + let res = []; + let cur = root; + while (cur) { + if (!cur.left) { + res.push(cur.val); + cur = cur.right; + } else { + let L = cur.left; + while (L.right) { + L = L.right; + } + L.right = cur; + let tmp = cur; + cur = cur.left; + tmp.left = null; + } + } + return res; +} +// @lc code=end + + diff --git a/Week_02/G20200343030583/LeetCode_105_583.py b/Week_02/G20200343030583/LeetCode_105_583.py new file mode 100644 index 00000000..11af5ef5 --- /dev/null +++ b/Week_02/G20200343030583/LeetCode_105_583.py @@ -0,0 +1,46 @@ +# +# @lc app=leetcode id=105 lang=python +# +# [105] Construct Binary Tree from Preorder and Inorder Traversal +# node in preorder will split nodes in inorder into left subtree and right subtree + + +# @lc code=start +# Definition for a binary tree node. +# class TreeNode(object): +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution(object): + def __init__(self): + # index in preorder + self.preidx = 0 + + def buildTree(self, preorder, inorder): + """ + :type preorder: List[int] + :type inorder: List[int] + :rtype: TreeNode + """ + def build(in_left = 0, in_right = len(inorder)): + if in_left == in_right: + return None + + root_val = preorder[self.preidx] + root = TreeNode(root_val) + + self.preidx += 1 + index = idx_map[root_val] + + root.left = build(in_left, index) + root.right = build(index + 1, in_right) + return root + + # consturct a map from val to index on inorder list + idx_map = {val:idx for idx,val in enumerate(inorder)} + + return build() +# @lc code=end + diff --git a/Week_02/G20200343030583/LeetCode_144_583.py b/Week_02/G20200343030583/LeetCode_144_583.py new file mode 100644 index 00000000..69027fe2 --- /dev/null +++ b/Week_02/G20200343030583/LeetCode_144_583.py @@ -0,0 +1,37 @@ +# +# @lc app=leetcode id=144 lang=python +# +# [144] Binary Tree Preorder Traversal +# + +# @lc code=start +# Definition for a binary tree node. +# class TreeNode(object): +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution(object): + def preorderTraversal(self, root): + """ + :type root: TreeNode + :rtype: List[int] + """ + if root is None: + return [] + + stack, output = [root,],[] + # stack is not empty, which means which have access all the nodes + while stack: + root = stack.pop() + if root is not None: + output.append(root.val) + # remember to check if is None + if root.right is not None: + stack.append(root.right) + if root.left is not None: + stack.append(root.left) + return output +# @lc code=end + diff --git a/Week_02/G20200343030583/LeetCode_236_583.py b/Week_02/G20200343030583/LeetCode_236_583.py new file mode 100644 index 00000000..c57b6833 --- /dev/null +++ b/Week_02/G20200343030583/LeetCode_236_583.py @@ -0,0 +1,100 @@ +# +# @lc app=leetcode id=236 lang=python +# +# [236] Lowest Common Ancestor of a Binary Tree +# recursively: +# 1. use left, right, mid as a sign +# 2. https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-tree/discuss/158060/Python-DFS-tm +# iteratively: +# 3. use parent pointer + +# @lc code=start +# Definition for a binary tree node. +# class TreeNode(object): +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +# First +class Solution(object): + def __init__(self): + self.ans = None + def lowestCommonAncestor(self, root, p, q): + """ + :type root: TreeNode + :type p: TreeNode + :type q: TreeNode + :rtype: TreeNode + """ + if p == q: + return p + + def searchdown(current_node): + if not current_node: + return False + + left = searchdown(current_node.left) + right = searchdown(current_node.right) + + mid = current_node == p or current_node == q + + if mid + left + right >= 2: + self.ans = current_node + + return mid or left or right + + searchdown(root) + return self.ans + +# Second +class Solution(object): + def lowestCommonAncestor(self, root, p, q): + """ + :type root: TreeNode + :type p: TreeNode + :type q: TreeNode + :rtype: TreeNode + """ + if root is None: + return None + + if root == q or root == p: + return root + + left = self.lowestCommonAncestor(root.left, p, q) + right = self.lowestCommonAncestor(root.right, p, q) + + return root if left and right else left or right + +# Third +class Solution(object): + def lowestCommonAncestor(self, root, p, q): + """ + :type root: TreeNode + :type p: TreeNode + :type q: TreeNode + :rtype: TreeNode + """ + stack = [root] + parent = {root:None} + while p not in parent or q not in parent: + node = stack.pop() + if node.right: + parent[node.right] = node + stack.append(node.right) + if node.left: + parent[node.left] = node + stack.append(node.left) + + ancestors = set() + while p: + ancestors.add(p) + p = parent[p] + + while q not in ancestors: + q = parent[q] + + return q +# @lc code=end + diff --git a/Week_02/G20200343030583/LeetCode_429_583.py b/Week_02/G20200343030583/LeetCode_429_583.py new file mode 100644 index 00000000..1e079316 --- /dev/null +++ b/Week_02/G20200343030583/LeetCode_429_583.py @@ -0,0 +1,84 @@ +# +# @lc app=leetcode id=429 lang=python +# +# [429] N-ary Tree Level Order Traversal +# + +# @lc code=start +""" +# Definition for a Node. +class Node(object): + def __init__(self, val=None, children=None): + self.val = val + self.children = children +""" +# recursively +class Solution(object): + def levelOrder(self, root): + """ + :type root: Node + :rtype: List[List[int]] + """ + if root is None: + return [] + + def leveldown(root,level): + if root is None: + return + + if len(result) == level: + result.append([]) + result[level].append(root.val) + for c in root.children: + leveldown(c, level + 1) + + result = [] + leveldown(root, 0) + return result + +# Use BFS with queue +import collections +class Solution(object): + def levelOrder(self, root): + """ + :type root: Node + :rtype: List[List[int]] + """ + if root is None: + return [] + + result = [] + queue = collections.deque([root]) + while queue: + level = [] + for _ in range(len(queue)): + node = queue.popleft() + level.append(node.val) + queue.extend(node.children) + result.append(level) + + return result + +# simplified BFS +class Solution(object): + def levelOrder(self, root): + """ + :type root: Node + :rtype: List[List[int]] + """ + if root is None: + return [] + + result = [] + previous_level = [root] + while previous_level: + result.append([]) + current_level = [] + for node in previous_level: + result[-1].append(node.val) + current_level.extend(node.children) + previous_level = current_level + + return result +# @lc code=end + diff --git a/Week_02/G20200343030583/LeetCode_49_583.py b/Week_02/G20200343030583/LeetCode_49_583.py new file mode 100644 index 00000000..31ac4cf9 --- /dev/null +++ b/Week_02/G20200343030583/LeetCode_49_583.py @@ -0,0 +1,28 @@ +# +# @lc app=leetcode id=49 lang=python +# +# [49] Group Anagrams +# hash function: sort, map str to a sorted_str + +# @lc code=start +class Solution(object): + def groupAnagrams(self, strs): + """ + :type strs: List[str] + :rtype: List[List[str]] + """ + if len(strs) == 0: + return [] + map = dict() + + for str in strs: + sorted_str = ''.join(sorted(str)) + if sorted_str not in map: + map[sorted_str] = [str] + else: + map[sorted_str].append(str) + # use dict.get() will be slower + # map[sorted_str] = map.get(sorted_str,[]) + [str] + return list(map.values()) +# @lc code=end + diff --git a/Week_02/G20200343030583/LeetCode_77_583.py b/Week_02/G20200343030583/LeetCode_77_583.py new file mode 100644 index 00000000..55e7279e --- /dev/null +++ b/Week_02/G20200343030583/LeetCode_77_583.py @@ -0,0 +1,35 @@ +# +# @lc app=leetcode id=77 lang=python +# +# [77] Combinations +# 1. f(k) = f(k-1) + f(1) brute force O(N^3) +# 2. backtrack + pruning +# @lc code=start +class Solution(object): + def __init__(self): + self.output = [] + def combine(self, n, k): + """ + :type n: int + :type k: int + :rtype: List[List[int]] + """ + if n < 0 or k > n or k < 0: + return [] + def backtrack(first, curr): + # has found k numbers, add to output + if len(curr) == k: + self.output.append(curr[:]) + return + # pruning: n - (k - len(curr)) + 1 = max(i) + for i in range(first,n - (k - len(curr)) + 2): + curr.append(i) + backtrack(i + 1,curr) + # reset status + curr.pop() + + backtrack(1,[]) + return self.output + +# @lc code=end + diff --git a/Week_02/G20200343030583/NOTE.md b/Week_02/G20200343030583/NOTE.md index 50de3041..b51aa42c 100644 --- a/Week_02/G20200343030583/NOTE.md +++ b/Week_02/G20200343030583/NOTE.md @@ -1 +1,66 @@ -学习笔记 \ No newline at end of file +## 学习笔记 +Hash table (hash function to project
+Key -> value
+Example: LRU cache
+碰撞:多个元素通过链表存储
+Average: Search O(1), Insertion O(1), Deletion O(1)
+Worst: All O(n)
+Map and set -> python: dict & set + +### 四步思考: +1. Clarification和面试官讨论 +2. Possible solution -> optimal (time&space) +3. Code +4. Test cases + +`Leetcode 242. valid anagram` +1. Brute force, sort string, if sorted_str equal? -> O(nlog n) +2. Hash, map -> to record frequency of every character + +### 二叉树遍历: +- Pre-order: root, left, right +- In-order: left, root, right +- Post-order: left, right, root + +### 二叉搜索树(binary search tree) = 有序二叉树(ordered binary tree) = 排序二叉树(sorted binary tree) +1. All the nodes on the left tree . Val < root. Val +2. All the nodes on the right tree . Val > root. Val +3. Both left and right trees are also binary search tree +- Thus **in-order -> ascending sorted array !可以用来验证是否为BST** +- 查询,插入O(log n) +- 注意,如果是无序,查询和插入则是O(n) +- 删除:1. 叶子 -> 直接删除 2. 非叶子结点 -> 删除后,将刚好大于的结点拉上去 + +### 递归 recursion +```python +#Python 代码模版 +Def recursion(level, param1, param2,…) +#recursion terminator 终止条件先写上 +If level > MAX_LEVEL: + process_result + return + +# process logic in current level 处理当前层的数据 +process(level, data,…) + +# drill down 下潜到下一层 +self.recursion(level+1, p1, …) + +# reverse the current level status if needed ( like global parameter) 清理当前层的状态 +``` +### 思维要点: +1. 不要人肉递归 +2. 找最近最简方法,将其拆解成重复子问题 (重复性) +3. 数学归纳法 (初始条件成立;保证在前一个条件成立的时候,后一个也成立) + +`Leetcode 爬楼梯问题`
+找包含所有的子问题、且没有重复计算 (mutual exclusive & complete exhaustive)的方法 + +`Leetcode 22. 括号生成 (只有小括号的情况` +1. 用递归去写能生成包含n个括号的各种情况的程序 +2. 考虑括号合法性,在递归中即可验证: +- left 随时可以加,只要不超标,不超过n +- Right 必须之前有左括号,且左个数 > 右个数 + +`Thoughts from Leetcode 429. N-ary tree`
+BFS use queue, DFS use stack diff --git a/Week_02/G20200343030585/LeetCode_105_585.py b/Week_02/G20200343030585/LeetCode_105_585.py new file mode 100644 index 00000000..15f0f978 --- /dev/null +++ b/Week_02/G20200343030585/LeetCode_105_585.py @@ -0,0 +1,58 @@ +# +# @lc app=leetcode.cn id=105 lang=python +# +# [105] 从前序与中序遍历序列构造二叉树 +# +# 解题思路 +# 1 递归 +# 1. 前序遍历,反向循环遍历逻辑,根、左、右,同时左要小于根,右要大于根 +# 2. 前序遍历的第一个元素就是根,这样把中序遍历的数组分成两个部分 +# 一部分是左子树,一部分是右子树 +# 3.然后重复遍历左子树,重复遍历右子树 + +# @lc code=start +# Definition for a binary tree node. +# class TreeNode(object): +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution(object): + def buildTree(self, preorder, inorder): + """ + :type preorder: List[int] + :type inorder: List[int] + :rtype: TreeNode + """ + self.preorder = preorder + self.inorder = inorder + + self.pre_idx = 0 + self.idx_map = {val:idx for idx, val in enumerate(inorder)} + return self.construct(0, len(inorder)) + + + def construct(self, in_left, in_right): + # there is no element to contruct subtree + if in_left == in_right: + return None # return for node + + root_val = self.preorder[self.pre_idx] + root = TreeNode(root_val) + + index = self.idx_map[root_val] + + self.pre_idx += 1 + root.left = self.construct(in_left, index) + root.right = self.construct(index + 1, in_right) + + return root + + + + + + +# @lc code=end + diff --git a/Week_02/G20200343030585/LeetCode_144_585.py b/Week_02/G20200343030585/LeetCode_144_585.py new file mode 100644 index 00000000..3dbecba8 --- /dev/null +++ b/Week_02/G20200343030585/LeetCode_144_585.py @@ -0,0 +1,33 @@ +# 解题思路: +# 前序遍历就是先访问根节点,再遍历左子树,然后是遍历右子树 +# 可以通过一个递归完成遍历过程 + +# Definition for a binary tree node. +class TreeNode(object): + def __init__(self, x): + self.val = x + self.left = None + self.right = None + +class Solution(object): + def preorderTraversal(self, root): + """ + :type root: TreeNode + :rtype: List[int] + """ + + if root is None: + return [] + + res = [] + self._preorderTraversal(root, res) + return res + + def _preorderTraversal(self, node, res = []): + res.append(node.val) + if node.left is not None: + self._preorderTraversal(node.left, res) + if node.right is not None: + self._preorderTraversal(node.right, res) + + \ No newline at end of file diff --git a/Week_02/G20200343030585/LeetCode_226_585.py b/Week_02/G20200343030585/LeetCode_226_585.py new file mode 100644 index 00000000..8459ecf4 --- /dev/null +++ b/Week_02/G20200343030585/LeetCode_226_585.py @@ -0,0 +1,79 @@ +# +# @lc app=leetcode.cn id=226 lang=python +# +# [226] 翻转二叉树 +# 题目理解 +# 1. 对二叉树翻转的认知首先是左子树和右子树交换位置 +# 2。对每个子树下的左右元素交换位置 +# 解题思路 +# 1.使用递归来解题,不断交换当前元素的左节点和右节点 +# 1。首先翻转根的左和右子树 +# 2. 递归左子树和右子树,实现两者的孩子进行交换 +# 3. 递归结束条件,如果孩子为空就结束了 +# 4. 如何没有根没有孩子也结束了 +# 时间复杂度 O(N) +# 空间复杂度 O(N), 因为使用递归调用,总共需要2^h - 2h - 1次递归 +# h为二叉树高度,2^h - 1 接近n,所有整体为O(N) + +# 2.使用循环来解题 +# 1。每次把子节点交换一遍,然后将左右节点添加入栈 +# 2. 循环栈的元素,知道没有元素为止 +# 时间复杂度O(N) 需要把每个元素都遍历一遍 +# 空间复杂度O(N) 最坏的情况有N/2的节点在stack里面 + +# @lc code=start +# Definition for a binary tree node. +# class TreeNode(object): +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + + +class Solution(object): + def invertTree(self, root): + """ + :type root: TreeNode + :rtype: TreeNode + """ + st = [] + if root is None: + return None + + st.append(root) + + while len(st) != 0: + node = st.pop() + + temp = node.left + node.left = node.right + node.right = temp + + if node.left: st.append(node.left) + if node.right: st.append(node.right) + + return root + + +# class Solution(object): +# def invertTree(self, root): +# """ +# :type root: TreeNode +# :rtype: TreeNode +# """ +# if root is None: +# return None +# left = root.left +# right = root.right +# if left: +# self.invertTree(left) +# if right: +# self.invertTree(right) + +# root.left = right +# root.right = left + +# return root + +# @lc code=end + diff --git a/Week_02/G20200343030585/LeetCode_236_585.py b/Week_02/G20200343030585/LeetCode_236_585.py new file mode 100644 index 00000000..52c34270 --- /dev/null +++ b/Week_02/G20200343030585/LeetCode_236_585.py @@ -0,0 +1,103 @@ +# +# @lc app=leetcode.cn id=236 lang=python +# +# [236] 二叉树的最近公共祖先 +# 解题思路 +# 1.递归 +# 1.从根节点找起,如果找到要找的节点就返回True +# 2。如果当前节点的两边都找到了当前节点,第一个查到的就是公共祖先 +# 3。如果当前节点就是要找的节点,同时其子节点也找到了其中一个元素证明当前节点为公共祖先 +# 复杂度分析 +# 时间复杂度:O(N),N 是二叉树中的节点数,最坏情况下,我们需要访问二叉树的所有节点。 +# 空间复杂度:O(N),这是因为递归堆栈使用的最大空间位 N,斜二叉树的高度可以是 N。 +# 2.递归 +# 1.先找到q和p节点的所有父节点存入字典,字典保存父子关系 +# 2.导出所有p的父节点,查找q节点的父节点是否在q的父节点里面 + +# @lc code=start +# Definition for a binary tree node. +# class TreeNode(object): +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + + +class Solution(object): + def lowestCommonAncestor(self, root, p, q): + """ + :type root: TreeNode + :type p: TreeNode + :type q: TreeNode + :rtype: TreeNode + """ + parent = collections.defaultdict() + # 添加root节点 + parent[root] = None + st = [root] + + while p not in parent or q not in parent: + node = st.pop() + + if node.left: + parent[node.left] = node + st.append(node.left) + if node.right: + parent[node.right] = node + st.append(node.right) + + ancestors = set() + + while p: + ancestors.add(p) + p = parent[p] + + + while q not in ancestors: + q = parent[q] + + return q + + + +# class Solution(object): +# def lowestCommonAncestor(self, root, p, q): +# """ +# :type root: TreeNode +# :type p: TreeNode +# :type q: TreeNode +# :rtype: TreeNode +# """ +# if root is None: +# return [] +# ans = None + +# def search(node): +# if node is None: +# return False + +# # 在左子树 or 右子树是否找到p,q +# left = search(node.left) +# right = search(node.right) + +# mid = False +# # 如果当前元素为q,p其中一个的时候 +# if node == p or node == q: +# mid = True + +# # 当前元素的子树找到了q,p +# # 当前元素为其中之一 同时子树里面找到另外一个 +# if mid + left + right >= 2: +# self.ans = node + +# # 任何一个方向找到了 or 当前找到了都是这条路径上找到了 +# return mid or left or right + +# search(root) +# return self.ans + + + + +# @lc code=end + diff --git a/Week_02/G20200343030585/LeetCode_429_585.py b/Week_02/G20200343030585/LeetCode_429_585.py new file mode 100644 index 00000000..06fd4ecf --- /dev/null +++ b/Week_02/G20200343030585/LeetCode_429_585.py @@ -0,0 +1,39 @@ +#解题思路 +# 1. 递归方法,逐级递归, 其中重复的部分是找子层级里面的每个元素 + + +# Definition for a Node. +class Node(object): + def __init__(self, val=None, children=None): + self.val = val + self.children = children + +class Solution(object): + def levelOrder(self, root): + """ + :type root: Node + :rtype: List[List[int]] + """ + if root is None: + return [] + + res = [[root.val]] + self._levelOrder(root.children, res) + return res + + def _levelOrder(self, children, res=[]): + if len(children) == 0: + return + + ret = [] + self_children = [] + length = len(children) + for i in range(length): + self_children += children[i].children + ret.append(children[i].val) + + res.append(ret) + self._levelOrder(self_children, res) + + + \ No newline at end of file diff --git a/Week_02/G20200343030585/LeetCode_46_585.py b/Week_02/G20200343030585/LeetCode_46_585.py new file mode 100644 index 00000000..6f157ea7 --- /dev/null +++ b/Week_02/G20200343030585/LeetCode_46_585.py @@ -0,0 +1,41 @@ +# +# @lc app=leetcode.cn id=46 lang=python +# +# [46] 全排列 +# 解题思路 +# 1. 暴力 +# 1.递归+循环 +# 复杂性分析 +# 时间复杂度:o(∑k=1 N P(N,k)), P(N, k) = N!/(N−k)! ​=N(N−1)...(N−k+1),该式被称作 n 的 k-排列,或者_部分排列_. +# 为了简单起见,使 first + 1 = kfirst+1=k. +# 这个公式很容易理解:对于每个 k (每个firstfirst), 有 N(N - 1) ... (N - k + 1)N(N−1)...(N−k+1) 次操作, +# 且 k 的范围从 1 到 N (firstfirst 从 0 到 N - 1). +# 即算法比 O(N×N!)更优 且比 O(N!) 稍慢. +# 空间复杂度:o(N!) 由于必须要保存N! 个解。 + +# @lc code=start +class Solution(object): + def permute(self, nums): + """ + :type nums: List[int] + :rtype: List[List[int]] + """ + if not nums: + return [] + res = [] + self.recur(nums, 0, len(nums), res) + return res + + def recur(self, nums, first, length, res): + if first == length: + res.append(nums[:]) # 一个坑记录下,必须要用:符号,要不添加的就是空 + return res + + for i in range(first, length): + nums[i], nums[first] = nums[first], nums[i] + self.recur(nums, first + 1, length, res) + nums[first], nums[i] = nums[i], nums[first] + + +# @lc code=end + diff --git a/Week_02/G20200343030585/LeetCode_47_585.py b/Week_02/G20200343030585/LeetCode_47_585.py new file mode 100644 index 00000000..38ad7a00 --- /dev/null +++ b/Week_02/G20200343030585/LeetCode_47_585.py @@ -0,0 +1,49 @@ +# +# @lc app=leetcode.cn id=47 lang=python +# +# [47] 全排列 II +# 解题思路 +# 1.基于全排列1的代码对数据去重, 再做计算 +# 1.使用递归和循环计算所有符合可能的结果 +# 2.使用回溯查找每个子树里面的可能性 +# 3.使用dict来记录每个正确的元素,在添加的时候去重 +# 2.思路类似上面,但在可能产生重复的地方剪枝 +# 1. +# +# @lc code=start + +class Solution(object): + def permuteUnique(self, nums): + """ + :type nums: List[int] + :rtype: List[List[int]] + """ + + if not nums: + return [] + nums.sort() + used = [False]*len(nums) + res, stack = [], [] + self.recur(nums, 0, len(nums), res, stack, used) + return res + + def recur(self, nums, first, length, res, stack, used): + if first == length: + res.append(stack[:]) # 一个坑记录下,必须要用:符号,要不添加的就是空 + return + + for i in range(length): + if not used[i]: + if i > 0 and nums[i] == nums[i - 1] and not used[i-1]: + continue + used[i] = True + stack.append(nums[i]) + self.recur(nums, first + 1, length, res, stack, used) + stack.pop() + used[i] = False + + + + +# @lc code=end + diff --git a/Week_02/G20200343030585/LeetCode_49_585.py b/Week_02/G20200343030585/LeetCode_49_585.py new file mode 100644 index 00000000..1c203924 --- /dev/null +++ b/Week_02/G20200343030585/LeetCode_49_585.py @@ -0,0 +1,48 @@ +# 解题思路 +# 1、使用hashmap 将每个词排序后和索引一起放到hashmap,然后循环查询单词 +# 2、生成每个词的有序数组,然后比较每个数组是否一样,一样的放一起,要保留一个数组和原数组对应关系 +# 3、将字符串数组的每个字母单独计算出现次数,每个字母按字母顺序排列,然后以此为key,字符串的list集合为值 + +class Solution(object): + def groupAnagrams(self, strs): + ans = collections.defaultdict(list) + for s in strs: + ans[tuple(sorted(s))].append(s) + return ans.values() + +# 效率太低执行不通过 +# class Solution(object): +# def groupAnagrams(self, strs): +# length = len(strs) +# arr = [] +# for i in range(length): +# arr.append(sorted(strs[i])) + +# _ret, ret = [], [] + +# for i in range(length): +# if arr[i] == '---': +# continue +# _ret.append(strs[i]) +# for j in range(i+1, length): +# if arr[j] == '---': +# continue +# if arr[j] == arr[i] and arr[j] != '---': +# _ret.append(strs[j]) +# arr[j] = '---' +# ret.append(_ret) +# _ret = [] +# return ret + + +# +class Solution(object): + def groupAnagrams(self, strs): + ans = collections.defaultdict(list) + for s in strs: + count = [0] * 26 #一个python简化的语句,很方便 + for c in s: + count[ord[c] - ord['a']] += 1 + ans[tuple(count)].append(s) + return ans.values() + \ No newline at end of file diff --git a/Week_02/G20200343030585/LeetCode_77_585.py b/Week_02/G20200343030585/LeetCode_77_585.py new file mode 100644 index 00000000..4c336480 --- /dev/null +++ b/Week_02/G20200343030585/LeetCode_77_585.py @@ -0,0 +1,45 @@ +# +# @lc app=leetcode.cn id=77 lang=python +# +# [77] 组合 +# +# 解题思路(直接用的leetcode官方解答) +# 1. 回溯法 +# 1. 通过遍历所有可能成员来寻找全部可行解的算法 +# 2. 将要添加到组合和现有组合作为参数 +# 3. 若已达到需要的大小就添加返回 +# 4. 遍历从 first 到 n 的所有整数。 +# 5. 继续向组合中添加更多参数 +# 6. 将添加的i移除,实现回溯 +# 复杂度分析 +# 时间复杂度 : O(k C_N^k),其中 C_N^k = N!/(N−k)!k! 是要构成的组合数。 +# append / pop (add / removeLast) 操作使用常数时间,唯一耗费时间的是将长度为 k 的组合添加到输出中。 +# 空间复杂度 : O(C_N^k),用于保存全部组合数以输出。 + +# @lc code=start +class Solution(object): + def combine(self, n, k): + """ + :type n: int + :type k: int + :rtype: List[List[int]] + """ + def backtrack(first = 1, curr = []): + # if the combination is done + if len(curr) == k: + output.append(curr[:]) + for i in range(first, n + 1): + # add i into the current combination + curr.append(i) + # use next integers to complete the combination + backtrack(i + 1, curr) + # backtrack + curr.pop() + + output = [] + backtrack() + return output + + +# @lc code=end + diff --git a/Week_02/G20200343030585/NOTE.md b/Week_02/G20200343030585/NOTE.md deleted file mode 100644 index 50de3041..00000000 --- a/Week_02/G20200343030585/NOTE.md +++ /dev/null @@ -1 +0,0 @@ -学习笔记 \ No newline at end of file diff --git a/Week_02/G20200343030585/leetCode_104_585.py b/Week_02/G20200343030585/leetCode_104_585.py new file mode 100644 index 00000000..a73df66f --- /dev/null +++ b/Week_02/G20200343030585/leetCode_104_585.py @@ -0,0 +1,44 @@ +# +# @lc app=leetcode.cn id=104 lang=python +# +# [104] 二叉树的最大深度 +# + +# @lc code=start +# 解题思路 +# 1、递归 递归几次就是最大深度,去掉最后可能为空的情况 +# 2、循环 不断循环子节点,每次加一 + +# Definition for a binary tree node. +# class TreeNode(object): +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution(object): + def maxDepth(self, root): + """ + :type root: TreeNode + :rtype: int + """ + if not root: + return 0 + + def depth(node, level): + if not node: + return level + + l_val = r_val = 0 + + if node.left: + l_val = depth(node.left, level + 1) + if node.right: + r_val = depth(node.right, level + 1) + return max(l_val, r_val, level) + + return depth(root, 1) + + +# @lc code=end + diff --git a/Week_02/G20200343030587/src/main/java/com/home/work/week02/LeetCode_105_587.java b/Week_02/G20200343030587/src/main/java/com/home/work/week02/LeetCode_105_587.java new file mode 100644 index 00000000..a8195521 --- /dev/null +++ b/Week_02/G20200343030587/src/main/java/com/home/work/week02/LeetCode_105_587.java @@ -0,0 +1,24 @@ +package com.home.work.week02; + +import java.util.HashMap; +import java.util.Map; + +public class LeetCode_105_587 { + Map map = new HashMap<>(); + private int preIdx = 0; + public TreeNode buildTree(int[] preorder, int[] inorder) { + int i = 0; + for (int key : inorder) map.put(key, i++); + return buildTreeHelp(preorder, 0, inorder.length -1); + } + TreeNode buildTreeHelp(int[] preorder, int left, int right) { + if (left > right) return null; + int rootVal = preorder[preIdx++]; + TreeNode node = new TreeNode(rootVal); + int idx = map.get(rootVal); + node.left = buildTreeHelp(preorder, left, idx - 1); + node.right = buildTreeHelp(preorder, idx + 1, right); + return node; + + } +} diff --git a/Week_02/G20200343030587/src/main/java/com/home/work/week02/LeetCode_144_587.java b/Week_02/G20200343030587/src/main/java/com/home/work/week02/LeetCode_144_587.java new file mode 100644 index 00000000..34b3c0ce --- /dev/null +++ b/Week_02/G20200343030587/src/main/java/com/home/work/week02/LeetCode_144_587.java @@ -0,0 +1,34 @@ +package com.home.work.week02; + +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; + +public class LeetCode_144_587 { + public List preorderTraversal(TreeNode root) { + //递归 + // List res = new ArrayList<>(); + // helper(root, res); + // return res; + + //迭代 + List res = new ArrayList<>(); + Stack stack = new Stack(); + if (root == null) return res; + stack.push(root); + while (!stack.isEmpty()) { + TreeNode node = stack.pop(); + res.add(node.val); + if (node.right != null) stack.push(node.right); + if (node.left != null) stack.push(node.left); + } + return res; + } + + void helper(TreeNode root, List res) { + if (root == null) return; + res.add(root.val); + if (root.left != null) helper(root.left, res); + if (root.right != null) helper(root.right, res); + } +} diff --git a/Week_02/G20200343030587/src/main/java/com/home/work/week02/LeetCode_236_587.java b/Week_02/G20200343030587/src/main/java/com/home/work/week02/LeetCode_236_587.java new file mode 100644 index 00000000..55a74749 --- /dev/null +++ b/Week_02/G20200343030587/src/main/java/com/home/work/week02/LeetCode_236_587.java @@ -0,0 +1,31 @@ +package com.home.work.week02; + +public class LeetCode_236_587 { + //分为二种情况 : p,q 在同一个树中,或p,q 在不同树中 + //递归结束条件 root == null || root == p || root == q + //递归左树和右树: + // 1.left && right 不为null 不在同一个树中,root 为公共祖先 + // 2.left || right 为null 在同一个树中 最先找的节点为公共祖先 + + public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { + //方案一:递归 + // root == null || root == p || root == q,root == null 为找到匹配, + // root == p || root == q 找到匹配 返回 root + // 分别递归root左右树 结果 :left right + // left != null && right != null root 为公共祖先。 + // left == null 公共祖先只能在 right中 + // right == null 反之 left==null + // 效率问题 如果,结果在左树种 右树需要递归 (剪枝改善) + + if (root == null || root == p || root == q) return root; + TreeNode left = lowestCommonAncestor(root.left,p,q); + //剪枝 + // 1.left 不为null时,判断(left != p && left != q) + // 即找到结果->left,不需要在遍历右树 + if (left != null && left != p && left != q) return left; + + TreeNode right = lowestCommonAncestor(root.right,p,q); + if (left != null && right != null) return root; + return left == null ? right : left; + } +} diff --git a/Week_02/G20200343030587/src/main/java/com/home/work/week02/LeetCode_39_587.java b/Week_02/G20200343030587/src/main/java/com/home/work/week02/LeetCode_39_587.java new file mode 100644 index 00000000..49206d90 --- /dev/null +++ b/Week_02/G20200343030587/src/main/java/com/home/work/week02/LeetCode_39_587.java @@ -0,0 +1,31 @@ +package com.home.work.week02; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; + +public class LeetCode_39_587 { + public List> groupAnagrams(String[] strs) { + HashMap> res = new HashMap<>(); + for (int i = 0; i < strs.length; i++) { + put(sort(strs[i]), strs[i], res); + } + return new ArrayList>(res.values()); + } + + private void put(String s,String rs, HashMap> map){ + List list = map.get(s); + if (list == null) { + list = new ArrayList<>(); + map.put(s, list); + } + list.add(rs); + } + + private String sort(String s) { + char[] chars = s.toCharArray(); + Arrays.sort(chars); + return String.valueOf(chars); + } +} diff --git a/Week_02/G20200343030587/src/main/java/com/home/work/week02/LeetCode_429_587.java b/Week_02/G20200343030587/src/main/java/com/home/work/week02/LeetCode_429_587.java new file mode 100644 index 00000000..6baa5323 --- /dev/null +++ b/Week_02/G20200343030587/src/main/java/com/home/work/week02/LeetCode_429_587.java @@ -0,0 +1,45 @@ +package com.home.work.week02; + +import java.util.ArrayList; +import java.util.List; + +public class LeetCode_429_587 { + public List> levelOrder(Node root) { + //队列广度优先 + // List> res = new ArrayList<>(); + // LinkedList queue = new LinkedList<>(); + // queue.offer(root); + // if (root == null) return res; + // while (!queue.isEmpty()) { + // List level = new ArrayList<>(); + // int size = queue.size(); + // for (int i = 0; i < size; i++) { + // Node node = queue.pop(); + // level.add(node.val); + // if(node.children != null && node.children.size() > 0) { + // queue.addAll(node.children); + // } + // } + // res.add(level); + // } + // return res; + + //递归实现 + List> res = new ArrayList<>(); + if (root == null) return res; + helper(root, 0, res); + return res; + } + + private void helper(Node root, int level, List> res) { + if (root == null) return; + if (level + 1 > res.size()) res.add(new ArrayList<>()); + res.get(level).add(root.val); + if (root.children != null) { + for (Node n : root.children) { + helper(n, level + 1, res); + } + } + + } +} diff --git a/Week_02/G20200343030587/src/main/java/com/home/work/week02/LeetCode_589_587.java b/Week_02/G20200343030587/src/main/java/com/home/work/week02/LeetCode_589_587.java new file mode 100644 index 00000000..fea09665 --- /dev/null +++ b/Week_02/G20200343030587/src/main/java/com/home/work/week02/LeetCode_589_587.java @@ -0,0 +1,40 @@ +package com.home.work.week02; + +import java.util.ArrayList; +import java.util.List; + +public class LeetCode_589_587 { + public List preorder(Node root) { + //迭代 + // List res = new ArrayList<>(); + // Stack stack = new Stack(); + // if (root == null) return res; + // stack.add(root); + // while (!stack.isEmpty()) { + // Node n = stack.pop(); + // res.add(n.val); + // if (n.children != null && n.children.size() > 0) { + // List childrens = n.children; + // for (int i = childrens.size() - 1; i >= 0 ; i--) { + // stack.push(childrens.get(i)); + // } + // } + // } + // return res; + + //递归 + List res = new ArrayList<>(); + helper(root, res); + return res; + } + + private void helper(Node root, List res) { + if (root == null) return; + res.add(root.val); + if (root.children != null && root.children.size() > 0) { + for (Node n : root.children) { + helper(n, res); + } + } + } +} diff --git a/Week_02/G20200343030587/src/main/java/com/home/work/week02/LeetCode_590_587.java b/Week_02/G20200343030587/src/main/java/com/home/work/week02/LeetCode_590_587.java new file mode 100644 index 00000000..f11b0b85 --- /dev/null +++ b/Week_02/G20200343030587/src/main/java/com/home/work/week02/LeetCode_590_587.java @@ -0,0 +1,63 @@ +package com.home.work.week02; + +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; + +public class LeetCode_590_587 { + public List postorder(Node root) { + //递归 + // List res = new ArrayList<>(); + // helper(root, res); + // return res; + + //迭代 + // 后序[左右根],前序[根左右] + // 把前序变为[根右左,根右左]反转后既得[左右根,左右根] + // LinkedList res = new LinkedList<>(); + // Stack stack = new Stack(); + // if (root == null) return res; + // stack.add(root); + // while (!stack.isEmpty()) { + // Node n = stack.pop(); + // res.addFirst(n.val);//双向链表 存储时候直接反转结果 + // if (n.children != null && n.children.size() > 0) { + // for (Node node : n.children) { + // stack.push(node); + // } + // } + // } + // return res; + + //双栈法 + List res = new ArrayList<>(); + Stack stack = new Stack(); + Stack stack2 = new Stack();//存储结果,遍历输出就是结果 + if (root == null) return res; + stack.push(root); + while (!stack.isEmpty()) { + Node n = stack.pop(); + stack2.push(n.val);//根-左-右 直接进值栈 + if (n.children != null && n.children.size() > 0) { + //入栈 左-右 + for (Node node : n.children) { + stack.push(node); + } + } + } + //遍历输出结果 + while (!stack2.isEmpty()) { + res.add(stack2.pop()); + } + return res; + } + + + void helper(Node root, List res) { + if (root == null) return; + for (Node node : root.children) { + helper(node, res); + } + res.add(root.val); + } +} diff --git a/Week_02/G20200343030587/src/main/java/com/home/work/week02/LeetCode_77_587.java b/Week_02/G20200343030587/src/main/java/com/home/work/week02/LeetCode_77_587.java new file mode 100644 index 00000000..8c00b4fc --- /dev/null +++ b/Week_02/G20200343030587/src/main/java/com/home/work/week02/LeetCode_77_587.java @@ -0,0 +1,39 @@ +package com.home.work.week02; + +import java.util.ArrayList; +import java.util.List; + +public class LeetCode_77_587 { + List> res = new ArrayList<>(); + public List> combine(int n, int k) { + //回溯算法 + backtrack(1, n, k, new ArrayList<>()); + return res; + } + + void backtrack(int start, int n, int k, List list) { + if (list.size() == k) { + res.add(new ArrayList<>(list)); + return; + } + //未剪枝前 + // for (int i = start; i <= n; i++) { + // list.add(i); + // backtrack(i + 1, n, k, list); + // list.remove(list.size() - 1); + // } + // 剪枝后 + // k - list.size = 还需要多少个数 + // (n - i) + 1 = n中还剩下多少个数 + // 剩下个数是包含i本身的,所以是n-i + 1 + // 如不满足 (n -i) + 1 >= k - list.size 后续操作都是无效的 + // k - list.size + i <= n - i + 1 = i + // i <= n - (k - list.size) + 1 + // + for (int i = start; i <= n - (k - list.size()) + 1; i++) { + list.add(i); + backtrack(i + 1, n, k, list); + list.remove(list.size() - 1); + } + } +} diff --git a/Week_02/G20200343030587/src/main/java/com/home/work/week02/Node.java b/Week_02/G20200343030587/src/main/java/com/home/work/week02/Node.java new file mode 100644 index 00000000..a9d6d044 --- /dev/null +++ b/Week_02/G20200343030587/src/main/java/com/home/work/week02/Node.java @@ -0,0 +1,19 @@ +package com.home.work.week02; + +import java.util.List; + +public class Node { + public int val; + public List children; + + public Node() {} + + public Node(int _val) { + val = _val; + } + + public Node(int _val, List _children) { + val = _val; + children = _children; + } +} diff --git a/Week_02/G20200343030587/src/main/java/com/home/work/week02/TreeNode.java b/Week_02/G20200343030587/src/main/java/com/home/work/week02/TreeNode.java new file mode 100644 index 00000000..3cd2abc9 --- /dev/null +++ b/Week_02/G20200343030587/src/main/java/com/home/work/week02/TreeNode.java @@ -0,0 +1,8 @@ +package com.home.work.week02; + +public class TreeNode { + int val; + TreeNode left; + TreeNode right; + TreeNode(int x) { val = x; } +} diff --git a/Week_02/G20200343030589/LeetCode_144_589.java b/Week_02/G20200343030589/LeetCode_144_589.java new file mode 100644 index 00000000..0df13dfd --- /dev/null +++ b/Week_02/G20200343030589/LeetCode_144_589.java @@ -0,0 +1,38 @@ +/* + * @lc app=leetcode.cn id=144 lang=java + * + * [144] 二叉树的前序遍历 + */ + +// @lc code=start +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; } + * } + */ +class Solution { + public List preorderTraversal(TreeNode root) { + LinkedList stack = new LinkedList<>(); + LinkedList result = new LinkedList<>(); + if (root == null) { + return result; + } + + stack.add(root); + while (!stack.isEmpty()) { + TreeNode node = stack.pollLast(); + result.add(node.val); + if (node.right != null) { + stack.add(node.right); + } + if (node.left != null) { + stack.add(node.left); + } + } + return result; + } +} \ No newline at end of file diff --git a/Week_02/G20200343030589/LeetCode_590_589.java b/Week_02/G20200343030589/LeetCode_590_589.java new file mode 100644 index 00000000..69ed6ace --- /dev/null +++ b/Week_02/G20200343030589/LeetCode_590_589.java @@ -0,0 +1,47 @@ +import java.util.ArrayList; +/* + * @lc app=leetcode.cn id=590 lang=java + * + * [590] N叉树的后序遍历 + */ + +// @lc code=start +/* +// Definition for a Node. +class Node { + public int val; + public List children; + + public Node() {} + + public Node(int _val) { + val = _val; + } + + public Node(int _val, List _children) { + val = _val; + children = _children; + } +}; +*/ +class Solution { + public List postorder(Node root) { + LinkedList stack = new LinkedList<>(); + LinkedList result = new LinkedList<>(); + if (root == null) { + return result; + } + + stack.add(root); + while (!stack.isEmpty()) { + Node node = stack.pollLast(); + result.addFirst(node.val); + for (Node item : node.children) { + if (item != null) { + stack.add(item); + } + } + } + return result; + } +} \ No newline at end of file diff --git a/Week_02/G20200343030591/LeetCode_105_591.java b/Week_02/G20200343030591/LeetCode_105_591.java new file mode 100644 index 00000000..3fe9b30a --- /dev/null +++ b/Week_02/G20200343030591/LeetCode_105_591.java @@ -0,0 +1,53 @@ + +class Solution { + + private int[] preorder; + private Map hash; + + /** + * 1、使用hash表把中序数组中的值 对应的 位置存储起来 这样就不用再遍历找根节点的位置了 + * 2、进入递归 在前序数组中找到根节 并在 中序遍历中找到 该根节点的所在位置 + * 3、 + * @param preorder 前序 + * @param inorder 中序 + * @return + */ + public TreeNode buildTree(int[] preorder, int[] inorder) { + int preLen = preorder.length; + int inLen = inorder.length; + if (preLen != inLen) { + throw new RuntimeException("Incorrect input data."); + } + this.preorder = preorder; + this.hash = new HashMap<>(); + for (int i = 0; i < inLen; i++) { + hash.put(inorder[i], i); + } + + return buildTree(0, preLen - 1, 0, inLen - 1); + } + + + private TreeNode buildTree(int preLeft, int preRight, int inLeft, int inRight) { + // 因为是递归调用的方法,按照国际惯例,先写递归终止条件 + if (preLeft > preRight || inLeft > inRight) { + return null; + } + // 先序遍历的起点元素很重要 + int pivot = preorder[preLeft]; + TreeNode root = new TreeNode(pivot); + int pivotIndex = hash.get(pivot); + root.left = buildTree(preLeft + 1, pivotIndex - inLeft + preLeft, + inLeft, pivotIndex - 1); + root.right = buildTree(pivotIndex - inLeft + preLeft + 1, preRight, + pivotIndex + 1, inRight); + return root; + } + +// 作者:liweiwei1419 +// 链接:https://leetcode-cn.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/solution/qian-xu-bian-li-python-dai-ma-java-dai-ma-by-liwei/ +// 来源:力扣(LeetCode) +// 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 + + +} \ No newline at end of file diff --git a/Week_02/G20200343030591/LeetCode_144_591.java b/Week_02/G20200343030591/LeetCode_144_591.java new file mode 100644 index 00000000..30ebeabf --- /dev/null +++ b/Week_02/G20200343030591/LeetCode_144_591.java @@ -0,0 +1,71 @@ +class Solution { + + /** + * 二叉树的前序遍历 + * 递归 比较好想 + * @param root + * @return + */ + public List preorderTraversal(TreeNode root) { + List res = new ArrayList<>(); + helper(root, res); + + return res; + } + + public void helper(TreeNode root, List res) { + if (root != null) { + res.add(root.val); + if (root.left!=null) { + helper(root.left, res); + } + if (root.right!=null) { + helper(root.right, res); + } + } + } + + /** + * 二叉树的前序遍历 + * 迭代法 + * 要想用迭代法 肯定就得用 栈 + * 从 根左右 -> 栈中顺序为 右左根 + * 这样出的时候就可以 根左右 的顺序出栈了 + * @param root + * @return + */ + public List preorderTraversal(TreeNode root) { + Stack stack = new Stack<>(); + // 使用链表更加灵活 头和尾插入的时间复杂度为O(1) + List res = new LinkedList<>(); + + if (root == null) return res; + + stack.push(root); + while (!stack.isEmpty()) { + TreeNode node = stack.pop(); + res.add(node.val); + + if (node.right!=null) { + stack.push(node.right); + } + + if (node.left!=null) { + stack.push(node.left); + } + + } + return res; + } + + + + + + + + + + + +} \ No newline at end of file diff --git a/Week_02/G20200343030591/LeetCode_145_591.java b/Week_02/G20200343030591/LeetCode_145_591.java new file mode 100644 index 00000000..f311c3fc --- /dev/null +++ b/Week_02/G20200343030591/LeetCode_145_591.java @@ -0,0 +1,68 @@ +class Solution { + + /** + * 二叉树的后序遍历 + * 递归 比较好想 + * @param root + * @return + */ + public List postorderTraversal(TreeNode root) { + List res = new ArrayList<>(); + helper(root, res); + + return res; + } + + public void helper(TreeNode root, List res) { + if (root != null) { + + if (root.left!=null) { + helper(root.left, res); + } + if (root.right!=null) { + helper(root.right, res); + } + res.add(root.val); + } + } + + /** + * 二叉树的后序遍历 + * 迭代法 + * 要想用迭代法 肯定就得用 栈 + * 从 左右根 -> 栈中顺序为 根右左 + * 这样出的时候就可以 根左右 的顺序出栈了 + * @param root + * @return + */ + public List postorderTraversal(TreeNode root) { + Stack stack1 = new Stack(); + List res = new LinkedList<>(); + if (root == null) return res; + + stack1.push(root); + + while (!stack1.isEmpty()) { + TreeNode node = stack1.pop(); + res.add(0, node.val); + if (node.left!=null) { + stack1.push(node.left); + } + if (node.right!=null) { + stack1.push(node.right); + } + } + return res; + } + + + + + + + + + + + +} \ No newline at end of file diff --git a/Week_02/G20200343030591/LeetCode_236_591.java b/Week_02/G20200343030591/LeetCode_236_591.java new file mode 100644 index 00000000..c0cc7f62 --- /dev/null +++ b/Week_02/G20200343030591/LeetCode_236_591.java @@ -0,0 +1,61 @@ + +class Solution { + + /** + * 递归 + * 题目:二叉树的最近公共祖先 + * 1、如果根节点为空 或者 根节点 等于 p 或者 根节点 等于 q 那么根节点就是最近公共祖先 + * 2、先到左子树中找 + * 3、再到柚子树中找 + * 4、如果最终 发现left 和 right都不为空 则说明 左右子树都找到了结果 那说明 跟节点 即为公共祖先 + * 5、如果4不满足 则left和right谁为null 则 说明为null的哪一方没有p 和 q 返回不为null的一方即可 + */ + public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { + if (root == null || root == p || root == q) return root; + + TreeNode left = lowestCommonAncestor(root.left, p, q); + + TreeNode right = lowestCommonAncestor(root.right, p, q); + + if (left != null && right!=null) return root; + + return left == null ? right : left; + } + + /** + * 迭代 + * 国际版解法 + * @param root + * @param p + * @param q + * @return + */ + public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { + Map parent = new HashMap<>(); + Deque stack = new ArrayDeque<>(); + parent.put(root, null); + stack.push(root); + + while (!parent.containsKey(p) || !parent.containsKey(q)) { + TreeNode node = stack.pop(); + if (node.left != null) { + parent.put(node.left, node); + stack.push(node.left); + } + if (node.right != null) { + parent.put(node.right, node); + stack.push(node.right); + } + } + Set ancestors = new HashSet<>(); + while (p != null) { + ancestors.add(p); + p = parent.get(p); + } + while (!ancestors.contains(q)) + q = parent.get(q); + return q; + } + + +} \ No newline at end of file diff --git a/Week_02/G20200343030591/LeetCode_242_591.java b/Week_02/G20200343030591/LeetCode_242_591.java new file mode 100644 index 00000000..03d6a783 --- /dev/null +++ b/Week_02/G20200343030591/LeetCode_242_591.java @@ -0,0 +1,58 @@ +class Solution { + /** + * 题目:有效的字母异位词 + * 解法1: + * 1、使用计数器来统计第一个字符串中 每个字母出现的频率 + * 2、第一个字符串 统计频率做加的操作,第二个字符串统计时候做减的操作 + * 3、最后查看这个计数器是否有不为0的元素 + * @param s + * @param t + * @return + */ + public boolean isAnagram(String s, String t) { + + if (s.length() != t.length()) { + return false; + } + + int[] counter = new int[26]; + for (int i = 0; i < s.length(); i++) { + counter[s.charAt(i) - 'a']++; + counter[t.charAt(i) - 'a']--; + } + + for (int i = 0; i < counter.length; i++) { + if (counter[i] != 0) { + return false; + } + } + + return true; + } + + /** + * 同上 写法不同而已 + * @param s + * @param t + * @return + */ + public boolean isAnagram2(String s, String t) { + if (s.length() != t.length()) { + return false; + } + + int[] counter = new int[26]; + for (int i = 0; i < s.length(); i++) { + counter[s.charAt(i) - 'a']++; + } + + for (int i = 0; i < t.length(); i++) { + int result = counter[t.charAt(i) - 'a']--; + if ((result - 1) < 0) { + return false; + } + } + return true; + } + +} \ No newline at end of file diff --git a/Week_02/G20200343030591/LeetCode_46_591.java b/Week_02/G20200343030591/LeetCode_46_591.java new file mode 100644 index 00000000..c3dc8bba --- /dev/null +++ b/Week_02/G20200343030591/LeetCode_46_591.java @@ -0,0 +1,37 @@ + +class Solution { + + /** + * 全排列 + * 这道题 感觉自己思考不出来 直接看了答案 + * @param nums + * @return + */ + public static List> permute(int[] nums) { + List> lists = new ArrayList<>(); + generatePermute(lists, new ArrayList<>(), nums, 0); + return lists; + } + + /** + * + * @param permuteLists 存储全排列 即最终的结果 + * @param list 存储其中一个排列 存储本层的排列结果 + * @param nums 给定的序列 + * @param cursorPos + */ + private static void generatePermute( + List> permuteLists, List list, int[] nums, int cursorPos) { + if (cursorPos == nums.length) { + // 必须要 new 一个 list 再 add,因为list 是引用传递 + // 在退出递归时 list.remove 会把 list 清空,permuteLists 也会变空 + permuteLists.add(new ArrayList<>(list)); + return; + } + for (int i = 0; i <= cursorPos; i++) { + list.add(i, nums[cursorPos]); + generatePermute(permuteLists, list, nums, cursorPos + 1); + list.remove(i); + } + } +} \ No newline at end of file diff --git a/Week_02/G20200343030591/LeetCode_49_591.java b/Week_02/G20200343030591/LeetCode_49_591.java new file mode 100644 index 00000000..6095e353 --- /dev/null +++ b/Week_02/G20200343030591/LeetCode_49_591.java @@ -0,0 +1,77 @@ +class Solution { + + /** + * 暴力法 也是最容易能想到的 + * 思路解析: + * 1、遍历 并对每个字符串数组中的 字符串转为字符后 排序 + * 2、将排序后的 字符数组 变为 字符串后 作为 map中的key(如果是异位词key一样,代表用key来分组) + * 3、如果key 在map中已经存在 则加入到map key对应的 list中 + * 4、如果key 在map中不存在 则创建该key对应的list + * + * 时间复杂度分析: + * O(n(klogk)) 遍历strs为 O(N) + * 字符排序为快排 平均时间复杂度为O(klogk) + * 合起来就是 O(NKlogK) + * @param strs + * @return + */ + public List> groupAnagrams(String[] strs) { + Map> map = new HashMap<>(); + for (String str : strs) { + char[] chars = str.toCharArray(); + Arrays.sort(chars); + String key = String.valueOf(chars); + if (map.get(key) == null) { + map.put(key, new ArrayList<>()); + } + map.get(key).add(str); + } + return new ArrayList>(map.values()); + } + + /** + * + * 首先初始化 key = "0#0#0#0#0#",数字分别代表 abcde 出现的次数,# 用来分割。 + * 这样的话,"abb" 就映射到了 "1#2#0#0#0"。 + * "cdc" 就映射到了 "0#0#2#1#0"。 + * "dcc" 就映射到了 "0#0#2#1#0"。 + * 作者:windliang + * 链接:https://leetcode-cn.com/problems/group-anagrams/solution/xiang-xi-tong-su-de-si-lu-fen-xi-duo-jie-fa-by--16/ + * 来源:力扣(LeetCode) + * 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 + * + * 时间复杂度分析: + * + * @param strs + * @return + */ + public List> groupAnagrams(String[] strs) { + HashMap> hash = new HashMap<>(); + for (int i = 0; i < strs.length; i++) { + int[] num = new int[26]; + //记录每个字符的次数 + for (int j = 0; j < strs[i].length(); j++) { + num[strs[i].charAt(j) - 'a']++; + } + // 转成 0#2#2# 类似的形式 + // 相当于代替排序的解法 + String key = ""; + for (int j = 0; j < num.length; j++) { + key = key + num[j] + '#'; + } + if (hash.containsKey(key)) { + hash.get(key).add(strs[i]); + } else { + List temp = new ArrayList(); + temp.add(strs[i]); + hash.put(key, temp); + } + + } + return new ArrayList>(hash.values()); + } + + + + +} \ No newline at end of file diff --git a/Week_02/G20200343030591/LeetCode_589_591.java b/Week_02/G20200343030591/LeetCode_589_591.java new file mode 100644 index 00000000..d3ab7aab --- /dev/null +++ b/Week_02/G20200343030591/LeetCode_589_591.java @@ -0,0 +1,61 @@ +class Solution { + + /** + * N叉树的前序遍历 + * 递归 比较好想 + * @param root + * @return + */ + public List preorder(Node root) { + List res = new ArrayList<>(); + helper(root, res); + return res; + } + + private void helper(Node root, List res) { + if (root!=null) { + res.add(root.val); + if (root.children!=null) { + for (Node node : root.children) { + helper(node, res); + } + } + } + } + + /** + * N叉树的前序遍历 + * 迭代法 + * 要想用迭代法 肯定就得用 栈 + * 从 根左右 -> 右左根 + * @param root + * @return + */ + public List preorder(Node root) { + Stack stack = new Stack<>(); + List res = new ArrayList<>(); + + if (root == null) return res; + + stack.push(root); + while (!stack.isEmpty()) { + Node node = stack.pop(); + res.add(node.val); + for (int i = node.children.size() - 1; i >= 0; i--) { + stack.push(node.children.get(i)); + } + } + return res; + } + + + + + + + + + + + +} \ No newline at end of file diff --git a/Week_02/G20200343030591/LeetCode_590_591.java b/Week_02/G20200343030591/LeetCode_590_591.java new file mode 100644 index 00000000..e0eef3fc --- /dev/null +++ b/Week_02/G20200343030591/LeetCode_590_591.java @@ -0,0 +1,64 @@ +class Solution { + + /** + * N叉树的后序遍历 + * 递归 比较好想 + * @param root + * @return + */ + public List postorder(Node root) { + List res = new ArrayList<>(); + helper(root, res); + return res; + } + + public void helper(Node root, List res) { + if (root != null) { + if (root.children!=null) { + for (Node node : root.children) { + helper(node, res); + } + } + res.add(root.val); + } + } + + /** + * N叉树的后序遍历 + * 迭代法 + * 要想用迭代法 肯定就得用 栈 + * 从 左右根 -> 栈中顺序为 根右左 + * 这样出的时候就可以 左右根 的顺序出栈了 + * @param root + * @return + */ + public List preorder(Node root) { + Stack stack = new Stack<>(); + List res = new LinkedList<>(); + + if (root == null) return res; + + stack.push(root); + while (!stack.isEmpty()) { + Node node = stack.pop(); + //每次向结果链表的第一个位置添加,之前的所有数组元素后移 + //与逆序输出结果相同 + res.add(0, node.val); + for (int i = 0; i < node.children.size(); i++) { + stack.push(node.children.get(i)); + } + } + return res; + } + + + + + + + + + + + +} \ No newline at end of file diff --git a/Week_02/G20200343030591/LeetCode_94_591.java b/Week_02/G20200343030591/LeetCode_94_591.java new file mode 100644 index 00000000..e22986c1 --- /dev/null +++ b/Week_02/G20200343030591/LeetCode_94_591.java @@ -0,0 +1,55 @@ +class Solution { + + /** + * 二叉树的中序遍历 + * 递归 比较好想 + * @param root + * @return + */ + public List < Integer > inorderTraversal(TreeNode root) { + List < Integer > res = new ArrayList < > (); + helper(root, res); + return res; + } + + public void helper(TreeNode root, List < Integer > res) { + if (root != null) { + if (root.left != null) { + helper(root.left, res); + } + res.add(root.val); + if (root.right != null) { + helper(root.right, res); + } + } + } + + /** + * 二叉树的中序遍历 + * 迭代法 + * 要想用迭代法 肯定就得用 栈 + * 从 左根右 -> 栈中顺序为 右根左 + * 这样出的时候就可以 左根右 的顺序出栈了 + * @param root + * @return + */ + public List inorderTraversal(TreeNode root) { + Stack stack = new Stack<>(); + // 使用链表更加灵活 头和尾插入的时间复杂度为O(1) + List res = new LinkedList<>(); + if (root == null) return res; + + TreeNode current = root; + while (!stack.isEmpty() || current!=null) { + while (current!=null) { + stack.push(current); + current = current.left; + } + current = stack.pop(); + res.add(current.val); + current = current.right; + } + return res; + } + +} \ No newline at end of file diff --git a/Week_02/G20200343030593/Leet_code_589_593.java b/Week_02/G20200343030593/Leet_code_589_593.java new file mode 100644 index 00000000..911ccc59 --- /dev/null +++ b/Week_02/G20200343030593/Leet_code_589_593.java @@ -0,0 +1,44 @@ +class Solution { + List result = new ArrayList<>(); + /*递归*/ + public List preorder(Node root) { + helper(root); + return result; + } + + public void helper(Node node) { + if (node == null) { + return; + } + result.add(node.val); + List children = node.children; + if (children != null) { + for (Node n : children) { + helper(n); + } + } + } +} + +class Solution { + LinkedList result = new LinkedList<>(); + /*递归*/ + public List preorder(Node root) { + if (root == null) { + return result; + } + LinkedList stack = new LinkedList<>(); + stack.add(root); + while (!stack.isEmpty()) { + Node n = stack.pollLast(); + result.add(n.val); + List children = n.children; + if (children != null) { + for (int i = children.size() - 1; i >= 0; i--) { + stack.add(children.get(i)); + } + } + } + return result; + } +} \ No newline at end of file diff --git a/Week_02/G20200343030593/Leet_code_590_593.java b/Week_02/G20200343030593/Leet_code_590_593.java new file mode 100644 index 00000000..ac5681b3 --- /dev/null +++ b/Week_02/G20200343030593/Leet_code_590_593.java @@ -0,0 +1,46 @@ +class Solution { + + List result = new ArrayList(); + /*递归遍历*/ + public List postorder(Node root) { + traversal(root); + return result; + } + + public void traversal(Node node) { + if (node == null) { + return; + } + List children = node.children; + if (children != null) { + for (Node n : children) { + traversal(n); + } + } + result.add(node.val); + } +} + +class Solution { + + LinkedList result=new LinkedList(); + /*迭代*/ + public List postorder(Node root) { + if(root==null){ + return result; + } + LinkedList stack=new LinkedList<>(); + stack.add(root); + while(!stack.isEmpty()){ + Node n=stack.pollLast(); + List children=n.children; + if(children!=null){ + for(Node no:children){ + stack.add(no); + } + } + result.addFirst(n.val); + } + return result; + } +} \ No newline at end of file diff --git a/Week_02/G20200343030595/105.go b/Week_02/G20200343030595/105.go new file mode 100644 index 00000000..8b2ee4ea --- /dev/null +++ b/Week_02/G20200343030595/105.go @@ -0,0 +1,26 @@ +package main + +func permute(nums []int) [][]int { + var res [][]int + backtrack(&res, len(nums), nums, 0) + return res +} + +func backtrack(res *[][]int, n int, nums []int, first int) { + if first == n { + tmp := make([]int, len(nums)) + copy(tmp, nums) + *res = append(*res, tmp[:]) + return + } + + for i := first; i < n; i++ { + swap(nums, first, i) + backtrack(res, n, nums, first+1) + swap(nums, first, i) + } +} + +func swap(nums []int, a, b int) { + nums[a], nums[b] = nums[b], nums[a] +} diff --git a/Week_02/G20200343030595/144.go b/Week_02/G20200343030595/144.go new file mode 100644 index 00000000..4ea362cc --- /dev/null +++ b/Week_02/G20200343030595/144.go @@ -0,0 +1,24 @@ +package main + +/** + * Definition for a binary tree node. + * type TreeNode struct { + * Val int + * Left *TreeNode + * Right *TreeNode + * } + */ +func preorderTraversal(root *TreeNode) []int { + var res []int + helper(root, &res) + return res +} + +func helper(root *TreeNode, res *[]int) { + if root == nil { + return + } + *res = append(*res, root.Val) + helper(root.Left, res) + helper(root.Right, res) +} diff --git a/Week_02/G20200343030595/236.go b/Week_02/G20200343030595/236.go new file mode 100644 index 00000000..6bca1e91 --- /dev/null +++ b/Week_02/G20200343030595/236.go @@ -0,0 +1,31 @@ +package main + +/** +* Definition for TreeNode. +* type TreeNode struct { +* Val int +* Left *ListNode +* Right *ListNode +* } + */ +func lowestCommonAncestor(root, p, q *TreeNode) *TreeNode { + if root == nil || root == p || root == q { + return root + } + + left := lowestCommonAncestor(root.Left, p, q) + right := lowestCommonAncestor(root.Right, p, q) + switch { + case left != nil && right != nil: + return root + + case left == nil && right != nil: + return right + + case left != nil && right == nil: + return left + + default: + return nil + } +} diff --git a/Week_02/G20200343030595/429.java b/Week_02/G20200343030595/429.java new file mode 100644 index 00000000..5be1fe3e --- /dev/null +++ b/Week_02/G20200343030595/429.java @@ -0,0 +1,37 @@ +/* +// Definition for a Node. +class Node { + public int val; + public List children; + + public Node() {} + + public Node(int _val) { + val = _val; + } + + public Node(int _val, List _children) { + val = _val; + children = _children; + } +}; +*/ +class Solution { + private List> res = new ArrayList<>(); + public List> levelOrder(Node root) { + if (root != null) { + helper(0, root); + } + return res; + } + + public void helper(int level, Node root) { + if (res.size() <= level) { + res.add(new ArrayList<>()); + } + res.get(level).add(root.val); + for (Node n: root.children) { + helper(level+1, n); + } + } +} \ No newline at end of file diff --git a/Week_02/G20200343030595/46.go b/Week_02/G20200343030595/46.go new file mode 100644 index 00000000..194d4fc5 --- /dev/null +++ b/Week_02/G20200343030595/46.go @@ -0,0 +1,26 @@ +package main + +func permute(nums []int) [][]int { + var res [][]int + backtrack(&res, len(nums), nums, 0) + return res +} + +func backtrack(res *[][]int, n int, nums []int, first int) { + if first == n { + tmp := make([]int, len(nums)) + copy(tmp, nums) + *res = append(*res, tmp[:]) + return + } + + for i := first; i < n; i++ { + swap(nums, first, i) + backtrack(res, n, nums, first+1) + swap(nums, first, i) + } +} + +func swap(nums []int, a, b int) { + nums[a], nums[b] = nums[b], nums[a] +} diff --git a/Week_02/G20200343030595/47.go b/Week_02/G20200343030595/47.go new file mode 100644 index 00000000..7eba81d4 --- /dev/null +++ b/Week_02/G20200343030595/47.go @@ -0,0 +1,32 @@ +package main + +import "sort" + +func permuteUnique(nums []int) [][]int { + if len(nums) == 0 { + return nil + } + + sort.Ints(nums) + ans := make([][]int, 0) + backtrackUnique(nums, nil, &ans) + + return ans +} + +func backtrackUnique(nums []int, prev []int, ans *[][]int) { + if len(nums) == 0 { + *ans = append(*ans, append([]int{}, prev...)) + return + } + + for i := 0; i < len(nums); i++ { + if i != 0 && nums[i] == nums[i-1] { + continue + } + tmp := append([]int{}, nums[0:i]...) + newNums := append(tmp, nums[i+1:]...) + newPrev := append(prev, nums[i]) + backtrackUnique(newNums, newPrev, ans) + } +} diff --git a/Week_02/G20200343030595/49.go b/Week_02/G20200343030595/49.go new file mode 100644 index 00000000..fa42e1f9 --- /dev/null +++ b/Week_02/G20200343030595/49.go @@ -0,0 +1,26 @@ +package main + +import "sort" +package main + +func groupAnagrams(strs []string) [][]string { + mm := make(map[string][]string) + for _, v := range strs{ + str := SortStringByCharacter(v) + mm[str] = append(mm[str], v) + } + + var res [][]string + for _, v := range mm { + res = append(res, v) + } + return res +} + +func SortStringByCharacter(s string) string { + r := []rune(s) + sort.Slice(r, func(i, j int) bool { + return r[i] < r[j] + }) + return string(r) +} \ No newline at end of file diff --git a/Week_02/G20200343030595/589.java b/Week_02/G20200343030595/589.java new file mode 100644 index 00000000..cb6d4827 --- /dev/null +++ b/Week_02/G20200343030595/589.java @@ -0,0 +1,33 @@ +/* +// Definition for a Node. +class Node { + public int val; + public List children; + + public Node() {} + + public Node(int _val) { + val = _val; + } + + public Node(int _val, List _children) { + val = _val; + children = _children; + } +}; +*/ +class Solution { + List list = new ArrayList<>(); + public List preorder(Node root) { + if (root == null) + return list; + + list.add(root.val); + + for (Node n: root.children){ + preorder(n); + } + + return list; + } +} \ No newline at end of file diff --git a/Week_02/G20200343030595/590.java b/Week_02/G20200343030595/590.java new file mode 100644 index 00000000..79d9bca8 --- /dev/null +++ b/Week_02/G20200343030595/590.java @@ -0,0 +1,34 @@ +// 这一题 Leetcode 上不支持 Go,所以就用 java 写了 +/* +// Definition for a Node. +class Node { + public int val; + public List children; + + public Node() {} + + public Node(int _val) { + val = _val; + } + + public Node(int _val, List _children) { + val = _val; + children = _children; + } +}; +*/ +class Solution { + List list = new ArrayList<>(); + public List postorder(Node root) { + if (root == null) + return list; + + for ( Node n: root.children) { + postorder(n); + } + + list.add(root.val); + + return list; + } +} \ No newline at end of file diff --git a/Week_02/G20200343030595/77.go b/Week_02/G20200343030595/77.go new file mode 100644 index 00000000..e49c6845 --- /dev/null +++ b/Week_02/G20200343030595/77.go @@ -0,0 +1,21 @@ +package main + +func combine(n int, k int) [][]int { + var ( + res [][]int + nums []int + ) + backtrack(&res, nums, n, k, 1) + return res +} + +func backtrack(res *[][]int, nums []int, n, k, first int) { + if len(nums) == k { + *res = append(*res, append([]int{}, nums...)) + return + } + + for i := first; i <= n; i++ { + backtrack(res, append(nums, i), n, k, i+1) + } +} diff --git a/Week_02/G20200343030597/Solution_589.java b/Week_02/G20200343030597/Solution_589.java new file mode 100644 index 00000000..a39ef65a --- /dev/null +++ b/Week_02/G20200343030597/Solution_589.java @@ -0,0 +1,35 @@ +import java.util.ArrayList; +import java.util.List; + +public class Solution_589 { + List result = new ArrayList(); + public List preorder(Node root) { + charge(root); + return result; + } + + private void charge(Node root) { + if (root == null) return; + + result.add(root.val); + for (Node node : root.children) { + charge(node); + } + } + +} +class Node { + public int val; + public List children; + + public Node() {} + + public Node(int _val) { + val = _val; + } + + public Node(int _val, List _children) { + val = _val; + children = _children; + } +}; diff --git a/Week_02/G20200343030597/Solution_590.java b/Week_02/G20200343030597/Solution_590.java new file mode 100644 index 00000000..a348925d --- /dev/null +++ b/Week_02/G20200343030597/Solution_590.java @@ -0,0 +1,39 @@ +import java.util.ArrayList; +import java.util.List; + +public class Solution_590 { + public List postorder(Node root) { + List result = new ArrayList(); + each(root,result); + return result; + } + + public void each(Node root, List result){ + if (root == null) { + return; + } + + for (int i=0; i < root.children.size() ;i++) { + each(root.children.get(i),result); + } + result.add(root.val); + } + + +} + +class Node { + public int val; + public List children; + + public Node() {} + + public Node(int _val) { + val = _val; + } + + public Node(int _val, List _children) { + val = _val; + children = _children; + } +}; \ No newline at end of file diff --git a/Week_02/G20200343030599/LeetCode_49_599.js b/Week_02/G20200343030599/LeetCode_49_599.js new file mode 100644 index 00000000..ea6d1e4a --- /dev/null +++ b/Week_02/G20200343030599/LeetCode_49_599.js @@ -0,0 +1,28 @@ +/* + * @lc app=leetcode.cn id=49 lang=javascript + * + * [49] 字母异位词分组 + */ + +// @lc code=start +/** + * @param {string[]} strs + * @return {string[][]} + */ +var groupAnagrams = function (strs) { + let hash = new Map() + + for (let i = 0; i < strs.length; i++) { + let str = strs[i].split('').sort().join() + if (hash.has(str)) { + let temp = hash.get(str) + temp.push(strs[i]) + hash.set(str, temp) + } else { + hash.set(str, [strs[i]]) + } + } + + return [...hash.values()] +}; +// @lc code=end diff --git a/Week_02/G20200343030599/LeetCode_589_599.js b/Week_02/G20200343030599/LeetCode_589_599.js new file mode 100644 index 00000000..72a9ddbb --- /dev/null +++ b/Week_02/G20200343030599/LeetCode_589_599.js @@ -0,0 +1,36 @@ +/* + * @lc app=leetcode.cn id=589 lang=javascript + * + * [589] N叉树的前序遍历 + */ + +// @lc code=start +/** + * // Definition for a Node. + * function Node(val, children) { + * this.val = val; + * this.children = children; + * }; + */ +/** + * @param {Node} root + * @return {number[]} + */ +var preorder = function (root) { + //递归 + if (!root) return []; + + let res = []; + recusion(root); + return res; + + function recusion(root) { + if (!root) return null; + + res.push(root.val); + for (let i = 0; i < root.children.length; i++) { + recusion(root.children[i]); + } + } +}; +// @lc code=end diff --git a/Week_02/G20200343030599/LeetCode_590_599.js b/Week_02/G20200343030599/LeetCode_590_599.js new file mode 100644 index 00000000..1798d8a9 --- /dev/null +++ b/Week_02/G20200343030599/LeetCode_590_599.js @@ -0,0 +1,36 @@ +/* + * @lc app=leetcode.cn id=590 lang=javascript + * + * [590] N叉树的后序遍历 + */ + +// @lc code=start +/** + * // Definition for a Node. + * function Node(val,children) { + * this.val = val; + * this.children = children; + * }; + */ +/** + * @param {Node} root + * @return {number[]} + */ +var postorder = function (root) { + //递归 + if (!root) return []; + + let res = []; + recusion(root); + return res; + + function recusion(root) { + if (!root) return null; + + for (let i = 0; i < root.children.length; i++) { + recusion(root.children[i]); + } + res.push(root.val) + } +}; +// @lc code=end diff --git a/Week_02/G20200343030599/NOTE.md b/Week_02/G20200343030599/NOTE.md deleted file mode 100644 index 50de3041..00000000 --- a/Week_02/G20200343030599/NOTE.md +++ /dev/null @@ -1 +0,0 @@ -学习笔记 \ No newline at end of file diff --git "a/Week_02/G20200343030601/589.n\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\351\201\215\345\216\206.java" "b/Week_02/G20200343030601/589.n\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\351\201\215\345\216\206.java" new file mode 100644 index 00000000..408f356e --- /dev/null +++ "b/Week_02/G20200343030601/589.n\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\351\201\215\345\216\206.java" @@ -0,0 +1,77 @@ +import java.util.LinkedList; +import java.util.List; + +/* + * @lc app=leetcode.cn id=589 lang=java + * + * [589] N叉树的前序遍历 + * + * https://leetcode-cn.com/problems/n-ary-tree-preorder-traversal/description/ + * + * algorithms + * Easy (72.06%) + * Likes: 66 + * Dislikes: 0 + * Total Accepted: 18.5K + * Total Submissions: 25.6K + * Testcase Example: '[1,null,3,2,4,null,5,6]' + * + * 给定一个 N 叉树,返回其节点值的前序遍历。 + * + * 例如,给定一个 3叉树 : + * + * + * + * + * + * + * + * 返回其前序遍历: [1,3,5,6,2,4]。 + * + * + * + * 说明: 递归法很简单,你可以使用迭代法完成此题吗? + */ + +// @lc code=start +/* +// Definition for a Node. +class Node { + public int val; + public List children; + + public Node() {} + + public Node(int _val) { + val = _val; + } + + public Node(int _val, List _children) { + val = _val; + children = _children; + } +}; +*/ +class Solution { + // N叉树遍历,在N未知时,没办法谈中序遍历 + // 前序遍历和后序遍历可采用一致的递归套路 + public List preorder(Node root) { + List preorderValues = new LinkedList(); + preorderRecursion(root, preorderValues); + return preorderValues; + } + + private void preorderRecursion(Node node, List preorderValues){ + if (null == node){ + return; + } + + preorderValues.add(node.val); + + for (Node child : node.children) { + preorderRecursion(child, preorderValues); + } + } +} +// @lc code=end + diff --git "a/Week_02/G20200343030601/590.n\345\217\211\346\240\221\347\232\204\345\220\216\345\272\217\351\201\215\345\216\206.java" "b/Week_02/G20200343030601/590.n\345\217\211\346\240\221\347\232\204\345\220\216\345\272\217\351\201\215\345\216\206.java" new file mode 100644 index 00000000..480348b9 --- /dev/null +++ "b/Week_02/G20200343030601/590.n\345\217\211\346\240\221\347\232\204\345\220\216\345\272\217\351\201\215\345\216\206.java" @@ -0,0 +1,101 @@ +import java.util.List; +import java.util.Vector; + +/* + * @lc app=leetcode.cn id=590 lang=java + * + * [590] N叉树的后序遍历 + * + * https://leetcode-cn.com/problems/n-ary-tree-postorder-traversal/description/ + * + * algorithms + * Easy (72.20%) + * Likes: 50 + * Dislikes: 0 + * Total Accepted: 16.2K + * Total Submissions: 22.5K + * Testcase Example: '[1,null,3,2,4,null,5,6]\r' + * + * 给定一个 N 叉树,返回其节点值的后序遍历。 + * + * 例如,给定一个 3叉树 : + * + * + * + * + * + * + * + * 返回其后序遍历: [5,6,3,2,4,1]. + * + * + * + * 说明: 递归法很简单,你可以使用迭代法完成此题吗? + */ + +// @lc code=start +/* +// Definition for a Node. +class Node { + public int val; + public List children; + + public Node() {} + + public Node(int _val) { + val = _val; + } + + public Node(int _val, List _children) { + val = _val; + children = _children; + } +}; +*/ + +class Solution { + // 树的遍历首先考虑递归解决,递归的套路代码结构: + // 1. Terminator + // 2. Current level logic + // 3. Drill down + // 4. Reverse + public List postorder(Node root) { + List postValues = new LinkedList(); + postorderRecursion(root, postValues); + return postValues; + } + + private void postorderRecursion(Node node, List postValues){ + if (null == node) { + return; + } + + // 优先遍历各子树 + for (Node child : node.children) { + postorderRecursion(child, postValues); + } + + postValues.add(node.val); + } + + /* + // 同样的思路,函数实现稍微变动(不额外增加迭代函数) + // 但频繁的开辟新List,消耗大 + public List postorder(Node root) { + List postValues = new LinkedList(); + if (null == root) { + return postValues; + } + + for (Node child : root.children) { + postValues.addAll(postorder(child)); + } + + postValues.add(root.val); + + return postValues; + } + */ +} +// @lc code=end + diff --git a/Week_02/G20200343030601/NOTE.md b/Week_02/G20200343030601/NOTE.md index 50de3041..2baf5d4e 100644 --- a/Week_02/G20200343030601/NOTE.md +++ b/Week_02/G20200343030601/NOTE.md @@ -1 +1,26 @@ -学习笔记 \ No newline at end of file +# 学习笔记(第一周) + +**学号:** G20200343030601 + +**姓名:** 冯学智 + +**微信:** SDMrFeng + +## 复习 + +将课程从头开始,重新梳理了一遍: + +- 将老师的讲到的学习思路、切题套路重新整理成自己可快速复习的摘要格式; +- 将每一节课每一小节的内容整理整摘要; +- 将讲到的每一道Leetcode题整理成目录形式放在excel中,增加第一遍、第二遍、第三遍。。。刷题的时间公式,提醒复习时间节点。 +- 周一到周五听取了五位老师的直播课程,收益匪浅,发现自己的学习方法、职业规划都存在很多误区,需要立即改正。 + +## 预习 + +- 对本周的预习内容,尤其是王争老师的《数据结构和算法之美》中的相关内容进行了非常详细的学习和总结; +- 对每一节课的ppt进行了提前整理,在听课过程中,再适当丰富,效果非常好; + +## 学习 + +- 完善了对哈希表、映射、集合、树、二叉树、二叉搜索树的认知; +- 虽能准确理解和使用递归,但自己的短板是:做递归时,对于“如何设定参数个数和类型“经常思路低效。通过本周的学习和练习,有了比较好的改善,应该可以在刷遍数之后还能得到进一步巩固。 \ No newline at end of file diff --git a/Week_02/G20200343030603/LeetCode_1_603.md b/Week_02/G20200343030603/LeetCode_1_603.md new file mode 100644 index 00000000..8adf933f --- /dev/null +++ b/Week_02/G20200343030603/LeetCode_1_603.md @@ -0,0 +1,13 @@ +##HashMap小结: +###1、HashMap底层结构: +Java8以前,HashMap采用数组+链表的数据结构,Java8及以后,采用数组+链表+红黑树数据结构。 +###2、HashMap的put方法 +主要总结一下put方法的逻辑: +(1)如果HashMap未被初始化过,则初始化; +(2)对Key求Hash值,然后再计算下标; +(3)如果没有碰撞,直接放入桶中; +(4)如果碰撞了,以链表的方式链接到后面; +(5)如果链表长度超过阀值,就把链表转成红黑树; +(6)如果链表长度低于阀值,就把红黑树转回链表; +(7)如果节点已经存在就替换旧值; +(8)如果桶满了(容量16*加载因子0.75),就需要resize(扩容2倍后重排); \ No newline at end of file diff --git a/Week_02/G20200343030603/LeetCode_2_603.java b/Week_02/G20200343030603/LeetCode_2_603.java new file mode 100644 index 00000000..15bc8a1f --- /dev/null +++ b/Week_02/G20200343030603/LeetCode_2_603.java @@ -0,0 +1,55 @@ +//N叉树后序遍历 + +/* +// Definition for a Node. +class Node { + public int val; + public List children; + + public Node() {} + + public Node(int _val) { + val = _val; + } + + public Node(int _val, List _children) { + val = _val; + children = _children; + } +}; +*/ +class Solution { + //方法一:递归 + // List result = new ArrayList<>(); + // public List postorder(Node root) { + // if (root != null){ + // for (int i = 0; i < root.children.size(); i++){ + // postorder(root.children.get(i)); + // } + // result.add(root.val); + // } + // return result; + // } + + + // 方法二:迭代 + public List postorder(Node root) { + LinkedList stack = new LinkedList<>(); + LinkedList output = new LinkedList<>(); + if (root == null){ + return output; + } + + stack.add(root); + while (!stack.isEmpty()){ + Node node = stack.pollLast();//pollLast 返回最后一个元素 + output.addFirst(node.val); + for (Node item : node.children){ + if (item != null){ + stack.add(item); + } + } + } + return output; + } +} \ No newline at end of file diff --git a/Week_02/G20200343030603/LeetCode_3_603.java b/Week_02/G20200343030603/LeetCode_3_603.java new file mode 100644 index 00000000..c79e2ab8 --- /dev/null +++ b/Week_02/G20200343030603/LeetCode_3_603.java @@ -0,0 +1,57 @@ +//N叉树前序遍历 + +/* +// Definition for a Node. +class Node { + public int val; + public List children; + + public Node() {} + + public Node(int _val) { + val = _val; + } + + public Node(int _val, List _children) { + val = _val; + children = _children; + } +}; +*/ +class Solution { + + // //方法一:递归 + // List result = new ArrayList<>(); + // public List preorder(Node root) { + // if (root == null){ + // return result; + // } + // result.add(root.val); + // for (int i = 0; i < root.children.size(); i++){ + // preorder(root.children.get(i)); + // } + // return result; + // } + + + //方法二:迭代 + public List preorder(Node root) { + LinkedList stack = new LinkedList<>(); + LinkedList output= new LinkedList<>(); + if (root == null){ + return output; + } + + stack.add(root); + + while (!stack.isEmpty()){ + Node node = stack.pollLast(); + output.add(node.val); + Collections.reverse(node.children); + for (Node item : node.children){ + stack.add(item); + } + } + return output; + } +} \ No newline at end of file diff --git a/Week_02/G20200343030603/LeetCode_4_603.java b/Week_02/G20200343030603/LeetCode_4_603.java new file mode 100644 index 00000000..9817160a --- /dev/null +++ b/Week_02/G20200343030603/LeetCode_4_603.java @@ -0,0 +1,32 @@ +// 字母异位词分组 + +class Solution { + public List> groupAnagrams(String[] strs) { + //方法一:排序 执行时间11ms 内存消耗45.1MB, + //时间复杂度 O(NKlogK) N 是strs数组长度 K是str中字符串的最大长度,空间复杂度O(NK) + //先判断原数组是否为null + if (strs.length == 0){ + return new ArrayList<>(); + } + + Map result = new HashMap<>();//创建要输出对象的实例 + for (String s : strs){ + //转换成char并进行排序 + char[] ca = s.toCharArray(); + Arrays.sort(ca); + + // 将排序后的char再转回string类型 + String key = String.valueOf(ca); + + if (!result.containsKey(key)){ + result.put(key,new ArrayList()); + } + + result.get(key).add(s); + + } + + return new ArrayList(result.values()); + + } +} \ No newline at end of file diff --git a/Week_02/G20200343030603/LeetCode_5_603.java b/Week_02/G20200343030603/LeetCode_5_603.java new file mode 100644 index 00000000..73271444 --- /dev/null +++ b/Week_02/G20200343030603/LeetCode_5_603.java @@ -0,0 +1,56 @@ +//二叉树前序遍历 + + +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; } + * } + */ +class Solution { + // //方法一:递归 + // List result = new ArrayList<>(); + // public List preorderTraversal(TreeNode root) { + // if (root == null){ + // return result; + // } + + // result.add(root.val); + // preorderTraversal(root.left); + // preorderTraversal(root.right); + + // return result; + // } + + + // 方法二:迭代 时间复杂度O(N) 空间复杂度O(N) + public List preorderTraversal(TreeNode root) { + LinkedList stack = new LinkedList<>(); + LinkedList output = new LinkedList<>(); + + if (root == null){ + return output; + } + + stack.add(root); + + while (!stack.isEmpty()){ + TreeNode treeNode = stack.pollLast(); + output.add(treeNode.val); + + if (treeNode.right != null){ + stack.add(treeNode.right); + } + + if (treeNode.left != null){ + stack.add(treeNode.left); + } + } + + return output; + } + +} \ No newline at end of file diff --git a/Week_02/G20200343030603/LeetCode_6_603.java b/Week_02/G20200343030603/LeetCode_6_603.java new file mode 100644 index 00000000..2aae1b1c --- /dev/null +++ b/Week_02/G20200343030603/LeetCode_6_603.java @@ -0,0 +1,50 @@ +//N叉树的层序遍历 +//队列->广度优先搜索,栈->深度优先搜索 + +/* +// Definition for a Node. +class Node { + public int val; + public List children; + + public Node() {} + + public Node(int _val) { + val = _val; + } + + public Node(int _val, List _children) { + val = _val; + children = _children; + } +}; +*/ +class Solution { + public List> levelOrder(Node root) { + + List> values = new ArrayList<>(); + if (root == null){ + return values; + } + //用队列存放节点 + Queue queue = new LinkedList<>(); + //首先将根节点放到队列中 + queue.add(root); + + //如果队列不为空 + while (!queue.isEmpty){ + //用一个列表存放节点值 + List level = new ArrayList<>(); + int size = queue.size; + for (int i = 0; i < size; i++){ + Node node = queue.poll(); + level.add(node.val); + queue.addAll(node.children); + } + result.add(level); + } + + return result; + + } +} \ No newline at end of file diff --git a/Week_02/G20200343030611/LeetCode_144_611.java b/Week_02/G20200343030611/LeetCode_144_611.java new file mode 100644 index 00000000..88b74389 --- /dev/null +++ b/Week_02/G20200343030611/LeetCode_144_611.java @@ -0,0 +1,33 @@ +package datast.tree; + +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; + +public class LeetCode_144_611 { + + public class TreeNode { + int val; + TreeNode left; + TreeNode right; + + TreeNode(int x) { + val = x; + } + } + + public List preorderTraversal(TreeNode root) { + // 迭代 + List res = new ArrayList<>(); + Stack stack = new Stack<>(); + if (root == null) return res; + stack.push(root); + while (!stack.isEmpty()) { + TreeNode node = stack.pop(); + res.add(node.val); + if (node.right != null) stack.push(node.right); + if (node.left != null) stack.push(node.left); + } + return res; + } +} diff --git a/Week_02/G20200343030611/LeetCode_242_611.java b/Week_02/G20200343030611/LeetCode_242_611.java new file mode 100644 index 00000000..6a9c9626 --- /dev/null +++ b/Week_02/G20200343030611/LeetCode_242_611.java @@ -0,0 +1,26 @@ +package datast.hashtable; + +public class LeetCode_242_611 { + + /** + * 给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。 + * + * @param s + * @param t + * @return + */ + public boolean isAnagram(String s, String t) { + if (s.length() != t.length()) return false; + int[] counter = new int[26]; + char[] sCharArray = s.toCharArray(); + char[] tCharArray = t.toCharArray(); + for (int i = 0; i < sCharArray.length; i++) { + counter[sCharArray[i] - 'a']++; + counter[tCharArray[i] - 'a']--; + } + for (int i = 0; i < counter.length; i++) { + if (counter[i] != 0) return false; + } + return true; + } +} diff --git a/Week_02/G20200343030611/LeetCode_429_611.java b/Week_02/G20200343030611/LeetCode_429_611.java new file mode 100644 index 00000000..586a1fb9 --- /dev/null +++ b/Week_02/G20200343030611/LeetCode_429_611.java @@ -0,0 +1,45 @@ +package datast.tree; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; + +public class LeetCode_429_611 { + + class Node { + public int val; + public List children; + + public Node() { + } + + public Node(int _val) { + val = _val; + } + + public Node(int _val, List _children) { + val = _val; + children = _children; + } + } + + public List> levelOrder(Node root) { + List> res = new ArrayList<>(); + if (root == null) return res; + Queue queue = new LinkedList<>(); + queue.offer(root); + while (queue.size() > 0) { + List level = new ArrayList<>(); + int size = queue.size(); + for (int i = 0; i < size; i++) { + Node node = queue.poll(); + level.add(node.val); + if (node.children != null) + queue.addAll(node.children); + } + res.add(level); + } + return res; + } +} diff --git a/Week_02/G20200343030611/LeetCode_49_611.java b/Week_02/G20200343030611/LeetCode_49_611.java new file mode 100644 index 00000000..9c3d7c90 --- /dev/null +++ b/Week_02/G20200343030611/LeetCode_49_611.java @@ -0,0 +1,27 @@ +package datast.hashtable; + +import java.util.*; + +public class LeetCode_49_611 { + + /** + * 给定一个字符串数组,将字母异位词组合在一起。字母异位词指字母相同,但排列不同的字符串。 + * + * @param strs + * @return + */ + public List> groupAnagrams(String[] strs) { + // 时间复杂度 O(nklongk) k 是str的最大长度 + Map> map = new HashMap<>(); + for (String str : strs) { + char[] charArray = str.toCharArray(); + Arrays.sort(charArray); + String key = String.valueOf(charArray); + if (!map.containsKey(key)) { + map.put(key, new ArrayList()); + } + map.get(key).add(str); + } + return new ArrayList(map.values()); + } +} diff --git a/Week_02/G20200343030611/LeetCode_589_611.java b/Week_02/G20200343030611/LeetCode_589_611.java new file mode 100644 index 00000000..7a32b5b5 --- /dev/null +++ b/Week_02/G20200343030611/LeetCode_589_611.java @@ -0,0 +1,44 @@ +package datast.tree; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Stack; + +public class LeetCode_589_611 { + + class Node { + public int val; + public List children; + + public Node() { + } + + public Node(int _val) { + val = _val; + } + + public Node(int _val, List _children) { + val = _val; + children = _children; + } + } + + public List preorder(Node root) { + List res = new ArrayList<>(); + if (root == null) return res; + Stack stack = new Stack<>(); + stack.push(root); + while (!stack.isEmpty()) { + Node node = stack.pop(); + res.add(node.val); + if (node.children != null) { + Collections.reverse(node.children); + for (Node n : node.children) { + stack.push(n); + } + } + } + return res; + } +} diff --git a/Week_02/G20200343030611/LeetCode_590_611.java b/Week_02/G20200343030611/LeetCode_590_611.java new file mode 100644 index 00000000..529fc76b --- /dev/null +++ b/Week_02/G20200343030611/LeetCode_590_611.java @@ -0,0 +1,42 @@ +package datast.tree; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Stack; + +public class LeetCode_590_611 { + + class Node { + public int val; + public List children; + + public Node() { + } + + public Node(int _val) { + val = _val; + } + + public Node(int _val, List _children) { + val = _val; + children = _children; + } + } + + public List postorder(Node root) { + List res = new ArrayList<>(); + Stack stack = new Stack<>(); + if (root == null) return res; + stack.push(root); + while (!stack.isEmpty()) { + Node node = stack.pop(); + res.add(node.val); + for (Node n : node.children) { + stack.push(n); + } + } + Collections.reverse(res); + return res; + } +} diff --git a/Week_02/G20200343030611/LeetCode_94_611.java b/Week_02/G20200343030611/LeetCode_94_611.java new file mode 100644 index 00000000..59973d20 --- /dev/null +++ b/Week_02/G20200343030611/LeetCode_94_611.java @@ -0,0 +1,37 @@ +package datast.tree; + +import java.util.ArrayList; +import java.util.List; + +public class LeetCode_94_611 { + + /** + * 给定一个二叉树,返回它的中序 遍历。 + * + * @param root + * @return + */ + public List inorderTraversal(TreeNode root) { + // 递归 + List res = new ArrayList<>(); + inOrder(root, res); + return res; + } + + public void inOrder(TreeNode node, List res) { + if (node == null) return; + inOrder(node.left, res); + res.add(node.val); + inOrder(node.right, res); + } + + public class TreeNode { + int val; + TreeNode left; + TreeNode right; + + TreeNode(int x) { + val = x; + } + } +} diff --git a/Week_02/G20200343030617/LeetCode_1_617.go b/Week_02/G20200343030617/LeetCode_1_617.go new file mode 100644 index 00000000..18669ec8 --- /dev/null +++ b/Week_02/G20200343030617/LeetCode_1_617.go @@ -0,0 +1,25 @@ +//49. 字母异位词分组 + +package main + +import "sort" + +type sortRunes []rune + +func (s sortRunes) Len() int { return len(s) } +func (s sortRunes) Less(i, j int) bool { return s[i] < s[j] } +func (s sortRunes) Swap(i, j int) { s[i], s[j] = s[j], s[i] } + +func groupAnagrams(strs []string) [][]string { + var m = make(map[string][]string) + for _, str := range strs { + s := []rune(str) + sort.Sort(sortRunes(s)) + m[string(s)] = append(m[string(s)], str) + } + var n [][]string + for _, k := range m { + n = append(n, k) + } + return n +} diff --git a/Week_02/G20200343030617/LeetCode_2_617.go b/Week_02/G20200343030617/LeetCode_2_617.go new file mode 100644 index 00000000..781d26ba --- /dev/null +++ b/Week_02/G20200343030617/LeetCode_2_617.go @@ -0,0 +1,27 @@ +// 144.二叉树的前序遍历 + + +package main + + +type TreeNode struct { + Val int + Left *TreeNode + Right *TreeNode +} + +func preorderTraversal(root *TreeNode) []int { + var a []int + return cds(root, &a) +} + +func cds(root *TreeNode, res *[]int) []int { + if root != nil { + *res = append(*res, root.Val) + cds(root.Left, res) + cds(root.Right, res) + return *res + } else { + return nil + } +} diff --git a/Week_02/G20200343030617/LeetCode_4_617.go b/Week_02/G20200343030617/LeetCode_4_617.go new file mode 100644 index 00000000..4d1f0165 --- /dev/null +++ b/Week_02/G20200343030617/LeetCode_4_617.go @@ -0,0 +1,26 @@ +// 236. 二叉树的最近公共祖先 + +package main + +type TreeNode struct { + Val int + Left *TreeNode + Right *TreeNode +} + +func lowestCommonAncestor(root, p, q *TreeNode) *TreeNode { + if root == p || root == q || root == nil { + return root + } + left := lowestCommonAncestor(root.Left, p, q) + right := lowestCommonAncestor(root.Right, p, q) + + if left != nil && right != nil { + return root + } else if left == nil { + return right + } else { + return left + } + +} diff --git a/Week_02/G20200343030625/LeetCode_144_625.java b/Week_02/G20200343030625/LeetCode_144_625.java new file mode 100644 index 00000000..521a4b81 --- /dev/null +++ b/Week_02/G20200343030625/LeetCode_144_625.java @@ -0,0 +1,45 @@ +public class Solution { + public List preorderTraversal(TreeNode root) { + List list = new ArrayList(); + travels(root, list); + return list; + //eturn travelsByIterator(root); + } + + // 递归方式 + private void travels(TreeNode root, List list) { + if(root != null){ + list.add(root.val); + if(root.left != null){ + travels(root.left, list); + } + if(root.right != null) { + travels(root.right, list); + } + } + } + + // 迭代方式 + private List travelsByIterator(TreeNode root) { + List list = new ArrayList(); + Stack stack = new Stack(); + + if (root == null) { + return list; + } + stack.push(root); + + while (!stack.isEmpty()) { + TreeNode currentNode = stack.pop(); + if (currentNode.right != null) { + stack.push(currentNode.right); + } + if (currentNode.left != null) { + stack.push(currentNode.left); + } + list.add(currentNode.val); + } + + return list; + } +} diff --git a/Week_02/G20200343030625/LeetCode_429_625.java b/Week_02/G20200343030625/LeetCode_429_625.java new file mode 100644 index 00000000..96245316 --- /dev/null +++ b/Week_02/G20200343030625/LeetCode_429_625.java @@ -0,0 +1,24 @@ +public class Solution { + public List> levelOrder(Node root) { + List> list = new ArrayList>(); + LinkedList queue = new LinkedList(); + if (root == null) { + return list; + } + queue.add(root); + while (!queue.isEmpty()) { + List levelList = new ArrayList(); + int size = queue.size(); + for (int idx = 0; idx < size; idx++) { + Node poll = queue.poll(); + levelList.add(poll.val); + if (poll.children != null) { + queue.addAll(poll.children); + } + } + list.add(levelList); + } + + return list; + } +} diff --git a/Week_02/G20200343030625/LeetCode_589_625.java b/Week_02/G20200343030625/LeetCode_589_625.java new file mode 100644 index 00000000..e49f9550 --- /dev/null +++ b/Week_02/G20200343030625/LeetCode_589_625.java @@ -0,0 +1,45 @@ +public class Solution { + public List preorder(Node root) { + // return preorderIter(root); + List list = new ArrayList(); + postorderRecursion(root, list); + + return list; + } + + public List preorderIter(Node root) { + LinkedList stack = new LinkedList(); + LinkedList list = new LinkedList(); + if (root == null) { + return list; + } + stack.add(root); + while (!stack.isEmpty()) { + Node node = stack.pollLast(); + list.add(node.val); + if(node.children == null){ + continue; + } + Collections.reverse(node.children); + for (Node child : node.children) { + stack.add(child); + } + } + + return list; + } + + public void postorderRecursion(Node root, List list) { + if (root == null) { + return; + } + list.add(root.val); + if (root.children == null) { + return; + } + for (Node each : root.children) { + postorderRecursion(each, list); + } + } + +} diff --git a/Week_02/G20200343030625/LeetCode_590_625.java b/Week_02/G20200343030625/LeetCode_590_625.java new file mode 100644 index 00000000..e825d47f --- /dev/null +++ b/Week_02/G20200343030625/LeetCode_590_625.java @@ -0,0 +1,22 @@ +public class Solution { + public List postorder(Node root) { + LinkedList stack = new LinkedList(); + LinkedList list = new LinkedList(); + + if (root == null) { + return list; + } + stack.add(root); + while (!stack.isEmpty()) { + Node currentNode = stack.pollLast(); + list.addFirst(currentNode.val); + for (Node each: currentNode.children) { + if (each != null) { + stack.add(each); + } + } + } + + return list; + } +} diff --git a/Week_02/G20200343030627/LeetCode_1_627.js b/Week_02/G20200343030627/LeetCode_1_627.js new file mode 100644 index 00000000..ad3bb81d --- /dev/null +++ b/Week_02/G20200343030627/LeetCode_1_627.js @@ -0,0 +1,36 @@ +// n-ary-tree-postorder-traversal + +// 递归,很慢,180ms +/* +var postorder = function(root) { + if (!root) return []; + + var result = []; + iter(root, result); + + return result; +}; +var iter = function(root, arr) { + if (!root) return + root.children.forEach(function(child){ + iter(child, arr); + }); + arr.push(root.val); +} +*/ + +// 迭代,80ms +var postorder = function(root) { + if (!root) return []; + + var stackArr = [root]; + var result = []; + + while (stackArr.length > 0) { + var curr = stackArr.pop(); + result.push(curr.val); + curr.children.forEach(child => stackArr.push(child)); + } + + return result.reverse(); +} \ No newline at end of file diff --git a/Week_02/G20200343030627/LeetCode_2_627.js b/Week_02/G20200343030627/LeetCode_2_627.js new file mode 100644 index 00000000..9bf5338b --- /dev/null +++ b/Week_02/G20200343030627/LeetCode_2_627.js @@ -0,0 +1,38 @@ +// n-ary-tree-preorder-traversal + +// 递归实现,非常慢232ms +/* +var preorder = function(root) { + if (!root) return []; + + var result = []; + iter(root, result); + + return result; +}; +var iter = function(root, arr) { + if (!root) return; + + arr.push(root.val); + root.children.forEach(function(child){ + iter(child, arr); + }); +} +*/ + +// 迭代实现 80ms +var preorder = function(root) { + if (!root) return [] + + var stackArr = [root]; + var result = []; + + while (stackArr.length > 0) { + var curr = stackArr.pop(); // 弹出节点 + result.push(curr.val); // 记录值 + for (var i=curr.children.length - 1; i >= 0; i--) { + stackArr.push(curr.children[i]); // 子节点逆序放回 + } + } + return result; +} \ No newline at end of file diff --git a/Week_02/G20200343030627/LeetCode_3_627.js b/Week_02/G20200343030627/LeetCode_3_627.js new file mode 100644 index 00000000..6d7b4495 --- /dev/null +++ b/Week_02/G20200343030627/LeetCode_3_627.js @@ -0,0 +1,54 @@ +// group-anagrams + + +/* +/* 字符排序比较 +var groupAnagrams = function(strs) { + var dict = {} + for (var i=0; i< strs.length; i++) { + var sortedStr = strs[i].split('').sort((a,b)=>a>b?1:-1).join(''); + if (dict[sortedStr]) { + dict[sortedStr].push(strs[i]); + } else { + dict[sortedStr] = [strs[i]]; + } + } + var result = [] + for (x in dict) { + result.push(dict[x]); + } + return result +}; +*/ + +// 字幕映射表,速度稍快 160ms +var groupAnagrams = function(strs) { + var dict = {}; + + for (var i=0; i< strs.length; i++) { + var strKey = toKey(strs[i]); + if (dict[strKey]) { + dict[strKey].push(strs[i]); + } else { + dict[strKey] = [strs[i]]; + } + } + var result = [] + for (x in dict) { + result.push(dict[x]); + } + return result +} + +function toKey(str) { + var map= {a:0,b:1,c:2,d:3,e:4,f:5,g:6,h:7,i:8,j:9,k:10,l:11,m:12,n:13,o:14,p:15,q:16,r:17,s:18,t:19,u:20,v:21,w:22,x:23,y:24,z:25}; + var arr = []; + for (var i=0; i 0) { + var currNode = stackArr.pop(); + if (!currNode) continue; + + resultArr.push(currNode.val); + stackArr.push(currNode.right); + stackArr.push(currNode.left); + } + + return resultArr; +} +*/ + +// 学习莫里斯遍历 +var preorderTraversal = function(root) { + var resultList= []; + + var node = root; + while (node != null) { + if (node.left == null) { + resultList.push(node.val) + node = node.right; + continue; + } + + var predecessor = node.left; + + while (predecessor.right != null && predecessor.right != node) { + predecessor = predecessor.right; + } + + if (predecessor.right == null) { + resultList.push(node.val); + predecessor.right = node; + node = node.left; + } else { + predecessor.right = null; + node = node.right; + } + + } + + return resultList; +} \ No newline at end of file diff --git a/Week_02/G20200343030627/LeetCode_5_627.js b/Week_02/G20200343030627/LeetCode_5_627.js new file mode 100644 index 00000000..94873230 --- /dev/null +++ b/Week_02/G20200343030627/LeetCode_5_627.js @@ -0,0 +1,59 @@ +// n-ary-tree-level-order-traversal/ +// 队列 +var levelOrder = function(root) { + if (!root) return []; + var queueList = [root]; + var result = []; + var level = 0; + + while(queueList.length > 0) { // 当前队列不为空 + var levelLimit = queueList.length; + for (var i= 0; i< levelLimit; i++) { + var node = queueList.shift(); + if (result[level]) { + result[level].push(node.val); + } else { + result[level] = [node.val]; + } + + for (var j = 0; j< node.children.length; j++) { + if (!node.children[j]) continue; + queueList.push(node.children[j]); + } + } + level ++; + } + + return result +}; +/** +/* 双队列 +var levelOrder = function(root) { + if (!root) return [] + var queueFlag = 0; + var queueList = [[root],[]]; + var result = []; + var level = 0; + + while(queueList[queueFlag].length > 0) { // 当前队列不为空 + var node = queueList[queueFlag].shift(); + + if (result[level]) { + result[level].push(node.val); + } else { + result[level] = [node.val]; + } + + for (var i = 0; i< node.children.length; i++) { + if (!node.children[i]) continue; + queueList[1-queueFlag].push(node.children[i]); + } + if (queueList[queueFlag].length == 0) { + queueFlag = 1 - queueFlag; + level += 1; + } + } + + return result +}; +*/ \ No newline at end of file diff --git a/Week_02/G20200343030627/LeetCode_6_627.js b/Week_02/G20200343030627/LeetCode_6_627.js new file mode 100644 index 00000000..76b78fe6 --- /dev/null +++ b/Week_02/G20200343030627/LeetCode_6_627.js @@ -0,0 +1,28 @@ +// lowest-common-ancestor-of-a-binary-tree + +var lowestCommonAncestor = function(root, p, q) { + if (!root) return null; + + var resultNode = null; + recurseTree(root, p, q); + + function recurseTree(root, p, q) { + // t + if (resultNode) return false; + if (!root) return false; + // p + var left = recurseTree(root.left, p, q) ? 1 : 0; + var right = recurseTree(root.right, p, q) ? 1 : 0; + var mid = (root == p || root == q) ? 1 : 0; + + if ((left + right + mid) > 1) { + resultNode = root; + return true; + } + + return (left + right + mid) > 0; + // d + } + + return resultNode; +}; \ No newline at end of file diff --git a/Week_02/G20200343030627/LeetCode_7_627.js b/Week_02/G20200343030627/LeetCode_7_627.js new file mode 100644 index 00000000..c9db0a1e --- /dev/null +++ b/Week_02/G20200343030627/LeetCode_7_627.js @@ -0,0 +1,19 @@ +// construct-binary-tree-from-preorder-and-inorder-traversal + +var buildTree = function(preorder, inorder) { + if (preorder.length == 0) { + return null; + } + + var root = new TreeNode(preorder[0]); + + var mid; + for (var i=0; i< inorder.length; i++) { + if (preorder[0] == inorder[i]) mid = i; + } + + root.left = buildTree(preorder.slice(1,mid+1), inorder.slice(0,mid)); + root.right = buildTree(preorder.slice(mid+1, preorder.length), inorder.slice(mid+1, inorder.length)); + + return root +}; \ No newline at end of file diff --git a/Week_02/G20200343030631/LeetCode_105_631.java b/Week_02/G20200343030631/LeetCode_105_631.java new file mode 100644 index 00000000..8a011b06 --- /dev/null +++ b/Week_02/G20200343030631/LeetCode_105_631.java @@ -0,0 +1,78 @@ + +public class Solution { + private static int currentNodeIndexInPreOrder = 0; + public static void main(String[] args) { + int[] preOrder = new int[]{-1}; + int[] inOrder = new int[]{-1}; + Version1 version1 = new Version1(); + TreeNode node = version1.buildTree(preOrder, inOrder); + System.out.println(node); + } + + /** + * 解题思路: 根据前序、中序的特点,递归找到根节点、子树根节点,构建树 + * 时间复杂度: O(n) + * 空间复杂度: O(n) + * 执行用时: 2 ms, 在所有 Java 提交中击败了97.23%的用户 + * 内存消耗: 41.2 MB, 在所有 Java 提交中击败了39.96%的用户 + * @Author: loe881@163.com + * @Date: 2020/3/3 + */ + public TreeNode buildTree(int[] preorder, int[] inorder) { + // 静态变量,每次初始化为0 + currentNodeIndexInPreOrder = 0; + // 边界条件,任何一个为空,或者大小为0,无法重建 + if (null == preorder || null == inorder + || preorder.length == 0 || inorder.length == 0) { + return null; + } + + // 将中序结果倒排索引式map存放,以便后续对前序结果快速找到在中序数组中位置 + Map inOrderMap = new HashMap<>(preorder.length); + for (int i = 0; i < inorder.length; i++) { + inOrderMap.put(inorder[i], i); + } + + return buildTreeInternal(preorder, inOrderMap, 0, inorder.length); + } + + /** + * @param preorder 前序遍历数组 + * @param inOrderMap 中序遍历转换后的map + * @param indexOfLeftTreeInInOrder 在中序遍历数组中左子树的边界索引 + * @param indexOfRightTreeInInOrder 在中序遍历数组中右子树的边界索引 + * @return 当前子树 + */ + private static TreeNode buildTreeInternal(int[] preorder, + Map inOrderMap, + int indexOfLeftTreeInInOrder, + int indexOfRightTreeInInOrder) { + // 递归终止条件,所有的数组元素都已经递归处理 + if (indexOfLeftTreeInInOrder == indexOfRightTreeInInOrder) { + return null; + } + + int currentRootNodeVal = preorder[currentNodeIndexInPreOrder]; + TreeNode currentRoot = new TreeNode(currentRootNodeVal); + + int leftSubTreeEdgeIndex = inOrderMap.get(currentRootNodeVal); + currentNodeIndexInPreOrder++; + currentRoot.left = buildTreeInternal(preorder, inOrderMap, indexOfLeftTreeInInOrder, leftSubTreeEdgeIndex); + currentRoot.right = buildTreeInternal(preorder, inOrderMap, leftSubTreeEdgeIndex + 1, indexOfRightTreeInInOrder); + return currentRoot; + } + + /** + * Definition for a binary tree node. + */ + public static class TreeNode { + int val; + TreeNode left; + TreeNode right; + + TreeNode(int x) { + val = x; + } + } + +} diff --git a/Week_02/G20200343030631/LeetCode_144_631.java b/Week_02/G20200343030631/LeetCode_144_631.java new file mode 100644 index 00000000..3f6b5ab8 --- /dev/null +++ b/Week_02/G20200343030631/LeetCode_144_631.java @@ -0,0 +1,101 @@ +package com.dsx.hundred.forty.four; + +import java.util.ArrayList; +import java.util.List; + +/** + * 解题思路: 典型递归方式 + * 时间复杂度: O(n) + * 空间复杂度: O(1) + * 执行用时: 0 ms, 在所有 Java 提交中击败了100.00%的用户 + * 内存消耗: 37.5 MB, 在所有 Java 提交中击败了5.19%的用户 + * @Author: loe881@163.com + * @Date: 2020/2/23 + */ +public class Version1 { + public static void main(String[] args) { + + } + public static List preorderTraversal(TreeNode root) { + if (null == root){ + return new ArrayList<>(); + } + List result = new ArrayList<>(); + preOrderTraversalInternal(root, result); + return result; + } + + private static void preOrderTraversalInternal(TreeNode node, List result){ + if (null == node){ + return; + } + result.add(node.val); + preOrderTraversalInternal(node.left, result); + preOrderTraversalInternal(node.right, result); + } + /** + * Definition for a binary tree node. + */ + public class TreeNode { + int val; + TreeNode left; + TreeNode right; + TreeNode(int x) { val = x; } + } +} + + +package com.dsx.hundred.forty.four; + + +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; + +/** + * 解题思路: 使用栈遍历 + * 时间复杂度: O(n) + * 空间复杂度: O(n) + * 执行用时: 1 ms, 在所有 Java 提交中击败了60.73%的用户 + * 内存消耗: 37.7 MB, 在所有 Java 提交中击败了5.19%的用户 + * @Author: loe881@163.com + * @Date: 2020/2/23 + */ +public class Version2 { + public static void main(String[] args) { + + } + public static List preorderTraversal(TreeNode root) { + if (null == root){ + return new ArrayList<>(); + } + List result = new ArrayList<>(); + Stack treeNodeStack = new Stack(); + treeNodeStack.add(root); + while (!treeNodeStack.isEmpty()){ + TreeNode tmpNode = treeNodeStack.pop(); + result.add(tmpNode.val); + if (tmpNode.right != null){ + treeNodeStack.add(tmpNode.right); + } + if (tmpNode.left != null){ + treeNodeStack.add(tmpNode.left); + } + } + return result; + } + + private static void preOrderTraversalInternal(TreeNode root, List result) { + + } + + /** + * Definition for a binary tree node. + */ + public class TreeNode { + int val; + TreeNode left; + TreeNode right; + TreeNode(int x) { val = x; } + } +} diff --git a/Week_02/G20200343030631/LeetCode_236_631.java b/Week_02/G20200343030631/LeetCode_236_631.java new file mode 100644 index 00000000..d8e9499f --- /dev/null +++ b/Week_02/G20200343030631/LeetCode_236_631.java @@ -0,0 +1,107 @@ + +public class Solution { + public static void main(String[] args) { + + } + + /** + * 解题思路: 递归 + * 时间复杂度: O(n) + * 空间复杂度: O(n) + * 执行用时: 8 ms, 在所有 Java 提交中击败了99.67%的用户 + * 内存消耗: 42 MB, 在所有 Java 提交中击败了5.02%的用户 + * + * @Author: loe881@163.com + * @Date: 2020/3/3 + */ + public static TreeNode lowestCommonAncestorV1(TreeNode root, TreeNode p, TreeNode q) { + // 边界条件 + if (null == root || null == p || null == q){ + return root; + } + recurseAncestorInternal(root, p, q); + return result; + } + + private static boolean recurseAncestorInternal(TreeNode current, TreeNode p, TreeNode q) { + // 递归终止条件 + if (null == current){ + return false; + } + + // 递归下钻 + int findInLeft = recurseAncestorInternal(current.left, p, q) ? 1 : 0; + int findInRight = recurseAncestorInternal(current.right, p, q) ? 1 : 0; + + // 本层处理 + int findArCurrent = (current == q || current == p) ? 1 : 0; + + // 如果在左右子树、当前节点任何两个中发现p q,则返回当前节点 + if ((findArCurrent + findInLeft + findInRight) >=2){ + result = current; + } + // 没有找到,返回当前节点下查找结果 + return (findArCurrent + findInLeft + findInRight) > 0 ; + } + + /** + * 解题思路: 分别找到从根节点到p q的节点路径,找到共同存在的一个节点 + * 时间复杂度: O(n) + * 空间复杂度: O(n) + * 执行用时: 15 ms, 在所有 Java 提交中击败了18.20%的用户 + * 内存消耗: 41.2 MB, 在所有 Java 提交中击败了5.02%的用户 + * @Author: loe881@163.com + * @Date: 2020/3/3 + */ + public TreeNode lowestCommonAncestorV2(TreeNode root, TreeNode p, TreeNode q) { + // 边界条件 + if (null == root || null == p || null == q){ + return root; + } + // 存放遍历时的节点 + Deque nodeTraversStack = new ArrayDeque<>(); + Map parentMap = new HashMap<>(); + // root的根为null + parentMap.put(root, null); + // root压入栈中 + nodeTraversStack.add(root); + while (!parentMap.containsKey(p) || !parentMap.containsKey(q)){ + TreeNode node = nodeTraversStack.pop(); + // 如果左子树不为空,左子树入栈,同时加入到parentMap中 + if (null != node.left){ + parentMap.put(node.left, node); + nodeTraversStack.add(node.left); + } + // 如果右子树不为空,左子树入栈,同时加入到parentMap中 + if (null != node.right){ + parentMap.put(node.right, node); + nodeTraversStack.add(node.right); + } + } + // 存放节点p祖先 + Set ancestors = new HashSet<>(); + // 循环将所有p的祖先加入set中 + while (p != null){ + ancestors.add(p); + p = parentMap.get(p); + } + // 循环q的祖先,找到第一个q的祖先且在p的祖先set中的节点 + while (!ancestors.contains(q)) { + q = parentMap.get(q); + } + return q; + } + + /** + * Definition for a binary tree node. + */ + public class TreeNode { + int val; + TreeNode left; + TreeNode right; + + TreeNode(int x) { + val = x; + } + } +} diff --git a/Week_02/G20200343030631/LeetCode_429_631.java b/Week_02/G20200343030631/LeetCode_429_631.java new file mode 100644 index 00000000..c8027f6e --- /dev/null +++ b/Week_02/G20200343030631/LeetCode_429_631.java @@ -0,0 +1,62 @@ +package com.dsx.fourhundred.twenty.nine; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; + +/** + * 解题思路: 使用队列,每次出队一个节点,记录值,然后如果有子节点则将当前节点子节点全部入队 + * 时间复杂度: O(n) + * 空间复杂度: O(n) + * 执行用时: 3 ms, 在所有 Java 提交中击败了79.55%的用户 + * 内存消耗: 41.7 MB, 在所有 Java 提交中击败了9.52%的用户 + * + * @Author: loe881@163.com + * @Date: 2020/2/23 + */ +public class Version1 { + public static void main(String[] args) { + + } + + public List> levelOrder(Node root) { + List> result = new ArrayList<>(); + if (root == null){ + return result; + } + Queue leverOrderAssit = new LinkedList<>(); + leverOrderAssit.add(root); + while (!leverOrderAssit.isEmpty()){ + // 当前层的值记录 + List currentLevel = new ArrayList<>(); + // 记录当前层共有几个节点 + int size = leverOrderAssit.size(); + for (int i = 0; i < size; i++) { + Node node = leverOrderAssit.poll(); + currentLevel.add(node.val); + leverOrderAssit.addAll(node.children); + } + result.add(currentLevel); + } + return result; + } + + // Definition for a Node. + class Node { + public int val; + public List children; + + public Node() { + } + + public Node(int _val) { + val = _val; + } + + public Node(int _val, List _children) { + val = _val; + children = _children; + } + } +} diff --git a/Week_02/G20200343030631/LeetCode_46_631.java b/Week_02/G20200343030631/LeetCode_46_631.java new file mode 100644 index 00000000..db9f4f53 --- /dev/null +++ b/Week_02/G20200343030631/LeetCode_46_631.java @@ -0,0 +1,115 @@ + +public class Solution { + public static void main(String[] args) { + int[] nums = new int[]{1, 2, 3, 4}; + System.out.println(permute(nums)); + } + + /** + * 解题思路: 递归方式,从两个数的全排列开始 + * 时间复杂度: O(n!) + * 空间复杂度: 开辟了n的从2~n个全排列之和的空间 + * 执行用时: 76 ms, 在所有 Java 提交中击败了5.76%的用户 + * 内存消耗: 41.4 MB, 在所有 Java 提交中击败了5.04%的用户 + * @Author: loe881@163.com + * @Date: 2020/3/3 + */ + public static List> permuteV1(int[] nums) { + // 存放结果集 + List> result = new LinkedList(); + // 边界条件 + if (null == nums || nums.length == 0) { + return result; + } + // 只有一个元素的数组,无需排列,直接返回结果 + if (nums.length == 1){ + result.add(new ArrayList<>(Arrays.asList(nums[0]))); + return result; + } + permuteV1Internal(nums, result); + return result; + } + + /** + * @param nums 需要全排列的数组 + * @param result 当前数据全排列结果 + */ + private static void permuteV1Internal(int[] nums, List> result) { + // 递归终止条件 + if (nums.length == 2){ + result.add(new ArrayList<>(Arrays.asList(nums[0], nums[1]))); + result.add(new ArrayList<>(Arrays.asList(nums[1], nums[0]))); + return; + } + + // 对数组所有数据逐个处理 + for (int i = 0; i < nums.length; i++) { + int tmpNum = nums[i]; + // 开辟一个新数组,存储不包含当前值的其他数据 + int[] tmpNums = new int[nums.length - 1]; + int k = 0; + for (int j = 0; j < nums.length; j++) { + if (tmpNum != nums[j]){ + tmpNums[k++] = nums[j]; + } + } + // 递归下层 + permuteInternal(tmpNums, result); + // 本层处理,对下层递归结果逐个处理,加入本层数据 + for (int j = 0; j < result.size(); j++) { + List tmpResult = result.get(j); + if (tmpResult.size() < nums.length){ + tmpResult.add(0, tmpNum); + } + } + } + } + + /** + * 解题思路: 回溯方式 + * 时间复杂度: + * 空间复杂度: + * 执行用时: 3 ms, 在所有 Java 提交中击败了30.68%的用户 + * 内存消耗: 41.6 MB, 在所有 Java 提交中击败了5.04%的用户 + * + * @Author: loe881@163.com + * @Date: 2020/3/3 + */ + public static List> permuteV2(int[] nums) { + // 存放结果集 + List> result = new LinkedList(); + // 边界条件 + if (null == nums || nums.length == 0) { + return result; + } + // 只有一个元素的数组,无需排列,直接返回结果 + if (nums.length == 1) { + result.add(new ArrayList<>(Arrays.asList(nums[0]))); + return result; + } + permuteV2Internal(nums, new LinkedList(), result); + return result; + } + + private static void permuteV2Internal(int[] nums, LinkedList currentResult, List> result) { + // 终止条件,排列结果集合大小与数据大小一致 + if (currentResult.size() == nums.length) { + result.add(new LinkedList(currentResult)); + return; + } + + // 编列数组每个元素 + for (int i = 0; i < nums.length; i++) { + // 如果当前结果已包含该元素,跳过 + if (currentResult.contains(nums[i])) { + continue; + } + // 将数组元素加入当前结果中 + currentResult.add(nums[i]); + // 回溯下一层 + permuteInternal(nums, currentResult, result); + // 删去最后添加的元素,继续回溯 + currentResult.removeLast(); + } + } +} \ No newline at end of file diff --git a/Week_02/G20200343030631/LeetCode_47_631.java b/Week_02/G20200343030631/LeetCode_47_631.java new file mode 100644 index 00000000..0b375d3f --- /dev/null +++ b/Week_02/G20200343030631/LeetCode_47_631.java @@ -0,0 +1,122 @@ + +public class Solution { + public static void main(String[] args) { + Node root = new Node(1); + Node node3 = new Node(3); + Node node2 = new Node(2); + Node node4 = new Node(4); + List subTree1 = new LinkedList<>(); + subTree1.add(node3); + subTree1.add(node2); + subTree1.add(node4); + Node node5 = new Node(5); + Node node6 = new Node(6); + List subTree2 = new LinkedList<>(); + subTree2.add(node5); + subTree2.add(node6); + node3.children = subTree2; + root.children = subTree1; + List result = preorder(root); + for (Integer integer : result) { + System.out.println(integer); + } + } + + /** + * 解题思路: 递归方式 + * 时间复杂度: O(n) + * 空间复杂度: O(1) + * 执行用时: 1 ms, 在所有 Java 提交中击败了99.62%的用户 + * 内存消耗: 41.5 MB, 在所有 Java 提交中击败了5.02%的用户 + * @Author: loe881@163.com + * @Date: 2020/3/3 + */ + public static List preorderV1(Node root) { + // 前序遍历结果集 + List result = new ArrayList<>(); + // 边界条件,如果root为null,直接返回空集合 + if (null == root){ + return result; + } + // 前序遍历辅助函数 + preOrderInternal(root, result); + return result; + } + + /** + * @param root 要进行前序遍历的节点 + * @param result 遍历后的节点结果值集合 + * @return + */ + private static void preOrderInternal(Node root, List result) { + // 递归终止条件 + if (root == null){ + return; + } + // 当前层处理:1. 将当前结果加入result, 2. 如果子节点为空则返回,不为空遍历当前节点的子节点 + result.add(root.val); + List childrens = root.children; + if (null == childrens){ + return; + } + // 子节点不为空,继续遍历子节点 + for (Node child : childrens) { + preOrderInternal(child, result); + } + } + + /** + * 解题思路: 使用栈的迭代方式 + * 时间复杂度: O(n) + * 空间复杂度: O(n) + * 执行用时: 7 ms, 在所有 Java 提交中击败了5.62%的用户 + * 内存消耗: 41.5 MB, 在所有 Java 提交中击败了5.02%的用户 + * + * @Author: loe881@163.com + * @Date: 2020/3/3 + */ + public static List preorderV2(Node root) { + // 前序遍历结果集 + List result = new ArrayList<>(); + // 边界条件,如果root为null,直接返回空集合 + if (null == root) { + return result; + } + // 记录节点的辅助栈 + Stack nodeRecordQueue = new Stack<>(); + // 首先将root节点压入栈中 + nodeRecordQueue.push(root); + // 栈不为空,说明还有节点需要遍历,继续循环 + while (!nodeRecordQueue.isEmpty()) { + Node tmpNode = nodeRecordQueue.pop(); + result.add(tmpNode.val); + List childrens = tmpNode.children; + if (null != childrens) { + // 使用栈,先进后出,为保证前序根左右的顺序,从右侧开始压入栈 + for (int i = (childrens.size() - 1); i >= 0; i--) { + nodeRecordQueue.add(childrens.get(i)); + } + } + } + return result; + } + + + // Definition for a Node. + static class Node { + public int val; + public List children; + + public Node() { + } + + public Node(int _val) { + val = _val; + } + + public Node(int _val, List _children) { + val = _val; + children = _children; + } + } +} diff --git a/Week_02/G20200343030631/LeetCode_49_631.java b/Week_02/G20200343030631/LeetCode_49_631.java new file mode 100644 index 00000000..0194e020 --- /dev/null +++ b/Week_02/G20200343030631/LeetCode_49_631.java @@ -0,0 +1,85 @@ +package com.dsx.forty.nine; + +import java.util.*; + +/** + * 解题思路: 遍历数组元素,对每个元素转为字符数组后排序,排序后放入结果map中,已存在的则取出结果map的value,放入value的list中 + * 时间复杂度: O(nklogk), n是 strs的长度,k是strs中字符串的最大长度 + * 空间复杂度: O(nk) + * 执行用时 :9 ms, 在所有 Java 提交中击败了99.61%的用户 + * 内存消耗 :45.2 MB, 在所有 Java 提交中击败了9.66%的用户 + * @Author: loe881@163.com + * @Date: 2020/2/21 + */ +public class Version1 { + + public static void main(String[] args) { + String[] strings = new String[]{"eat", "tea", "tan", "ate", "nat", "bat"}; + System.out.println(groupAnagrams(strings)); + } + + public static List> groupAnagrams(String[] strs) { + if (null == strs || strs.length == 0){ + return new ArrayList<>(); + } + Map> result = new HashMap<>(); + for (String str : strs) { + char[] tmpChars = str.toCharArray(); + Arrays.sort(tmpChars); + String tmpStr = String.valueOf(tmpChars); + if (!result.containsKey(tmpStr)) { + result.put(tmpStr, new ArrayList<>()); + } + result.get(tmpStr).add(str); + } + return new ArrayList<>(result.values()); + } +} + +package com.dsx.forty.nine; + +import java.util.*; + +/** + * 解题思路: 用数组存储字符串中每个字符出现的次数,最后拼接数组为统计字符串如#1#1,代表ab各出现1次 + * 对比字符串形成的统计字符串是否相等 + * 时间复杂度: O(nk) + * 空间复杂度: O(nk) + * 执行用时: 41 ms, 在所有 Java 提交中击败了100.00%的用户 + * 内存消耗 :45.2 MB, 在所有 Java 提交中击败了9.66%的用户 + * @Author: loe881@163.com + * @Date: 2020/2/21 + */ +public class Version2 { + public static void main(String[] args) { + String[] strings = new String[]{"eat", "tea", "tan", "ate", "nat", "bat"}; + System.out.println(groupAnagrams(strings)); + } + + public static List> groupAnagrams(String[] strs) { + if (null == strs || strs.length == 0){ + return new ArrayList<>(); + } + + Map> result = new HashMap<>(); + int[] counts = new int[26]; + for (String str : strs) { + Arrays.fill(counts, -1); + char[] tmpChars = str.toCharArray(); + for (char tmpChar : tmpChars) { + counts[tmpChar - 'a']++; + } + StringBuilder stringBuilder = new StringBuilder(""); + for (int i = 0; i < 26; i++) { + stringBuilder.append("#"); + stringBuilder.append(counts[i]); + } + String key = stringBuilder.toString(); + if (!result.containsKey(key)){ + result.put(key, new ArrayList<>()); + } + result.get(key).add(str); + } + return new ArrayList<>(result.values()); + } +} diff --git a/Week_02/G20200343030631/LeetCode_589_631.java b/Week_02/G20200343030631/LeetCode_589_631.java new file mode 100644 index 00000000..0b375d3f --- /dev/null +++ b/Week_02/G20200343030631/LeetCode_589_631.java @@ -0,0 +1,122 @@ + +public class Solution { + public static void main(String[] args) { + Node root = new Node(1); + Node node3 = new Node(3); + Node node2 = new Node(2); + Node node4 = new Node(4); + List subTree1 = new LinkedList<>(); + subTree1.add(node3); + subTree1.add(node2); + subTree1.add(node4); + Node node5 = new Node(5); + Node node6 = new Node(6); + List subTree2 = new LinkedList<>(); + subTree2.add(node5); + subTree2.add(node6); + node3.children = subTree2; + root.children = subTree1; + List result = preorder(root); + for (Integer integer : result) { + System.out.println(integer); + } + } + + /** + * 解题思路: 递归方式 + * 时间复杂度: O(n) + * 空间复杂度: O(1) + * 执行用时: 1 ms, 在所有 Java 提交中击败了99.62%的用户 + * 内存消耗: 41.5 MB, 在所有 Java 提交中击败了5.02%的用户 + * @Author: loe881@163.com + * @Date: 2020/3/3 + */ + public static List preorderV1(Node root) { + // 前序遍历结果集 + List result = new ArrayList<>(); + // 边界条件,如果root为null,直接返回空集合 + if (null == root){ + return result; + } + // 前序遍历辅助函数 + preOrderInternal(root, result); + return result; + } + + /** + * @param root 要进行前序遍历的节点 + * @param result 遍历后的节点结果值集合 + * @return + */ + private static void preOrderInternal(Node root, List result) { + // 递归终止条件 + if (root == null){ + return; + } + // 当前层处理:1. 将当前结果加入result, 2. 如果子节点为空则返回,不为空遍历当前节点的子节点 + result.add(root.val); + List childrens = root.children; + if (null == childrens){ + return; + } + // 子节点不为空,继续遍历子节点 + for (Node child : childrens) { + preOrderInternal(child, result); + } + } + + /** + * 解题思路: 使用栈的迭代方式 + * 时间复杂度: O(n) + * 空间复杂度: O(n) + * 执行用时: 7 ms, 在所有 Java 提交中击败了5.62%的用户 + * 内存消耗: 41.5 MB, 在所有 Java 提交中击败了5.02%的用户 + * + * @Author: loe881@163.com + * @Date: 2020/3/3 + */ + public static List preorderV2(Node root) { + // 前序遍历结果集 + List result = new ArrayList<>(); + // 边界条件,如果root为null,直接返回空集合 + if (null == root) { + return result; + } + // 记录节点的辅助栈 + Stack nodeRecordQueue = new Stack<>(); + // 首先将root节点压入栈中 + nodeRecordQueue.push(root); + // 栈不为空,说明还有节点需要遍历,继续循环 + while (!nodeRecordQueue.isEmpty()) { + Node tmpNode = nodeRecordQueue.pop(); + result.add(tmpNode.val); + List childrens = tmpNode.children; + if (null != childrens) { + // 使用栈,先进后出,为保证前序根左右的顺序,从右侧开始压入栈 + for (int i = (childrens.size() - 1); i >= 0; i--) { + nodeRecordQueue.add(childrens.get(i)); + } + } + } + return result; + } + + + // Definition for a Node. + static class Node { + public int val; + public List children; + + public Node() { + } + + public Node(int _val) { + val = _val; + } + + public Node(int _val, List _children) { + val = _val; + children = _children; + } + } +} diff --git a/Week_02/G20200343030631/LeetCode_590_631.java b/Week_02/G20200343030631/LeetCode_590_631.java new file mode 100644 index 00000000..c914926e --- /dev/null +++ b/Week_02/G20200343030631/LeetCode_590_631.java @@ -0,0 +1,217 @@ +package com.dsx.fivehundred.ninety.zero; + +import java.util.ArrayList; +import java.util.List; + +/** + * 解题思路: 递归方式 + * 时间复杂度: O(n) + * 空间复杂度: O(1) + * 执行用时: 1 ms, 在所有 Java 提交中击败了99.73%的用户 + * 内存消耗: 41.2 MB, 在所有 Java 提交中击败了5.01%的用户 + * + * @Author: loe881@163.com + * @Date: 2020/2/23 + */ +public class Version1 { + public static void main(String[] args) { + + } + + public List postorder(Node root) { + List result = new ArrayList<>(); + if (null == root){ + return result; + } + postOrderInternal(root, result); + return result; + } + + private void postOrderInternal(Node root, List result) { + if (null == root){ + return; + } + List children = root.children; + for (Node child : children) { + postOrderInternal(child, result); + } + result.add(root.val); + } + + // Definition for a Node. + static class Node { + public int val; + public List children; + + public Node() { + } + + public Node(int _val) { + val = _val; + } + + public Node(int _val, List _children) { + val = _val; + children = _children; + } + } +} + + +package com.dsx.fivehundred.ninety.zero; + + import java.util.*; +/** + * 解题思路: 迭代方式 + * 时间复杂度: O(nk) n是节点总数,k是节点的最大子节点数目 + * 空间复杂度: O(n) + * 执行用时: 10 ms, 在所有 Java 提交中击败了5.85%的用户 + * 内存消耗: 41.5 MB, 在所有 Java 提交中击败了5.01%的用户 + * + * @Author: loe881@163.com + * @Date: 2020/2/23 + */ +public class Version2 { + public static void main(String[] args) { + Node root = new Node(1); + Node node3 = new Node(3); + Node node2 = new Node(2); + Node node4 = new Node(4); + List subTree1 = new LinkedList<>(); + subTree1.add(node3); + subTree1.add(node2); + subTree1.add(node4); + Node node5 = new Node(5); + Node node6 = new Node(6); + List subTree2 = new LinkedList<>(); + subTree2.add(node5); + subTree2.add(node6); + node3.children = subTree2; + root.children = subTree1; + List result = postorder(root); + for (Integer integer : result) { + System.out.println(integer); + } + } + + public static List postorder(Node root) { + List result = new ArrayList<>(); + if (null == root) { + return result; + } + Stack nodeTraverStack = new Stack<>(); + Map nodeRecord = new HashMap<>(); + nodeTraverStack.add(root); + while (!nodeTraverStack.isEmpty()) { + Node tmpNode = nodeTraverStack.peek(); + if (!nodeRecord.keySet().contains(tmpNode) && null != tmpNode.children) { + nodeRecord.put(tmpNode, 1); + List children = tmpNode.children; + for (int i = (children.size() - 1); i >= 0; i--) { + nodeTraverStack.add(children.get(i)); + } + } else { + result.add(tmpNode.val); + nodeTraverStack.pop(); + } + + } + return result; + } + + // Definition for a Node. + static class Node { + public int val; + public List children; + + public Node() { + } + + public Node(int _val) { + val = _val; + } + + public Node(int _val, List _children) { + val = _val; + children = _children; + } + } +} + + +package com.dsx.fivehundred.ninety.zero; + + import java.util.*; + +/** + * 解题思路: 迭代方式,参考官方解答简约版本,使用的是双端队列 + * 时间复杂度: O(n) + * 空间复杂度: O(n) + * 执行用时: 10 ms, 在所有 Java 提交中击败了5.85%的用户 + * 内存消耗: 41.5 MB, 在所有 Java 提交中击败了5.01%的用户 + * + * @Author: loe881@163.com + * @Date: 2020/2/23 + */ +public class Version3 { + public static void main(String[] args) { + Node root = new Node(1); + Node node3 = new Node(3); + Node node2 = new Node(2); + Node node4 = new Node(4); + List subTree1 = new LinkedList<>(); + subTree1.add(node3); + subTree1.add(node2); + subTree1.add(node4); + Node node5 = new Node(5); + Node node6 = new Node(6); + List subTree2 = new LinkedList<>(); + subTree2.add(node5); + subTree2.add(node6); + node3.children = subTree2; + root.children = subTree1; + List result = postorder(root); + for (Integer integer : result) { + System.out.println(integer); + } + } + + public static List postorder(Node root) { + LinkedList result = new LinkedList<>(); + if (null == root) { + return result; + } + LinkedList stack = new LinkedList<>(); + stack.add(root); + while (!stack.isEmpty()){ + Node tmpNode = stack.pollLast(); + result.addFirst(tmpNode.val); + if (null != tmpNode.children){ + for (Node child : tmpNode.children) { + if (null != child){ + stack.add(child); + } + } + } + } + return result; + } + + // Definition for a Node. + static class Node { + public int val; + public List children; + + public Node() { + } + + public Node(int _val) { + val = _val; + } + + public Node(int _val, List _children) { + val = _val; + children = _children; + } + } +} \ No newline at end of file diff --git a/Week_02/G20200343030631/LeetCode_77_631.java b/Week_02/G20200343030631/LeetCode_77_631.java new file mode 100644 index 00000000..277b4ceb --- /dev/null +++ b/Week_02/G20200343030631/LeetCode_77_631.java @@ -0,0 +1,40 @@ +package com.dsx.seventy.seven; + +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; + +/** + * 解题思路: 基于数学组合思路,一个个数字回溯穷举 + * 时间复杂度: + * 空间复杂度: + * 执行用时: 33 ms, 在所有 Java 提交中击败了32.33%的用户 + * 内存消耗: 44.4 MB, 在所有 Java 提交中击败了5.02%的用户 + * @Author: loe881@163.com + * @Date: 2020/2/23 + */ +public class Version1 { + public static void main(String[] args) { + List> result = combine(4, 2); + for (List integers : result) { + System.out.println(Arrays.toString(integers.toArray())); + } + } + + public static List> combine(int n, int k) { + List> result = new LinkedList(); + combineInternal(1, result, n, k, new LinkedList()); + return result; + } + + private static void combineInternal(int first, List> result, int n, int k, LinkedList current) { + if (current.size() == k){ + result.add(new LinkedList<>(current)); + } + for (int i = first; i <= n; i++) { + current.add(i); + combineInternal(i + 1, result, n, k, current); + current.removeLast(); + } + } +} diff --git a/Week_02/G20200343030631/LeetCode_94_631.java b/Week_02/G20200343030631/LeetCode_94_631.java new file mode 100644 index 00000000..888cda5e --- /dev/null +++ b/Week_02/G20200343030631/LeetCode_94_631.java @@ -0,0 +1,97 @@ +package com.dsx.ninety.four; + +import java.util.ArrayList; +import java.util.List; + +/** + * 解题思路: 使用递归方式,中序遍历,中止条件为节点为null + * 时间复杂度: O(n) + * 空间复杂度: 最坏情况下需要空间O(n),平均情况为O(logn) + * 执行用时: 0 ms, 在所有 Java 提交中击败了100.00%的用户 + * 内存消耗: 37.8 MB, 在所有 Java 提交中击败了5.10%的用户 + * @Author: loe881@163.com + * @Date: 2020/2/21 + */ +public class Version1 { + public static void main(String[] args) { + + } + + public List inorderTraversal(TreeNode root) { + List result = new ArrayList<>(); + traversalHelper(root, result); + return result; + } + + private void traversalHelper(TreeNode node, List result){ + if (null == node){ + return; + } + if (null != node.left){ + traversalHelper(node.left, result); + } + result.add(node.val); + if (null != node.right){ + traversalHelper(node.right, result); + } + } + + /** + * Definition for a binary tree node. + */ + public class TreeNode { + int val; + TreeNode left; + TreeNode right; + TreeNode(int x) { val = x; } + } + +} + + +package com.dsx.ninety.four; + +import java.util.ArrayList; +import java.util.List; +import java.util.Queue; +import java.util.Stack; + +/** + * 解题思路: 使用栈遍历,非最左节点即进栈,找到后出栈,接着出栈父节点,然后遍历父节点的右子节点 + * 时间复杂度: O(n) + * 空间复杂度: O(n) + * 执行用时: 1 ms, 在所有 Java 提交中击败了67.61%的用户 + * 内存消耗: 38.3 MB, 在所有 Java 提交中击败了5.10%的用户 + * @Author: loe881@163.com + * @Date: 2020/2/21 + */ +public class Version2 { + public static void main(String[] args) { + + } + public List inorderTraversal(TreeNode root) { + List result = new ArrayList<>(); + Stack traversalStack = new Stack<>(); + TreeNode current = root; + while (current != null || !traversalStack.isEmpty()){ + while (current != null){ + traversalStack.push(current); + current = current.left; + } + current = traversalStack.pop(); + result.add(current.val); + current = current.right; + } + return result; + } + + /** + * Definition for a binary tree node. + */ + public class TreeNode { + int val; + TreeNode left; + TreeNode right; + TreeNode(int x) { val = x; } + } +} diff --git a/Week_02/G20200343030631/NOTE.md b/Week_02/G20200343030631/NOTE.md index 50de3041..99273f5c 100644 --- a/Week_02/G20200343030631/NOTE.md +++ b/Week_02/G20200343030631/NOTE.md @@ -1 +1,43 @@ -学习笔记 \ No newline at end of file +# 学习笔记 +## 第五课 哈希表、映射、集合 + - 哈希表 + - 基本概念 + - 也叫散列表 + - 根据关键码值而直接进行访问的数据结构 + - 把关键码值通过映射函数直接存放在某一个位置 + - 映射函数叫做散列函数 + - 存放记录的数组叫做哈希表 + - 实现原理 + - 哈希冲突解决方式 + - 拉链法 + - 开放地址法 + - rehash + - 工程实践 + - LRC Cache + - Redis键值对存储 + - Java实现 + - Map:key不重复 + - Set:不重复元素集合 + +## 第六课 树、二叉树、二叉搜索树的实现和特性 +- 树 + - 出现的原因:多维表示的需求 + - 树与图的区别就是是否有环 + - 二叉树 + - 二叉搜索树 + - 二叉排序树、有序二叉树 + - 一颗空树或者具有下列性质的二叉树 + - 左子树所有结点的值均小于根结点的值 + - 右子树所有结点的值均大于根结点的值 + - 以此类推:左、右子树也分别为二叉查找树 + +## 第七课 泛型递归、树的递归 +- 递归代码模板 + 1. 递归中止条件 + 2. 当前层处理逻辑 + 3. 进入下一层 + 4. 清理当前层(可选) +- 递归思维要点 + 1. 不要人肉递归 + 2. 找到最近最简方法,将其拆解成可重复解决的问题 + 3. 数学归纳法 \ No newline at end of file diff --git a/Week_02/G20200343030633/leetcode_144.py b/Week_02/G20200343030633/leetcode_144.py new file mode 100644 index 00000000..1a8c2833 --- /dev/null +++ b/Week_02/G20200343030633/leetcode_144.py @@ -0,0 +1,118 @@ +# 迭代:通过更新变量的值层层推进到所要的答案 + +class TreeNode(object): + def __init__(self, x): + self.val = x + self.left = None + self.right = None + +#前序 +def preorderTraversal(root: TreeNode): + if not root: + return [] + res = [] + stack = [root] + while stack: + node = stack.pop() # python列表,移出最后一个元素,所以符合栈的特性 + res.append(node.val) + if node.right: + stack.append(node.right) + if node.left: + stack.append(node.left) + return res +#中序 +def inorderTraversal(root: TreeNode): + if not root: + return [] + res = [] + stack = [] + cur = root + while cur or stack: + while cur: + stack.append(cur) + cur = cur.left + cur = stack.pop() + res.append(cur.val) + cur = cur.right + return res + +#后续 +def postorderTraversal(root: TreeNode): + if not root: + return [] + res = [] + stack = [root] + while stack: + node = stack.pop() # python列表,移出最后一个元素,所以符合栈的特性 + if node.left: + stack.append(node.left) + if node.right: + stack.append(node.right) + res.append(node.val) + return res[::-1] + +def levelOrder( root): + if not root: + return [] + + res, cur_level = [], [root] + while cur_level: + temp = [] + next_level = [] + for i in cur_level: + temp.append(i.val) + + if i.left: + next_level.append(i.left) + if i.right: + next_level.append(i.right) + res.append(temp) + cur_level = next_level + return res + +# 从数组构建树--这里是按层级 +def buildtree(nodes, treevals): + print(treevals) + if len(treevals) == 0: + return + temp = [] + for node in nodes: + + if len(treevals) == 1: + node.left = TreeNode(treevals[0]) + temp.append(node.left) + treevals = [] + print(node.val, ":", node.left.val) + break + if len(treevals) == 2: + node.left = TreeNode(treevals[0]) + temp.append(node.left) + node.right = TreeNode(treevals[1]) + temp.append(node.right) + treevals = [] + print(node.val, ":", node.left.val, node.right.val) + break + if len(treevals) > 2: + node.left = TreeNode(treevals[0]) + temp.append(node.left) + node.right = TreeNode(treevals[1]) + temp.append(node.right) + treevals = treevals[2:] + print(node.val, ":", node.left.val, node.right.val) + + buildtree(temp, treevals) + +l = [3, 5, 1, 6, 2, 0, 8, None, None, 7, 4] + +if len(l): + r = TreeNode(l[0]) + buildtree([r], l[1:]) + print("前序:", preorderTraversal(r)) + print("中序:", inorderTraversal(r)) + print("后序:", postorderTraversal(r)) + print("广度优先:", levelOrder(r)) + +# 前序: [3, 5, 6, None, None, 2, 7, 4, 1, 0, 8] +# 中序: [None, 6, None, 5, 7, 2, 4, 3, 0, 1, 8] +# 后序: [None, None, 6, 7, 4, 2, 5, 0, 8, 1, 3] +# 广度优先: [[3], [5, 1], [6, 2, 0, 8], [None, None, 7, 4]] \ No newline at end of file diff --git a/Week_02/G20200343030633/leetcode_236.py b/Week_02/G20200343030633/leetcode_236.py new file mode 100644 index 00000000..78a1116c --- /dev/null +++ b/Week_02/G20200343030633/leetcode_236.py @@ -0,0 +1,105 @@ +# 递归出两个指定数的到根节点的路径;然后在两个路径中寻找交叉点;最靠后的那个交叉点既是 + +class TreeNode(object): + def __init__(self, x): + self.val = x + self.left = None + self.right = None + + +def buildlist(root: TreeNode, v: int): + result = [] + if v == root.val: # 如果当前节点是指定节点则终结,同时将其本身加入路径中 + result.append(root.val) + else: + if root.left: + l1 = buildlist(root.left, v) # 下探 + if v in l1: # 如果列表中存在指定数值则将此节点加入、否则忽略 + result.append(root.val) + result += l1 + if root.right: + l2 = buildlist(root.right, v) + if v in l2: + result.append(root.val) + result += l2 + return result + + +def isinlist(v, l): + for i in l: + if v == i: + return True + return False + + +def lowestCommonAncestor(root, p, q): + listp = buildlist(root, p) + listq = buildlist(root, q) + print(p, ":", listp) + print(q, ":", listq) + result = [] + for x in listp: + for y in listq: + if x == y: + result.append(x) + if len(result) > 0: + return result[len(result) - 1] + return root.val + + +# 从数组构建树--这里是按层级 +def buildtree(nodes, treevals): + print(treevals) + if len(treevals) == 0: + return + temp = [] + for node in nodes: + + if len(treevals) == 1: + node.left = TreeNode(treevals[0]) + temp.append(node.left) + treevals = [] + print(node.val, ":", node.left.val) + break + if len(treevals) == 2: + node.left = TreeNode(treevals[0]) + temp.append(node.left) + node.right = TreeNode(treevals[1]) + temp.append(node.right) + treevals = [] + print(node.val, ":", node.left.val, node.right.val) + break + if len(treevals) > 2: + node.left = TreeNode(treevals[0]) + temp.append(node.left) + node.right = TreeNode(treevals[1]) + temp.append(node.right) + treevals = treevals[2:] + print(node.val, ":", node.left.val, node.right.val) + + buildtree(temp, treevals) + + +# 按层级打印 +def levelprint(nodes: list): + if len(nodes) == 0: + return + temp = [] + for node in nodes: + print(node.val) + if node.left: + temp.append(node.left) + if node.right: + temp.append(node.right) + levelprint(temp) + + +l = [3, 5, 1, 6, 2, 0, 8, None, None, 7, 4] + +if len(l): + r = TreeNode(l[0]) + buildtree([r], l[1:]) + print("################################") + levelprint([r]) + + print("答案是:", lowestCommonAncestor(r, 5, 4)) diff --git a/Week_02/G20200343030633/leetcode_242.py b/Week_02/G20200343030633/leetcode_242.py new file mode 100644 index 00000000..e74827d2 --- /dev/null +++ b/Week_02/G20200343030633/leetcode_242.py @@ -0,0 +1,25 @@ +def isAnagram(s: str, t: str) -> bool: + if len(s) != len(t): + return False + l = {} + for i in range(len(s)): + j1 = ord(s[i]) - ord('a') + j2 = ord(t[i]) - ord('a') + l[j1] = l.get(j1, 0) + 1 + l[j2] = l.get(j2, 0) - 1 + print(l) + for val in l.values(): + if val != 0: + return False + return True + + +# return abs(sum([ord(x)**0.5 for x in s])-sum([ord(y)**0.5 for y in t]))<1e-5 +s = "axncxlhjle" + +t = "xxconlaelh" + +print(isAnagram(s, t)) + + + diff --git a/Week_02/G20200343030633/leetcode_49.py b/Week_02/G20200343030633/leetcode_49.py new file mode 100644 index 00000000..3401b6fd --- /dev/null +++ b/Week_02/G20200343030633/leetcode_49.py @@ -0,0 +1,17 @@ +# 遍历,压入map,以异位词的字母元组座位key,关键就在这个key,只要找到一种办法让每组异位词的key对应到一个key即可 +def groupAnagrams(strs): + result = {} + for s in strs: + key = tuple(sorted(s)) + if key in result: + result.get(key).append(s) + else: + result[key] = [s] + + return result.values() + +strs = ["eat", "tea", "tan", "ate", "nat", "bat"] + +result = groupAnagrams(strs) + +print(result) \ No newline at end of file diff --git a/Week_02/G20200343030635/id_635/589.py b/Week_02/G20200343030635/id_635/589.py new file mode 100644 index 00000000..09ba4965 --- /dev/null +++ b/Week_02/G20200343030635/id_635/589.py @@ -0,0 +1,26 @@ +""" +# Definition for a Node. +class Node: + def __init__(self, val=None, children=None): + self.val = val + self.children = children +""" + +class Solution(object): + def preorder(self, root): + """ + :type root: Node + :rtype: List[int] + """ + if root is None: + return [] + + stack, output = [root, ], [] + while stack: + root = stack.pop() + output.append(root.val) + stack.extend(root.children[::-1]) + + return output + + diff --git a/Week_02/G20200343030635/id_635/590.py b/Week_02/G20200343030635/id_635/590.py new file mode 100644 index 00000000..b5208328 --- /dev/null +++ b/Week_02/G20200343030635/id_635/590.py @@ -0,0 +1,22 @@ +""" +# Definition for a Node. +class Node: + def __init__(self, val=None, children=None): + self.val = val + self.children = children +""" +class Solution: + def postorder(self, root: 'Node') -> List[int]: + if root is None: + return [] + out = [] + stack = [root] #空栈初始化一个root + while stack: + #根 右 左 + temp = stack.pop() #弹出来一个进行先入out 再判断是否有子节点 + out.append(temp.val) + if temp.children: #有子节点按照 从左到右的 方向压入栈 + for item in temp.children: + stack.append(item) + return out[::-1] + diff --git a/Week_02/G20200343030639/LeetCode_049_639.java b/Week_02/G20200343030639/LeetCode_049_639.java new file mode 100644 index 00000000..c83f3250 --- /dev/null +++ b/Week_02/G20200343030639/LeetCode_049_639.java @@ -0,0 +1,30 @@ +class LeetCode_049_639 { + public List> groupAnagrams(String[] strs) { + //判断参数是否为空 + if (strs.length == 0) return new ArrayList(); + Map map = new HashMap(); + //循环字符串数组 + for (String s : strs) { + //将字符串转化为字符数组 + char[] ca = s.toCharArray(); + //将字符数组排序 + Arrays.sort(ca); + //将排序后的结果作为Key + String key = String.valueOf(ca); + //如果map中不包含这个Key + if (!map.containsKey(key)){ + //则map插入一条包含Key的记录 + map.put(key, new ArrayList()); + } + //如果map中包含该Key,则将字符串作为该的value + map.get(key).add(s); + } + return new ArrayList(map.values()); + } + + + public static void main(String[] args) { + String[] strs = {"eat", "tea", "tan", "ate", "nat", "bat"}; + System.out.println(groupAnagrams(strs)); + } +} \ No newline at end of file diff --git a/Week_02/G20200343030639/LeetCode_589_639.java b/Week_02/G20200343030639/LeetCode_589_639.java new file mode 100644 index 00000000..2b30db61 --- /dev/null +++ b/Week_02/G20200343030639/LeetCode_589_639.java @@ -0,0 +1,19 @@ +/* + 类似于中序遍历,根据根-左-右的顺序递归 +*/ +class LeetCode_589_639 { + public List preorder(Node root) { + List res=new ArrayList(); + public List preorder(Node root) { + helper(root); + return res; + } + public void helper(Node root){ + if (root==null) return; + res.add(root.val); + for (int i = 0; i arr[mid + 1]) { + return mid + } else { + left = mid + } + } +} \ No newline at end of file diff --git a/Week_03/G20190282010007/leetcode_122.007.js b/Week_03/G20190282010007/leetcode_122.007.js new file mode 100644 index 00000000..c73c1ffe --- /dev/null +++ b/Week_03/G20190282010007/leetcode_122.007.js @@ -0,0 +1,31 @@ +// 题目: 买卖股票的最佳时机II +/** + * 题目描述: + *给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。 + +设计一个算法来计算你所能获取的最大利润。 +你可以尽可能地完成更多的交易(多次买卖一支股票)。 + +注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。 + + + */ + + // 解题语言: javaScript + + // 解题 + +/** + * @param {number[]} prices + * @return {number} + */ +var maxProfit = function(prices) { + // 这好像就是个暴力解法 --- 只要明天比今天价格高,就进行买卖 + let res = 0 + for (let i = 0; i < prices.length; i++) { + if (prices[i+1] > prices[i]) { + res += prices[i + 1] - prices[i] + } + } + return res +}; \ No newline at end of file diff --git a/Week_03/G20190282010007/leetcode_455_007.js b/Week_03/G20190282010007/leetcode_455_007.js new file mode 100644 index 00000000..cc71c5c5 --- /dev/null +++ b/Week_03/G20190282010007/leetcode_455_007.js @@ -0,0 +1,45 @@ +// 题目: 分发饼干 +/** + * 题目描述: + * 假设你是一位很棒的家长,想要给你的孩子们一些小饼干。 + * 但是,每个孩子最多只能给一块饼干。对每个孩子 i , + * 都有一个胃口值 gi , + * 这是能让孩子们满足胃口的饼干的最小尺寸;并且每块饼干 j ,都有一个尺寸 sj 。 + * 如果 sj >= gi ,我们可以将这个饼干 j 分配给孩子 i , + * 这个孩子会得到满足。你的目标是尽可能满足越多数量的孩子,并输出这个最大数值。 + +注意: + +你可以假设胃口值为正。 +一个小朋友最多只能拥有一块饼干。 + + */ + + // 解题语言: javaScript + + // 解题 + +/** + * @param {number[]} g + * @param {number[]} s + * @return {number} + */ +var findContentChildren = function(g, s) { + // 先将孩子的胃口值与饼干的尺寸值按从大到小排序 + g.sort((a, b) => {return b - a}) + s.sort((a, b) => {return b - a}) + // 声明 胃口值下标,尺寸值小标、结果 + let [gi, sj, res] = [0,0,0] + + // 将两个数组元素在自身长度内进行比较 + while (gi < g.length && sj < s.length) { + if (s[sj] >= g[gi]) { // 如果尺寸值满足胃口值,则完成一个分配 + gi++ // 下一个孩子 + sj++ // 下一个饼干 + res++ // 分配完成数 + } else { + gi++ // 不匹配,则将当前尺寸值去匹配下一个孩子 + } + } + return res +}; \ No newline at end of file diff --git a/Week_03/G20190282010007/leetcode_860_007.js b/Week_03/G20190282010007/leetcode_860_007.js new file mode 100644 index 00000000..155bc678 --- /dev/null +++ b/Week_03/G20190282010007/leetcode_860_007.js @@ -0,0 +1,56 @@ +// 题目: 买卖股票的最佳时机II +/** + * 题目描述: + *在柠檬水摊上,每一杯柠檬水的售价为 5 美元。 + +顾客排队购买你的产品,(按账单 bills 支付的顺序)一次购买一杯。 + +每位顾客只买一杯柠檬水,然后向你付 5 美元、10 美元或 20 美元。你必须给每个顾客正确找零,也就是说净交易是每位顾客向你支付 5 美元。 + +注意,一开始你手头没有任何零钱。 + +如果你能给每位顾客正确找零,返回 true ,否则返回 false 。 + + */ + + // 解题语言: javaScript + + // 解题 +/** + * @param {number[]} bills + * @return {boolean} + */ +var lemonadeChange = function(bills) { + // 没人来买汽水,或者第一个就给大钱的,直接做不了生意了 + if (bills.length == 0 || bills[0] > 5) { + return false + } + // 统计 收到的5块钱和10块钱的数量 + let [five, ten] = [0, 0]; + // 循环判断 + for (let i = 0; i< bills.length; i++) { + // 收到5块钱的直接入账 + if (bills[i] == 5) { + five++ + } else if (bills[i] == 10) { // 收到十块钱时,需要找5块 + if (five <= 0) { + return false // 没钱找,gg + } else { + // 收10块找5块 + five-- + ten++ + } + + } else if (bills[i] == 20) { + if (ten > 0 && five > 0) { // 优先使用10块钱的找零 + ten-- + five-- + } else if (five >=3) { // 10块钱不够就看5块钱够不够 + five-=3 + } else { + return false // 都不够,gg + } + } + } + return true +}; \ No newline at end of file diff --git a/Week_03/G20190379010083/LeetCode_033_083.swift b/Week_03/G20190379010083/LeetCode_033_083.swift new file mode 100644 index 00000000..894f0988 --- /dev/null +++ b/Week_03/G20190379010083/LeetCode_033_083.swift @@ -0,0 +1,39 @@ +// +// 0033_SearchInRotatedSortedArray.swift +// AlgorithmPractice +// +// https://leetcode-cn.com/problems/search-in-rotated-sorted-array/ +// Created by Ryeagler on 2020/3/1. +// Copyright © 2020 Ryeagle. All rights reserved. +// + +import Foundation + +class SearchInRotatedSortedArray { + func search(_ nums: [Int], _ target: Int) -> Int { + var left = 0, right = nums.count - 1 + while left <= right { + let mid = (left + right) / 2 + if nums[mid] == target { + return mid + } + + // 1. 先找出有序区域 + // 2. 再确定target所在区域 + if nums[left] <= nums[mid] { + if nums[left] <= target && target < nums[mid] { + right = mid - 1 + } else { + left = mid + 1 + } + } else { + if nums[mid] < target && target <= nums[right] { + left = mid + 1 + } else { + right = mid - 1 + } + } + } + return -1 + } +} diff --git a/Week_03/G20190379010083/LeetCode_154_083.swift b/Week_03/G20190379010083/LeetCode_154_083.swift new file mode 100644 index 00000000..413260e7 --- /dev/null +++ b/Week_03/G20190379010083/LeetCode_154_083.swift @@ -0,0 +1,27 @@ +// +// 0154_FindMinimumInRotatedSortedArrayII.swift +// AlgorithmPractice +// +// https://leetcode-cn.com/problems/find-minimum-in-rotated-sorted-array-ii/ +// Created by Ryeagler on 2020/3/1. +// Copyright © 2020 Ryeagle. All rights reserved. +// + +import Foundation + +class FindMinimumInRotatedSortedArrayII { + func findMin(_ nums: [Int]) -> Int { + var left = 0, right = nums.count - 1 + while left < right { + let mid = (left + right) / 2 + if nums[mid] > nums[right] { + left = mid + 1 + } else if nums[mid] < nums[right] { + right = mid - 1 + } else { + right -= 1 + } + } + return -1 + } +} diff --git a/Week_03/G20200343030001/Leetcode_055_001.java b/Week_03/G20200343030001/Leetcode_055_001.java new file mode 100644 index 00000000..083b7c02 --- /dev/null +++ b/Week_03/G20200343030001/Leetcode_055_001.java @@ -0,0 +1,15 @@ +package Week_03; + +public class Leetcode_055_001 { + public boolean canJump(int[] nums) { + int lastPos = nums.length - 1; + + for (int i = nums.length - 1; i >= 0; i--) { + if (i + nums[i] >= lastPos) { + lastPos = i; + } + } + + return lastPos == 0; + } +} diff --git a/Week_03/G20200343030001/Leetcode_122_001.java b/Week_03/G20200343030001/Leetcode_122_001.java new file mode 100644 index 00000000..91b73ef1 --- /dev/null +++ b/Week_03/G20200343030001/Leetcode_122_001.java @@ -0,0 +1,15 @@ +package Week_03; + +public class Leetcode_122_001 { + public int maxProfit(int[] prices) { + int profit = 0; + + for (int i = 1; i < prices.length; i++){ + if ( prices[i] > prices[i-1] ) { + profit += prices[i] - prices[i-1]; + } + } + + return profit; + } +} diff --git a/Week_03/G20200343030001/Leetcode_455_001.java b/Week_03/G20200343030001/Leetcode_455_001.java new file mode 100644 index 00000000..8a6ccb58 --- /dev/null +++ b/Week_03/G20200343030001/Leetcode_455_001.java @@ -0,0 +1,26 @@ +package Week_03; + +import java.util.Arrays; + +public class Leetcode_455_001 { + public int findContentChildren(int[] g, int[] s) { + if(g == null || s == null) { + return 0; + }; + + Arrays.sort(g); + Arrays.sort(s); + + int gi = 0, si = 0; + + while(gi < g.length && si < s.length) { + if(g[gi] <= s[si]) { + gi++; + } + + si++; + } + + return gi; + } +} diff --git a/Week_03/G20200343030001/Leetcode_860_001.java b/Week_03/G20200343030001/Leetcode_860_001.java new file mode 100644 index 00000000..d8be9ab3 --- /dev/null +++ b/Week_03/G20200343030001/Leetcode_860_001.java @@ -0,0 +1,33 @@ +package Week_03; + + +public class Leetcode_860_001 { + public boolean lemonadeChange(int[] bills) { + int five = 0, ten = 0; + + for (int bill: bills) { + if (bill == 5) { + five++; + } + else if (bill == 10) { + if (five == 0) { + return false; + } + + five--; + ten++; + } else { + if (five > 0 && ten > 0) { + five--; + ten--; + } else if (five >= 3) { + five -= 3; + } else { + return false; + } + } + } + + return true; + } +} diff --git a/Week_03/G20200343030001/Leetcode_874_001.java b/Week_03/G20200343030001/Leetcode_874_001.java new file mode 100644 index 00000000..daaca31b --- /dev/null +++ b/Week_03/G20200343030001/Leetcode_874_001.java @@ -0,0 +1,83 @@ +package Week_03; + +import java.util.*; + +public class Leetcode_874_001 { + class Solution { + public int ladderLength(String beginWord, String endWord, List wordList) { + if (!wordList.contains(endWord)) { + return 0; + } + + Set beginSet = new HashSet<>(); + Set endSet = new HashSet<>(); + + beginSet.add(beginWord); + endSet.add(endWord); + + Map> dict = generateMap(wordList); + Set visited = new HashSet<>(); + + visited.add(beginWord); + visited.add(endWord); + + return bfs(beginSet, endSet, dict, visited, 1); + } + + private int bfs(Set beginSet, Set endSet, Map> dict, Set visited, int level) { + Set nextBeginSet = new HashSet<>(); + + for (String str : beginSet) { + int len = str.length(); + + for (int i = 0; i < len; i++) { + String key = str.substring(0, i) + "*" + str.substring(i + 1, len); + Set neighborDict = dict.get(key); + + if (neighborDict == null) { + continue; + } + + for (String neighbor : neighborDict) { + if (endSet.contains(neighbor)) { + return level + 1; + } + + if (!visited.contains(neighbor)) { + visited.add(neighbor); + nextBeginSet.add(neighbor); + } + } + } + } + + if (nextBeginSet.isEmpty()) { + return 0; + } + + if (nextBeginSet.size() > endSet.size()) { + return bfs(endSet, nextBeginSet, dict, visited, level + 1); + } else { + return bfs(nextBeginSet, endSet, dict, visited, level + 1); + } + } + + private Map> generateMap(List wordList) { + Map> map = new HashMap<>(); + + for (String str : wordList) { + for (int i = 0; i < str.length(); i++) { + String key = str.substring(0, i) + "*" + str.substring(i + 1, str.length()); + + if (!map.containsKey(key)) { + map.put(key, new HashSet<>()); + } + + map.get(key).add(str); + } + } + + return map; + } + } +} diff --git a/Week_03/G20200343030005/Leetcode_122_001.js b/Week_03/G20200343030005/Leetcode_122_001.js new file mode 100644 index 00000000..87e223f1 --- /dev/null +++ b/Week_03/G20200343030005/Leetcode_122_001.js @@ -0,0 +1,19 @@ +/** +122. 买卖股票的最佳时机 II +*/ + +/** + * @param {number[]} prices + * @return {number} + */ +var maxProfit = function(prices) { + var res = 0; + var len = prices.length; + for (var i = 0; i < len - 1; i++) { + var diff = prices[i + 1] - prices[i]; + if (diff > 0) { + res += diff; + } + } + return res; +}; \ No newline at end of file diff --git a/Week_03/G20200343030005/Leetcode_127_001.js b/Week_03/G20200343030005/Leetcode_127_001.js new file mode 100644 index 00000000..674c9a6d --- /dev/null +++ b/Week_03/G20200343030005/Leetcode_127_001.js @@ -0,0 +1,28 @@ +/** +127. 单词接龙 +*/ + +const ladderLength = (beginWord, endWord, wordList) => { + let wordSet = new Set(wordList); + if (!wordSet.has(endWord)) return 0; + let queue = [[beginWord, 1]]; + while (queue.length) { + let [word, transNumber] = queue.pop(); + if (word === endWord) return transNumber; + for (let str of wordSet) { + if (charDiff(word, str) === 1) { + queue.unshift([str, transNumber + 1]); + wordSet.delete(str); + } + } + } + return 0; +}; + +const charDiff = (str1, str2) => { + let changes = 0; + for (let i = 0; i < str1.length; i++) { + if (str1[i] != str2[i]) changes += 1; + } + return changes; +}; diff --git a/Week_03/G20200343030005/Leetcode_455_001.js b/Week_03/G20200343030005/Leetcode_455_001.js new file mode 100644 index 00000000..d4f111e5 --- /dev/null +++ b/Week_03/G20200343030005/Leetcode_455_001.js @@ -0,0 +1,14 @@ +/** +455. 分发饼干 +*/ + + +var findContentChildren = (g, s) => { + g.sort((a,b)=>a-b) + s.sort((a,b)=>a-b) + let len = g.length + while (s.length) { + if (s.shift() >= g[0]) g.shift() + } + return len - g.length +}; \ No newline at end of file diff --git a/Week_03/G20200343030005/NOTE.md b/Week_03/G20200343030005/NOTE.md index 50de3041..e29e3744 100644 --- a/Week_03/G20200343030005/NOTE.md +++ b/Week_03/G20200343030005/NOTE.md @@ -1 +1,8 @@ -学习笔记 \ No newline at end of file +学习笔记 + +本周算法点: +1、深度优先/广度优先 二叉树的 +2、贪心算法 +4、二分查找 + +一道题目反应半天才能理解。 \ No newline at end of file diff --git a/Week_03/G20200343030007/Leetcode_007_122.java b/Week_03/G20200343030007/Leetcode_007_122.java new file mode 100644 index 00000000..905237e4 --- /dev/null +++ b/Week_03/G20200343030007/Leetcode_007_122.java @@ -0,0 +1,24 @@ +class Solution { + public int maxProfit(int[] prices) { + return calculate(prices, 0); + } + + public int calculate(int prices[], int s) { + if (s >= prices.length) + return 0; + int max = 0; + for (int start = s; start < prices.length; start++) { + int maxprofit = 0; + for (int i = start + 1; i < prices.length; i++) { + if (prices[start] < prices[i]) { + int profit = calculate(prices, i + 1) + prices[i] - prices[start]; + if (profit > maxprofit) + maxprofit = profit; + } + } + if (maxprofit > max) + max = maxprofit; + } + return max; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030007/Leetcode_007_860.java b/Week_03/G20200343030007/Leetcode_007_860.java new file mode 100644 index 00000000..bd945cd1 --- /dev/null +++ b/Week_03/G20200343030007/Leetcode_007_860.java @@ -0,0 +1,35 @@ +class Solution { + public boolean lemonadeChange(int[] bills) { + int five = 0, ten = 0; + for (int bill : bills) { + // 顾客给了 5 美元 + if (bill == 5) five++; + // 顾客给了 10 美元 + else if (bill == 10) { + // 自己手里没有 5 美元的话,就不能换钱 + if (five == 0) return false; + five--; + ten++; + } else { + // 顾客给了 20 美元 + // 如果手里正好有 5 美元和 10 美元就换给顾客 + if (five > 0 && ten > 0) { + five--; + ten--; + // 如果手里有 3 个以上的 5 美元,正好换给顾客 + } else if (five >= 3) { + five -= 3; + } else { + return false; + } + } + } + + return true; + } +} + +/** +* 这道题就是按照题目正常思路一步一步推导的 +* 模拟真实的场景 +*/ \ No newline at end of file diff --git a/Week_03/G20200343030009/LeetCode_200_009.js b/Week_03/G20200343030009/LeetCode_200_009.js new file mode 100644 index 00000000..a811d897 --- /dev/null +++ b/Week_03/G20200343030009/LeetCode_200_009.js @@ -0,0 +1,58 @@ +/* + 给定一个由 '1'(陆地)和 '0'(水)组成的的二维网格,计算岛屿的数量。一个岛被水包围,并且它是通过水平方向或垂直方向上相邻的陆地连接而成的。你可以假设网格的四个边均被水包围。 + 示例 1: + 输入: + 11110 + 11010 + 11000 + 00000 + 输出: 1 + + 示例 2: + 输入: + 11000 + 11000 + 00100 + 00011 + 输出: 3 +*/ + +/** + * @param {character[][]} grid + * @return {number} + */ + +let row +let column +var numIslands = function(grid) { + if (!grid.length) return 0 + row = grid.length + if (!row) return 0 + let column = grid[0].length + let count = 0 + // 遍历行 + for (let i = 0; i < row; i++) { + // 遍历列 + for (let j = 0; j < column; j++) { + // 当前节点为岛屿 + if (grid[i][j] === '1') { + // 数量加1 + count += 1 + // 启动深度优先搜索,将相邻(前后左右)的岛屿夷为平地(置为海洋) + DFSMasking(i, j, grid) + } + } + } + return count +}; +function DFSMasking (i, j, grid) { + // terminator -- 到达边界或遇到海洋 + if (i < 0 || j < 0 || i >= row || j >= column || grid[i][j] != '1') return + // 当前节点夷为平地(置为海洋-0) + grid[i][j] = '0' + // 前后左右四个方向下探下去 + DFSMasking(i-1, j, grid) + DFSMasking(i+1, j, grid) + DFSMasking(i, j-1, grid) + DFSMasking(i, j+1, grid) +} \ No newline at end of file diff --git a/Week_03/G20200343030009/LeetCode_455_009.js b/Week_03/G20200343030009/LeetCode_455_009.js new file mode 100644 index 00000000..51372bd5 --- /dev/null +++ b/Week_03/G20200343030009/LeetCode_455_009.js @@ -0,0 +1,49 @@ +/* + 455.分发饼干 难度简单 + 假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。对每个孩子 i ,都有一个胃口值 gi ,这是能让孩子们满足胃口的饼干的最小尺寸;并且每块饼干 j ,都有一个尺寸 sj 。如果 sj >= gi ,我们可以将这个饼干 j 分配给孩子 i ,这个孩子会得到满足。你的目标是尽可能满足越多数量的孩子,并输出这个最大数值。 + 注意: + 你可以假设胃口值为正。 + 一个小朋友最多只能拥有一块饼干。 + + 示例 1: + 输入: [1,2,3], [1,1] + 输出: 1 + 解释: + 你有三个孩子和两块小饼干,3个孩子的胃口值分别是:1,2,3。 + 虽然你有两块小饼干,由于他们的尺寸都是1,你只能让胃口值是1的孩子满足。 + 所以你应该输出1。 + + 示例 2: + 输入: [1,2], [1,2,3] + 输出: 2 + 解释: + 你有两个孩子和三块小饼干,2个孩子的胃口值分别是1,2。 + 你拥有的饼干数量和尺寸都足以让所有孩子满足。 + 所以你应该输出2. +*/ +/** + * @param {number[]} g + * @param {number[]} s + * @return {number} + */ +var findContentChildren = function(g, s) { + if (!g.length || !s.length) return 0 + g = sortNum(g) + s = sortNum(s) + let lenG = g.length + let lenS = s.length + let i = 0, j = 0 + while (i < lenG && j < lenS) { + if (g[i] <= s[j]) i++ + j++ + } + return i +}; + +function sortNum (list) { + // 排序-数字递增 + return list.sort(function (a, b) { + // return Number(a) - Number(b) // 影响性能 + return a-b + }) +} \ No newline at end of file diff --git a/Week_03/G20200343030009/LeetCode_55_009.js b/Week_03/G20200343030009/LeetCode_55_009.js new file mode 100644 index 00000000..328d6eda --- /dev/null +++ b/Week_03/G20200343030009/LeetCode_55_009.js @@ -0,0 +1,33 @@ +/* + 55.跳跃游戏 难度:中等 + 给定一个非负整数数组,你最初位于数组的第一个位置。 + 数组中的每个元素代表你在该位置可以跳跃的最大长度。 + 判断你是否能够到达最后一个位置。 + + 示例 1: + 输入: [2,3,1,1,4] + 输出: true + 解释: 我们可以先跳 1 步,从位置 0 到达 位置 1, 然后再从位置 1 跳 3 步到达最后一个位置。 + + 示例 2: + 输入: [3,2,1,0,4] + 输出: false + 解释: 无论怎样,你总会到达索引为 3 的位置。但该位置的最大跳跃长度是 0 , 所以你永远不可能到达最后一个位置。 +*/ +/** + * @param {number[]} nums + * @return {boolean} + */ +var canJump = function(nums) { + if (!nums.length) return false + // 初始化为最后一个元素下标 + let endReachable = nums.length - 1 + for (let i = nums.length-1; i >= 0; i--) { + // 前一个元素能跳的步数+前一个下标 大于 endReachable, 更新endReachable + if (nums[i] + i >= endReachable) { + endReachable = i + } + } + // 判断标记能否到达下标0 + return endReachable === 0 +}; \ No newline at end of file diff --git a/Week_03/G20200343030015/LeetCode_122_015.java b/Week_03/G20200343030015/LeetCode_122_015.java new file mode 100644 index 00000000..b6de5240 --- /dev/null +++ b/Week_03/G20200343030015/LeetCode_122_015.java @@ -0,0 +1,20 @@ +package G20200343030015.week_03; + +/** + * 122. 买卖股票的最佳时机 II + * site:: https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/description/ + * Created by majiancheng on 2020/3/2. + */ +public class LeetCode_122_015 { + + public int maxProfit(int[] prices) { + int res = 0; + for(int i = 1; i < prices.length; i++) { + if(prices[i] > prices[i-1]) { + res += prices[i] - prices[i-1]; + } + } + + return res; + } +} diff --git a/Week_03/G20200343030015/LeetCode_127_015.java b/Week_03/G20200343030015/LeetCode_127_015.java new file mode 100644 index 00000000..a41313ec --- /dev/null +++ b/Week_03/G20200343030015/LeetCode_127_015.java @@ -0,0 +1,58 @@ +package G20200343030015.week_03; + +import javafx.util.Pair; + +import java.util.*; + +/** + * 127. 单词接龙 + * site:: https://leetcode-cn.com/problems/word-ladder/ + * Created by majiancheng on 2020/3/2. + */ +public class LeetCode_127_015 { + //将wordList中的词统一变为 *bc, a*c, ab* + //采用广度搜索 遍历每个值 + public int ladderLength(String beginWord, String endWord, List wordList) { + if(!wordList.contains(endWord)) { + return 0; + } + + int length = beginWord.length(); + Map> wordMap = new HashMap>(); + for (String word : wordList) { + for(int i = 0; i < length; i++) { + String tmpWord = word.substring(0, i) + "*" + word.substring(i + 1, length); + List tmpList = wordMap.getOrDefault(tmpWord, new ArrayList()); + tmpList.add(word); + wordMap.put(tmpWord, tmpList); + } + } + + Queue> queue = new LinkedList>(); + queue.add(new Pair(beginWord, 1)); + Set visited = new HashSet(); + visited.add(beginWord); + + while(!queue.isEmpty()) { + Pair tmpPair = queue.remove(); + String word = (String)tmpPair.getKey(); + int level = (Integer)tmpPair.getValue(); + for(int i = 0; i < length; i++) { + List tmpWordList = wordMap.getOrDefault(word.substring(0, i) + "*" + word.substring(i + 1, length), new ArrayList(0)); + for(String tmpWord : tmpWordList) { + + if(tmpWord.equals(endWord)) { + return level + 1; + } + if(!visited.contains(tmpWord)) { + visited.add(tmpWord); + queue.add(new Pair(tmpWord, level + 1)); + } + } + } + + } + + return 0; + } +} diff --git a/Week_03/G20200343030015/LeetCode_455_015.java b/Week_03/G20200343030015/LeetCode_455_015.java new file mode 100644 index 00000000..eca85988 --- /dev/null +++ b/Week_03/G20200343030015/LeetCode_455_015.java @@ -0,0 +1,30 @@ +package G20200343030015.week_03; + +import java.util.Arrays; + +/** + * 455. 分发饼干 + * site:: https://leetcode-cn.com/problems/assign-cookies/description/ + * Created by majiancheng on 2020/3/2. + */ +public class LeetCode_455_015 { + public int findContentChildren(int[] g, int[] s) { + if(g.length == 0 || s.length == 0) return 0; + Arrays.sort(g); + Arrays.sort(s); + int gi = 0; + int si = 0; + int res = 0; + while(gi < g.length && si < s.length) { + if(s[si] >= g[gi]) { + si ++; + gi ++; + res ++; + } else { + si ++; + } + } + + return res; + } +} diff --git a/Week_03/G20200343030015/LeetCode_860_015.java b/Week_03/G20200343030015/LeetCode_860_015.java new file mode 100644 index 00000000..b4ba6556 --- /dev/null +++ b/Week_03/G20200343030015/LeetCode_860_015.java @@ -0,0 +1,24 @@ +package G20200343030015.week_03; + +/** + * 860. 柠檬水找零 + * site:: https://leetcode-cn.com/problems/lemonade-change/description/ + * Created by majiancheng on 2020/3/2. + */ +public class LeetCode_860_015 { + //注意点,当金额为20时,两种情况是满足的 + //1. 1个10元, 1个5元。 + //2. 3个5元。 + public boolean lemonadeChange(int[] bills) { + int five = 0, ten = 0; + for(int bill : bills) { + if (bill == 5) five ++; + else if(bill == 10) {five --; ten++;} + else if(ten > 0) {ten --; five --;} + else five = five - 3; + if(five < 0) return false; + } + + return true; + } +} diff --git a/Week_03/G20200343030015/LeetCode_874_015.java b/Week_03/G20200343030015/LeetCode_874_015.java new file mode 100644 index 00000000..2cc021e4 --- /dev/null +++ b/Week_03/G20200343030015/LeetCode_874_015.java @@ -0,0 +1,42 @@ +package G20200343030015.week_03; + +import java.util.HashSet; +import java.util.Set; + +/** + * 874. 模拟行走机器人 + * site:: https://leetcode-cn.com/problems/walking-robot-simulation/description/ + * Created by majiancheng on 2020/3/2. + */ +public class LeetCode_874_015 { + public int robotSim(int[] commands, int[][] obstacles) { + int[] dx = new int[]{0, 1, 0, -1}; + int[] dy = new int[]{1, 0, -1, 0}; + int x = 0, y = 0, di = 0, max = 0; + + Set obstacleSet = new HashSet(); + for(int[] obstacle : obstacles) { + obstacleSet.add(String.format("%d-%d", obstacle[0], obstacle[1])); + } + + for(int cmd : commands) { + if(cmd == -2) { + di = (di + 3) % 4; + } else if(cmd == -1) { + di = (di + 1) % 4; + } else { + while(cmd-- > 0) { + int nx = x + dx[di]; + int ny = y + dy[di]; + if(!obstacleSet.contains(String.format("%d-%d", nx, ny))) { + x = nx; + y = ny; + + max = Math.max(max, x*x + y*y); + } + } + } + } + return max; + } +} diff --git a/Week_03/G20200343030015/NOTE.md b/Week_03/G20200343030015/NOTE.md index 50de3041..5161f066 100644 --- a/Week_03/G20200343030015/NOTE.md +++ b/Week_03/G20200343030015/NOTE.md @@ -1 +1,24 @@ -学习笔记 \ No newline at end of file +学习笔记 + +本周时间学习时间有限, 没有太多总结, 后面会不上 +分治代码模板 +def divide_conquer(problem, param1, param2, ...):  + # 处理结束递归方法 + if problem is None:  + print_result  + return  + + # 准备数据 + data = prepare_data(problem)  + subproblems = split_problem(problem, data)  + + # 执行子问题 + subresult1 = self.divide_conquer(subproblems[0], p1, ...)  + subresult2 = self.divide_conquer(subproblems[1], p1, ...)  + subresult3 = self.divide_conquer(subproblems[2], p1, ...)  + … + + # 生成最终结果 + result = process_result(subresult1, subresult2, subresult3, …) + + # 重置当前状态 diff --git a/Week_03/G20200343030017/assign_cookies/Solution.java b/Week_03/G20200343030017/assign_cookies/Solution.java new file mode 100644 index 00000000..01ef7425 --- /dev/null +++ b/Week_03/G20200343030017/assign_cookies/Solution.java @@ -0,0 +1,29 @@ +package week3.assign_cookies; + +import java.util.Arrays; + +public class Solution { + public int findContentChildren(int[] g, int[] s) { + if(g == null || s == null) return 0; + Arrays.sort(g); + Arrays.sort(s); + int n = 0; + for (int a=0;aprices[n+1])){ + continue; + } + if (n=0;k--){ + if (nums[k]+k>n){ + break; + } + if (k==0){ + return false; + } + } + } + } + return true; + } + + public static void main(String[] args) { + int[] nums={2,0,0}; + Solution s = new Solution(); + System.out.println(s.canJump(nums)); + } +} diff --git a/Week_03/G20200343030017/lemonade_change/Solution.java b/Week_03/G20200343030017/lemonade_change/Solution.java new file mode 100644 index 00000000..3ece2be3 --- /dev/null +++ b/Week_03/G20200343030017/lemonade_change/Solution.java @@ -0,0 +1,42 @@ +package week3.lemonade_change; + +public class Solution { + public boolean lemonadeChange(int[] bills) { + if (bills[0]!=5){ + return false; + } + int w5=1; + int w10=0; + for (int n=1;n=1){ + w10++; + w5--; + }else{ + return false; + } + }else{ + if (w5>=1&&w10>=1){ + w5--; + w10--; + continue; + }else if(w5>=3) { + w5=w5-3; + continue; + }else{ + return false; + } + } + } + return true; + } + + + public static void main(String[] args) { + int[] bills={5,5,5,10,20}; + Solution s = new Solution(); + System.out.println(s.lemonadeChange(bills)); + } +} diff --git a/Week_03/G20200343030017/minesweeper/Solution.java b/Week_03/G20200343030017/minesweeper/Solution.java new file mode 100644 index 00000000..85664d7a --- /dev/null +++ b/Week_03/G20200343030017/minesweeper/Solution.java @@ -0,0 +1,80 @@ +package week3.minesweeper; + +import java.util.Arrays; + +public class Solution { + public char[][] updateBoard(char[][] board, int[] click) { + if (board[click[0]][click[1]]=='M'){ + board[click[0]][click[1]] = 'X'; + return board; + } + recursion(board,click[0],click[1]); + return board; + } + public void recursion(char[][] board,int y,int x){ + if (x<0||y<0){ + return; + } + if (x>board[y].length||y>board.length){ + return; + } + if(board[y][x]=='B'||(board[y][x]>='1'&&board[y][x]<='9')){ + return; + }else{ + int bomb = 0; + for (int n=x-1;n<=x+1;n++){ + for (int q=y-1;q<=y+1;q++){ + if (n>=0&&q>=0&&n=0&&board[y][x]=='B'){ + recursion(board,y,x-1); + } + if (x+1=0&&board[y][x]=='B'){ + recursion(board,y-1,x); + } + if (y+1=0&&y-1>=0&&board[y][x]=='B'){ + recursion(board,y-1,x-1); + } + if (x+1=0&&board[y][x]=='B'){ + recursion(board,y-1,x+1); + } + if (x-1>=0&&y+1grid.length-1||x>grid[y].length-1){ + return; + } + if (grid[y][x]=='1'){ + grid[y][x]='0'; + if (level==0){ + islandNum++; + } + if (x==0){ + recursion(grid,y,x+1,++level); + }else{ + recursion(grid,y,x-1,++level); + recursion(grid,y,x+1,++level); + } + if (y==0){ + recursion(grid,y+1,x,++level); + }else{ + recursion(grid,y+1,x,++level); + recursion(grid,y-1,x,++level); + } + }else{ + return; + } + } + + public static void main(String[] args) { + char[][] grid = {{'1','1','0','0','0'},{'1','1','0','0','0'},{'0','0','1','0','0'},{'0','0','0','1','1'}}; + Solution s = new Solution(); + System.out.println(s.numIslands(grid)); + } +} diff --git a/Week_03/G20200343030017/search_a_2d_matrix/Solution.java b/Week_03/G20200343030017/search_a_2d_matrix/Solution.java new file mode 100644 index 00000000..3610741e --- /dev/null +++ b/Week_03/G20200343030017/search_a_2d_matrix/Solution.java @@ -0,0 +1,53 @@ +package week3.search_a_2d_matrix; + +public class Solution { + public boolean searchMatrix(int[][] matrix, int target) { + if (matrix.length==0||matrix[0].length==0){ + return false; + } + int begin = 0; + int end = matrix.length-1; + int mid = 0; + int size = matrix[0].length; + int k = -1; + while(begin<=end){ + mid = (begin+end)/2; + if (k==-1){ + if (matrix[mid][0]==target){ + return true; + } + if (target>matrix[mid][0] && target<=matrix[mid][size-1]){ + begin=0; + end=size-1; + k = mid; + } + if (targetmatrix[mid][0]){ + begin++; + } + }else{ + if (matrix[k][mid]==target){ + return true; + } + if (targetmatrix[k][mid]){ + begin++; + } + } + } + return false; + } + + public static void main(String[] args) { + //int[][] matrix = {{1,3,5,7},{10, 11, 16, 20},{23, 30, 34, 50}}; + //int target = 3; + int[][] matrix ={{1,3}}; + int target = 3; + Solution s = new Solution(); + System.out.println(s.searchMatrix(matrix,target)); + } +} diff --git a/Week_03/G20200343030017/search_in_rotated_sorted_array/Solution.java b/Week_03/G20200343030017/search_in_rotated_sorted_array/Solution.java new file mode 100644 index 00000000..43d19792 --- /dev/null +++ b/Week_03/G20200343030017/search_in_rotated_sorted_array/Solution.java @@ -0,0 +1,40 @@ +package week3.search_in_rotated_sorted_array; + +public class Solution { + public int search(int[] nums, int target) { + int begin = 0; + int end = nums.length-1; + int mid = 0; + while(begin<=end){ + mid = (begin+end)/2; + if (nums[mid]==target){ + return mid; + }else{ + if (nums[begin]<=nums[mid]){ + if (target=nums[begin]){ + end=mid; + --end; + }else{ + begin=mid; + ++begin; + } + }else{ + if (target>nums[mid]&&target<=nums[end]){ + begin=mid; + ++begin; + }else{ + end=mid; + --end; + } + } + } + } + return -1; + } + + public static void main(String[] args) { + int[] nums = {4,5,6,7,0,1,2}; + Solution s = new Solution(); + System.out.println(s.search(nums,0)); + } +} diff --git a/Week_03/G20200343030017/walking_robot_simulation/Solution.java b/Week_03/G20200343030017/walking_robot_simulation/Solution.java new file mode 100644 index 00000000..77d8b0bc --- /dev/null +++ b/Week_03/G20200343030017/walking_robot_simulation/Solution.java @@ -0,0 +1,101 @@ +package week3.walking_robot_simulation; + +import java.util.HashSet; +import java.util.Set; + +public class Solution { + public int robotSim(int[] commands, int[][] obstacles) { + int sum=0; + Set set = new HashSet<>(); + for (int[] temp:obstacles){ + set.add(temp[0]+","+temp[1]); + } + set.remove(0+","+0); + int endx=0; + int endy=0; + char[] direct={'n','e','s','w'}; + int z = 0; + int flag =-520; + for (int n=0;nflag)){ + endy=p+1; + flag = p; + } + } + } + if (flag==-520) { + endy = endy - commands[n]; + } + } + if (direct[z]=='w'){ + for (int p=endx-commands[n];p<=endx;p++){ + if (set.contains(p+","+endy)){ + if ((flag==-520)||(flag != -520 && p>flag)){ + endx=p+1; + flag = p; + } + } + } + if (flag==-520) { + endx = endx - commands[n]; + } + } + flag=-520; + sum=Math.max(sum,endx*endx+endy*endy); + System.out.println(endx+","+endy); + } + } + return sum; + } + + public static void main(String[] args) { + int[] commands = {9,8,4,8,1,6,3,-2,-2,-1,4,6,3,-1,5,3,8,6,2,5,-2,7,8,-2,4,5,2,7,3,4,8,6,5,6,6,-1,-1,-1,6,9,-1,-2,-2,2,3,-1,5,5,-1,-1,1,8,-1,1,-1,1,6,2,-1,6,4,7,3,6,7,-2,9,8,-1,4,-2,6,1,3,5,5,6,-1,6,-2,-1,-1,-2,-2,6,3,-1,-2,7,1,7,3,2,7,4,7,4,8,-1,1}; + int[][] obstacles = {{97,-2},{-65,69},{0,-19},{99,96},{-89,-97},{82,50},{-88,-5},{-83,17},{-85,-6},{15,58},{-89,86},{12,41},{-84,2},{-92,-45},{-96,4},{-14,29},{-94,76},{40,-89},{75,-29},{-96,-83},{-99,-79},{-2,88},{-55,30},{-94,-11},{42,83},{99,-5},{15,92},{-38,-49},{61,-50},{52,97},{97,-31},{-64,-65},{-1,-25},{-46,97},{75,-74},{60,-74},{-15,2},{-88,-61},{-16,-31},{-100,74},{29,-98},{-79,-57},{-47,-94},{-38,-40},{-92,-39},{15,96},{-28,86},{78,94},{-1,19},{-70,54},{54,-40},{-10,43},{-32,9},{13,36},{55,-51},{-93,45},{57,57},{78,13},{74,-7},{-45,-29},{-45,-76},{-2,6},{28,49},{79,8},{-81,-52},{-67,-41},{-7,-43},{-60,29},{8,39},{48,-10},{35,-8},{-84,4},{0,32},{43,91},{37,89},{-60,34},{92,77},{61,-63},{-92,24},{-41,65},{77,-65},{74,99},{0,26},{-31,-57},{40,94},{-78,-10},{-89,-37},{-19,25},{-62,27},{-83,53},{69,-43},{-21,13},{-90,-90},{86,20},{63,43},{81,73},{-9,-100},{62,62},{16,10},{34,-38},{-89,-57},{74,49},{42,-44},{18,97},{-80,-58},{17,61},{42,51},{-57,-64},{-80,36},{-60,57},{25,62},{-42,20},{-100,95},{7,-24},{-98,84},{49,83},{-83,42},{9,97},{39,-7},{-100,9},{-39,-38},{-15,10},{84,-93},{16,85},{-35,82},{-92,14},{86,5},{32,-100},{-23,-35},{-80,-32},{-1,26},{-68,52},{-5,-59},{63,-28},{26,-65},{-42,9},{36,42},{-9,-18},{19,96},{19,-99},{66,94},{18,-53},{49,100},{8,-14},{-1,9},{-81,56},{96,-94},{6,30},{71,39},{71,-73},{41,-9},{-91,93},{99,-59},{-56,-64},{32,-16},{-8,56},{-27,2},{-31,89},{98,49},{0,-86},{86,95},{-52,66},{9,26},{89,-51},{-77,-22},{34,-32},{-22,-41},{40,-72},{-61,62},{22,-62},{72,91},{81,-33},{-25,60},{20,64},{93,100},{73,22},{-39,57},{55,51},{-12,-49},{-84,99},{-59,39},{23,86},{-53,-100},{-12,-31},{-20,65},{-98,-39},{69,59},{-33,-32},{63,26},{-90,27},{33,71},{37,88},{-73,-47},{2,35},{57,-88},{-83,46},{92,76},{-29,10},{-73,51},{4,-22}}; + Solution s = new Solution(); + System.out.println(s.robotSim(commands,obstacles)); + } +} diff --git a/Week_03/G20200343030017/word_ladder/Solution.java b/Week_03/G20200343030017/word_ladder/Solution.java new file mode 100644 index 00000000..1eaf0bbe --- /dev/null +++ b/Week_03/G20200343030017/word_ladder/Solution.java @@ -0,0 +1,71 @@ +package week3.word_ladder; + +import java.util.*; + +public class Solution { + public int ladderLength(String beginWord, String endWord, List wordList) { + if (!wordList.contains(endWord)) { + return 0; + } + int level = 0; + Queue queue = new LinkedList<>(); + //HashSet set = new HashSet<>(); + boolean[] set = new boolean[wordList.size()]; + int idx = wordList.indexOf(beginWord); + if (idx!=-1){ + set[idx] = true; + } + List tempList = new ArrayList<>(); + queue.add(beginWord); + while (!queue.isEmpty()) { + level++; + int size = queue.size(); + for (int g =0;g wordList = Arrays.asList(aaa) ; + Solution s = new Solution(); + System.out.println(s.ladderLength(beginWord,endWord,wordList)); + } +} diff --git "a/Week_03/G20200343030017/\346\257\217\345\221\250\346\200\273\347\273\223.txt" "b/Week_03/G20200343030017/\346\257\217\345\221\250\346\200\273\347\273\223.txt" new file mode 100644 index 00000000..17a57786 --- /dev/null +++ "b/Week_03/G20200343030017/\346\257\217\345\221\250\346\200\273\347\273\223.txt" @@ -0,0 +1,4 @@ +这周没有学习新的数据结构,学了许多搜索遍历的方法 +DFS和BFS是比较重要的,在实际工程中都会有用到,这周对于一些图的解法都用到的DFS和BFS,由于代码量巨大特别难以理解,动不动就会写出超时代码,所以这时候数据结构选择就很重要,比如单词接龙的,一开始我用的是list存放查看过的单词,代码巨乱,我看了下题解,用的set,而且set没有get方法,逼迫我重写搜索算法,调试的时候发现如果量大就会超市,通不过提交。后来看到了数组记录的方法,实验了下可以提交了,虽然慢,不过思路和题解差不多了。 +贪心算法/二分查找就是另一种方法了,代码极端简单,运行速度1ms已经算很慢很慢的了,但是这就要考验分析能力,把问题的条件列举出来,或者把问题转换一下。比如那个找起点是否能到终点的题目,一开始我熟练的写了个递归,一旦节点到了10+个,就跑不动了,发现可以用贪心,不过官方思路实在看不懂,看评论发现,可以转化为找0,然后根据思路写出了代码。二分查找法基本就是考IF的能力,有时候写了一大堆if勉强解决,看看题解,发现很多IF可以放到一起。 +确实是需要一定的天赋以及经验 \ No newline at end of file diff --git a/Week_03/G20200343030019/LeetCode_ 874_019.java b/Week_03/G20200343030019/LeetCode_ 874_019.java new file mode 100644 index 00000000..39f66031 --- /dev/null +++ b/Week_03/G20200343030019/LeetCode_ 874_019.java @@ -0,0 +1,59 @@ +class Solution { + public int robotSim(int[] commands, int[][] obstacles) { + int direction = 0; + Set set = new HashSet(); + for (int index = 0; index < obstacles.length; index ++) { + set.add(((long)obstacles[index][0] << 16) + obstacles[index][1]); + } + int[] position = new int[2]; + int max = 0; + for (int index = 0; index < commands.length; index ++) { + if (commands[index] < 0) { + direction = changeDirection(direction, commands[index]); + continue; + } + int x = run(position, direction, commands[index], set); + max = x > max? x: max; + } + return max; + } + + private int run(int[] position, int direction, int step, Set obstacles) { + for (int index = 1; index <= step; index ++) { + oneStep(position, direction, 1); + if (obstacles.contains(((long)position[1] << 16) + position[0])){ + oneStep(position, direction, -1); + return position[0] * position[0] + position[1] * position[1]; + } + } + return position[0] * position[0] + position[1] * position[1]; + } + + private void oneStep(int[] position, int direction, int step) { + if (direction == 0) { + position[0] += step; + return; + } + if (direction == 1) { + position[1] += step; + return; + } + if (direction == 2) { + position[0] -= step; + return; + } + if (direction == 3) { + position[1] -= step; + return; + } + } + + private int changeDirection(int cur, int action) { + if (action == -1) { + return (cur + 1) % 4; + } else if (action == -2) { + return (cur + 3) % 4; + } + return cur; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030019/LeetCode_122_019.java b/Week_03/G20200343030019/LeetCode_122_019.java new file mode 100644 index 00000000..e625cbed --- /dev/null +++ b/Week_03/G20200343030019/LeetCode_122_019.java @@ -0,0 +1,11 @@ +class Solution { + public int maxProfit(int[] prices) { + int count = o; + for (int index = 0; index < prices.length - 1; index ++) { + if (prices[index] < prices[index + 1]) { + count += prices[index + 1] - prices[index]; + } + } + return count; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030019/LeetCode_153_019.java b/Week_03/G20200343030019/LeetCode_153_019.java new file mode 100644 index 00000000..3d99d8d8 --- /dev/null +++ b/Week_03/G20200343030019/LeetCode_153_019.java @@ -0,0 +1,19 @@ +class Solution { + public int findMin(int[] nums) { + if (nums[0] < nums[nums.length - 1]) { + return nums[0]; + } + int lo = 0; + int hi = nums.length - 1; + int mi = 0; + while (lo < hi) { + mi = lo + (hi - lo) / 2; + if (nums[0] > nums[mi]) { + hi = mi; + } else { + lo = mi + 1; + } + } + return nums[lo]; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030019/LeetCode_200_019.java b/Week_03/G20200343030019/LeetCode_200_019.java new file mode 100644 index 00000000..00a8313f --- /dev/null +++ b/Week_03/G20200343030019/LeetCode_200_019.java @@ -0,0 +1,34 @@ +class Solution { + int n = 0; + int m = 0; + public int numIslands(char[][] grid) { + if (grid == null || grid.length <= 0 || grid[0].length <= 0) { + return 0; + } + int count = 0; + n = grid.length; + m = grid[0].length; + for (int i = 0; i < grid.length; i ++) { + for (int j = 0; j < grid[0].length; j ++) { + if (grid[i][j] == '1') { + dfs(grid, i, j); + count ++; + } + } + } + return count; + } + + private void dfs(char[][] grid, int i, int j) { + if (!(i < n && i >=0 && j < m && j >=0 && grid[i][j] == '1')) { + return; + } + + grid[i][j] = '0'; + + dfs(grid, i + 1, j); + dfs(grid, i - 1, j); + dfs(grid, i, j + 1); + dfs(grid, i, j - 1); + } +} \ No newline at end of file diff --git a/Week_03/G20200343030019/LeetCode_33_019.java b/Week_03/G20200343030019/LeetCode_33_019.java new file mode 100644 index 00000000..fabae029 --- /dev/null +++ b/Week_03/G20200343030019/LeetCode_33_019.java @@ -0,0 +1,21 @@ +class Solution { + public int search(int[] nums, int target) { + if (nums == null || nums.length == 0) { + return -1; + } + int lo = 0; + int hi = nums.length - 1; + int middle = 0; + while (lo < hi) { + middle = lo + (hi - lo) / 2; + if (nums[0] <= target ^ target <= nums[middle] ^ nums[middle] < nums[0]) { + lo = middle + 1; + } else { + hi = middle; + } + } + + return nums[lo] == target? lo: -1; + + } +} \ No newline at end of file diff --git a/Week_03/G20200343030019/LeetCode_455_019.java b/Week_03/G20200343030019/LeetCode_455_019.java new file mode 100644 index 00000000..119ee41e --- /dev/null +++ b/Week_03/G20200343030019/LeetCode_455_019.java @@ -0,0 +1,15 @@ +class Solution { + public int findContentChildren(int[] g, int[] s) { + Arrays.sort(g); + Arrays.sort(s); + int si = s.length - 1; + int gi = g.length - 1; + while (gi >= 0 && si >= 0) { + if (g[gi] <= s[si]) { + si --; + } + gi --; + } + return s.length - 1 - si; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030019/LeetCode_45_019.java b/Week_03/G20200343030019/LeetCode_45_019.java new file mode 100644 index 00000000..85dd71d9 --- /dev/null +++ b/Week_03/G20200343030019/LeetCode_45_019.java @@ -0,0 +1,37 @@ +class Solution { + public int jump(int[] nums) { + if (nums.length < 2){ + return 0; + } + int end = nums.length - 1; + int step = 0; + Node list = new Node(nums.length - 1); + Node node = list; + for (int index = nums.length - 2; index >= 0; index --) { + int i = nums[index] + index; + node = new Node(index); + while (list != null) { + if (i >= list.val) { + node.next = list; + list = list.next; + } else { + break; + } + } + if (node.next != null) { + list = node; + } + } + while (list != null) { + step ++; + list = list.next; + } + return step - 1; + } + + class Node { + int val; + Node next; + public Node(int val) {this.val = val;} + } +} \ No newline at end of file diff --git a/Week_03/G20200343030019/LeetCode_529_019.java b/Week_03/G20200343030019/LeetCode_529_019.java new file mode 100644 index 00000000..26cc9c75 --- /dev/null +++ b/Week_03/G20200343030019/LeetCode_529_019.java @@ -0,0 +1,50 @@ +class Solution { + int maxX = 0; + int maxY = 0; + public char[][] updateBoard(char[][] board, int[] click) { + maxX = board.length - 1; + maxY = board[0].length - 1; + minesweeper(board, click[0], click[1]); + return board; + } + + private void minesweeper(char[][] board, int x, int y) { + if (x < 0 || x > maxX || y < 0 || y > maxY) { + return; + } + if (board[x][y] == 'M') { + board[x][y] = 'X'; + return; + } + if (board[x][y] != 'E') { + return; + } + int count = mineCount(board, x, y); + if (count > 0) { + board[x][y] = (char) ((int) '1' + count -1); + return; + } + board[x][y] = 'B'; + minesweeper(board, x + 1, y); + minesweeper(board, x, y + 1); + minesweeper(board, x - 1, y); + minesweeper(board, x, y - 1); + minesweeper(board, x + 1, y + 1); + minesweeper(board, x - 1, y + 1); + minesweeper(board, x - 1, y - 1); + minesweeper(board, x + 1, y - 1); + } + + private int mineCount(char[][] board, int x, int y) { + int count = 0; + if (x < maxX && board[x + 1][y] == 'M') count ++; + if (y < maxY && board[x][y + 1] == 'M') count ++; + if (x > 0 && board[x - 1][y] == 'M') count ++; + if (y > 0 && board[x][y - 1] == 'M') count ++; + if (x < maxX && y < maxY && board[x + 1][y + 1] == 'M') count ++; + if (x > 0 && y > 0 && board[x - 1][y - 1] == 'M') count ++; + if (x < maxX && y > 0 && board[x + 1][y - 1] == 'M') count ++; + if (x > 0 && y < maxY && board[x - 1][y + 1] == 'M') count ++; + return count; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030019/LeetCode_55_019.java b/Week_03/G20200343030019/LeetCode_55_019.java new file mode 100644 index 00000000..2157180b --- /dev/null +++ b/Week_03/G20200343030019/LeetCode_55_019.java @@ -0,0 +1,14 @@ +class Solution { + public boolean canJump(int[] nums) { + if (nums == null) { + return false; + } + int end = nums.length - 1; + for (int index = nums.length - 1; index >= 0; index --) { + if (nums[index] + index >= end) { + end = index; + } + } + return end == 0; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030019/LeetCode_74_019.java b/Week_03/G20200343030019/LeetCode_74_019.java new file mode 100644 index 00000000..8cbc5acc --- /dev/null +++ b/Week_03/G20200343030019/LeetCode_74_019.java @@ -0,0 +1,37 @@ +class Solution { + public boolean searchMatrix(int[][] matrix, int target) { + if (matrix == null || matrix.length == 0 || matrix[0].length == 0) { + return false; + } + int lo = 0; + int hi = matrix.length - 1; + int mi = 0; + while (lo < hi) { + mi = lo + (hi - lo) / 2; + if (target < matrix[mi][0]) { + hi = mi - 1; + } else if (target > matrix[mi][0]) { + lo = mi + 1; + } else { + lo = mi; + break; + } + } + int i = matrix[lo][0] > target && lo > 0? lo - 1: lo; + lo = 0; + hi = matrix[i].length - 1; + while (lo < hi) { + mi = lo + (hi - lo) / 2; + if (target < matrix[i][mi]) { + hi = mi - 1; + } else if (target > matrix[i][mi]){ + lo = mi + 1; + } else { + lo = mi; + break; + } + } + + return matrix[i][lo] == target; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030019/LeetCode_860_019.java b/Week_03/G20200343030019/LeetCode_860_019.java new file mode 100644 index 00000000..0ff0705e --- /dev/null +++ b/Week_03/G20200343030019/LeetCode_860_019.java @@ -0,0 +1,33 @@ +class Solution { + public boolean lemonadeChange(int[] bills) { + if (bills == null || bills.length == 0) { + return true; + } + if (bills[0] > 5) { + return false; + } + int[] box = new int[2]; + for (int index = 0; index < bills.length; index ++) { + if (bills[index] == 5) { + box[0] ++; + } else if (bills[index] == 10) { + if (box[0] == 0) { + return false; + } + box[1] ++; + box[0] --; + } else { + if (box[1] > 0){ + box[1] --; + box[0] --; + } else { + box[0] -= 3; + } + if (box[0] < 0) { + return false; + } + } + } + return true; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030021/LeetCode_122_021.java b/Week_03/G20200343030021/LeetCode_122_021.java new file mode 100644 index 00000000..53947737 --- /dev/null +++ b/Week_03/G20200343030021/LeetCode_122_021.java @@ -0,0 +1,16 @@ +class Solution { + public static void main(String[] args) { + System.out.println(maxProfit(new int[]{7, 1, 53, 6, 4})); + } + + public static int maxProfit(int[] prices) { + int tem = 0; + for (int i = 1; i < prices.length; i++) { +// 关键:贪心算法思想,后一天大于前一天的收益才加和 + if (prices[i] > prices[i - 1]) { + tem += prices[i] - prices[i - 1]; + } + } + return tem; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030021/LeetCode_455_021.java b/Week_03/G20200343030021/LeetCode_455_021.java new file mode 100644 index 00000000..30c4dc0e --- /dev/null +++ b/Week_03/G20200343030021/LeetCode_455_021.java @@ -0,0 +1,23 @@ +import java.util.Arrays; + +class Solution { + public static void main(String[] args) { + System.out.println(findContentChildren(new int[]{1, 2, 3}, new int[]{1, 1, 1, 2, 1})); + } + + public static int findContentChildren(int[] g, int[] s) { +// 整体思路:贪心算法,将小饼干给胃口最小的小朋友 +// 题目限定条件:一个小朋友最多一个饼干 +// 排序 + Arrays.sort(g); + Arrays.sort(s); + int g1 = 0, s1 = 0; + while (g1 < g.length && s1 < s.length) { + if (g[g1] <= s[s1]) { + g1++; + } + s1++; + } + return g1; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030021/LeetCode_860_021.java b/Week_03/G20200343030021/LeetCode_860_021.java new file mode 100644 index 00000000..63f59d78 --- /dev/null +++ b/Week_03/G20200343030021/LeetCode_860_021.java @@ -0,0 +1,37 @@ +class Solution { + public static void main(String[] args) { + System.out.println(lemonadeChange(new int[]{5, 5, 10, 10, 5, 20, 5, 20})); + } + + + /** + * 如果是20元,先找10+5体现了贪心算法 + * + * @param bills + * @return + */ + public static boolean lemonadeChange(int[] bills) { + int five = 0, ten = 0; + for (int bill : bills) { + if (bill == 5) { + five++; + } else if (bill == 10) { + if (five == 0) { + return false; + } + five--; + ten++; + } else { + if (five > 0 && ten > 0) { + five--; + ten--; + } else if (five > 2) { + five = five - 3; + } else { + return false; + } + } + } + return true; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030025/LeetCode_1_025.java b/Week_03/G20200343030025/LeetCode_1_025.java new file mode 100644 index 00000000..06012061 --- /dev/null +++ b/Week_03/G20200343030025/LeetCode_1_025.java @@ -0,0 +1,23 @@ +public class LeetCode_1_025 { + public boolean searchMatrix(int[][] matrix, int target) { + int m = matrix.length; + if (m == 0) return false; + int n = matrix[0].length; + + // 二分查找 + int left = 0, right = m * n - 1; + int mid, midVal; + while (left <= right) { + mid = (left + right) / 2; + midVal = matrix[mid / n][mid % n]; + if (target == midVal) { + return true; + } else if (target < midVal) { + right = mid - 1; + } else { + left = mid + 1; + } + } + return false; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030025/LeetCode_2_025.java b/Week_03/G20200343030025/LeetCode_2_025.java new file mode 100644 index 00000000..a5578dcf --- /dev/null +++ b/Week_03/G20200343030025/LeetCode_2_025.java @@ -0,0 +1,15 @@ +public class LeetCode_1_025{ + public int findMin(int[] nums) { + int left = 0; + int right = nums.length - 1; + while (left < right) { + int mid = left + (right - left) / 2; + if (nums[mid] > nums[right]) { + left = mid + 1; + } else { + right = mid; + } + } + return nums[left]; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030025/NOTE.md b/Week_03/G20200343030025/NOTE.md index 50de3041..84d516a6 100644 --- a/Week_03/G20200343030025/NOTE.md +++ b/Week_03/G20200343030025/NOTE.md @@ -1 +1,157 @@ -学习笔记 \ No newline at end of file +#### 分治 +* 概念:将一个大问题拆解为若干个子问题,子问题得到结果时再以某种方式去合并结果集。从而得到最终的答案。 +* 代码模版 + ```java + public void divideConquer(Problem problem ,Param p1 ,Param p2 , ...){ + // recursion terminator + if (porblem == null) { + // print result; + return; + } + + // prepare data + Object data = prepare_data(problem) + List subproblems = splitProblem(problem, data) + // conquer subproblems + Object subresult1 = this.divideConquer(subproblems[0], p1, ...) + Object subresult2 = this.divideConquer(subproblems[1], p1, ...) + Object subresult3 = this.divideConquer(subproblems[2], p1, ...) + // ... + // process and generate the final result + Object result = processResult(subresult1, subresult2, subresult3, ...) + // # revert the current level states + } + ``` +* 分治回溯的递归状态树 + ```text + problem root + / \ + root:p1 root:p2 + / \ / \ + p1:p3 p1:p4 p2:p5 p2:p6 + . . . . + . . . . + . . . . + ``` +#### 回溯 +回溯法采用试错的思想,它尝试分步去解决一个问题。在分步解决问题的过程中,当它通过尝试发现现有的分步解答答案不能有效的正确的解答的时候,它将取消上一步甚至是上几步的计算,再通过其他的可能的分步解答再次尝试寻找问题的答案。 + +回溯法尝试上述步骤后可能出现出现两种结果: +1. 找到可能存在的正确的答案。 +2. 在尝试了所有的可能的分步方法后宣告该问题没有答案。 + +在最坏的情况下,回溯法会导致一次复杂度为指数时间的计算。 + +#### 深度优先遍历(DFS),广度优先遍历(BFS) + +* 二叉树定义模板 +```java + +public class TreeNode{ + public TreeNode left, right; + public int val; + + public TreeNode(int val) { + this.val = val; + this.left = null; + this.right = null; + } +} +``` + +* N叉树定义模板 +```java +import java.util.List; + +public class Node { + public int val; + public List children; + + public Node(int val) { + this.val = val; + } +} +``` + +* DFS 递归遍历模板 + ```java + private Set visited; + + // N叉树 + public void dfs(Node root, List traversalPath) { + if (visited.contains(root)) { + // already visited; + return; + } + visited.add(root); + traversalPath.add(root); + // process current node + List children = root.children; + if (children == null) { + return; + } + + for (Node node : children) { + if (!visited.contains(node)) { + dfs(node); + } + } + } + ``` +* DFS 迭代遍历 +```text +def DFS(self, tree): + if tree.root is None: + return [] + visited, stack = [], [tree.root] + while stack: + node = stack.pop() + visited.add(node) + process (node) + nodes = generate_related_nodes(node) + stack.push(nodes) + # other processing work + ... +``` +* BFS 遍历 +```text +def BFS(graph, start, end): + queue = [] + queue.append([start]) + visited.add(start) + while queue: + node = queue.pop() + visited.add(node) + process(node) + nodes = generate_related_nodes(node) + queue.push(nodes) + ... +``` +#### 贪心算法 +贪心算法是一种在每一步选择中都采取在当前状态下最好或最优(即最有利)的选择,从而希望导致结果是全局最好或最优的算法。 + +贪心法可以解决一些最优化问题,如:求图中的最小生成树、求哈夫曼编码等。然而对于工程和生活中的问题,贪心法一般不能得到我们所要求的答案。 + +一旦一个问题可以通过贪心法来解决,那么贪心法一般是解决这个问题的最好办法。由于贪心法的高效性以及其所求得的答案比较接近最优结果,贪心法也可以用作辅助算法或者直接解决一些要求结果不特别精确的问题。 + +适用贪心算法的场景:简单地说,问题能够分解成子问题来解决,子问题的最优解能递推到最终问题的最优解。这种子问题最优解称为最优子结构。 +贪心算法与动态规划的不同在于它对每个子问题的解决方案都做出选择,不能回退。动态规划则会保存以前的运算结果,并根据以前的结果对当前进行选择,有回退功能。 + +#### 二分查找 +* 前提: + 1. 目标函数单调性(单调递增或者递减) + 2. 存在上下界(bounded) + 3. 能够通过索引访问(index accessible) +* 模板: +```text + left, right = 0, len(array) - 1 + while left <= right: + mid = (left + right) / 2 + if array[mid] == target: + # find the target!! + break or return result + elif array[mid] < target: + left = mid + 1 + else: + right = mid - 1 +``` \ No newline at end of file diff --git a/Week_03/G20200343030029/LeetCode_12_029.java b/Week_03/G20200343030029/LeetCode_12_029.java new file mode 100644 index 00000000..5b5278e2 --- /dev/null +++ b/Week_03/G20200343030029/LeetCode_12_029.java @@ -0,0 +1,72 @@ +class LeetCode_12_029{ + // 题目描述:假设按照升序排序的数组在预先未知的某个点上进行了旋转。 + // + //( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。 + // + //请找出其中最小的元素。 + // + //你可以假设数组中不存在重复元素。 + // + //来源:力扣(LeetCode) + //链接:https://leetcode-cn.com/problems/find-minimum-in-rotated-sorted-array + //著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + + public static void main(String[] args) { + int[] array1 = {3,1,2}; + int[] array2 = {3,4,5,1,2}; + System.out.println("violent solution result of array1: " + violentSolutionOfFindMin(array1) ); + System.out.println("violent solution result of array2: " + violentSolutionOfFindMin(array2)); + System.out.println("binary serach result of array2: " + binarySearchOfFindMin(array1)); + System.out.println("binary serach result of array2: " + binarySearchOfFindMin(array2)); + } + + /** + * 暴力解法 + */ + public static int violentSolutionOfFindMin(int[] nums) { + if(null == nums){ + throw new IllegalArgumentException("method param is null."); + } + int num = nums[0]; + for(int i = 0; i < nums.length; i++) { + num = num < nums[i] ? num : nums[i]; + } + return num; + } + + /** + * 1.存在上下边界 + * 2.单调性(有序) + * 3.能够通过索引访问 + */ + public static int binarySearchOfFindMin(int[] nums){ + if(null == nums) { + throw new IllegalArgumentException("method param exception"); + } + + if((nums.length == 1) || (nums[0] < nums[nums.length - 1]) ){ + return nums[0]; + } + + int left = 0; + int right = nums.length - 1; + + while(left < right) { + int mid = left + (right - left) / 2; + + if(nums[mid] > nums[mid + 1]){ + return nums[mid + 1]; + } + + if(nums[mid - 1] > nums[mid]) { + return nums[mid]; + } + if(nums[mid] > nums[0]){ + left++; + }else{ + right--; + } + } + return -1; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030029/LeetCode_1_029.java b/Week_03/G20200343030029/LeetCode_1_029.java new file mode 100644 index 00000000..96090365 --- /dev/null +++ b/Week_03/G20200343030029/LeetCode_1_029.java @@ -0,0 +1,52 @@ +class LeetCode_1_029{ + + // 题目描述:在柠檬水摊上,每一杯柠檬水的售价为 5 美元。 + // + //顾客排队购买你的产品,(按账单 bills 支付的顺序)一次购买一杯。 + // + //每位顾客只买一杯柠檬水,然后向你付 5 美元、10 美元或 20 美元。你必须给每个顾客正确找零,也就是说净交易是每位顾客向你支付 5 美元。 + // + //注意,一开始你手头没有任何零钱。 + // + //如果你能给每位顾客正确找零,返回 true ,否则返回 false 。 + // + //来源:力扣(LeetCode) + //链接:https://leetcode-cn.com/problems/lemonade-change + //著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + + public static void main(String[] args) { + int[] array1 = {5,5,5,10,20}; + int[] array2 = {5,5,10}; + int[] array3 = {5,5,10,10,20}; + System.out.println(lemonadeChange(array1)); + System.out.println(lemonadeChange(array2)); + System.out.println(lemonadeChange(array3)); + } + + public static boolean lemonadeChange(int[] bills) { + int five = 0; + int ten = 0; + for(int bill : bills) { + if(5 == bill) { + five++; + }else if(10 == bill){ + if(five < 0) { + return false; + } + five--; + ten++; + }else{ + // 20 + if(five > 0 && ten > 0) { + five--; + ten--; + }else if(five >= 3){ + five = five - 3; + }else{ + return false; + } + } + } + return true; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030029/LeetCode_7_029.java b/Week_03/G20200343030029/LeetCode_7_029.java new file mode 100644 index 00000000..5fec4853 --- /dev/null +++ b/Week_03/G20200343030029/LeetCode_7_029.java @@ -0,0 +1,40 @@ +class LeetCode_7_029{ + + public static void main(String[] args){ + char[][] grid = {{'1','1','0','0','0'},{'1','1','0','0','0'},{'0','0','1','0','0'},{'0','0','0','1','1'}}; + System.out.println(numIslands(grid)); + } + + public static int numIslands(char[][] grid) { + + if(null == grid || grid.length == 0) { + return 0; + } + + int landNum = 0; + + for(int r = 0; r < grid.length; r++){ + for(int c = 0; c < grid[0].length; c++){ + if(grid[r][c] == '1'){ + // 深度优先,将改节点周边为1的节点修改为0 + dfs(r,c,grid); + landNum++; + } + } + } + return landNum; + } + + public static void dfs(int r, int c, char[][] grid) { + + if(r < 0 || c < 0 || r >= grid.length || c >= grid[0].length || grid[r][c] == '0'){ + return; + } + + grid[r][c] = '0'; + dfs(r - 1, c, grid); + dfs(r + 1, c, grid); + dfs(r, c - 1, grid); + dfs(r, c + 1, grid); + } +} \ No newline at end of file diff --git a/Week_03/G20200343030029/NOTE.md b/Week_03/G20200343030029/NOTE.md index 50de3041..022bd295 100644 --- a/Week_03/G20200343030029/NOTE.md +++ b/Week_03/G20200343030029/NOTE.md @@ -1 +1,26 @@ -学习笔记 \ No newline at end of file +#二分查找 理解 +*** +####使用二分查找,寻找一个半有序数组 [4, 5, 6, 7, 0, 1, 2] 中间无序的地方 理解 +*** +* 二分查找法条件: + * 有界性(存在上下边界) + * 有序性(升序|降序) + * 通过索引可以获取到 + +* 针对寻找一半有序数组,例如[4, 5, 6, 7, 0, 1, 2],重要条件在于中间值 +```nums[mid]```的比较,以及```left``` 和 ```right``` 脚标,具体代码如下(数组默认升序): +``` + if(nums[mid] > nums[mid + 1]){ + return nums[mid + 1]; + } + + if(nums[mid - 1] > nums[mid]){ + return nums[mid]; + } + + if(nums[mid] > nums[0]){ + left++; + }else{ + right--; + } +``` \ No newline at end of file diff --git a/Week_03/G20200343030035/LeetCode_122_035.py b/Week_03/G20200343030035/LeetCode_122_035.py new file mode 100644 index 00000000..36f1fde7 --- /dev/null +++ b/Week_03/G20200343030035/LeetCode_122_035.py @@ -0,0 +1,23 @@ +''' +122. 买卖股票的最佳时机 II + +给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。 + +设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。 + +注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。 + +''' + + + +class Solution: + def maxProfit(self, prices): + if not prices or len(prices) is 1: + return 0 + profit = 0 + for i in range(1, len(prices)): + if prices[i] > prices[i - 1]: + profit += prices[i] - prices[i - 1] + + return profit \ No newline at end of file diff --git a/Week_03/G20200343030035/LeetCode_860_035.py b/Week_03/G20200343030035/LeetCode_860_035.py new file mode 100644 index 00000000..0b1beeac --- /dev/null +++ b/Week_03/G20200343030035/LeetCode_860_035.py @@ -0,0 +1,36 @@ +''' +860. 柠檬水找零 + +在柠檬水摊上,每一杯柠檬水的售价为 5 美元。 + +顾客排队购买你的产品,(按账单 bills 支付的顺序)一次购买一杯。 + +每位顾客只买一杯柠檬水,然后向你付 5 美元、10 美元或 20 美元。你必须给每个顾客正确找零,也就是说净交易是每位顾客向你支付 5 美元。 + +注意,一开始你手头没有任何零钱。 + +如果你能给每位顾客正确找零,返回 true ,否则返回 false 。 + +''' + + +class Solution: + def lemonadeChange(self, bills): + fiveCounter, tenCounter = 0, 0 + for i in bills: + if i == 5: + fiveCounter += 1 + elif i == 10: + if not fiveCounter: + return False + fiveCounter -= 1 + tenCounter += 1 + else: + if tenCounter and fiveCounter: + tenCounter -= 1 + fiveCounter -= 1 + elif fiveCounter > 2: + fiveCounter -= 3 + else: + return False + return True diff --git a/Week_03/G20200343030363/LeetCode_055_363.java b/Week_03/G20200343030363/LeetCode_055_363.java new file mode 100644 index 00000000..0aba69c9 --- /dev/null +++ b/Week_03/G20200343030363/LeetCode_055_363.java @@ -0,0 +1,36 @@ +package cn.geek.week3; + +/** + * + * 跳跃游戏 + * + * @author lemon + * @version 1.0.0 + * @Description TODO + * @createTime 2020年02月29日 17:14:00 + */ +public class LeetCode_055_363 { + + /** + * Can jump boolean. + * + * @param nums + * the nums + * @return the boolean + */ + public boolean canJump(int[] nums) { + int k = 0; + for (int i = 0; i < nums.length; i++) { + + // 如果当前位置超过了能到达的最远位置,返回false + if (i > k) { + return false; + } + k = Math.max(k, i + nums[i]); + if (k > nums.length - 1) { + break; + } + } + return true; + } +} diff --git a/Week_03/G20200343030363/LeetCode_200_363.java b/Week_03/G20200343030363/LeetCode_200_363.java new file mode 100644 index 00000000..638edba3 --- /dev/null +++ b/Week_03/G20200343030363/LeetCode_200_363.java @@ -0,0 +1,63 @@ +package cn.geek.week3; + +/** + * + * 岛屿数量 + * + * @author lemon + * @version 1.0.0 + * @Description TODO + * @createTime 2020年02月29日 16:26:00 + */ +public class LeetCode_200_363 { + + /** + * Num islands int. + * + * @param grid + * the grid + * @return the int + */ + public int numIslands(char[][] grid) { + + if (null == grid || grid.length == 0) { + return 0; + } + + int height = grid.length; + int width = grid[0].length; + int isLand = 0; + for (int h = 0; h < width; h++) { + for (int w = 0; w < height; w++) { + if (grid[h][w] == '1') { + ++isLand; + dfs(grid, h, w); + } + } + } + return isLand; + } + + /** + * Dfs. + * + * @param grid + * the grid + * @param h + * the h + * @param w + * the w + */ + public void dfs(char[][] grid, int h, int w) { + int height = grid.length; + int width = grid[0].length; + if (h < 0 || w < 0 || h >= height || w >= width || grid[h][w] == '0') { + return; + } + grid[h][w] = '0'; + dfs(grid, h - 1, w); + dfs(grid, h + 1, w); + dfs(grid, h, w - 1); + dfs(grid, h, w + 1); + } +} diff --git "a/Week_03/G20200343030369/122.\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272-ii.swift" "b/Week_03/G20200343030369/122.\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272-ii.swift" new file mode 100644 index 00000000..60db7e20 --- /dev/null +++ "b/Week_03/G20200343030369/122.\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272-ii.swift" @@ -0,0 +1,81 @@ +/* + * @lc app=leetcode.cn id=122 lang=golang + * + * [122] 买卖股票的最佳时机 II + * + * https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/description/ + * + * algorithms + * Easy (57.34%) + * Likes: 600 + * Dislikes: 0 + * Total Accepted: 120K + * Total Submissions: 208.2K + * Testcase Example: '[7,1,5,3,6,4]' + * + * 给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。 + * + * 设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。 + * + * 注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。 + * + * 示例 1: + * + * 输入: [7,1,5,3,6,4] + * 输出: 7 + * 解释: 在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。 + * 随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6-3 = 3 。 + * + * + * 示例 2: + * + * 输入: [1,2,3,4,5] + * 输出: 4 + * 解释: 在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 + * 。 + * 注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。 + * 因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。 + * + * + * 示例 3: + * + * 输入: [7,6,4,3,1] + * 输出: 0 + * 解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。 + * + */ + +// @lc code=start +class Solution { + func maxProfit(_ prices: [Int]) -> Int { + + } + + // 峰谷法 + func maxProfit0(_ prices: [Int]) -> Int { + if prices.count == 0 {return 0} + var peek = prices[0], valley = prices[0], maxProfit = 0 + var i = 0 + while i < prices.count - 1 { + while i < prices.count - 1 && prices[i] >= prices[i+1] {i += 1} + valley = prices[i] + while i < prices.count - 1 && prices[i] < prices[i+1] {i += 1} + peek = prices[i] + maxProfit += peek - valley + } + return maxProfit + } + // 简化峰谷法 + func maxProfit1(_ prices: [Int]) -> Int { + if prices.count == 0 {return 0} + var maxProfit = 0 + for i in 1.. prices[i-1] { + maxProfit += prices[i] - prices[i-1] + } + } + return maxProfit + } +} +// @lc code=end + diff --git "a/Week_03/G20200343030369/127.\345\215\225\350\257\215\346\216\245\351\276\231.swift" "b/Week_03/G20200343030369/127.\345\215\225\350\257\215\346\216\245\351\276\231.swift" new file mode 100644 index 00000000..19b71e0c --- /dev/null +++ "b/Week_03/G20200343030369/127.\345\215\225\350\257\215\346\216\245\351\276\231.swift" @@ -0,0 +1,138 @@ +/* + * @lc app=leetcode.cn id=127 lang=golang + * + * [127] 单词接龙 + * + * https://leetcode-cn.com/problems/word-ladder/description/ + * + * algorithms + * Medium (39.53%) + * Likes: 218 + * Dislikes: 0 + * Total Accepted: 23.5K + * Total Submissions: 58.4K + * Testcase Example: '"hit"\n"cog"\n["hot","dot","dog","lot","log","cog"]' + * + * 给定两个单词(beginWord 和 endWord)和一个字典,找到从 beginWord 到 endWord + * 的最短转换序列的长度。转换需遵循如下规则: + * + * + * 每次转换只能改变一个字母。 + * 转换过程中的中间单词必须是字典中的单词。 + * + * + * 说明: + * + * + * 如果不存在这样的转换序列,返回 0。 + * 所有单词具有相同的长度。 + * 所有单词只由小写字母组成。 + * 字典中不存在重复的单词。 + * 你可以假设 beginWord 和 endWord 是非空的,且二者不相同。 + * + * + * 示例 1: + * + * 输入: + * beginWord = "hit", + * endWord = "cog", + * wordList = ["hot","dot","dog","lot","log","cog"] + * + * 输出: 5 + * + * 解释: 一个最短转换序列是 "hit" -> "hot" -> "dot" -> "dog" -> "cog", + * ⁠ 返回它的长度 5。 + * + * + * 示例 2: + * + * 输入: + * beginWord = "hit" + * endWord = "cog" + * wordList = ["hot","dot","dog","lot","log"] + * + * 输出: 0 + * + * 解释: endWord "cog" 不在字典中,所以无法进行转换。 + * + */ + +// @lc code=start +class Solution { + func ladderLength(_ beginWord: String, _ endWord: String, _ wordList: [String]) -> Int { + + } + + func findAdjacents(_ start: String, _ wordList: [String]) -> [String] { + var adjacents = [String]() + for word in wordList { + let wordChar = [Character](word) + let startChar = [Character](start) + var diff = 0 + for i in 0.. 1 {break} + } + if diff == 1 {adjacents.append(word)} + } + return adjacents + } + + // BFS + func ladderLength0(_ beginWord: String, _ endWord: String, _ wordList: [String]) -> Int { + var queue = [(String, Int)]() + var visited = Set() + queue.append((beginWord, 0)) + + while !queue.isEmpty { + let (word, level) = queue.removeFirst() + visited.insert(word) + if word == endWord {return level} + for adj in findAdjacents(word, wordList) where !visited.contains(adj) { + queue.append((adj, level + 1)) + } + } + return -1 + } + + // + func ladderLength1(_ beginWord: String, _ endWord: String, _ wordList: [String]) -> Int { + var allCombosDict = [String: [String]]() + var queue = [(String, Int)]() + var visited = Set() + // 预处理 + for word in wordList { + for i in 0.. Int { + + } + + func findMin0(_ nums: [Int]) -> Int { + var left = 0, right = nums.count - 1 + if nums[right] >= nums[left] {return nums[left]} + while left <= right { + let mid = left + (right - left) / 2 + if nums[mid] > nums[mid+1] { + return nums[mid+1] + } else { + if nums[mid] < nums[left] { + right = mid - 1 + } else { + left = mid + 1 + } + } + } + return 0 + } +} +// @lc code=end + diff --git "a/Week_03/G20200343030369/200.\345\262\233\345\261\277\346\225\260\351\207\217.swift" "b/Week_03/G20200343030369/200.\345\262\233\345\261\277\346\225\260\351\207\217.swift" new file mode 100644 index 00000000..8a9f48f2 --- /dev/null +++ "b/Week_03/G20200343030369/200.\345\262\233\345\261\277\346\225\260\351\207\217.swift" @@ -0,0 +1,110 @@ +/* + * @lc app=leetcode.cn id=200 lang=golang + * + * [200] 岛屿数量 + * + * https://leetcode-cn.com/problems/number-of-islands/description/ + * + * algorithms + * Medium (46.89%) + * Likes: 389 + * Dislikes: 0 + * Total Accepted: 58.6K + * Total Submissions: 124.3K + * Testcase Example: '[["1","1","1","1","0"],["1","1","0","1","0"],["1","1","0","0","0"],["0","0","0","0","0"]]' + * + * 给定一个由 '1'(陆地)和 + * '0'(水)组成的的二维网格,计算岛屿的数量。一个岛被水包围,并且它是通过水平方向或垂直方向上相邻的陆地连接而成的。你可以假设网格的四个边均被水包围。 + * + * 示例 1: + * + * 输入: + * 11110 + * 11010 + * 11000 + * 00000 + * + * 输出: 1 + * + * + * 示例 2: + * + * 输入: + * 11000 + * 11000 + * 00100 + * 00011 + * + * 输出: 3 + * + * + */ + +// @lc code=start +class Solution { + func numIslands(_ grid: [[Character]]) -> Int { + + } + + // DFS + func numIslands0(_ grid: [[Character]]) -> Int { + if grid.count == 0 {return 0} + var grid = grid + var numIslands = 0 + + func dfs(_ i: Int, _ j: Int) { + guard i < grid.count && i >= 0 && j < grid[i].count && j >= 0 else { + return + } + if grid[i][j] == "0" {return} + grid[i][j] = "0" + dfs(i-1, j) + dfs(i+1, j) + dfs(i, j-1) + dfs(i, j+1) + } + + for i in 0.. Int { + if grid.count == 0 {return 0} + var grid = grid + var queue = [(Int, Int)]() + var numIslands = 0 + + func bfs(_ i: Int, _ j: Int) { + var queue = [(Int, Int)]() + queue.append((i, j)) + while !queue.isEmpty { + let (i, j) = queue.removeFirst() + grid[i][j] = "0" + if i - 1 >= 0 && grid[i-1][j] == "1" {queue.append((i-1, j))} + if j - 1 >= 0 && grid[i][j-1] == "1" {queue.append((i, j-1))} + if i + 1 < grid.count && grid[i+1][j] == "1" {queue.append((i+1, j))} + if j + 1 < grid[i].count && grid[i][j+1] == "1" {queue.append((i, j+1))} + } + } + + for i in 0.. Int { + + } + + func search0(_ nums: [Int], _ target: Int) -> Int { + var left = 0, right = nums.count - 1 + while left <= right { + let mid = left + (right - left) / 2 + if nums[mid] == target {return mid} + if nums[left] < nums[mid] { // 左边升序 + if target >= nums[left] && target <= nums[mid] { + right = mid - 1 + } else { + left = mid + 1 + } + } else { // 右边升序 + if target >= nums[mid] && target <= nums[right] { + left = mid + 1 + } else { + right = mid - 1 + } + } + } + return -1 + } +} +// @lc code=end + diff --git "a/Week_03/G20200343030369/45.\350\267\263\350\267\203\346\270\270\346\210\217-ii.swift" "b/Week_03/G20200343030369/45.\350\267\263\350\267\203\346\270\270\346\210\217-ii.swift" new file mode 100644 index 00000000..c4675a3a --- /dev/null +++ "b/Week_03/G20200343030369/45.\350\267\263\350\267\203\346\270\270\346\210\217-ii.swift" @@ -0,0 +1,65 @@ +/* + * @lc app=leetcode.cn id=45 lang=golang + * + * [45] 跳跃游戏 II + * + * https://leetcode-cn.com/problems/jump-game-ii/description/ + * + * algorithms + * Hard (33.06%) + * Likes: 374 + * Dislikes: 0 + * Total Accepted: 31.6K + * Total Submissions: 95.1K + * Testcase Example: '[2,3,1,1,4]' + * + * 给定一个非负整数数组,你最初位于数组的第一个位置。 + * + * 数组中的每个元素代表你在该位置可以跳跃的最大长度。 + * + * 你的目标是使用最少的跳跃次数到达数组的最后一个位置。 + * + * 示例: + * + * 输入: [2,3,1,1,4] + * 输出: 2 + * 解释: 跳到最后一个位置的最小跳跃数是 2。 + * 从下标为 0 跳到下标为 1 的位置,跳 1 步,然后跳 3 步到达数组的最后一个位置。 + * + * + * 说明: + * + * 假设你总是可以到达数组的最后一个位置。 + * + */ + +// @lc code=start +class Solution { + func jump(_ nums: [Int]) -> Int { + + } + + // 回溯遍历 + func jump0(_ nums: [Int]) -> Int { + + var minTimes = 0 + func jump(_ start: Int, _ times: Int) { + if start + nums[start] >= nums.count - 1 { + minTimes = min(minTimes, times) + return + } + var p = nums[start] + while p > 0 { + jump(start+p, times+1) + p -= 1 + } + } + } + + // + func jump1(_ nums: [Int]) -> Int { + + } +} +// @lc code=end + diff --git "a/Week_03/G20200343030369/455.\345\210\206\345\217\221\351\245\274\345\271\262.swift" "b/Week_03/G20200343030369/455.\345\210\206\345\217\221\351\245\274\345\271\262.swift" new file mode 100644 index 00000000..a0655743 --- /dev/null +++ "b/Week_03/G20200343030369/455.\345\210\206\345\217\221\351\245\274\345\271\262.swift" @@ -0,0 +1,94 @@ +/* + * @lc app=leetcode.cn id=455 lang=golang + * + * [455] 分发饼干 + * + * https://leetcode-cn.com/problems/assign-cookies/description/ + * + * algorithms + * Easy (52.81%) + * Likes: 135 + * Dislikes: 0 + * Total Accepted: 26.1K + * Total Submissions: 49K + * Testcase Example: '[1,2,3]\n[1,1]' + * + * 假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。对每个孩子 i ,都有一个胃口值 gi + * ,这是能让孩子们满足胃口的饼干的最小尺寸;并且每块饼干 j ,都有一个尺寸 sj 。如果 sj >= gi ,我们可以将这个饼干 j 分配给孩子 i + * ,这个孩子会得到满足。你的目标是尽可能满足越多数量的孩子,并输出这个最大数值。 + * + * 注意: + * + * 你可以假设胃口值为正。 + * 一个小朋友最多只能拥有一块饼干。 + * + * 示例 1: + * + * + * 输入: [1,2,3], [1,1] + * + * 输出: 1 + * + * 解释: + * 你有三个孩子和两块小饼干,3个孩子的胃口值分别是:1,2,3。 + * 虽然你有两块小饼干,由于他们的尺寸都是1,你只能让胃口值是1的孩子满足。 + * 所以你应该输出1。 + * + * + * 示例 2: + * + * + * 输入: [1,2], [1,2,3] + * + * 输出: 2 + * + * 解释: + * 你有两个孩子和三块小饼干,2个孩子的胃口值分别是1,2。 + * 你拥有的饼干数量和尺寸都足以让所有孩子满足。 + * 所以你应该输出2. + * + * + */ + +// @lc code=start +class Solution { + func findContentChildren(_ g: [Int], _ s: [Int]) -> Int { + + } + + // 原答案 412 ms + func findContentChildren0(_ g: [Int], _ s: [Int]) -> Int { + if g.count == 0 || s.count == 0 {return 0} + let sortedG = g.sorted(), sortedS = s.sorted() + var gi = 0, sj = 0, satisfies = 0 + while gi < sortedG.count && sj < sortedS.count { + if sortedG[gi] <= sortedS[sj] { + satisfies += 1 + gi += 1 + sj += 1 + continue + } + if sortedG[gi] > sortedS[sj] {sj += 1} + } + return satisfies + } + + // 用时最少答案 240 ms + func findContentChildren1(_ g: [Int], _ s: [Int]) -> Int { + var g = g, s = s + g.sort(by: <); s.sort(by: <) + var gi = 0, sj = 0, satisfies = 0 + while gi < g.count && sj < s.count { + if g[gi] <= s[sj] { + satisfies += 1 + gi += 1 + sj += 1 + continue + } + if g[gi] > s[sj] {sj += 1} + } + return satisfies + } +} +// @lc code=end + diff --git "a/Week_03/G20200343030369/529.\346\211\253\351\233\267\346\270\270\346\210\217.swift" "b/Week_03/G20200343030369/529.\346\211\253\351\233\267\346\270\270\346\210\217.swift" new file mode 100644 index 00000000..c9fc2c77 --- /dev/null +++ "b/Week_03/G20200343030369/529.\346\211\253\351\233\267\346\270\270\346\210\217.swift" @@ -0,0 +1,157 @@ +/* + * @lc app=leetcode.cn id=529 lang=golang + * + * [529] 扫雷游戏 + * + * https://leetcode-cn.com/problems/minesweeper/description/ + * + * algorithms + * Medium (58.74%) + * Likes: 49 + * Dislikes: 0 + * Total Accepted: 4.4K + * Total Submissions: 7.4K + * Testcase Example: '[["E","E","E","E","E"],["E","E","M","E","E"],["E","E","E","E","E"],["E","E","E","E","E"]]\n[3,0]' + * + * 让我们一起来玩扫雷游戏! + * + * 给定一个代表游戏板的二维字符矩阵。 'M' 代表一个未挖出的地雷,'E' 代表一个未挖出的空方块,'B' + * 代表没有相邻(上,下,左,右,和所有4个对角线)地雷的已挖出的空白方块,数字('1' 到 '8')表示有多少地雷与这块已挖出的方块相邻,'X' + * 则表示一个已挖出的地雷。 + * + * 现在给出在所有未挖出的方块中('M'或者'E')的下一个点击位置(行和列索引),根据以下规则,返回相应位置被点击后对应的面板: + * + * + * 如果一个地雷('M')被挖出,游戏就结束了- 把它改为 'X'。 + * 如果一个没有相邻地雷的空方块('E')被挖出,修改它为('B'),并且所有和其相邻的方块都应该被递归地揭露。 + * 如果一个至少与一个地雷相邻的空方块('E')被挖出,修改它为数字('1'到'8'),表示相邻地雷的数量。 + * 如果在此次点击中,若无更多方块可被揭露,则返回面板。 + * + * + * + * + * 示例 1: + * + * 输入: + * + * [['E', 'E', 'E', 'E', 'E'], + * ⁠['E', 'E', 'M', 'E', 'E'], + * ⁠['E', 'E', 'E', 'E', 'E'], + * ⁠['E', 'E', 'E', 'E', 'E']] + * + * Click : [3,0] + * + * 输出: + * + * [['B', '1', 'E', '1', 'B'], + * ⁠['B', '1', 'M', '1', 'B'], + * ⁠['B', '1', '1', '1', 'B'], + * ⁠['B', 'B', 'B', 'B', 'B']] + * + * 解释: + * + * + * + * 示例 2: + * + * 输入: + * + * [['B', '1', 'E', '1', 'B'], + * ⁠['B', '1', 'M', '1', 'B'], + * ⁠['B', '1', '1', '1', 'B'], + * ⁠['B', 'B', 'B', 'B', 'B']] + * + * Click : [1,2] + * + * 输出: + * + * [['B', '1', 'E', '1', 'B'], + * ⁠['B', '1', 'X', '1', 'B'], + * ⁠['B', '1', '1', '1', 'B'], + * ⁠['B', 'B', 'B', 'B', 'B']] + * + * 解释: + * + * + * + * + * + * 注意: + * + * + * 输入矩阵的宽和高的范围为 [1,50]。 + * 点击的位置只能是未被挖出的方块 ('M' 或者 'E'),这也意味着面板至少包含一个可点击的方块。 + * 输入面板不会是游戏结束的状态(即有地雷已被挖出)。 + * 简单起见,未提及的规则在这个问题中可被忽略。例如,当游戏结束时你不需要挖出所有地雷,考虑所有你可能赢得游戏或标记方块的情况。 + * + */ + +// @lc code=start +class Solution { + func updateBoard(_ board: [[Character]], _ click: [Int]) -> [[Character]] { + + } + + func updateBoard0(_ board: [[Character]], _ click: [Int]) -> [[Character]] { + var board = board + let (i, j) = (click[0], click[1]) + if board[i][j] == "M" { + board[i][j] = "X" + return board + } + + var queue = [(Int, Int)]() + queue.append((i, j)) + while !queue.isEmpty { + let (i, j) = queue.removeFirst() + var numAdjMines = 0 + var tmp = [(Int, Int)]() + for (ai, aj) in adjs(i, j, board) { + if board[ai][aj] == "M" {numAdjMines += 1} + if board[ai][aj] == "E" {tmp.append((ai, aj))} + } + if numAdjMines != 0 { + board[i][j] = Character("\(numAdjMines)") + } else { + board[i][j] = "B" + queue.append(contentsOf: tmp) + } + } + + return board + } + + func adjs(_ i: Int, _ j: Int, _ board: [[Character]]) -> [(Int, Int)] { + var adjs = [(Int, Int)]() + let n = board.count, m = board[0].count + if i - 1 >= 0 && j - 1 >= 0 {adjs.append((i-1, j-1))} + if i - 1 >= 0 {adjs.append((i-1, j))} + if i - 1 >= 0 && j + 1 < m {adjs.append((i-1, j+1))} + if j - 1 >= 0 {adjs.append((i, j-1))} + if j + 1 < m {adjs.append((i, j+1))} + if i + 1 < n && j - 1 >= 0 {adjs.append((i+1, j-1))} + if i + 1 < n {adjs.append((i+1, j))} + if i + 1 < n && j + 1 < m {adjs.append((i+1, j+1))} + return adjs + } + + // DFS + func updateBoard1(_ board: [[Character]], _ click: [Int]) -> [[Character]] { + var board = board + let (i, j) = (click[0], click[1]) + if board[i][j] == "M" { + board[i][j] = "X" + return board + } + + let dirs = [(-1, -1), (-1, 0), (-1, 1), (0, -1), (0, 1), (1, -1), (1, 0), (1, 1)] + func dfs(_ i: Int, _ j: Int) { + if board[i][j] == "M" || board[i][j] == "X" {return} + + } + + return board + } +} +// @lc code=end + diff --git "a/Week_03/G20200343030369/55.\350\267\263\350\267\203\346\270\270\346\210\217.swift" "b/Week_03/G20200343030369/55.\350\267\263\350\267\203\346\270\270\346\210\217.swift" new file mode 100644 index 00000000..3bdcfc8a --- /dev/null +++ "b/Week_03/G20200343030369/55.\350\267\263\350\267\203\346\270\270\346\210\217.swift" @@ -0,0 +1,124 @@ +/* + * @lc app=leetcode.cn id=55 lang=golang + * + * [55] 跳跃游戏 + * + * https://leetcode-cn.com/problems/jump-game/description/ + * + * algorithms + * Medium (38.00%) + * Likes: 476 + * Dislikes: 0 + * Total Accepted: 62.6K + * Total Submissions: 164.1K + * Testcase Example: '[2,3,1,1,4]' + * + * 给定一个非负整数数组,你最初位于数组的第一个位置。 + * + * 数组中的每个元素代表你在该位置可以跳跃的最大长度。 + * + * 判断你是否能够到达最后一个位置。 + * + * 示例 1: + * + * 输入: [2,3,1,1,4] + * 输出: true + * 解释: 我们可以先跳 1 步,从位置 0 到达 位置 1, 然后再从位置 1 跳 3 步到达最后一个位置。 + * + * + * 示例 2: + * + * 输入: [3,2,1,0,4] + * 输出: false + * 解释: 无论怎样,你总会到达索引为 3 的位置。但该位置的最大跳跃长度是 0 , 所以你永远不可能到达最后一个位置。 + * + * + */ + +// @lc code=start +class Solution { + func canJump(_ nums: [Int]) -> Bool { + + } + + // 回溯法(超时)O(2^n) + func canJump0(_ nums: [Int]) -> Bool { + + func jump(_ i: Int) -> Bool { + if i == nums.count - 1 {return true} + if i >= nums.count {return false} + let val = nums[i] + if val == 0 {return false} + for j in 1...val { + if jump(i + j) {return true} + } + return false + } + return jump(0) + } + + // 回溯法 + 记忆表 O(n^2)(还是超时,那自底向上的动态规划也会超时咯) + func canJump00(_ nums: [Int]) -> Bool { + var memo = Array(repeating: 0, count: nums.count) + memo[nums.count-1] = 2 + func jump00(_ i: Int) -> Bool { + if memo[i] != 0 {return memo[i] == 2 ? true : false} + let furthestJump = min(i + nums[i], nums.count - 1) + var j = furthestJump + while j > i { + if jump00(j) {memo[j] = 2; return true} + j -= 1 + } + memo[i] = 1 + return false + } + return jump00(0) + } + + // 自底向上的动态规划 O(n^2)(没有超时) + func canJump01(_ nums: [Int]) -> Bool { + var memo = Array(repeating: 0, count: nums.count) + memo[nums.count-1] = 2 + for i in stride(from: nums.count - 2, through: 0, by: -1) { + let furthestJump = min(i + nums[i], nums.count - 1) + var j = i + 1 + while j <= furthestJump { + if memo[j] == 2 { + memo[i] = 2 + break + } + j += 1 + } + } + return memo[0] == 2 + } + + // 贪心算法 + func canJump1(_ nums: [Int]) -> Bool { + var i = 0, k = 0 + while i < nums.count { + if i > k {return false} + k = max(k, i + nums[i]) + i += 1 + } + return true + } + + func canJump2(_ nums: [Int]) -> Bool { + if nums.count > 1 { + var p = nums.count - 1 + var i = p + while i >= 0 { + if i + nums[i] > p { + p = i + } + i -= 1 + } + return p == 0 + } else { + return true + } + } +} +// @lc code=end + diff --git "a/Week_03/G20200343030369/74.\346\220\234\347\264\242\344\272\214\347\273\264\347\237\251\351\230\265.swift" "b/Week_03/G20200343030369/74.\346\220\234\347\264\242\344\272\214\347\273\264\347\237\251\351\230\265.swift" new file mode 100644 index 00000000..3410423c --- /dev/null +++ "b/Week_03/G20200343030369/74.\346\220\234\347\264\242\344\272\214\347\273\264\347\237\251\351\230\265.swift" @@ -0,0 +1,72 @@ +/* + * @lc app=leetcode.cn id=74 lang=golang + * + * [74] 搜索二维矩阵 + * + * https://leetcode-cn.com/problems/search-a-2d-matrix/description/ + * + * algorithms + * Medium (37.29%) + * Likes: 136 + * Dislikes: 0 + * Total Accepted: 32.8K + * Total Submissions: 87.5K + * Testcase Example: '[[1,3,5,7],[10,11,16,20],[23,30,34,50]]\n3' + * + * 编写一个高效的算法来判断 m x n 矩阵中,是否存在一个目标值。该矩阵具有如下特性: + * + * + * 每行中的整数从左到右按升序排列。 + * 每行的第一个整数大于前一行的最后一个整数。 + * + * + * 示例 1: + * + * 输入: + * matrix = [ + * ⁠ [1, 3, 5, 7], + * ⁠ [10, 11, 16, 20], + * ⁠ [23, 30, 34, 50] + * ] + * target = 3 + * 输出: true + * + * + * 示例 2: + * + * 输入: + * matrix = [ + * ⁠ [1, 3, 5, 7], + * ⁠ [10, 11, 16, 20], + * ⁠ [23, 30, 34, 50] + * ] + * target = 13 + * 输出: false + * + */ + +// @lc code=start +class Solution { + func searchMatrix(_ matrix: [[Int]], _ target: Int) -> Bool { + + } + + func searchMatrix0(_ matrix: [[Int]], _ target: Int) -> Bool { + if maxtrix.count == 0 {return false} + let n = matrix.count, m = matrix[0].count + var left = 0, right = n * m - 1 + while left <= right { + let mid = left + (right - left) / 2 + let r = mid / m, c = mid % m + if matrix[r][c] == target {return true} + if matrix[r][c] > target { + right = mid - 1 + } else { + left = mid + 1 + } + } + return false + } +} +// @lc code=end + diff --git "a/Week_03/G20200343030369/860.\346\237\240\346\252\254\346\260\264\346\211\276\351\233\266.swift" "b/Week_03/G20200343030369/860.\346\237\240\346\252\254\346\260\264\346\211\276\351\233\266.swift" new file mode 100644 index 00000000..a3f26450 --- /dev/null +++ "b/Week_03/G20200343030369/860.\346\237\240\346\252\254\346\260\264\346\211\276\351\233\266.swift" @@ -0,0 +1,128 @@ +/* + * @lc app=leetcode.cn id=860 lang=golang + * + * [860] 柠檬水找零 + * + * https://leetcode-cn.com/problems/lemonade-change/description/ + * + * algorithms + * Easy (53.73%) + * Likes: 95 + * Dislikes: 0 + * Total Accepted: 16.2K + * Total Submissions: 30.1K + * Testcase Example: '[5,5,5,10,20]' + * + * 在柠檬水摊上,每一杯柠檬水的售价为 5 美元。 + * + * 顾客排队购买你的产品,(按账单 bills 支付的顺序)一次购买一杯。 + * + * 每位顾客只买一杯柠檬水,然后向你付 5 美元、10 美元或 20 美元。你必须给每个顾客正确找零,也就是说净交易是每位顾客向你支付 5 美元。 + * + * 注意,一开始你手头没有任何零钱。 + * + * 如果你能给每位顾客正确找零,返回 true ,否则返回 false 。 + * + * 示例 1: + * + * 输入:[5,5,5,10,20] + * 输出:true + * 解释: + * 前 3 位顾客那里,我们按顺序收取 3 张 5 美元的钞票。 + * 第 4 位顾客那里,我们收取一张 10 美元的钞票,并返还 5 美元。 + * 第 5 位顾客那里,我们找还一张 10 美元的钞票和一张 5 美元的钞票。 + * 由于所有客户都得到了正确的找零,所以我们输出 true。 + * + * + * 示例 2: + * + * 输入:[5,5,10] + * 输出:true + * + * + * 示例 3: + * + * 输入:[10,10] + * 输出:false + * + * + * 示例 4: + * + * 输入:[5,5,10,10,20] + * 输出:false + * 解释: + * 前 2 位顾客那里,我们按顺序收取 2 张 5 美元的钞票。 + * 对于接下来的 2 位顾客,我们收取一张 10 美元的钞票,然后返还 5 美元。 + * 对于最后一位顾客,我们无法退回 15 美元,因为我们现在只有两张 10 美元的钞票。 + * 由于不是每位顾客都得到了正确的找零,所以答案是 false。 + * + * + * + * + * 提示: + * + * + * 0 <= bills.length <= 10000 + * bills[i] 不是 5 就是 10 或是 20  + * + * + */ + +// @lc code=start +class Solution { + func lemonadeChange(_ bills: [Int]) -> Bool { + + } + + func lemonadeChange0(_ bills: [Int]) -> Bool { + var (five, ten, twenty) = (0, 0, 0) // 5, 10, 20 的个数 + for b in bills { + if b == 5 { + five += 1 + } else if b == 10 { + ten += 1 + if five > 0 { + five -= 1 + } else { + return false + } + } else if b == 20 { + twenty += 1 + if ten > 0 { + if five > 0 { + ten -= 1 + five -= 1 + } else { + return false + } + } else if five >= 3 { + five -= 3 + } else { + return false + } + } + } + return true + } + + func lemonadeChange1(_ bills: [Int]) -> Bool { + var five = 0, ten = 0 + for cash in bills { + if cash == 5 { + five += 1 + } else if cash == 10 { + ten += 1 + five -= 1 + } else if ten > 0 { + ten -= 1 + five -= 1 + } else { + five -= 3 + } + if five < 0 {return false} + } + return true + } +} +// @lc code=end + diff --git a/Week_03/G20200343030373/LeetCode_102_373/LeetCode_102_373_test.go b/Week_03/G20200343030373/LeetCode_102_373/LeetCode_102_373_test.go new file mode 100644 index 00000000..2bcb6b29 --- /dev/null +++ b/Week_03/G20200343030373/LeetCode_102_373/LeetCode_102_373_test.go @@ -0,0 +1,239 @@ +//https://leetcode-cn.com/problems/binary-tree-level-order-traversal/ +package binary_tree_level_order_traversal_test + +import ( + "container/list" + "github.com/stretchr/testify/assert" + "testing" +) + +func TestTreeTraversal(t *testing.T) { + t.Log("Binary Tree Level Order Traversal: BFS, DFS") + + root := TreeNode{ + Val: 3, + Left: &TreeNode{ + Val: 9, + Left: nil, + Right: nil, + }, + Right: &TreeNode{ + Val: 20, + Left: &TreeNode{ + Val: 15, + Left: nil, + Right: nil, + }, + Right: &TreeNode{ + Val: 7, + Left: nil, + Right: nil, + }, + }, + } + + expect := [][]int{ + {3}, + {9, 20}, + {15, 7}, + } + + assert.Equal(t, expect, levelOrder(&root)) + assert.Equal(t, expect, bfsSlice(&root)) + assert.Equal(t, expect, bfsList(&root)) + assert.Equal(t, expect, dfsLevelOrder(&root)) + + root1 := TreeNode{ + Val: 0, + Left: &TreeNode{ + Val: 2, + Left: &TreeNode{ + Val: 1, + Left: &TreeNode{ + Val: 5, + Left: nil, + Right: nil, + }, + Right: &TreeNode{ + Val: 1, + Left: nil, + Right: nil, + }, + }, + Right: nil, + }, + Right: &TreeNode{ + Val: 4, + Left: &TreeNode{ + Val: 3, + Left: nil, + Right: &TreeNode{ + Val: 6, + Left: nil, + Right: nil, + }, + }, + Right: &TreeNode{ + Val: -1, + Left: nil, + Right: &TreeNode{ + Val: 8, + Left: nil, + Right: nil, + }, + }, + }, + } + + expect1 := [][]int{ + {0}, + {2, 4}, + {1, 3, -1}, + {5, 1, 6, 8}, + } + + assert.Equal(t, expect, bfsSliceVisited(&root)) + assert.Equal(t, expect1, bfsSliceVisited(&root1)) //Val=1有重复,但允许 +} + +type TreeNode struct { + Val int + Left *TreeNode + Right *TreeNode +} + +func levelOrder(root *TreeNode) [][]int { + //return bfsSlice(root) + return dfsLevelOrder(root) +} + +//method1: dfs +func dfsLevelOrder(root *TreeNode) [][]int { + var levels [][]int //定义好一个二维数组,在每个level层填充二维数组内部的一维数组 + dfs(root, 0, &levels) + return levels +} + +func dfs(root *TreeNode, level int, levels *[][]int) { + //终止条件,所以无需额外判断有无子节点 + if root == nil { + return + } + + if len(*levels) <= level { //当前层为新层 + *levels = append(*levels, []int{root.Val}) + } else { //之前已经深度遍历过:dfs + (*levels)[level] = append((*levels)[level], root.Val) + } + + dfs(root.Left, level+1, levels) + dfs(root.Right, level+1, levels) +} + +//method2.1 bfs +//queue in slice +func bfsSlice(root *TreeNode) [][]int { + if root == nil { + return [][]int{} + } + var levels [][]int + var queue []*TreeNode //申请一个队列 + queue = append(queue, root) //根节点插入 + + for len(queue) > 0 { + var level []int + //完全可以使用range,因为range使用的是range那一刻的拷贝,不会随后面queue的append而延长 + //但为了表示Batch Process,先获得当前长度后遍历,表示当前层结束 - 更清晰表达算法 + //for _, node := range queue { + n := len(queue) + for i := 0; i < n; i++ { + node := queue[0] + queue = queue[1:] //删除队首元素 + + level = append(level, node.Val) //将当前层的所有节点加入结果数组中 + + //将当前节点子节点加入队列 + if node.Left != nil { + queue = append(queue, node.Left) + } + if node.Right != nil { + queue = append(queue, node.Right) + } + } + levels = append(levels, level) //添加当前层次的所有节点 + } + return levels +} + +//method2.2: bfs with visited +//if need visited to adjust repeat +func bfsSliceVisited(root *TreeNode) [][]int { + if root == nil { + return [][]int{} + } + var levels [][]int + + //判重,不应存储.Val值,应存储node的地址 - 允许Val值重复 + //var visited map[*TreeNode]int - 会报错,make不仅生成实例还会初始化初值 + visited := make(map[*TreeNode]int) + + var queue []*TreeNode + queue = append(queue, root) + + for len(queue) > 0 { + var level []int + n := len(queue) + for i := 0; i < n; i++ { + node := queue[0] + queue = queue[1:] + + //判重,如果之前已经处理过了,就跳过;否则就记录下来 + //二叉树中有环的话,即可通过visited判重 + if _, ok := visited[node]; ok { + continue + } + visited[node] = node.Val + + level = append(level, node.Val) + if node.Left != nil { + queue = append(queue, node.Left) + } + if node.Right != nil { + queue = append(queue, node.Right) + } + } + levels = append(levels, level) + } + return levels +} + +//method2.3: bfs +//queue in container.list +func bfsList(root *TreeNode) [][]int { + if root == nil { + return [][]int{} + } + var levels [][]int + + queue := list.New() + queue.PushBack(root) + + for queue.Len() > 0 { + var level []int + n := queue.Len() + for i := 0; i < n; i++ { + node := queue.Remove(queue.Front()).(*TreeNode) //取队首元素并删除队首元素 + + level = append(level, node.Val) + + if node.Left != nil { + queue.PushBack(node.Left) + } + if node.Right != nil { + queue.PushBack(node.Right) + } + } + levels = append(levels, level) + } + return levels +} diff --git a/Week_03/G20200343030373/LeetCode_122_373/LeetCode_122_373_test.go b/Week_03/G20200343030373/LeetCode_122_373/LeetCode_122_373_test.go new file mode 100644 index 00000000..fee3644c --- /dev/null +++ b/Week_03/G20200343030373/LeetCode_122_373/LeetCode_122_373_test.go @@ -0,0 +1,31 @@ +//https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/ +package buy_sell_stock_test + +import ( + "github.com/stretchr/testify/assert" + "testing" +) + +func TestGreedy(t *testing.T) { + t.Log("Buy Sell Stock: Greedy") + + nums1 := []int{7, 1, 5, 3, 6, 4} + nums2 := []int{1, 2, 3, 4, 5} + nums3 := []int{7, 6, 4, 3, 1} + assert.Equal(t, 7, maxProfit(nums1)) + assert.Equal(t, 4, maxProfit(nums2)) + assert.Equal(t, 0, maxProfit(nums3)) +} + +//贪心算法:只要后一天价格比前一天高,就在前一天买进、后一天卖出 +//限制 或者 使用贪心算法的条件:最多持仓一股,可以0股; 可以买卖无数次; 当天既可买又可卖;无手续费 +//O(n) +func maxProfit(prices []int) int { + var max int + for i := 0; i <= len(prices)-2; i++ { + if prices[i+1] > prices[i] { + max += prices[i+1] - prices[i] + } + } + return max +} diff --git a/Week_03/G20200343030373/LeetCode_169_373/LeetCode_169_373_test.go b/Week_03/G20200343030373/LeetCode_169_373/LeetCode_169_373_test.go new file mode 100644 index 00000000..d4d08dba --- /dev/null +++ b/Week_03/G20200343030373/LeetCode_169_373/LeetCode_169_373_test.go @@ -0,0 +1,143 @@ +//https://leetcode-cn.com/problems/majority-element/ +package majority_element_test + +import ( + "github.com/stretchr/testify/assert" + "sort" + "testing" +) + +func TestMajorityElement(t *testing.T) { + t.Log("Divide&Conquer - Majority Element") + + nums1 := []int{3, 2, 3} + assert.Equal(t, 3, majorityElement(nums1)) + assert.Equal(t, 3, majorityElementMap1(nums1)) + assert.Equal(t, 3, majorityElementMap2(nums1)) + assert.Equal(t, 3, majorityElementSort(nums1)) + assert.Equal(t, 3, majorityElementDC(nums1)) + assert.Equal(t, 3, majorityElementVote(nums1)) + + nums2 := []int{2, 2, 1, 1, 1, 2, 2} + assert.Equal(t, 2, majorityElement(nums2)) + assert.Equal(t, 2, majorityElementMap1(nums2)) + assert.Equal(t, 2, majorityElementMap2(nums2)) + assert.Equal(t, 2, majorityElementSort(nums2)) + assert.Equal(t, 2, majorityElementDC(nums2)) + assert.Equal(t, 2, majorityElementVote(nums2)) +} + +func majorityElement(nums []int) int { + return majorityElementVote(nums) +} + +//method1.1: map, key: 元素,value: 数量 +//遍历map,找到数量的最大值 +//O(n), O(n) +func majorityElementMap1(nums []int) int { + //将元素的数量存入map + hash := make(map[int]int) + for _, v := range nums { + hash[v]++ + } + + majorityE, maxCount := 0, 0 + //遍历、覆盖找到最大值,题目有前提 + for element, count := range hash { + if count > maxCount { + majorityE, maxCount = element, count + } + } + return majorityE +} + +//method1.2: map, key: 元素, value:数量 +//较上一方法,只需要遍历一次,无需再次遍历hash,边遍历边比较 - 压缩空间 +//O(n), O(n) +func majorityElementMap2(nums []int) int { + //初始值是第一个元素,初始数量为0 + majorityE := nums[0] + hash := map[int]int{ + majorityE: 0, + } + //边遍历边比较、覆盖 + for _, element := range nums { + hash[element]++ //每次遍历就计数,反映真实数量 + if hash[element] > hash[majorityE] { + majorityE = element + } + } + return majorityE +} + +//method2: 题目有前提,肯定存在众数,且众数的个数大于len/2 +//则排序后,第len/2个肯定为众数 +//快排 O(nlogn), O(1) +func majorityElementSort(nums []int) int { + sort.Ints(nums) + return nums[len(nums)/2] +} + +//method3: 分治 +//题目有前提,肯定存在众数,且众数的个数大于len/2 +//左边找众数,右边也找 +//如果找到的众数元素值相等,则返回 +//如果不相等,则返回计数多的那一边 +//O(nlogn), O(logn) +func majorityElementDC(nums []int) int { + //包含左边和右边的索引 + return majority(nums, 0, len(nums)-1) +} + +func majority(nums []int, leftIndex int, rightIndex int) int { + //终止条件,遍历结束,直接返回当前值 + if leftIndex == rightIndex { + return nums[leftIndex] + } + + //无需区分奇偶,奇偶/2得到相同的值,总能包含完全 + midIndex := (leftIndex + rightIndex) / 2 + leftMax := majority(nums, leftIndex, midIndex) + rightMax := majority(nums, midIndex+1, rightIndex) + + //回归判断1:如果左右两边众数相等,则直接返回 + if leftMax == rightMax { + return leftMax + } + //回归判断2:如果不相等,则找左右两边分别的众数 出现的次数 多的那个众数 + leftCount, rightCount := 0, 0 + for i := leftIndex; i < midIndex; i++ { + if leftMax == nums[i] { + leftCount++ + } + } + for i := midIndex; i < rightIndex; i++ { + if rightMax == nums[i] { + rightCount++ + } + } + if leftCount > rightCount { + return leftMax + } + return rightMax +} + +//method4: 摩尔投票法只关注次数 +//众数比其他数多:众数的次数+1,其他的-1,则将次数全部加起来,和大于0 +//如果初始值就为众数、计数为1,则count一直累加,直接返回众数 +//如果初始值不为众数、计数为1,后续众数的出现会将计数累减为0。此时将众数赋值给计数的数值,后续的数字就没机会覆盖众数计数值了 +func majorityElementVote(nums []int) int { + cur, count := 0, 0 + for _, v := range nums { + if count == 0 { + cur = v + } + + if cur == v { + count++ + } else { + count-- + } + } + return cur +} diff --git a/Week_03/G20200343030373/LeetCode_22_373/LeetCode_22_373_test.go b/Week_03/G20200343030373/LeetCode_22_373/LeetCode_22_373_test.go new file mode 100644 index 00000000..c217dec2 --- /dev/null +++ b/Week_03/G20200343030373/LeetCode_22_373/LeetCode_22_373_test.go @@ -0,0 +1,48 @@ +//https://leetcode-cn.com/problems/generate-parentheses/ +package generate_parentheses_test + +import ( + "github.com/stretchr/testify/assert" + "testing" +) + +func TestGenerateParentheses(t *testing.T) { + t.Log("Generate Parentheses") + + expect := []string{ + "((()))", + "(()())", + "(())()", + "()(())", + "()()()", + } + assert.Equal(t, expect, generateParenthesis(3)) +} + +//字符串长度为2n,每个元素有两种选择,则O(2^(2n)),再判断合法 +//改进,DFS+Prune +//记录左右括号各使用多少个,最多n +//保证左括号比右括号先用 +//O(2^n) +func generateParenthesis(n int) []string { + if n <= 0 { + return []string{} + } + var result []string + generateOneByOne(&result, "", n, n) + return result +} + +func generateOneByOne(result *[]string, sublist string, left, right int) { + if left == 0 && right == 0 { + *result = append(*result, sublist) + return + } + + if left > 0 { //left和right的个数为n + generateOneByOne(result, sublist+"(", left-1, right) + } + if right > left { //剩余右括号比左括号多:左括号先用,右括号后用 - 则无需在判断right>0 + generateOneByOne(result, sublist+")", left, right-1) + } +} diff --git a/Week_03/G20200343030373/LeetCode_50_373/LeetCode_50_373_test.go b/Week_03/G20200343030373/LeetCode_50_373/LeetCode_50_373_test.go new file mode 100644 index 00000000..98d98d81 --- /dev/null +++ b/Week_03/G20200343030373/LeetCode_50_373/LeetCode_50_373_test.go @@ -0,0 +1,92 @@ +//https://leetcode-cn.com/problems/powx-n/ +package power_test + +import ( + "fmt" + "github.com/stretchr/testify/assert" + "strconv" + "testing" +) + +func TestPower(t *testing.T) { + t.Log("Power(x,n)") + //power(x,n) + x1 := 2.00000 + n1 := 10 + expect1 := 1024.00000 + ret1, _ := strconv.ParseFloat(fmt.Sprintf("%.5f", powRD(x1, n1)), 64) + ret1b, _ := strconv.ParseFloat(fmt.Sprintf("%.5f", powBit(x1, n1)), 64) + x2 := 2.10000 + n2 := 3 + expect2 := 9.26100 + ret2, _ := strconv.ParseFloat(fmt.Sprintf("%.5f", powRD(x2, n2)), 64) + ret2b, _ := strconv.ParseFloat(fmt.Sprintf("%.5f", powBit(x2, n2)), 64) + x3 := 2.00000 + n3 := -2 + expect3 := 0.25000 + ret3, _ := strconv.ParseFloat(fmt.Sprintf("%.5f", powRD(x3, n3)), 64) + ret3b, _ := strconv.ParseFloat(fmt.Sprintf("%.5f", powBit(x3, n3)), 64) + assert.Equal(t, expect1, ret1) + assert.Equal(t, expect2, ret2) + assert.Equal(t, expect3, ret3) + assert.Equal(t, expect1, ret1b) + assert.Equal(t, expect2, ret2b) + assert.Equal(t, expect3, ret3b) +} + +//method1: recursion + divide&conquer +//O(logn) +func powRD(x float64, n int) float64 { + //terminator + if n == 0 { + return 1 + } + //process + //drill down + //如果n小于0 + //都是return,不需要else + if n < 0 { + //x^-n = 1/(x^n) + //一旦遇到除数,就要考虑非零 + if x == 0 { + return 0 + } + return powRD(1/x, -n) + } + //如果n大于0,n要区分奇偶 + r := powRD(x, n/2) //无论奇偶,n/2都是一样的值,所以不用n-1/2 + //clear + //if n % 2 == 1 + if n&1 == 1 { + //如果是奇数 + return x * r * r + } + return r * r +} + +//method2: x^(a+b) = x^a * x^b +//n可以拆解为二进制累加,如10=8*1+4*0+2*1+1*0 +//x^10 = x^8 * x^2, 即n的二进制为1的,乘进去 +//每次乘进去的,就是前一个的x*x +//TCL O(logn) - n的二进制表示最多为logn +func powBit(x float64, n int) float64 { + if n < 0 { + if x == 0 { + return 0 + } + //不使用递归,直接处理 + x, n = 1/x, -n + } + + res := 1.0 + //n一直右移,最终会变成0 + //每次移动后,x就自乘 + //如果当前位为1,则将x乘入结果内 + for ; n != 0; n >>= 1 { + if n&1 == 1 { + res *= x + } + x *= x + } + return res +} diff --git a/Week_03/G20200343030373/LeetCode_51_373/LeetCode_51_373_test.go b/Week_03/G20200343030373/LeetCode_51_373/LeetCode_51_373_test.go new file mode 100644 index 00000000..dc334704 --- /dev/null +++ b/Week_03/G20200343030373/LeetCode_51_373/LeetCode_51_373_test.go @@ -0,0 +1,95 @@ +//https://leetcode-cn.com/problems/n-queens/ +package n_queens_test + +import ( + "github.com/stretchr/testify/assert" + "testing" +) + +func TestNQueens(t *testing.T) { + t.Log("N-Queens: DFS Prune") + expect := [][]string{ + {".Q..", + "...Q", + "Q...", + "..Q."}, + {"..Q.", + "Q...", + "...Q", + ".Q.."}, + } + //[[1 3 0 2] [2 0 3 1]] + assert.Equal(t, expect, solveNQueens(4)) +} + +//从第一行开始 +//循环列并试图在每个列中放置皇后 +//在`坐标1`位置放置皇后 +//记忆化排除行、列、撇、捺的位置 +//如果所有的行都被考虑过了,递归终止,找到其中一个解 +//否则,继续考虑下一行皇后位置 +//回溯:将`坐标1`位置的皇后移除 +//O(n!), O(n) +func solveNQueens(n int) [][]string { + if n == 0 { + return [][]string{} + } + + var res [][]int //一个结果:从每一行上取一个列坐标 + //行,一行只能有一个皇后 + //列,一列只能有一个皇后,只需按列循环,将列号进行记忆化(map, key是列号,value是是否被占用) + //撇,行号 + 列号 = 常数,将其作为撇的坐标进行记忆化 + //捺,行号 - 列号 = 常数,将其作为捺的坐标进行记忆化 + var rows []int //行,二维数组的第一维 + cols := make(map[int]bool, n) //列,记录'|'方向上的占用情况 + pies := make(map[int]bool, 2*n) //撇,记录'/'方向上的占用情况 + nas := make(map[int]bool, 2*n) //捺,记录'\'方向上的占用情况 + //递归,传入的是值时,回归到本层不会被修改;传入的是引用时,每一层的修改都有效 + dfs(n, rows, cols, pies, nas, &res) + return generateResult(res, n) +} + +func dfs(n int, rows []int, cols, pies, nas map[int]bool, res *[][]int) { + row := len(rows) + //终止条件:访问的row行已经大于等于n + if row == n { + //go的切片是地址,往数组中添加要复制新的,否则会被后续操作修改 + //如果直接append rows,leetcode Not AC + tmp := make([]int, n) + copy(tmp, rows) + *res = append(*res, tmp) + return + } + //对于每一行遍历所有列 + for col := 0; col < n; col++ { + //查看该列是否被占用,记录在set中 + if cols[col] || pies[row+col] || nas[row-col] { + continue + } + //标记占用,更新set表示被占用,不能放置皇后 + cols[col], pies[row+col], nas[row-col] = true, true, true + //递归到下一行 + dfs(n, append(rows, col), cols, pies, nas, res) + //回溯,解除标记不影响下次递归使用 + cols[col], pies[row+col], nas[row-col] = false, false, false + } +} + +func generateResult(res [][]int, n int) (result [][]string) { + for _, v := range res { + var s []string + for _, val := range v { + str := "" + for i := 0; i < n; i++ { + if i == val { + str += "Q" + } else { + str += "." + } + } + s = append(s, str) + } + result = append(result, s) + } + return +} diff --git a/Week_03/G20200343030373/LeetCode_52_373/LeetCode_52_373_test.go b/Week_03/G20200343030373/LeetCode_52_373/LeetCode_52_373_test.go new file mode 100644 index 00000000..82cc76cd --- /dev/null +++ b/Week_03/G20200343030373/LeetCode_52_373/LeetCode_52_373_test.go @@ -0,0 +1,83 @@ +//https://leetcode-cn.com/problems/n-queens-ii/ +//Final Best Answer: dsa-geek-qichao/i_bitwise_operation/b_n_queens_2/n_queens_2_test.go +package n_queens_2_test + +import ( + "github.com/stretchr/testify/assert" + "testing" +) + +func TestNQueens2(t *testing.T) { + t.Log("N-Queens 2: DFS Prune") + assert.Equal(t, 2, totalNQueens1(4)) + assert.Equal(t, 2, totalNQueens2(4)) +} + +func totalNQueens1(n int) int { + if n == 0 { + return 0 + } + + res := 0 + row := 0 + cols := make(map[int]bool, n) + pies := make(map[int]bool, 2*n) + nas := make(map[int]bool, 2*n) + dfs1(n, row, cols, pies, nas, &res) + return res +} + +func dfs1(n int, row int, cols, pies, nas map[int]bool, res *int) { + if row == n { + *res++ + return + } + + for col := 0; col < n; col++ { + if cols[col] || pies[row+col] || nas[row-col] { + continue + } + + cols[col], pies[row+col], nas[row-col] = true, true, true + dfs1(n, row+1, cols, pies, nas, res) + cols[col], pies[row+col], nas[row-col] = false, false, false + } +} + +//1. 递归终止条件:row行数扫描结束;则肯定找到了一个,需要加1 +//2. 得到空位:`bits := (^(col | pie | na)) & ((1<>1 +func totalNQueens2(n int) int { + if n == 0 { + return 0 + } + + res := 0 + dfs2(n, 0, 0, 0, 0, &res) + return res +} + +func dfs2(n, row, col, pie, na int, res *int) { + if row >= n { + *res++ + return + } + + bits := (^(col | pie | na)) & ((1 << uint(n)) - 1) + for bits != 0 { + bit := bits & -bits + dfs2(n, row+1, col|bit, (pie|bit)<<1, (na|bit)>>1, res) + bits = bits & (bits - 1) + } +} diff --git a/Week_03/G20200343030373/LeetCode_69_373/LeetCode_69_373_test.go b/Week_03/G20200343030373/LeetCode_69_373/LeetCode_69_373_test.go new file mode 100644 index 00000000..6e898321 --- /dev/null +++ b/Week_03/G20200343030373/LeetCode_69_373/LeetCode_69_373_test.go @@ -0,0 +1,63 @@ +//https://leetcode-cn.com/problems/sqrtx/ +package sqrt_test + +import ( + "github.com/stretchr/testify/assert" + "testing" +) + +func TestSqrt(t *testing.T) { + assert.Equal(t, 2, mySqrt(4)) + assert.Equal(t, 2, mySqrt(8)) + assert.Equal(t, 2, binarySearchSqrt(4)) + assert.Equal(t, 2, binarySearchSqrt(8)) + assert.Equal(t, 2, newtonSqrt(4)) + assert.Equal(t, 2, newtonSqrt(8)) + + //expect1, _ := strconv.ParseFloat(fmt.Sprintf("%.5f", math.Sqrt(2)), 64) + //expect2, _ := strconv.ParseFloat(fmt.Sprintf("%.10f", math.Sqrt(2)), 64) + //assert.Equal(t, expect1, floatSqrt(2, 5)) + //assert.Equal(t, expect2, floatSqrt(2, 10)) +} + +func mySqrt(x int) int { + return binarySearchSqrt(x) +} + +func binarySearchSqrt(x int) int { + if x == 0 || x == 1 { + return x + } + //题目要求返回int,所以left从1开始 + left, right := 1, x + //left, right, res := 1, x, 0 + for left <= right { + //mid := (left + right) / 2 会溢出 + mid := left + (right-left)/2 + //mid * mid == x 会溢出 + if mid == x/mid { + return mid + } else if mid > x/mid { + right = mid - 1 + } else { + left = mid + 1 + //res = mid + } + } + //left和right逐渐逼近,是向下取整,当left+1时跳出循环,大于了mid,所以结果就是 left-1 或者上一次的 mid + return left - 1 + //return res +} + +func newtonSqrt(x int) int { + if x == 0 { + return 0 + } + + r := x + //除数不能为0 + for r > x/r { + r = (r + x/r) / 2 + } + return r +} diff --git a/Week_03/G20200343030373/LeetCode_74_373/LeetCode_74_373_test.go b/Week_03/G20200343030373/LeetCode_74_373/LeetCode_74_373_test.go new file mode 100644 index 00000000..187671b5 --- /dev/null +++ b/Week_03/G20200343030373/LeetCode_74_373/LeetCode_74_373_test.go @@ -0,0 +1,55 @@ +//https://leetcode-cn.com/problems/search-a-2d-matrix/ +package search_2d_matrix_t_test + +import ( + "github.com/stretchr/testify/assert" + "testing" +) + +func TestSearchMatrix(t *testing.T) { + t.Log("Binary Search: Search 2d Matrix") + matrix1 := [][]int{ + {1, 3, 5, 7}, + {10, 11, 16, 20}, + {23, 30, 34, 50}, + } + assert.Equal(t, true, searchMatrix(matrix1, 3)) + + matrix2 := [][]int{ + {1, 3, 5, 7}, + {10, 11, 16, 20}, + {23, 30, 34, 50}, + } + assert.Equal(t, false, searchMatrix(matrix2, 13)) +} + +func searchMatrix(matrix [][]int, target int) bool { + if len(matrix) == 0 || len(matrix[0]) == 0 { + return false + } + + l, r := 0, len(matrix)-1 + for l < r { + mid := (l + r + 1) >> 1 + if matrix[mid][0] > target { + r = mid - 1 + } else { + l = mid + } + } + if matrix[l][0] > target { + return false + } + + array := matrix[l] + l, r = 0, len(array)-1 + for l < r { + mid := (l + r) >> 1 + if array[mid] < target { + l = mid + 1 + } else { + r = mid + } + } + return array[l] == target +} diff --git a/Week_03/G20200343030375/LeetCode_33_375.java b/Week_03/G20200343030375/LeetCode_33_375.java new file mode 100644 index 00000000..56db9775 --- /dev/null +++ b/Week_03/G20200343030375/LeetCode_33_375.java @@ -0,0 +1,21 @@ +package G20200343030375; + +public class LeetCode_33_375 { + public int search(int[] nums, int target) { + int left = 0; + int right = nums.length-1; + while(left < right ){ + int mid = (left + right)/2; + //左侧有序 && 目标大于mid,或目标小于开始0,说明目标不在左边 + if(nums[0] <= nums[mid] &&(target > nums[mid] || target nums[mid] && target < nums[0]) { + left = mid + 1; + } else { + right = mid; + } + } + return left == right && nums[left] == target ? left : -1; + + } +} diff --git a/Week_03/G20200343030375/LeetCode_74_375.java b/Week_03/G20200343030375/LeetCode_74_375.java new file mode 100644 index 00000000..fb5b4700 --- /dev/null +++ b/Week_03/G20200343030375/LeetCode_74_375.java @@ -0,0 +1,14 @@ +package G20200343030375; + +public class LeetCode_74_375 { + public boolean searchMatrix(int[][] matrix, int target) { + for(int i=0;i prices[i - 1]) { + maxProfit += prices[i] - prices[i - 1]; + } + } + return maxProfit; + } + + public int maxProfit1(int[] prices) { + if (prices.length == 0) { + return 0; + } + int valley = prices[0]; + int peek = prices[0]; + int i = 0; + int maxProfit = 0; + while (i < prices.length - 1) { + while (i < prices.length - 1 && prices[i] >= prices[i + 1]) { + i++; + } + valley = prices[i]; + while (i < prices.length - 1 && prices[i] <= prices[i + 1]) { + i++; + } + peek = prices[i]; + maxProfit += peek - valley; + } + return maxProfit; + } +} diff --git a/Week_03/G20200343030377/LeetCode_200_377.java b/Week_03/G20200343030377/LeetCode_200_377.java new file mode 100644 index 00000000..3e42f001 --- /dev/null +++ b/Week_03/G20200343030377/LeetCode_200_377.java @@ -0,0 +1,35 @@ +class Solution { + int m; + int n; + public int numIslands(char[][] grid) { + m = grid.length; + if(m==0){ + return 0; + } + n = grid[0].length; + int count = 0; + for(int i=0; i=m || j>=n || grid[i][j]=='0'){ + return; + } + grid[i][j]='0'; + dfsMarking(grid, i+1,j); + dfsMarking(grid, i-1,j); + dfsMarking(grid, i,j+1); + dfsMarking(grid, i,j-1); + } +} + + + + diff --git a/Week_03/G20200343030377/LeetCode_33_377.java b/Week_03/G20200343030377/LeetCode_33_377.java new file mode 100644 index 00000000..00f49b6b --- /dev/null +++ b/Week_03/G20200343030377/LeetCode_33_377.java @@ -0,0 +1,26 @@ +class Solution { + public int search(int[] nums, int target) { + int left = 0; + int right = nums.length - 1; + while(left <= right){ + int mid = left + (right-left)/2; + if(nums[mid]==target){ + return mid; + } + if(nums[left]<=nums[mid]){ + if(target>=nums[left] && targetnums[mid]){ + left = mid+1; + }else{ + right = mid-1; + } + } + } + return -1; + } +} diff --git a/Week_03/G20200343030377/LeetCode_455_377.java b/Week_03/G20200343030377/LeetCode_455_377.java new file mode 100644 index 00000000..f26efa0c --- /dev/null +++ b/Week_03/G20200343030377/LeetCode_455_377.java @@ -0,0 +1,16 @@ +class Solution { + public int findContentChildren(int[] g, int[] s) { + Arrays.sort(g); + Arrays.sort(s); + int g1 = 0, s1 = 0; + while (g1 < g.length && s1 < s.length) { + if (g[g1] <= s[s1]) { + g1++; + s1++; + } else { + s1++; + } + } + return g1; + } +} diff --git a/Week_03/G20200343030377/LeetCode_860_377.java b/Week_03/G20200343030377/LeetCode_860_377.java new file mode 100644 index 00000000..358a3cad --- /dev/null +++ b/Week_03/G20200343030377/LeetCode_860_377.java @@ -0,0 +1,26 @@ +class Solution { + public boolean lemonadeChange(int[] bills) { + int five = 0, ten = 0; + for (int bill : bills) { + if (bill == 5) { + five++; + } else if (bill == 10) { + if (five == 0) { + return false; + } + five--; + ten++; + } else if (bill == 20) { + if (five > 0 && ten > 0) { + five--; + ten--; + } else if (five >= 3) { + five -= 3; + } else { + return false; + } + } + } + return true; + } +} diff --git a/Week_03/G20200343030377/LeetCode_874_377.java b/Week_03/G20200343030377/LeetCode_874_377.java new file mode 100644 index 00000000..33ab0a90 --- /dev/null +++ b/Week_03/G20200343030377/LeetCode_874_377.java @@ -0,0 +1,29 @@ +class Solution { + public int robotSim(int[] commands, int[][] obstacles) { + int[] dx = {0, 1, 0, -1}; + int[] dy = {1, 0, -1, 0}; + int x = 0, y = 0, di = 0, res = 0; + Set obsSet = new HashSet(); + for (int[] obs : obstacles) { + obsSet.add(obs[0] + " " + obs[1]); + } + for (int cmd : commands) { + if (cmd == -2) { + di = (di + 3) % 4; + } else if (cmd == -1) { + di = (di + 1) % 4; + } else { + for (int k = 0; k < cmd; k++) { + int nx = x + dx[di]; + int ny = y + dy[di]; + if (!obsSet.contains(nx + " " + ny)) { + x = nx; + y = ny; + res = Math.max(res, x * x + y * y); + } + } + } + } + return res; + } +} diff --git a/Week_03/G20200343030379/LeetCode_102_379.java b/Week_03/G20200343030379/LeetCode_102_379.java new file mode 100644 index 00000000..8043c079 --- /dev/null +++ b/Week_03/G20200343030379/LeetCode_102_379.java @@ -0,0 +1,108 @@ +package G20200343030379; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Deque; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Queue; +import java.util.Set; +import java.util.concurrent.RecursiveTask; + +/** + * 102. IJα + * һ䰴αĽڵֵ أҷнڵ㣩 + * + * : + * :?[3,9,20,null,null,15,7], + * + * 3 + * / \ + * 9 20 + * / \ + * 15 7 + * α + * + * [ + * [3], + * [9,20], + * [15,7] + * ] + * + * ԴۣLeetCode + * ӣhttps://leetcode-cn.com/problems/binary-tree-level-order-traversal + * ȨСҵתϵٷȨҵתע + * + * ⣺ + */ + + + +public class LeetCode_102_379 { + public class TreeNode { + int val; + TreeNode left; + TreeNode right; + TreeNode(int x) { val = x; } + } + + //- + public List> levelOrder(TreeNode root) { + List> res=new ArrayList<>(); + if(root==null) return res; + + Queue queue=new LinkedList(); + //1 ͷ + queue.add(root); + + //2. + while(!queue.isEmpty()){ + int size=queue.size(); + List temp=new ArrayList<>(); + //2.1 ǰ + for (int i = 0; i < size; i++) { + TreeNode node = queue.poll(); + //2.1.1 ѡǰԪ + temp.add(node.val); + + //2.1.2 ѯй + if (node.left != null) { + queue.add(node.left); + } + if (node.right != null) { + queue.add(node.right); + } + } + + //2.2 ռÿһ + res.add(temp); + } + + return res; + } + + //ݹ鷨- + public List> levelOrder2(TreeNode root) { + List> res=new ArrayList<>(); + + + helper(res,root,0); + + return res; + } + + private void helper(List> res, TreeNode root, int depth) { + if(root==null) return; + if(depth==res.size()) res.add(new ArrayList<>()); + res.get(depth).add(root.val); + + //ݹ + if(root.left!=null) helper(res,root.left,depth+1); + if(root.right!=null) helper(res,root.right,depth+1); + } + + +} diff --git a/Week_03/G20200343030379/LeetCode_122_379.java b/Week_03/G20200343030379/LeetCode_122_379.java new file mode 100644 index 00000000..391e1d4d --- /dev/null +++ b/Week_03/G20200343030379/LeetCode_122_379.java @@ -0,0 +1,62 @@ +package G20200343030379; + +import java.util.Arrays; + +/** + * 122. Ʊʱ II + * + * һ飬ĵ?i Ԫһ֧Ʊ i ļ۸ + * + * һ㷨ܻȡԾܵɸĽףһ֧Ʊ + * + * ע⣺㲻ͬʱʽףٴιǰ۵֮ǰĹƱ + * + * ʾ 1: + * + * : [7,1,5,3,6,4] + * : 7 + * : ڵ 2 죨Ʊ۸ = 1ʱ룬ڵ 3 죨Ʊ۸ = 5ʱ, ʽܻ = 5-1 = 4 + * ? ڵ 4 죨Ʊ۸ = 3ʱ룬ڵ 5 죨Ʊ۸ = 6ʱ, ʽܻ = 6-3 = 3 + * ʾ 2: + * + * : [1,2,3,4,5] + * : 4 + * : ڵ 1 죨Ʊ۸ = 1ʱ룬ڵ 5 Ʊ۸ = 5ʱ, ʽܻ = 5-1 = 4 + * ? ע㲻ڵ 1 ͵ 2 Ʊ֮ٽ + * ? Ϊͬʱ˶ʽףٴιǰ۵֮ǰĹƱ + * ʾ?3: + * + * : [7,6,4,3,1] + * : 0 + * : , ûн, Ϊ 0 + * + * ԴۣLeetCode + * ӣhttps://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii + * ȨСҵתϵٷȨҵתע + * + * ⣺ + * https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/solution/mai-mai-gu-piao-de-zui-jia-shi-ji-ii-by-leetcode/ + */ + + + +public class LeetCode_122_379 { + + /** + * ̰㷨 + * @param prices + * @return + */ + public int maxProfit(int[] prices) { + int maxValue=0; + for (int i = 1; i < prices.length; i++) { + //ǰһļ۸ڵļ۸ߣǰһ + if(prices[i]>prices[i-1]){ + maxValue+=prices[i]-prices[i-1]; + } + } + + return maxValue; + } + +} diff --git a/Week_03/G20200343030379/LeetCode_126_379.java b/Week_03/G20200343030379/LeetCode_126_379.java new file mode 100644 index 00000000..c0525088 --- /dev/null +++ b/Week_03/G20200343030379/LeetCode_126_379.java @@ -0,0 +1,216 @@ +package G20200343030379; + + + + + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Queue; +import java.util.Set; + +/** + * 126. ʽ II + * ʣbeginWord endWordһֵ wordListҳд beginWord endWord תСתѭ¹ + * + * ÿתֻܸıһĸ + * תем䵥ʱֵеĵʡ + * ˵: + * + * תУһб + * еʾͬijȡ + * еֻСдĸɡ + * ֵвظĵʡ + * Լ beginWord endWord ǷǿյģҶ߲ͬ + * ʾ 1: + * + * : + * beginWord = "hit", + * endWord = "cog", + * wordList = ["hot","dot","dog","lot","log","cog"] + * + * : + * [ + * ["hit","hot","dot","dog","cog"], + * ? ["hit","hot","lot","log","cog"] + * ] + * ʾ 2: + * + * : + * beginWord = "hit" + * endWord = "cog" + * wordList = ["hot","dot","dog","lot","log"] + * + * : [] + * + * :?endWord "cog" ֵУԲڷҪתС + * + * ԴۣLeetCode + * ӣhttps://leetcode-cn.com/problems/word-ladder-ii + * ȨСҵתϵٷȨҵתע + * + * ⣨ȫֵŻ㷨 + * https://leetcode.com/problems/word-ladder-ii/discuss/40477/Super-fast-Java-solution-(two-end-BFS) + * + * + * https://leetcode.com/problems/word-ladder-ii/discuss/40475/My-concise-JAVA-solution-based-on-BFS-and-DFS + * https://leetcode-cn.com/problems/word-ladder-ii/solution/bfs-dfs-by-powcai/ + */ + + + +public class LeetCode_126_379 { + /*** + * ע⣬ʵΪһ + * 1while (size-- >0){ÿһζУһ㣬 + * 2 ÿܰӽ㣬ܰ·ֻȡ·Ա wordlistﲻarraylistֻhashSetƵģDZƥ䣩.containsƥ + * @param args + */ + public static void main(String[] args) { + /** + * "hit" + * "cog" + * ["hot","dot","dog","lot","log","cog"] + */ + new LeetCode_126_379().findLadders("hit","cog",Arrays.asList("hot","dot","dog","lot","log","cog")); + } + + /** + * + nodeNeighborsÿƥǵ {lot=[dot, log, hot], hit=[hot], log=[cog, dog, lot], dot=[dog, hot, lot], cog=[], hot=[dot, hit, lot], dog=[cog, log, dot]} + dict [lot, hit, log, dot, cog, hot, dog] + distance· {lot=2, hit=0, log=3, dot=2, cog=4, hot=1, dog=3} + Ԥڽ + [["hit","hot","dot","dog","cog"],["hit","hot","lot","log","cog"]] + * @param start + * @param end + * @param wordList + * @return + */ + public List> findLadders(String start, String end, List wordList) { + //· + Map distance=new HashMap<>(); + //set + Set dict=new HashSet<>(wordList); + //ٽֵ + Map> nodeNeighbors=new HashMap<>(); + //ÿһֵ + List solution=new ArrayList<>(); + //ֵ + List> res=new ArrayList<>(); + //ѵһӽȥ·,Ϊ + distance.put(start,0); + dict.add(start); + + + bfs(start,end,dict,nodeNeighbors,distance); + dfs(start,end,nodeNeighbors,distance,res,solution); + + return res; + } + + private void bfs(String start, String end, Set dict, Map> nodeNeighbors, Map distance) { + //ʼÿʵٽֵ + for (String str : dict) { + nodeNeighbors.put(str,new ArrayList<>()); + } + Queue queue=new LinkedList(); + queue.offer(start); + + while (!queue.isEmpty()){ + int size = queue.size(); + //Ƿҵβ + boolean foundEnd=false; + for (int i = 0; i < size; i++) { + String cur = queue.poll(); + //ǰ· + int curDistance = distance.get(cur); + + //ȡÿٽֵ + List neighbors = getNeighbors(cur, dict); + for (String neighbor : neighbors) { + //ӵٽ + nodeNeighbors.get(cur).add(neighbor); + + //Ƿ + if(!distance.containsKey(neighbor)){ + //· + distance.put(neighbor,curDistance+1); + + //ǷENDֵ + if(neighbor.equals(end)){ + foundEnd=true; + }else{ + //ֵ + queue.offer(neighbor); + } + + } + } + + + } + + //ҵβٲ + if(foundEnd){ + break; + } + } + + } + + private void dfs(String cur, String end, Map> nodeNeighbors, Map distance,List> res, List solution) { + //ÿԪ + solution.add(cur); + + //ֵ׷ӵβ + if(cur.equals(end)){ + res.add(new ArrayList<>(solution)); + //עⲻҪreturnº治ܳѡ񣬵» + }else{ + //ǰٽֵ + for (String neighbor : nodeNeighbors.get(cur)) { + //·жǷݹҪϲ·Ƚϵǰ·Ҫ1 + if(distance.get(neighbor)==distance.get(cur)+1){ + dfs(neighbor,end,nodeNeighbors,distance,res,solution); + } + } + } + + + //ѡ + solution.remove(solution.size()-1); + } + + + /** + * ǰַַ + * @param node ʼ + * @param dict б + * @return + */ + private List getNeighbors(String node, Set dict) { + List res=new ArrayList<>(); + char[] chars = node.toCharArray(); + for (int i = 0; i < chars.length; i++) { + char old=chars[i]; + for(char c='a';c<='z';c++){ + chars[i]=c; + String next = new String(chars); + if(dict.contains(next)){ + res.add(next); + } + } + chars[i]=old; + } + return res; + } + + + +} diff --git a/Week_03/G20200343030379/LeetCode_127_379.java b/Week_03/G20200343030379/LeetCode_127_379.java new file mode 100644 index 00000000..7e909647 --- /dev/null +++ b/Week_03/G20200343030379/LeetCode_127_379.java @@ -0,0 +1,623 @@ +package G20200343030379; + + +import java.util.Arrays; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; +import java.util.Set; + +/** + * 127. ʽ + * + * ʣbeginWord? endWordһֵ䣬ҵ?beginWord ?endWord תеijȡתѭ¹ + * + * ÿתֻܸıһĸ + * תем䵥ʱֵеĵʡ + * ˵: + * + * תУ 0 + * еʾͬijȡ + * еֻСдĸɡ + * ֵвظĵʡ + * Լ beginWord endWord ǷǿյģҶ߲ͬ + * ʾ?1: + * + * : + * beginWord = "hit", + * endWord = "cog", + * wordList = ["hot","dot","dog","lot","log","cog"] + * + * : 5 + * + * : һת "hit" -> "hot" -> "dot" -> "dog" -> "cog", + * ij 5 + * ʾ 2: + * + * : + * beginWord = "hit" + * endWord = "cog" + * wordList = ["hot","dot","dog","lot","log"] + * + * :?0 + * + * :?endWord "cog" ֵУ޷ת + * + * ԴۣLeetCode + * ӣhttps://leetcode-cn.com/problems/word-ladder + * ȨСҵתϵٷȨҵתע + * + * ⣨ȫֵŻ㷨https://leetcode-cn.com/problems/word-ladder/solution/suan-fa-shi-xian-he-you-hua-javashuang-xiang-bfs23/ + */ + + + +public class LeetCode_127_379 { + /*** + * ע⣬ʵΪһ + * 1while (size-- >0){ÿһζУһ㣬 + * 2 ÿܰӽ㣬ܰ·ֻȡ·Ա wordlistﲻarraylistֻhashSetƵģDZƥ䣩.containsƥ + * @param args + */ + public static void main(String[] args) { +// int i = new LeetCode_127_379().ladderLength3("hit", "cog", +// Arrays.asList("hot","cog","dog","lot","log","cog")); +// int i = new LeetCode_127_379().ladderLength("qa", "sq", +// Arrays.asList("si","go","se","cm","so","ph","mt","db","mb","sb","kr","ln","tm","le","av","sm","ar","ci","ca","br","ti","ba","to","ra","fa","yo","ow","sn","ya","cr","po","fe","ho","ma","re","or","rn","au","ur","rh","sr","tc","lt","lo","as","fr","nb","yb","if","pb","ge","th","pm","rb","sh","co","ga","li","ha","hz","no","bi","di","hi","qa","pi","os","uh","wm","an","me","mo","na","la","st","er","sc","ne","mn","mi","am","ex","pt","io","be","fm","ta","tb","ni","mr","pa","he","lr","sq","ye")); //5 + long start= System.currentTimeMillis(); + List strings = Arrays.asList("ricky","grind","cubic","panic","lover","farce","gofer","sales","flint","omens","lipid","briny","cloth","anted","slime","oaten","harsh","touts","stoop","cabal","lazed","elton","skunk","nicer","pesky","kusch","bused","kinda","tunis","enjoy","aches","prowl","babar","rooms","burst","slush","pines","urine","pinky","bayed","mania","light","flare","wares","women","verne","moron","shine","bluer","zeros","bleak","brief","tamra","vasts","jamie","lairs","penal","worst","yowls","pills","taros","addle","alyce","creep","saber","floyd","cures","soggy","vexed","vilma","cabby","verde","euler","cling","wanna","jenny","donor","stole","sakha","blake","sanes","riffs","forge","horus","sered","piked","prosy","wases","glove","onset","spake","benin","talks","sites","biers","wendy","dante","allan","haven","nears","shaka","sloth","perky","spear","spend","clint","dears","sadly","units","vista","hinds","marat","natal","least","bough","pales","boole","ditch","greys","slunk","bitch","belts","sense","skits","monty","yawns","music","hails","alien","gibes","lille","spacy","argot","wasps","drubs","poops","bella","clone","beast","emend","iring","start","darla","bells","cults","dhaka","sniff","seers","bantu","pages","fever","tacky","hoses","strop","climb","pairs","later","grant","raven","stael","drips","lucid","awing","dines","balms","della","galen","toned","snips","shady","chili","fears","nurse","joint","plump","micky","lions","jamal","queer","ruins","frats","spoof","semen","pulps","oldie","coors","rhone","papal","seals","spans","scaly","sieve","klaus","drums","tided","needs","rider","lures","treks","hares","liner","hokey","boots","primp","laval","limes","putts","fonda","damon","pikes","hobbs","specs","greet","ketch","braid","purer","tsars","berne","tarts","clean","grate","trips","chefs","timex","vicky","pares","price","every","beret","vices","jodie","fanny","mails","built","bossy","farms","pubic","gongs","magma","quads","shell","jocks","woods","waded","parka","jells","worse","diner","risks","bliss","bryan","terse","crier","incur","murky","gamed","edges","keens","bread","raced","vetch","glint","zions","porno","sizes","mends","ached","allie","bands","plank","forth","fuels","rhyme","wimpy","peels","foggy","wings","frill","edgar","slave","lotus","point","hints","germs","clung","limed","loafs","realm","myron","loopy","plush","volts","bimbo","smash","windy","sours","choke","karin","boast","whirr","tiber","dimes","basel","cutes","pinto","troll","thumb","decor","craft","tared","split","josue","tramp","screw","label","lenny","apses","slept","sikhs","child","bouts","cites","swipe","lurks","seeds","fists","hoard","steed","reams","spoil","diego","peale","bevel","flags","mazes","quart","snipe","latch","lards","acted","falls","busby","holed","mummy","wrong","wipes","carlo","leers","wails","night","pasty","eater","flunk","vedas","curse","tyros","mirth","jacky","butte","wired","fixes","tares","vague","roved","stove","swoon","scour","coked","marge","cants","comic","corns","zilch","typos","lives","truer","comma","gaily","teals","witty","hyper","croat","sways","tills","hones","dowel","llano","clefs","fores","cinch","brock","vichy","bleed","nuder","hoyle","slams","macro","arabs","tauts","eager","croak","scoop","crime","lurch","weals","fates","clipt","teens","bulls","domed","ghana","culls","frame","hanky","jared","swain","truss","drank","lobby","lumps","pansy","whews","saris","trite","weeps","dozes","jeans","flood","chimu","foxes","gelds","sects","scoff","poses","mares","famed","peers","hells","laked","zests","wring","steal","snoot","yodel","scamp","ellis","bandy","marry","jives","vises","blurb","relay","patch","haley","cubit","heine","place","touch","grain","gerry","badly","hooke","fuchs","savor","apron","judge","loren","britt","smith","tammy","altar","duels","huber","baton","dived","apace","sedan","basts","clark","mired","perch","hulks","jolly","welts","quack","spore","alums","shave","singe","lanny","dread","profs","skeet","flout","darin","newed","steer","taine","salvo","mites","rules","crash","thorn","olive","saves","yawed","pique","salon","ovens","dusty","janie","elise","carve","winds","abash","cheep","strap","fared","discs","poxed","hoots","catch","combo","maize","repay","mario","snuff","delve","cored","bards","sudan","shuns","yukon","jowls","wayne","torus","gales","creek","prove","needy","wisps","terri","ranks","books","dicky","tapes","aping","padre","roads","nines","seats","flats","rains","moira","basic","loves","pulls","tough","gills","codes","chest","teeny","jolts","woody","flame","asked","dulls","hotly","glare","mucky","spite","flake","vines","lindy","butts","froth","beeps","sills","bunny","flied","shaun","mawed","velds","voled","doily","patel","snake","thigh","adler","calks","desks","janus","spunk","baled","match","strip","hosed","nippy","wrest","whams","calfs","sleet","wives","boars","chain","table","duked","riped","edens","galas","huffs","biddy","claps","aleut","yucks","bangs","quids","glenn","evert","drunk","lusts","senna","slate","manet","roted","sleep","loxes","fluky","fence","clamp","doted","broad","sager","spark","belch","mandy","deana","beyer","hoist","leafy","levee","libel","tonic","aloes","steam","skews","tides","stall","rifts","saxon","mavis","asama","might","dotes","tangs","wroth","kited","salad","liens","clink","glows","balky","taffy","sided","sworn","oasis","tenth","blurt","tower","often","walsh","sonny","andes","slump","scans","boded","chive","finer","ponce","prune","sloes","dined","chums","dingo","harte","ahead","event","freer","heart","fetch","sated","soapy","skins","royal","cuter","loire","minot","aisle","horny","slued","panel","eight","snoop","pries","clive","pored","wrist","piped","daren","cells","parks","slugs","cubed","highs","booze","weary","stain","hoped","finny","weeds","fetid","racer","tasks","right","saint","shahs","basis","refer","chart","seize","lulls","slant","belay","clots","jinny","tours","modes","gloat","dunks","flute","conch","marts","aglow","gayer","lazes","dicks","chime","bears","sharp","hatch","forms","terry","gouda","thins","janet","tonya","axons","sewed","danny","rowdy","dolts","hurry","opine","fifty","noisy","spiky","humid","verna","poles","jayne","pecos","hooky","haney","shams","snots","sally","ruder","tempe","plunk","shaft","scows","essie","dated","fleet","spate","bunin","hikes","sodas","filly","thyme","fiefs","perks","chary","kiths","lidia","lefty","wolff","withe","three","crawl","wotan","brown","japed","tolls","taken","threw","crave","clash","layer","tends","notes","fudge","musky","bawdy","aline","matts","shirr","balks","stash","wicks","crepe","foods","fares","rotes","party","petty","press","dolly","mangy","leeks","silly","leant","nooks","chapt","loose","caged","wages","grist","alert","sheri","moody","tamps","hefts","souls","rubes","rolex","skulk","veeps","nonce","state","level","whirl","bight","grits","reset","faked","spiny","mixes","hunks","major","missy","arius","damns","fitly","caped","mucus","trace","surat","lloyd","furry","colin","texts","livia","reply","twill","ships","peons","shear","norms","jumbo","bring","masks","zippy","brine","dorks","roded","sinks","river","wolfs","strew","myths","pulpy","prank","veins","flues","minus","phone","banns","spell","burro","brags","boyle","lambs","sides","knees","clews","aired","skirt","heavy","dimer","bombs","scums","hayes","chaps","snugs","dusky","loxed","ellen","while","swank","track","minim","wiled","hazed","roofs","cantu","sorry","roach","loser","brass","stint","jerks","dirks","emory","campy","poise","sexed","gamer","catty","comte","bilbo","fasts","ledge","drier","idles","doors","waged","rizal","pured","weirs","crisp","tasty","sored","palmy","parts","ethel","unify","crows","crest","udder","delis","punks","dowse","totes","emile","coded","shops","poppa","pours","gushy","tiffs","shads","birds","coils","areas","boons","hulls","alter","lobes","pleat","depth","fires","pones","serra","sweat","kline","malay","ruled","calve","tired","drabs","tubed","wryer","slung","union","sonya","aided","hewed","dicey","grids","nixed","whits","mills","buffs","yucky","drops","ready","yuppy","tweet","napes","cadre","teach","rasps","dowdy","hoary","canto","posed","dumbo","kooks","reese","snaky","binge","byron","phony","safer","friar","novel","scale","huron","adorn","carla","fauna","myers","hobby","purse","flesh","smock","along","boils","pails","times","panza","lodge","clubs","colby","great","thing","peaks","diana","vance","whets","bergs","sling","spade","soaks","beach","traps","aspen","romps","boxed","fakir","weave","nerds","swazi","dotty","curls","diver","jonas","waite","verbs","yeast","lapel","barth","soars","hooks","taxed","slews","gouge","slags","chang","chafe","saved","josie","syncs","fonds","anion","actor","seems","pyrex","isiah","glued","groin","goren","waxes","tonia","whine","scads","knelt","teaks","satan","tromp","spats","merry","wordy","stake","gland","canal","donna","lends","filed","sacks","shied","moors","paths","older","pooch","balsa","riced","facet","decaf","attic","elder","akron","chomp","chump","picky","money","sheer","bolls","crabs","dorms","water","veers","tease","dummy","dumbs","lethe","halls","rifer","demon","fucks","whips","plops","fuses","focal","taces","snout","edict","flush","burps","dawes","lorry","spews","sprat","click","deann","sited","aunts","quips","godly","pupil","nanny","funks","shoon","aimed","stacy","helms","mints","banks","pinch","local","twine","pacts","deers","halos","slink","preys","potty","ruffs","pusan","suits","finks","slash","prods","dense","edsel","heeds","palls","slats","snits","mower","rares","ailed","rouge","ellie","gated","lyons","duded","links","oaths","letha","kicks","firms","gravy","month","kongo","mused","ducal","toted","vocal","disks","spied","studs","macao","erick","coupe","starr","reaps","decoy","rayon","nicks","breed","cosby","haunt","typed","plain","trays","muled","saith","drano","cower","snows","buses","jewry","argus","doers","flays","swish","resin","boobs","sicks","spies","bails","wowed","mabel","check","vapid","bacon","wilda","ollie","loony","irked","fraud","doles","facts","lists","gazed","furls","sunks","stows","wilde","brick","bowed","guise","suing","gates","niter","heros","hyped","clomp","never","lolls","rangy","paddy","chant","casts","terns","tunas","poker","scary","maims","saran","devon","tripe","lingo","paler","coped","bride","voted","dodge","gross","curds","sames","those","tithe","steep","flaks","close","swops","stare","notch","prays","roles","crush","feuds","nudge","baned","brake","plans","weepy","dazed","jenna","weiss","tomes","stews","whist","gibed","death","clank","cover","peeks","quick","abler","daddy","calls","scald","lilia","flask","cheer","grabs","megan","canes","jules","blots","mossy","begun","freak","caved","hello","hades","theed","wards","darcy","malta","peter","whorl","break","downs","odder","hoofs","kiddo","macho","fords","liked","flees","swing","elect","hoods","pluck","brook","astir","bland","sward","modal","flown","ahmad","waled","craps","cools","roods","hided","plath","kings","grips","gives","gnats","tabby","gauls","think","bully","fogey","sawed","lints","pushy","banes","drake","trail","moral","daley","balds","chugs","geeky","darts","soddy","haves","opens","rends","buggy","moles","freud","gored","shock","angus","puree","raves","johns","armed","packs","minis","reich","slots","totem","clown","popes","brute","hedge","latin","stoke","blend","pease","rubik","greer","hindi","betsy","flows","funky","kelli","humps","chewy","welds","scowl","yells","cough","sasha","sheaf","jokes","coast","words","irate","hales","camry","spits","burma","rhine","bends","spill","stubs","power","voles","learn","knoll","style","twila","drove","dacca","sheen","papas","shale","jones","duped","tunny","mouse","floss","corks","skims","swaps","inned","boxer","synch","skies","strep","bucks","belau","lower","flaky","quill","aural","rufus","floes","pokes","sends","sates","dally","boyer","hurts","foyer","gowns","torch","luria","fangs","moats","heinz","bolts","filet","firth","begot","argue","youth","chimp","frogs","kraft","smite","loges","loons","spine","domes","pokey","timur","noddy","doggy","wades","lanes","hence","louts","turks","lurid","goths","moist","bated","giles","stood","winos","shins","potts","brant","vised","alice","rosie","dents","babes","softy","decay","meats","tanya","rusks","pasts","karat","nuked","gorge","kinks","skull","noyce","aimee","watch","cleat","stuck","china","testy","doses","safes","stage","bayes","twins","limps","denis","chars","flaps","paces","abase","grays","deans","maria","asset","smuts","serbs","whigs","vases","robyn","girls","pents","alike","nodal","molly","swigs","swill","slums","rajah","bleep","beget","thanh","finns","clock","wafts","wafer","spicy","sorer","reach","beats","baker","crown","drugs","daisy","mocks","scots","fests","newer","agate","drift","marta","chino","flirt","homed","bribe","scram","bulks","servo","vesta","divas","preps","naval","tally","shove","ragas","blown","droll","tryst","lucky","leech","lines","sires","pyxed","taper","trump","payee","midge","paris","bored","loads","shuts","lived","swath","snare","boned","scars","aeons","grime","writs","paige","rungs","blent","signs","davis","dials","daubs","rainy","fawns","wrier","golds","wrath","ducks","allow","hosea","spike","meals","haber","muses","timed","broom","burks","louis","gangs","pools","vales","altai","elope","plied","slain","chasm","entry","slide","bawls","title","sings","grief","viola","doyle","peach","davit","bench","devil","latex","miles","pasha","tokes","coves","wheel","tried","verdi","wanda","sivan","prior","fryer","plots","kicky","porch","shill","coats","borne","brink","pawed","erwin","tense","stirs","wends","waxen","carts","smear","rival","scare","phase","bragg","crane","hocks","conan","bests","dares","molls","roots","dunes","slips","waked","fours","bolds","slosh","yemen","poole","solid","ports","fades","legal","cedes","green","curie","seedy","riper","poled","glade","hosts","tools","razes","tarry","muddy","shims","sword","thine","lasts","bloat","soled","tardy","foots","skiff","volta","murks","croci","gooks","gamey","pyxes","poems","kayla","larva","slaps","abuse","pings","plows","geese","minks","derby","super","inked","manic","leaks","flops","lajos","fuzes","swabs","twigs","gummy","pyres","shrew","islet","doled","wooly","lefts","hunts","toast","faith","macaw","sonia","leafs","colas","conks","altos","wiped","scene","boors","patsy","meany","chung","wakes","clear","ropes","tahoe","zones","crate","tombs","nouns","garth","puked","chats","hanks","baked","binds","fully","soaps","newel","yarns","puers","carps","spelt","lully","towed","scabs","prime","blest","patty","silky","abner","temps","lakes","tests","alias","mines","chips","funds","caret","splat","perry","turds","junks","cramp","saned","peary","snarl","fired","stung","nancy","bulge","styli","seams","hived","feast","triad","jaded","elvin","canny","birth","routs","rimed","pusey","laces","taste","basie","malls","shout","prier","prone","finis","claus","loops","heron","frump","spare","menus","ariel","crams","bloom","foxed","moons","mince","mixed","piers","deres","tempt","dryer","atone","heats","dario","hawed","swims","sheet","tasha","dings","clare","aging","daffy","wried","foals","lunar","havel","irony","ronny","naves","selma","gurus","crust","percy","murat","mauro","cowed","clang","biker","harms","barry","thump","crude","ulnae","thong","pager","oases","mered","locke","merle","soave","petal","poser","store","winch","wedge","inlet","nerdy","utter","filth","spray","drape","pukes","ewers","kinds","dates","meier","tammi","spoor","curly","chill","loped","gooey","boles","genet","boost","beets","heath","feeds","growl","livid","midst","rinds","fresh","waxed","yearn","keeps","rimes","naked","flick","plies","deeps","dirty","hefty","messy","hairy","walks","leper","sykes","nerve","rover","jived","brisk","lenin","viper","chuck","sinus","luger","ricks","hying","rusty","kathy","herds","wider","getty","roman","sandy","pends","fezes","trios","bites","pants","bless","diced","earth","shack","hinge","melds","jonah","chose","liver","salts","ratty","ashed","wacky","yokes","wanly","bruce","vowel","black","grail","lungs","arise","gluts","gluey","navel","coyer","ramps","miter","aldan","booth","musty","rills","darns","tined","straw","kerri","hared","lucks","metes","penny","radon","palms","deeds","earls","shard","pried","tampa","blank","gybes","vicki","drool","groom","curer","cubes","riggs","lanky","tuber","caves","acing","golly","hodge","beard","ginny","jibed","fumes","astor","quito","cargo","randi","gawky","zings","blind","dhoti","sneak","fatah","fixer","lapps","cline","grimm","fakes","maine","erika","dealt","mitch","olden","joist","gents","likes","shelf","silts","goats","leads","marin","spire","louie","evans","amuse","belly","nails","snead","model","whats","shari","quote","tacks","nutty","lames","caste","hexes","cooks","miner","shawn","anise","drama","trike","prate","ayers","loans","botch","vests","cilia","ridge","thugs","outed","jails","moped","plead","tunes","nosed","wills","lager","lacks","cried","wince","berle","flaws","boise","tibet","bided","shred","cocky","brice","delta","congo","holly","hicks","wraps","cocks","aisha","heard","cured","sades","horsy","umped","trice","dorky","curve","ferry","haler","ninth","pasta","jason","honer","kevin","males","fowls","awake","pores","meter","skate","drink","pussy","soups","bases","noyes","torts","bogus","still","soupy","dance","worry","eldon","stern","menes","dolls","dumpy","gaunt","grove","coops","mules","berry","sower","roams","brawl","greed","stags","blurs","swift","treed","taney","shame","easel","moves","leger","ville","order","spock","nifty","brian","elias","idler","serve","ashen","bizet","gilts","spook","eaten","pumas","cotes","broke","toxin","groan","laths","joins","spots","hated","tokay","elite","rawer","fiats","cards","sassy","milks","roost","glean","lutes","chins","drown","marks","pined","grace","fifth","lodes","rusts","terms","maxes","savvy","choir","savoy","spoon","halve","chord","hulas","sarah","celia","deems","ninny","wines","boggy","birch","raved","wales","beams","vibes","riots","warty","nigel","askew","faxes","sedge","sheol","pucks","cynic","relax","boers","whims","bents","candy","luann","slogs","bonny","barns","iambs","fused","duffy","guilt","bruin","pawls","penis","poppy","owing","tribe","tuner","moray","timid","ceded","geeks","kites","curio","puffy","perot","caddy","peeve","cause","dills","gavel","manse","joker","lynch","crank","golda","waits","wises","hasty","paves","grown","reedy","crypt","tonne","jerky","axing","swept","posse","rings","staff","tansy","pared","glaze","grebe","gonna","shark","jumps","vials","unset","hires","tying","lured","motes","linen","locks","mamas","nasty","mamie","clout","nader","velma","abate","tight","dales","serer","rives","bales","loamy","warps","plato","hooch","togae","damps","ofter","plumb","fifes","filmy","wiper","chess","lousy","sails","brahe","ounce","flits","hindu","manly","beaux","mimed","liken","forts","jambs","peeps","lelia","brews","handy","lusty","brads","marne","pesos","earle","arson","scout","showy","chile","sumps","hiked","crook","herbs","silks","alamo","mores","dunce","blaze","stank","haste","howls","trots","creon","lisle","pause","hates","mulch","mined","moder","devin","types","cindy","beech","tuned","mowed","pitts","chaos","colds","bidet","tines","sighs","slimy","brain","belle","leery","morse","ruben","prows","frown","disco","regal","oaken","sheds","hives","corny","baser","fated","throe","revel","bores","waved","shits","elvia","ferns","maids","color","coifs","cohan","draft","hmong","alton","stine","cluck","nodes","emily","brave","blair","blued","dress","bunts","holst","clogs","rally","knack","demos","brady","blues","flash","goofy","blocs","diane","colic","smile","yules","foamy","splay","bilge","faker","foils","condo","knell","crack","gallo","purls","auras","cakes","doves","joust","aides","lades","muggy","tanks","middy","tarps","slack","capet","frays","donny","venal","yeats","misty","denim","glass","nudes","seeps","gibbs","blows","bobbi","shane","yards","pimps","clued","quiet","witch","boxes","prawn","kerry","torah","kinko","dingy","emote","honor","jelly","grins","trope","vined","bagel","arden","rapid","paged","loved","agape","mural","budge","ticks","suers","wendi","slice","salve","robin","bleat","batik","myles","teddy","flatt","puppy","gelid","largo","attar","polls","glide","serum","fundy","sucks","shalt","sewer","wreak","dames","fonts","toxic","hines","wormy","grass","louse","bowls","crass","benny","moire","margo","golfs","smart","roxie","wight","reign","dairy","clops","paled","oddly","sappy","flair","shown","bulgy","benet","larch","curry","gulfs","fends","lunch","dukes","doris","spoke","coins","manna","conga","jinns","eases","dunno","tisha","swore","rhino","calms","irvin","clans","gully","liege","mains","besot","serge","being","welch","wombs","draco","lynda","forty","mumps","bloch","ogden","knits","fussy","alder","danes","loyal","valet","wooer","quire","liefs","shana","toyed","forks","gages","slims","cloys","yates","rails","sheep","nacho","divan","honks","stone","snack","added","basal","hasps","focus","alone","laxes","arose","lamed","wrapt","frail","clams","plait","hover","tacos","mooch","fault","teeth","marva","mucks","tread","waves","purim","boron","horde","smack","bongo","monte","swirl","deals","mikes","scold","muter","sties","lawns","fluke","jilts","meuse","fives","sulky","molds","snore","timmy","ditty","gasps","kills","carey","jawed","byers","tommy","homer","hexed","dumas","given","mewls","smelt","weird","speck","merck","keats","draws","trent","agave","wells","chews","blabs","roves","grieg","evens","alive","mulls","cared","garbo","fined","happy","trued","rodes","thurs","cadet","alvin","busch","moths","guild","staci","lever","widen","props","hussy","lamer","riley","bauer","chirp","rants","poxes","shyer","pelts","funny","slits","tinge","ramos","shift","caper","credo","renal","veils","covey","elmer","mated","tykes","wooed","briar","gears","foley","shoes","decry","hypes","dells","wilds","runts","wilts","white","easts","comer","sammy","lochs","favor","lance","dawns","bushy","muted","elsie","creel","pocks","tenet","cagey","rides","socks","ogled","soils","sofas","janna","exile","barks","frank","takes","zooms","hakes","sagan","scull","heaps","augur","pouch","blare","bulbs","wryly","homey","tubas","limbo","hardy","hoagy","minds","bared","gabby","bilks","float","limns","clasp","laura","range","brush","tummy","kilts","cooed","worms","leary","feats","robes","suite","veals","bosch","moans","dozen","rarer","slyer","cabin","craze","sweet","talon","treat","yanks","react","creed","eliza","sluts","cruet","hafts","noise","seder","flies","weeks","venus","backs","eider","uriel","vouch","robed","hacks","perth","shiny","stilt","torte","throb","merer","twits","reeds","shawl","clara","slurs","mixer","newts","fried","woolf","swoop","kaaba","oozed","mayer","caned","laius","lunge","chits","kenny","lifts","mafia","sowed","piled","stein","whack","colts","warms","cleft","girds","seeks","poets","angel","trade","parsi","tiers","rojas","vexes","bryce","moots","grunt","drain","lumpy","stabs","poohs","leapt","polly","cuffs","giddy","towns","dacha","quoth","provo","dilly","carly","mewed","tzars","crock","toked","speak","mayas","pssts","ocher","motel","vogue","camps","tharp","taunt","drone","taint","badge","scott","scats","bakes","antes","gruel","snort","capes","plate","folly","adobe","yours","papaw","hench","moods","clunk","chevy","tomas","narcs","vonda","wiles","prigs","chock","laser","viced","stiff","rouse","helps","knead","gazer","blade","tumid","avail","anger","egged","guide","goads","rabin","toddy","gulps","flank","brats","pedal","junky","marco","tinny","tires","flier","satin","darth","paley","gumbo","rared","muffs","rower","prude","frees","quays","homes","munch","beefs","leash","aston","colon","finch","bogey","leaps","tempo","posts","lined","gapes","locus","maori","nixes","liven","songs","opted","babel","wader","barer","farts","lisps","koran","lathe","trill","smirk","mamma","viler","scurf","ravel","brigs","cooky","sachs","fulls","goals","turfs","norse","hauls","cores","fairy","pluto","kneed","cheek","pangs","risen","czars","milne","cribs","genes","wefts","vents","sages","seres","owens","wiley","flume","haded","auger","tatty","onion","cater","wolfe","magic","bodes","gulls","gazes","dandy","snags","rowed","quell","spurn","shore","veldt","turns","slavs","coach","stalk","snuck","piles","orate","joyed","daily","crone","wager","solos","earns","stark","lauds","kasey","villa","gnaws","scent","wears","fains","laced","tamer","pipes","plant","lorie","rivet","tamed","cozen","theme","lifer","sunny","shags","flack","gassy","eased","jeeps","shire","fargo","timer","brash","behan","basin","volga","krone","swiss","docks","booed","ebert","gusty","delay","oared","grady","buick","curbs","crete","lucas","strum","besom","gorse","troth","donne","chink","faced","ahmed","texas","longs","aloud","bethe","cacao","hilda","eagle","karyn","harks","adder","verse","drays","cello","taped","snide","taxis","kinky","penes","wicca","sonja","aways","dyers","bolas","elfin","slope","lamps","hutch","lobed","baaed","masts","ashes","ionic","joyce","payed","brays","malts","dregs","leaky","runny","fecal","woven","hurls","jorge","henna","dolby","booty","brett","dykes","rural","fight","feels","flogs","brunt","preen","elvis","dopey","gripe","garry","gamma","fling","space","mange","storm","arron","hairs","rogue","repel","elgar","ruddy","cross","medan","loses","howdy","foams","piker","halts","jewel","avery","stool","cruel","cases","ruses","cathy","harem","flour","meted","faces","hobos","charm","jamar","cameo","crape","hooey","reefs","denny","mitts","sores","smoky","nopes","sooty","twirl","toads","vader","julep","licks","arias","wrote","north","bunks","heady","batch","snaps","claws","fouls","faded","beans","wimps","idled","pulse","goons","noose","vowed","ronda","rajas","roast","allah","punic","slows","hours","metal","slier","meaty","hanna","curvy","mussy","truth","troys","block","reels","print","miffs","busts","bytes","cream","otter","grads","siren","kilos","dross","batty","debts","sully","bares","baggy","hippy","berth","gorky","argon","wacko","harry","smoke","fails","perms","score","steps","unity","couch","kelly","rumps","fines","mouth","broth","knows","becky","quits","lauri","trust","grows","logos","apter","burrs","zincs","buyer","bayer","moose","overt","croon","ousts","lands","lithe","poach","jamel","waive","wiser","surly","works","paine","medal","glads","gybed","paint","lorre","meant","smugs","bryon","jinni","sever","viols","flubs","melts","heads","peals","aiken","named","teary","yalta","styes","heist","bongs","slops","pouts","grape","belie","cloak","rocks","scone","lydia","goofs","rents","drive","crony","orlon","narks","plays","blips","pence","march","alger","baste","acorn","billy","croce","boone","aaron","slobs","idyls","irwin","elves","stoat","doing","globe","verve","icons","trial","olsen","pecks","there","blame","tilde","milky","sells","tangy","wrack","fills","lofty","truce","quark","delia","stowe","marty","overs","putty","coral","swine","stats","swags","weans","spout","bulky","farsi","brest","gleam","beaks","coons","hater","peony","huffy","exert","clips","riven","payer","doped","salas","meyer","dryad","thuds","tilts","quilt","jetty","brood","gulch","corps","tunic","hubby","slang","wreck","purrs","punch","drags","chide","sulks","tints","huger","roped","dopes","booby","rosin","outer","gusto","tents","elude","brows","lease","ceres","laxer","worth","necks","races","corey","trait","stuns","soles","teems","scrip","privy","sight","minor","alisa","stray","spank","cress","nukes","rises","gusts","aurae","karma","icing","prose","biked","grand","grasp","skein","shaky","clump","rummy","stock","twain","zoned","offed","ghats","mover","randy","vault","craws","thees","salem","downy","sangs","chore","cited","grave","spinx","erica","raspy","dying","skips","clerk","paste","moved","rooks","intel","moses","avers","staid","yawls","blast","lyres","monks","gaits","floor","saner","waver","assam","infer","wands","bunch","dryly","weedy","honey","baths","leach","shorn","shows","dream","value","dooms","spiro","raped","shook","stead","moran","ditto","loots","tapir","looms","clove","stops","pinks","soppy","ripen","wench","shone","bauds","doric","leans","nadia","cries","camus","boozy","maris","fools","morns","bides","greek","gauss","roget","lamar","hazes","beefy","dupes","refed","felts","larry","guile","ables","wants","warns","toils","bathe","edger","paced","rinks","shoos","erich","whore","tiger","jumpy","lamas","stack","among","punts","scalp","alloy","solon","quite","comas","whole","parse","tries","reeve","tiled","deena","roomy","rodin","aster","twice","musts","globs","parch","drawn","filch","bonds","tells","droop","janis","holds","scant","lopes","based","keven","whiny","aspic","gains","franz","jerri","steel","rowel","vends","yelps","begin","logic","tress","sunni","going","barge","blood","burns","basks","waifs","bones","skill","hewer","burly","clime","eking","withs","capek","berta","cheap","films","scoot","tweed","sizer","wheat","acton","flung","ponds","tracy","fiver","berra","roger","mutes","burke","miked","valve","whisk","runes","parry","toots","japes","roars","rough","irons","romeo","cages","reeks","cigar","saiph","dully","hangs","chops","rolls","prick","acuff","spent","sulla","train","swell","frets","names","anita","crazy","sixth","blunt","fewer","large","brand","slick","spitz","rears","ogres","toffy","yolks","flock","gnawn","eries","blink","skier","feted","tones","snail","ether","barbs","noses","hears","upset","awash","cloud","trunk","degas","dungs","rated","shall","yeahs","coven","sands","susan","fable","gunny","began","serfs","balls","dinky","madge","prong","spilt","lilly","brawn","comet","spins","raids","dries","sorts","makes","mason","mayra","royce","stout","mealy","pagan","nasal","folds","libby","coups","photo","mosey","amens","speed","lords","board","fetal","lagos","scope","raked","bonus","mutts","willy","sport","bingo","thant","araby","bette","rebel","gases","small","humus","grosz","beset","slays","steve","scrap","blahs","south","pride","heels","tubes","beady","lacey","genus","mauls","vying","spice","sexes","ester","drams","today","comae","under","jests","direr","yoked","tempi","early","boats","jesus","warts","guppy","gilda","quota","token","edwin","ringo","gaped","lemon","hurst","manor","arrow","mists","prize","silas","blobs","diets","ervin","stony","buddy","bates","rabid","ducat","ewing","jaunt","beads","doyen","blush","thoth","tiles","piper","short","peron","alley","decks","shunt","whirs","cushy","roils","betty","plugs","woken","jibes","foray","merak","ruing","becks","whale","shoot","dwelt","spawn","fairs","dozed","celts","blond","tikes","sabin","feint","vamps","cokes","willa","slues","bills","force","curst","yokel","surer","miler","fices","arced","douse","hilly","lucio","tongs","togas","minty","sagas","pates","welsh","bruno","decal","elate","linux","gyros","pryor","mousy","pains","shake","spica","pupal","probe","mount","shirk","purus","kilns","rests","graze","hague","spuds","sweep","momma","burch","maces","samar","brace","riser","booms","build","camel","flyer","synge","sauna","tonga","tings","promo","hides","clair","elisa","bower","reins","diann","lubed","nulls","picks","laban","milch","buber","stomp","bosom","lying","haled","avert","wries","macon","skids","fumed","ogles","clods","antic","nosey","crimp","purge","mommy","cased","taxes","covet","clack","butch","panty","lents","machs","exude","tooth","adore","shuck","asses","after","terra","dices","aryan","regor","romes","stile","cairo","maura","flail","eaves","estes","sousa","visas","baron","civet","kitty","freed","ralph","tango","gawks","cheat","study","fancy","fiber","musks","souse","brims","claim","bikes","venue","sired","thymi","rivas","skimp","pleas","woman","gimpy","cawed","minos","pints","knock","poked","bowen","risky","towel","oinks","linus","heals","pears","codas","inner","pitch","harpy","niger","madly","bumpy","stair","files","nobel","celli","spars","jades","balmy","kooky","plums","trues","gloss","trims","daunt","tubby","dared","wadis","smell","darby","stink","drill","dover","ruler","laden","dikes","layla","fells","maker","joked","horns","these","baize","spahn","whens","edged","mushy","plume","tucks","spurs","husky","dried","bigot","pupas","drily","aware","hagar","newly","knots","pratt","feces","sabik","watts","cooke","riles","seamy","fleas","dusts","barfs","roans","pawns","vivid","kirks","tania","feral","tubae","horne","aries","brits","combs","chunk","stork","waned","texan","elide","glens","emery","autos","trams","dosed","cheri","baits","jacks","whose","fazed","matte","swans","maxed","write","spays","orion","traci","horse","stars","strut","goods","verge","scuff","award","dives","wires","burnt","dimly","sleds","mayan","biped","quirk","sofia","slabs","waste","robby","mayor","fatty","items","bowel","mires","swarm","route","swash","sooth","paved","steak","upend","sough","throw","perts","stave","carry","burgs","hilts","plane","toady","nadir","stick","foist","gnarl","spain","enter","sises","story","scarf","ryder","glums","nappy","sixes","honed","marcy","offer","kneel","leeds","lites","voter","vince","bursa","heave","roses","trees","argos","leann","grimy","zelma","crick","tract","flips","folks","smote","brier","moore","goose","baden","riled","looks","sober","tusks","house","acmes","lubes","chows","neath","vivas","defer","allay","casey","kmart","pests","proms","eying","cider","leave","shush","shots","karla","scorn","gifts","sneer","mercy","copes","faxed","spurt","monet","awoke","rocky","share","gores","drawl","tears","mooed","nones","wined","wrens","modem","beria","hovel","retch","mates","hands","stymy","peace","carat","coots","hotel","karen","hayed","mamet","cuing","paper","rages","suave","reuse","auden","costs","loner","rapes","hazel","rites","brent","pumps","dutch","puffs","noons","grams","teats","cease","honda","pricy","forgo","fleck","hired","silos","merge","rafts","halon","larks","deere","jello","cunts","sifts","boner","morin","mimes","bungs","marie","harts","snobs","sonic","hippo","comes","crops","mango","wrung","garbs","natty","cents","fitch","moldy","adams","sorta","coeds","gilds","kiddy","nervy","slurp","ramon","fuzed","hiker","winks","vanes","goody","hawks","crowd","bract","marla","limbs","solve","gloom","sloop","eaton","memos","tames","heirs","berms","wanes","faint","numbs","holes","grubs","rakes","waist","miser","stays","antis","marsh","skyed","payne","champ","jimmy","clues","fatal","shoed","freon","lopez","snowy","loins","stale","thank","reads","isles","grill","align","saxes","rubin","rigel","walls","beers","wispy","topic","alden","anton","ducts","david","duets","fries","oiled","waken","allot","swats","woozy","tuxes","inter","dunne","known","axles","graph","bumps","jerry","hitch","crews","lucia","banal","grope","valid","meres","thick","lofts","chaff","taker","glues","snubs","trawl","keels","liker","stand","harps","casks","nelly","debby","panes","dumps","norma","racks","scams","forte","dwell","dudes","hypos","sissy","swamp","faust","slake","maven","lowed","lilts","bobby","gorey","swear","nests","marci","palsy","siege","oozes","rates","stunt","herod","wilma","other","girts","conic","goner","peppy","class","sized","games","snell","newsy","amend","solis","duane","troop","linda","tails","woofs","scuds","shies","patti","stunk","acres","tevet","allen","carpi","meets","trend","salty","galls","crept","toner","panda","cohen","chase","james","bravo","styed","coals","oates","swami","staph","frisk","cares","cords","stems","razed","since","mopes","rices","junes","raged","liter","manes","rearm","naive","tyree","medic","laded","pearl","inset","graft","chair","votes","saver","cains","knobs","gamay","hunch","crags","olson","teams","surge","wests","boney","limos","ploys","algae","gaols","caked","molts","glops","tarot","wheal","cysts","husks","vaunt","beaus","fauns","jeers","mitty","stuff","shape","sears","buffy","maced","fazes","vegas","stamp","borer","gaged","shade","finds","frock","plods","skied","stump","ripes","chick","cones","fixed","coled","rodeo","basil","dazes","sting","surfs","mindy","creak","swung","cadge","franc","seven","sices","weest","unite","codex","trick","fusty","plaid","hills","truck","spiel","sleek","anons","pupae","chiba","hoops","trash","noted","boris","dough","shirt","cowls","seine","spool","miens","yummy","grade","proxy","hopes","girth","deter","dowry","aorta","paean","corms","giant","shank","where","means","years","vegan","derek","tales"); + +// int i = new LeetCode_127_379().ladderLength5("nanny", "aloud",strings ); //50 + int i = new LeetCode_127_379().ladderLength("a", "c", Arrays.asList("a","b","c")); + long end= System.currentTimeMillis(); + System.out.println(i); + System.out.println(end-start); + } + + + /** + * ݹ鷨- ʱûгɹDSFעBSFʱ + * ִʱ : + * ڴ + * + * ο⣺ + * + */ + int minCount=Integer.MAX_VALUE; + public int ladderLength(String beginWord, String endWord, List wordList) { + + if(beginWord.equals(endWord)) return 1; + Set visited=new HashSet(); + dfs(beginWord,endWord,wordList,visited,1); + return (minCount==Integer.MAX_VALUE)?0:minCount; + + } + + /* private void dfs(String begin, String end, List wordList,Set visited,int level) { + if(begin.equals(end)){ + if(minCount>level){ + minCount=level; + } + return ; + } + + long start = System.currentTimeMillis(); + for (String word : wordList) { + if (visited.contains(word)) { + continue; + } + int diff=0; + for (int i = 0; i < begin.length(); i++) { + if (begin.charAt(i)!=word.charAt(i)) { + if(++diff >1){ + break; + } + } + + } + if(diff==1 && !visited.contains(word)){ + visited.add(word); + dfs(word,end,wordList,visited,level+1); + // visited.remove(word); + } + } + long end1 =System.currentTimeMillis(); + *//***ڵݹ飬ʵ׼***//* + System.out.println("ִʱ"+(end1-start)); + }*/ + private void dfs(String begin, String end, List wordList,Set visited,int level) { + if(begin.equals(end)){ + if(minCount>level){ + minCount=level; + } + return ; + } + visited.add(begin); + char[] chars = begin.toCharArray(); + for (int i = 0; i < chars.length; i++) { + char old=chars[i]; + for (char c='a' ;c<='z';c++) { + chars[i] = c; + + String next=new String(chars); + + /*if(end.equals(next)){ + //level++; + return; + }*/ + if(!visited.contains(next) && wordList.contains(next)){ + System.out.println(next); + visited.add(next); + dfs(next,end,wordList,visited,level+1); + visited.remove(next); + } + } + chars[i]=old; + } + } + + /** + * BSF ĸƴӷ1 + * -(ע⣺־ɺעⲻҪ) + * + * ִʱ : 231 ms , Java ύл 38.35% û + * ڴ : 43.7 MB , Java ύл 29.44% û + * + * ο⣺ + * https://leetcode.com/problems/word-ladder/discuss/40728/Simple-Java-BFS-solution-with-explanation + * https://leetcode-cn.com/problems/word-ladder/solution/suan-fa-shi-xian-he-you-hua-javashuang-xiang-bfs23/ ˼·5 + * + */ + public int ladderLength2(String beginWord, String endWord, List wordList) { + if(beginWord.equals(endWord)){ + return 0; + } + + Queue queue=new LinkedList<>(); + Set visited=new HashSet<>(); + Set wordSet=new HashSet<>(wordList); + queue.offer(beginWord); + visited.add(beginWord); + //Լȥ + int level=1; + while (!queue.isEmpty()){ + + int size = queue.size(); + while (size-- >0){ + String poll = queue.poll(); + if(poll.equals(endWord)) return level; + if(wordList.size()==0) return 0; + + char[] chars = poll.toCharArray(); + for (int i = 0; i < chars.length; i++) { + char old=chars[i]; + //ڱwordListںܶݣԲʽ + for (char c='a' ;c<='z';c++) { + chars[i] = c; + + String next=new String(chars); + + if(endWord.equals(next)){ + return level+1; + } + if(!visited.contains(next) && wordSet.contains(next)){ + queue.offer(next); + visited.add(next); + // + wordList.remove(next); + } + } + chars[i]=old; + } + } + level++; + } + return 0; + } + + /** + * BSF ĸƴӷ2 + * ִʱ : 109 ms , Java ύл 45.14% û + * ڴ : 44 MB , Java ύл 29.41% û + */ + public int ladderLength111(String beginWord, String endWord, List wordList) { + int end = wordList.indexOf(endWord); + if (end == -1) { + return 0; + } + wordList.add(beginWord); + + // BFSҪõĶ + Queue queue1 = new LinkedList<>(); + // ѾĽڵ + Set visited1 = new HashSet<>(); + queue1.offer(beginWord); + visited1.add(beginWord); + + int count = 0; + Set allWordSet = new HashSet<>(wordList); + + while (!queue1.isEmpty()) { + count++; + int size1 = queue1.size(); + while (size1-- > 0) { + String s = queue1.poll(); + char[] chars = s.toCharArray(); + for (int j = 0; j < s.length(); ++j) { + // jλԭʼַ + char c0 = chars[j]; + for (char c = 'a'; c <= 'z'; ++c) { + chars[j] = c; + String newString = new String(chars); + // Ѿʹˣ + if (visited1.contains(newString)) { + continue; + } + if(newString.equals(endWord)){ + return count+1; + } + // бдڣӵУΪѷ + if (allWordSet.contains(newString)) { + queue1.offer(newString); + visited1.add(newString); + } + } + // ָjλԭʼַ + chars[j] = c0; + } + } + } + return 0; + + } + + //㷨 + /** + * ִʱ : 2522 ms , Java ύл 5.02% û + * ڴ : 43.9 MB , Java ύл 28.33% û + * @param beginWord + * @param endWord + * @param wordList + * @return + */ + public int ladderLength3(String beginWord, String endWord, List wordList) { + if(beginWord.equals(endWord)){ + return 0; + } + + //arraylistƥеԪֻʹ hash + Set wordSet=new HashSet<>(); + for (String s : wordList) { + wordSet.add(s); + } + + Queue queue=new LinkedList<>(); + Set visited=new HashSet<>(); + queue.offer(beginWord); + visited.add(beginWord); + //Լȥ + int level=1; + int k=0; + while (!queue.isEmpty()){ + + int size = queue.size(); + //1while (size-- >0){ÿһζУһ㣬 + while (size-- >0){ + String poll = queue.poll(); + System.out.println(" k"+(++k)+" :"+poll); + //System.out.println(""+poll); + if(poll.equals(endWord)) { + return level; + } + if(wordList.size()==0) return 0; + + char[] chars = poll.toCharArray(); + long start=System.currentTimeMillis(); + for (String word : wordList) { + if(visited.contains(word)){ + continue; + } + int diff=0; + for (int i = 0; i < chars.length; i++) { + String next = new String(chars); + //ֹദüϣΪܴڶֵ + ////arraylistƥеԪֻʹ hash + // 2 ÿܰӽ㣬ܰ·ֻȡ·Ա wordlistﲻarraylistֻhashSetƵģDZƥ䣩.containsƥ + // by lyb:֮ǰlist⣬ȡ + + if(chars[i]!=word.charAt(i)){ + diff++; + } + if(diff>1){ + //ֹظ + break; + }; + } + + if(diff==1 /*&& !visited.contains(word)*/){ + queue.offer(word); + visited.add(word); + } + } + long end=System.currentTimeMillis(); + System.out.println("ִʱ"+(end-start)); + } + level++; + } + return 0; + } + + + + /** + * 㷨 ɹύ-- ֵ㷨ԭʼ + * ȱ㣺̫ʱ + * ִʱ : 1162 ms , Java ύл 7.25% û + * ڴ : 40.8 MB , Java ύл 46.57% û + * + * ο⣺https://leetcode-cn.com/problems/word-ladder/solution/suan-fa-shi-xian-he-you-hua-javashuang-xiang-bfs23/ + */ + public int ladderLength4(String beginWord, String endWord, List wordList) { + + if(beginWord.equals(endWord)){ + return 0; + } + + Queue queue=new LinkedList<>(); + Set visited=new HashSet<>(); + queue.offer(beginWord); + visited.add(beginWord); + //Լȥ + int level=1; + int k=0; + while (!queue.isEmpty()){ + + int size = queue.size(); + while (size-- >0){ + String poll = queue.poll(); + //System.out.println(" k"+(++k)+" :"+poll); + if(poll.equals(endWord)) return level; + if(wordList.size()==0) return 0; + char[] chars = poll.toCharArray(); + long start=System.currentTimeMillis(); + for (String word : wordList) { + if(visited.contains(word)){ + continue; + } + int diff=0; + for (int i = 0; i < chars.length; i++) { + if (chars[i]!=word.charAt(i)) { + if(++diff >1){ + break; + } + } + } + //if(word.equals(endWord)) return level+1; + if(diff==1){ + queue.add(word); + visited.add(word); + } + } + long end=System.currentTimeMillis(); + //System.out.println("ִʱ"+(end-start)); + } + level++; + } + return 0; + } + + /** + * 㷨 visited SetŻ-- ֵ㷨 + * + * + * һʱ̫һŻvisitedHashSetijboolean飬ͨindexжǷѷʡжvisitedֻҪbooleanжϣʡ˴HashSetʱ½Ϊ291 ms + * + * ߣjzj1993 + * ӣhttps://leetcode-cn.com/problems/word-ladder/solution/suan-fa-shi-xian-he-you-hua-javashuang-xiang-bfs23/ + * ԴۣLeetCode + * ȨСҵתϵ߻Ȩҵתע + * + * + * ִʱ : 596 ms , Java ύл 20.98% û + * ڴ : 41.5 MB , Java ύл 40.73% û + * + * ο⣺https://leetcode-cn.com/problems/word-ladder/solution/suan-fa-shi-xian-he-you-hua-javashuang-xiang-bfs23/ + */ + public int ladderLength5(String beginWord, String endWord, List wordList) { + + if(beginWord.equals(endWord)){ + return 0; + } + + Queue queue=new LinkedList<>(); + //Set visited=new HashSet<>(); + // visited޸Ϊboolean + boolean[] visited = new boolean[wordList.size()]; + //ѯʼֵַλ + int idx=wordList.indexOf(beginWord); + if(idx!=-1) { + visited[idx]=true; + } + + queue.offer(beginWord); + //visited.add(beginWord); + //Լȥ + int level=1; + int k=0; + while (!queue.isEmpty()){ + + int size = queue.size(); + while (size-- >0){ + String poll = queue.poll(); + if(poll.equals(endWord)) return level; + if(wordList.size()==0) return 0; + char[] chars = poll.toCharArray(); + //long start=System.currentTimeMillis(); + for (int i = 0; i < wordList.size(); i++) { + String word=wordList.get(i); + if(visited[i]==true){ + continue; + } + int diff=0; + for (int j = 0; j < chars.length; j++) { + if (chars[j]!=word.charAt(j)) { + if(++diff >1){ + break; + } + } + } + //if(word.equals(endWord)) return level+1; + if(diff==1){ + queue.add(word); + visited[i]=true; + } + } + //long end=System.currentTimeMillis(); + //System.out.println("ִʱ"+(end-start)); + } + level++; + } + return 0; + } + + + + /*** + * ˫BFSУvisited Ż,鷽ʽѯ + * ִʱ : 132 ms , Java ύл 42.94% û + * ڴ : 42.1 MB , Java ύл 38.75% û + * @return + */ + public int ladderLength7(String beginWord, String endWord, List wordList) { + int end =wordList.indexOf(endWord); + if(end==-1) return 0; + wordList.add(beginWord); + int start=wordList.size()-1; + + Queue queue1=new LinkedList<>(); + Queue queue2=new LinkedList<>(); + Set visited1=new HashSet<>(); + Set visited2=new HashSet<>(); + queue1.add(start); + queue2.add(end); + + visited1.add(start); + visited2.add(end); + + // + int count=0; + while (!queue1.isEmpty() && !queue2.isEmpty()){ + if(queue1.size()>queue2.size()){ + Queue temp=queue1; + queue1=queue2; + queue2=temp; + + Set t=visited1; + visited1=visited2; + visited2=t; + } + + int size = queue1.size(); + count++; + //һ + while (size-- >0){ + + String s = wordList.get(queue1.poll()); + for (int i = 0; i < wordList.size(); i++) { + if(visited1.contains(i)) continue; + if(!canConver(s,wordList.get(i))) continue; + if(visited2.contains(i)) return count+1; + + queue1.add(i); + visited1.add(i); + } + + } + + } + + //ûҵԪأ˳ + return 0; + } + + private boolean canConver(String next, String s) { + int diff=0; + for (int i = 0; i < next.length(); i++) { + if(next.charAt(i)!=s.charAt(i)){ + if(++diff >1){ + return false; + } + } + } + return diff==1; + } + + /** + * ʱ + * ˫BSF-ĸƴӷladderLength7()ƣֻѭСĶ + * ע㣺List wordList ڴڶʣ漰containsƥ䣬ԱתSetϣhashѯ + * ִʱ : 23 ms , Java ύл 89.34% û + * ڴ : 42 MB , Java ύл 39.34% û + * ο⣺棺https://leetcode-cn.com/problems/word-ladder/solution/suan-fa-shi-xian-he-you-hua-javashuang-xiang-bfs23/ + * @return + */ + public int ladderLength8(String beginWord, String endWord, List wordList) { + if(wordList.indexOf(endWord)==-1) return 0; + //˫˶ + Queue queue1 =new LinkedList(); + Queue queue2 =new LinkedList(); + Set visited1=new HashSet<>(); + Set visited2=new HashSet<>(); + queue1.add(beginWord); + queue2.add(endWord); + visited1.add(beginWord); + visited2.add(endWord); + + Set wordSet=new HashSet<>(wordList); + + int count=0; + while (!queue1.isEmpty() && !queue2.isEmpty()){ + if(queue1.size()>queue2.size()){ + Queue temp=queue1; + queue1=queue2; + queue2=temp; + + Set t=visited1; + visited1=visited2; + visited2=t; + } + + int size = queue1.size(); + count++; + while (size-- >0){ + + String poll = queue1.poll(); + char[] chars = poll.toCharArray(); + for (int i = 0; i < chars.length; i++) { + char old=chars[i]; + + for (char c='a'; c <= 'z'; c++) { + chars[i]=c; + + String next=new String(chars); + if(visited1.contains(next)) continue; + if(visited2.contains(next)) return count+1; + + //wordSetϣӰЧ + if(wordSet.contains(next)){ + queue1.add(next); + visited1.add(next); + } + } + + chars[i]=old; + } + + } + } + return 0; + } + + +} diff --git a/Week_03/G20200343030379/LeetCode_153_379.java b/Week_03/G20200343030379/LeetCode_153_379.java new file mode 100644 index 00000000..2ee5e294 --- /dev/null +++ b/Week_03/G20200343030379/LeetCode_153_379.java @@ -0,0 +1,79 @@ +package G20200343030379; + +import java.util.Arrays; + +/** + * 153. ѰתеСֵ + * + * 谴Ԥδ֪ijϽת + * + * ( 磬?[0,1,2,4,5,6,7] ܱΪ?[4,5,6,7,0,1,2]?) + * + * ҳСԪء + * + * ԼвظԪء + * + * ʾ 1: + * + * : [3,4,5,1,2] + * : 1 + * ʾ 2: + * + * : [4,5,6,7,0,1,2] + * : 0 + * + * ԴۣLeetCode + * ӣhttps://leetcode-cn.com/problems/find-minimum-in-rotated-sorted-array + * ȨСҵתϵٷȨҵתע + * + * ο⣺ + * + */ +public class LeetCode_153_379 { + + /** + * + * + * ִʱ : 2 ms , Java ύл 26.08% û + * ڴ : 38 MB , Java ύл 32.06% û + * + * @return + */ + public int findMin(int[] nums) { + if(nums.length==0) return 0; + Arrays.sort(nums); + return nums[0]; + } + + /** + * ֲҷ߲ϼбƽӽСֵ + * + * ִʱ : 0 ms , Java ύл 100.00% û + * ڴ : 38 MB , Java ύл 32.24% û + * + * ⣺https://leetcode-cn.com/problems/find-minimum-in-rotated-sorted-array/solution/er-fen-by-powcai-2/ + * + * @return + */ + public int findMin2(int[] nums) { + int left=0,right=nums.length-1; + int mid=0; + //ֵȼ˳жϽѭⲿreturnѭѭreturn + while (left map=new HashMap(); + for (int num : nums) { + //洢ִ + if(map.get(num)!=null){ + map.put(num,map.get(num)+1); + }else{ + map.put(num,1); + } + } + + //ҳn/2Ҵ֡ + int n=0; + //ִn/2ĴĬΪСֵ + int count=Integer.MIN_VALUE; + for (Map.Entry entry : map.entrySet()) { + Integer integerCount = map.get(entry.getKey()); + //Ҫn/2Ҫִ + //ps&& integerCount>count ʵԲÿǣΪҪϣԲܳǰڰִڰȫÿ + if(integerCount>(nums.length/2) && integerCount>count){ + n=entry.getKey().intValue(); + //¼ + count=integerCount; + } + } + + + return n; + } + /*** + * ڶֹϣʹùϣ洢ֳִʡһʵʲķˣû㶮 + * ִʱ : 22 ms , Java ύл 22.64% û + * ڴ : 47.3 MB , Java ύл 5.10% û + */ + public int majorityElement3(int[] nums) { + Map map=new HashMap(); + int major=0; + for (int num : nums) { + //洢ִ + if(map.get(num)!=null){ + map.put(num,map.get(num)+1); + }else{ + map.put(num,1); + } + if(map.get(num)>nums.length/2){ + major=num; + //ΪҪϣԲܳǰڰִڰȫÿ + break; + } + } + + return major; + } + + /*** + * ѧõУnʱ±Ϊ n/2 , n żʱ±Ϊ (n/2)+1 + * ʵλ n/2㼴 + * 2 ms 41.8 MB Java + */ + public int majorityElement2(int[] nums) { + Arrays.sort(nums); + return nums[nums.length/2]; + } +} diff --git a/Week_03/G20200343030379/LeetCode_17_379.java b/Week_03/G20200343030379/LeetCode_17_379.java new file mode 100644 index 00000000..2542ecec --- /dev/null +++ b/Week_03/G20200343030379/LeetCode_17_379.java @@ -0,0 +1,81 @@ +package G20200343030379; + +import java.sql.Statement; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Stack; + +/** + * 17. 绰ĸ + * һ 2-9 ַܱʾĸϡ + * + * ֵĸӳ£绰ͬע 1 Ӧκĸ + * + * 룺"23" + * ["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"]. + * + * ο⣺https://leetcode.com/problems/letter-combinations-of-a-phone-number/discuss/8109/My-recursive-solution-using-Java + */ +public class LeetCode_17_379 { + public static void main(String[] args) { + List strings = new LeetCode_17_379().letterCombinations("2"); + System.out.println(strings); + } + + /*** + * η + * ִʱ : 4 ms , Java ύл 10.34% û + * ڴ : 38.1 MB , Java ύл 5.14% û + */ + public List letterCombinations(String digits) { + List list = new ArrayList<>(); + if(digits==null || digits.length()==0 ){ + return list; + } + + //װMapĵ绰ṹ + Map map=new HashMap(); + map.put("2","abc"); + map.put("3","def"); + map.put("4","ghi"); + map.put("5","jkl"); + map.put("6","mno"); + map.put("7","pqrs"); + map.put("8","tuv"); + map.put("9","wxyz"); + + + //ݹ + find(list,digits,0,"",map); + + return list; + } + + private void find(List list, String digits, int level, String str,Map map) { + //־ + if(level==digits.length()){ + list.add(str); + return ; + } + + //ִ߼ + //һڶҪѭ + char[] chars = ((String) map.get(digits.charAt(level)+"")).toCharArray(); + for (int i = 0; i < chars.length; i++) { + //һдӺԼɾβ + /*str+=(String.valueOf(chars[i])); + find(list,digits,level+1,str,map); + //ɾβ + str=str.substring(0,str.length()-1);*/ + + //ڶдֻʱ޸ıֵͲβ + find(list,digits,level+1,str+(String.valueOf(chars[i])),map); + //ɾβ + //str=str.substring(0,str.length()-1); + } + + } +} diff --git a/Week_03/G20200343030379/LeetCode_200_379_1.java b/Week_03/G20200343030379/LeetCode_200_379_1.java new file mode 100644 index 00000000..21419ccf --- /dev/null +++ b/Week_03/G20200343030379/LeetCode_200_379_1.java @@ -0,0 +1,115 @@ +package G20200343030379; + + + + + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Queue; +import java.util.Set; + +/** + * + * 200. + * + * һ?'1'½أ '0'ˮɵĵĶά񣬼㵺һˮΧͨˮƽֱڵ½ӶɵġԼĸ߾ˮΧ + * + * ʾ 1: + * + * : + * 11110 + * 11010 + * 11000 + * 00000 + * + * :?1 + * ʾ?2: + * + * : + * 11000 + * 11000 + * 00100 + * 00011 + * + * : 3 + * + * ԴۣLeetCode + * ӣhttps://leetcode-cn.com/problems/number-of-islands + * ȨСҵתϵٷȨҵתע + * + * ⣨ȫֵŻ㷨 + * + * + */ + + + +public class LeetCode_200_379_1 { + public static void main(String[] args) { + /** + * "hit" + * "cog" + * ["hot","dot","dog","lot","log","cog"] + */ +// new LeetCode_200_379().findLadders("hit","cog",Arrays.asList("hot","dot","dog","lot","log","cog")); + } + + /*** + * BSF ݹ鷨 + * ִʱ : 2 ms , Java ύл 93.24% û + * ڴ : 42.2 MB , Java ύл 5.23% û + * + * ο⣺https://leetcode.com/problems/number-of-islands/discuss/56359/Very-concise-Java-AC-solution + * @param grid + */ + public int numIslands(char[][] grid) { + // '1'½أ '0'ˮ + int count=0; + // + int n=grid.length; + if(n==0) return 0; + int m=grid[0].length; + + for (int i = 0; i < n; i++) { + for (int j = 0; j < m; j++) { + //½صʱŵݹ + if(grid[i][j]=='1'){ + dfs(grid,i,j,n,m); + count++; + } + } + } + return count; + } + + /** + * ݹҪ½رΪˮֹظ + * @param grid + * @param i + * @param j + * @param n + * @param m + */ + private void dfs(char[][] grid, int i, int j, int n, int m) { + //УǷֵ,ˮҲ + if(i<0 || j<0 || i>=n || j>=m || grid[i][j]=='0') return; + + //½شΪˮֹظ + grid[i][j]='0'; + dfs(grid,i-1,j,n,m); + dfs(grid,i+1,j,n,m); + dfs(grid,i,j-1,n,m); + dfs(grid,i,j+1,n,m); + } + + + + + +} diff --git a/Week_03/G20200343030379/LeetCode_22_379.java b/Week_03/G20200343030379/LeetCode_22_379.java new file mode 100644 index 00000000..1665d090 --- /dev/null +++ b/Week_03/G20200343030379/LeetCode_22_379.java @@ -0,0 +1,125 @@ +package G20200343030379; + + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; + +/** + * + * 22. + * ?n?ŵĶдһʹܹпܵIJЧϡ + * + * 磬?n = 3ɽΪ + * + * [ + * "((()))", + * "(()())", + * "(())()", + * "()(())", + * "()()()" + * ] + * + * ԴۣLeetCode + * ӣhttps://leetcode-cn.com/problems/generate-parentheses + * ȨСҵתϵٷȨҵתע + * + */ +public class LeetCode_22_379 { + public static void main(String[] args) { + List strings = new LeetCode_22_379().generateParenthesis2(3); + System.out.println(strings); + + + } + + /** + * ݹ鷨--> DFS + */ + public List generateParenthesis(int n) { + List res=new ArrayList<>(); + dfs(res,n,n,n*2,""); + return res; + } + + /** + * + * @param res + * @param left жٸ + * @param right ұжٸ + * @param n ܵĸжǷ + * @param curStr ǰַ + */ + private void dfs(List res, int left, int right, int n, String curStr) { + // + if(curStr.length()==n){ + res.add(curStr); + return ; + } + + //ߵѾ꣬ÿż1left-1 + if(left>0){ + dfs(res,left-1,right,n,curStr+"("); + } + //ұߵѾ,ұʹŵ(left0 && left BFS + * Ϊǵݹãû취öдݶΪ˷ԼһṹĿԻȡӦֵ + * 磺1ǰַ 2 3 + * + * ο⣺https://leetcode-cn.com/problems/generate-parentheses/solution/hui-su-suan-fa-by-liweiwei1419/ + */ + + class Node { + /** + * ǰõַ + */ + private String res; + /** + * ʣ + */ + private int left; + /** + * ʣ + */ + private int right; + + public Node(String str, int left, int right) { + this.res = str; + this.left = left; + this.right = right; + } + } + + public List generateParenthesis2(int n) { + List res=new ArrayList<>(); + Queue queue=new LinkedList<>(); + queue.add(new Node("",n,n)); + + while (!queue.isEmpty()){ + Node node = queue.poll(); + if(node.left==0 && node.right==0){ + res.add(node.res); + } + + if(node.left>0){ + queue.offer(new Node(node.res+"(",node.left-1,node.right)); + } + if(node.right>0 && node.left= 0; i--) { + int chu=amount/coins[i]; + count+=chu; + if(chu==0) continue; + // + amount=amount-(chu*coins[i]); + + if(amount==0){ + return count; + } + } + + + return -1; + + } + +} diff --git a/Week_03/G20200343030379/LeetCode_33_379.java b/Week_03/G20200343030379/LeetCode_33_379.java new file mode 100644 index 00000000..81eda13b --- /dev/null +++ b/Week_03/G20200343030379/LeetCode_33_379.java @@ -0,0 +1,96 @@ +package G20200343030379; + +import org.omg.CORBA.IRObject; + +import javax.swing.*; +import java.util.List; + +/** + * 33. ת + * + * 谴Ԥδ֪ijϽת + * + * ( 磬?[0,1,2,4,5,6,7]?ܱΪ?[4,5,6,7,0,1,2]?) + * + * һĿֵдĿֵ򷵻򷵻?-1? + * + * ԼвظԪء + * + * 㷨ʱ临Ӷȱ?O(log?n) + * + * ʾ 1: + * + * : nums = [4,5,6,7,0,1,2], target = 0 + * : 4 + * ʾ?2: + * + * : nums = [4,5,6,7,0,1,2], target = 3 + * : -1 + * + * ԴۣLeetCode + * ӣhttps://leetcode-cn.com/problems/search-in-rotated-sorted-array + * ȨСҵתϵٷȨҵתע + * + * ο⣺ + * + */ +public class LeetCode_33_379 { + public static void main(String[] args) { + new LeetCode_33_379().search2(new int[]{4,5,6,7,0,1,2},0); + } + + /** + * -ԭ + * @param nums + * @param target + * @return + */ + public int search(int[] nums, int target) { + return 1; + } + + /** + * ֲҷ + * + * : nums = [4,5,6,7,0,1,2], target = 0 + * : 4 + * ʾ?2: + * + * ⣺ֲңhttps://leetcode-cn.com/problems/search-in-rotated-sorted-array/solution/ji-bai-liao-9983de-javayong-hu-by-reedfan/ + * @param nums + * @param target + * @return + */ + public int search2(int[] nums, int target) { + int left=0,right=nums.length-1; + int mid=0; + while (left<=right){ + mid=(left+right)/2; + if(nums[mid]==target){ + return mid; + + }else if(nums[left] <= nums[mid]){ + //ߵ + //ߵķΧ + if(nums[left]<=target && nums[mid] > target){ + right=mid-1; + }else{ + left=mid+1; + } + }else{ + //Ұߵ + + // жǷҰߵķΧ + if(nums[mid] < target && nums[right] >= target){ + left=mid+1; + }else{ + right=mid-1; + } + } + + } + return -1; + } + + +} diff --git a/Week_03/G20200343030379/LeetCode_367_379.java b/Week_03/G20200343030379/LeetCode_367_379.java new file mode 100644 index 00000000..36d2900a --- /dev/null +++ b/Week_03/G20200343030379/LeetCode_367_379.java @@ -0,0 +1,83 @@ +package G20200343030379; + +import java.util.List; + +/** + * 367. Чȫƽ + * + * һ numдһ num һȫƽ򷵻 True򷵻 False + * + * ˵ҪʹκõĿ⺯? sqrt + * + * ʾ 1 + * + * 룺16 + * True + * ʾ 2 + * + * 룺14 + * False + * + * ԴۣLeetCode + * ӣhttps://leetcode-cn.com/problems/valid-perfect-square + * ȨСҵתϵٷȨҵתע + * + * + * ο⣺ + */ +public class LeetCode_367_379 { + public static void main(String[] args) { + } + + /** + * ֲҷ + * + * ִʱ : 0 ms , Java ύл 100.00% û + * ڴ : 36.3 MB , Java ύл 5.01% û + * @param num + * @return + */ + public boolean isPerfectSquare(int num) { + if(num==1) return true; + //Ϊ˼򻯲ҪIJѯright=num/2; + long left=2,right=num/2; + long mid=0; + while (left<=right){ + mid=(left+right)/2; + + if(mid*mid==num){ + return true; + }else if(mid*mid>num){ + right=mid-1; + }else{ + left=mid+1; + } + + } + return right*right==num; + //return false Ҳû + //return false; + } + + + /** + * ţٵ + * + * ִʱ : 0 ms , Java ύл 100.00% û + * ڴ : 36.1 MB , Java ύл 5.01% ûz + * + * @param num + * @return + */ + public boolean isPerfectSquare2(int num) { + if(num==1)return true; + + long x=num; + while (x*x>num){ + x=(x + num / x) / 2; + } + return x*x==num; + } + + +} diff --git a/Week_03/G20200343030379/LeetCode_433_379.java b/Week_03/G20200343030379/LeetCode_433_379.java new file mode 100644 index 00000000..8d452620 --- /dev/null +++ b/Week_03/G20200343030379/LeetCode_433_379.java @@ -0,0 +1,240 @@ +package G20200343030379; + +import javafx.concurrent.Worker; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; +import java.util.Set; +import java.util.Stack; + +/** + * 433. С仯 + * һһ8ַַʾÿַ "A", "C", "G", "T"еһ + * + * Ҫһеı仯һλ仯ζеһַ˱仯 + * + * 磬"AACCGGTT"?仯?"AACCGGTA"?һλ仯 + * + * ͬʱÿһλ仯ĽҪһϷĻ򴮣ýһ⡣ + * + * ڸ3 start, end, bankֱʼУĿм⣬ҳܹʹʼб仯ΪĿٱ仯޷ʵĿ仯뷵 -1 + * + * ע: + * + * ʼĬǺϷģһڻС + * еĿбǺϷġ + * ٶʼĿDzһġ + * ʾ 1: + * + * start: "AACCGGTT" + * end: "AACCGGTA" + * bank: ["AACCGGTA"] + * + * ֵ: 1 + * ʾ 2: + * + * start: "AACCGGTT" + * end: "AAACGGTA" + * bank: ["AACCGGTA", "AACCGCTA", "AAACGGTA"] + * + * ֵ: 2 + * ʾ 3: + * + * start: "AAAAACCC" + * end: "AACCCCCC" + * bank: ["AAAACCCC", "AAACCCCC", "AACCCCCC"] + * + * ֵ: 3 + * + * ԴۣLeetCode + * ӣhttps://leetcode-cn.com/problems/minimum-genetic-mutation + * ȨСҵתϵٷȨҵתע + * + * ο⣺https://leetcode-cn.com/problems/minimum-genetic-mutation/solution/java-dfs-hui-su-by-1yx/ + */ +public class LeetCode_433_379 { + public static void main(String[] args) { + int i = new LeetCode_433_379().minMutation_2("AACCGGTT", "AAACGGTA", new String[]{"AACCGGTA", "AACCGCTA", "AAACGGTA"}); + System.out.println(i); + + + } + + /** + * б--> BFS + * ִʱ : 1 ms , Java ύл 75.78% û + * ڴ : 36.9 MB , Java ύл 5.13% û + */ + public int minMutation(String start, String end, String[] bank) { + if(start.equals(end)) return 1; + + //ʼϡ + Set bankSet=new HashSet(); + char[] charSet=new char[]{'A','C','G','T'}; + Queue queue=new LinkedList<>(); + Set visited=new HashSet(); + + + //ʼ + int lever=0; + queue.add(start); + visited.add(start); + + for (String b : bank) { + bankSet.add(b); + } + + // + while (!queue.isEmpty()){ + int size = queue.size(); + while (size-- >0){ + String poll = queue.poll(); + if(poll.equals(end)){ + return lever; + } + + //ÿַ + char[] chars = poll.toCharArray(); + for (int i = 0; i < chars.length; i++) { + char old=chars[i]; + + for (char c : charSet) { + //µַ + chars[i]=c; + + String next=new String(chars); + + //жǷbank,Ƿʹ + if(!visited.contains(next) && bankSet.contains(next)){ + //ӵ + queue.add(next); + visited.add(next); + } + + } + + chars[i]=old; + } + + + } + lever++; + } + return -1; + + } + + /** + * б--> BFSԱminMutation()дŻ + * + * ִʱ : 0 ms , Java ύл 100.00% û + * ڴ : 37.6 MB , Java ύл 5.13% û + */ + public int minMutation_2(String start, String end, String[] bank) { + if(start.equals(end)) return 1; + + //ʼϡ + Queue queue=new LinkedList<>(); + Set visited=new HashSet(); + + + //ʼ + int lever=0; + queue.add(start); + visited.add(start); + + // + while (!queue.isEmpty()){ + int size = queue.size(); + //ÿһ㣬ÿ level+1 + while (size-- >0){ + String poll = queue.poll(); + if(poll.equals(end)){ + return lever; + } + + //ÿַ + char[] chars = poll.toCharArray(); + for (String b : bank) { + if(visited.contains(b)){ + continue; + } + int diff=0; + for (int i = 0; i < chars.length; i++) { + if(chars[i]!=b.charAt(i)){ + if(++diff>1){ + break; + } + } + } + + //Ƿڻ + if(diff==1){ + queue.add(b); + visited.add(b); + } + + } + } + lever++; + } + return -1; + + } + + /** + * ݹ鷨--> DFSʹȣbankܶ࣬dzʱDZȻģ + * ο⣺https://leetcode-cn.com/problems/minimum-genetic-mutation/solution/java-dfs-hui-su-by-1yx/ + */ + int minStepCount=Integer.MAX_VALUE; + public int minMutation2(String start, String end, String[] bank) { + //Ƿж + if(start.equals(end)) return 1; + if(bank==null || bank.length==0) return -1; + dfs(new HashSet(),0,start,end,bank); + return (minStepCount==Integer.MAX_VALUE)?-1:minStepCount; + } + + /** + * + * @param visited ַ + * @param stepCount ߹Ĵ + * @param currentStr ǰַ + * @param end Ŀַ + * @param bank + */ + public void dfs(Set visited,int stepCount,String currentStr,String end, + String[] bank){ + if(currentStr.equals(end)){ + minStepCount=Math.min(minStepCount,stepCount); + return; + } + + //ɨ⣬ֵΪ1Ļ + for (String str : bank) { + int diff=0;//ַԱмͬ + for (int i = 0; i < currentStr.length(); i++) { + if(currentStr.charAt(i)!=str.charAt(i)){ + //1ϼ˳,ûҪж + if(++diff >1) { + break; + } + } + } + + //Ƿ,ֵΪ1 + if(diff==1 && !visited.contains(str) ){ + visited.add(str); + //ݹ + dfs(visited,stepCount+1,str,end,bank); + //visited.remove(str); + } + + } + } + + +} diff --git a/Week_03/G20200343030379/LeetCode_455_379.java b/Week_03/G20200343030379/LeetCode_455_379.java new file mode 100644 index 00000000..d037a396 --- /dev/null +++ b/Week_03/G20200343030379/LeetCode_455_379.java @@ -0,0 +1,74 @@ +package G20200343030379; + +import java.util.Arrays; + +/** + * 455. ַ + * + * һλܰļҳҪĺһЩСɡǣÿֻܸһɡÿ i һθֵ?gi úθڵıɵСߴ磻ÿ j һߴ sj? sj >= gi?ǿԽ j i ӻõ㡣ĿǾԽĺӣֵ + * + * ע⣺ + * + * ԼθֵΪ + * һСֻӵһɡ + * + * ʾ?1: + * + * : [1,2,3], [1,1] + * + * : 1 + * + * : + * ӺСɣ3ӵθֱֵǣ1,2,3 + * ȻСɣǵijߴ綼1ֻθֵ1ĺ㡣 + * Ӧ1 + * ʾ?2: + * + * : [1,2], [1,2,3] + * + * : 2 + * + * : + * ӺСɣ2ӵθֱֵ1,2 + * ӵеıͳߴ綼к㡣 + * Ӧ2. + * + * ԴۣLeetCode + * ӣhttps://leetcode-cn.com/problems/assign-cookies + * ȨСҵתϵٷȨҵתע + * + * ⣺ + * https://leetcode-cn.com/problems/assign-cookies/solution/tan-xin-suan-fa-fen-fa-bing-gan-by-humbert/ + * https://leetcode-cn.com/problems/assign-cookies/solution/you-xian-man-zu-wei-kou-xiao-de-xiao-peng-you-de-x/ + */ + + + +public class LeetCode_455_379 { + + /** + * ̰㷨 + * @param g + * @param s + * @return + */ + public int findContentChildren(int[] g, int[] s) { + //ȫС + Arrays.sort(g); + Arrays.sort(s); + + int i =0; + int j=0; + int count=0; + while (i=g[i]){ + i++;j++; + count++; + }else{ + j++; + } + } + return count; + } + +} diff --git a/Week_03/G20200343030379/LeetCode_45_379.java b/Week_03/G20200343030379/LeetCode_45_379.java new file mode 100644 index 00000000..3331e287 --- /dev/null +++ b/Week_03/G20200343030379/LeetCode_45_379.java @@ -0,0 +1,63 @@ +package G20200343030379; + +/** + * 45. ԾϷ II + * + * һǸ飬λĵһλá + * + * еÿԪشڸλÿԾ󳤶ȡ + * + * ĿʹٵԾһλá + * + * ʾ: + * + * : [2,3,1,1,4] + * : 2 + * : һλõСԾ 2 + * ? ±Ϊ 0 ±Ϊ 1 λã?1?Ȼ?3?һλá + * + * ԴۣLeetCode + * ӣhttps://leetcode-cn.com/problems/jump-game-ii + * ȨСҵתϵٷȨҵתע + * + * ⣺(ȿ˼·) + * https://leetcode-cn.com/problems/jump-game-ii/solution/xiang-xi-tong-su-de-si-lu-fen-xi-duo-jie-fa-by-10/ + * + * + */ + + + +public class LeetCode_45_379 { + public static void main(String[] args) { + new LeetCode_45_379().jump(new int[]{2,3,1,1,4,1}); + } + + /** + * ̰㷨 + * + * ִʱ : 2 ms , Java ύл 95.03% û + * ڴ : 41 MB , Java ύл 5.04% û + * @return + */ + public int jump(int[] nums) { + //ǰһԶܵλ + int end=0; + //ǰԶܵλ + int maxPosition=0; + //Ծ + int setp=0; + + //nums.length-1 ڿһģһҪжϣֶһ + for (int i = 0; i < nums.length-1; i++) { + maxPosition=Math.max(maxPosition,nums[i]+i); + //±ֵ߽ + if(end==i){ + end=maxPosition; + setp++; + } + } + return setp; + } + +} diff --git a/Week_03/G20200343030379/LeetCode_50_379.java b/Week_03/G20200343030379/LeetCode_50_379.java new file mode 100644 index 00000000..ea5f2492 --- /dev/null +++ b/Week_03/G20200343030379/LeetCode_50_379.java @@ -0,0 +1,41 @@ +package G20200343030379; + +/** + * 50. Pow(x, n) + */ +public class LeetCode_50_379 { + public static void main(String[] args) { + int x=-2147483648; + System.out.println(-x); + long X=x; + long abs = -X; + System.out.println(abs); + + } + public double myPow(double x, int n) { + long N=n; + if(n<0){ + //ڷabs(int),intСֵ-2147483648 + // ֣Դ߼С -a ػ-2147483648Ǿԭ,Աת2147483648û⡣ + //n=Math.abs(n); + N=Math.abs(N); + x=1/x; + } + return fastPow(x,N); + } + + public double fastPow(double x, long n){ + + if(n==0){ + return 1; + } + + double val = fastPow(x, n / 2); + + if(n%2==1){ + return val*val*x; + } + + return val*val; + } +} diff --git a/Week_03/G20200343030379/LeetCode_515_379.java b/Week_03/G20200343030379/LeetCode_515_379.java new file mode 100644 index 00000000..25b32f56 --- /dev/null +++ b/Week_03/G20200343030379/LeetCode_515_379.java @@ -0,0 +1,129 @@ +package G20200343030379; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Queue; +import java.util.Set; + +/** + * 515. ÿֵ + * + * Ҫڶÿһҵֵ + * + * ʾ + * + * : + * + * 1 + * / \ + * 3 2 + * / \ \ + * 5 3 9 + * + * : [1, 3, 9] + * + * ԴۣLeetCode + * ӣhttps://leetcode-cn.com/problems/find-largest-value-in-each-tree-row + * ȨСҵתϵٷȨҵתע + * + * ⣺ + */ + + + +public class LeetCode_515_379 { + + public class TreeNode { + int val; + TreeNode left; + TreeNode right; + TreeNode(int x) { val = x; } + } + + public static void main(String[] args) { + } + + /** + * -(ע⣺־ɺעⲻҪ) + * + * ִʱ : 2 ms , Java ύл 82.08% û + * ڴ : 41.8 MB , Java ύл 5.13% û + * + */ + public List largestValues(TreeNode root) { + List res=new ArrayList<>(); + if (root == null) { + return res; + } + Queue queue=new LinkedList(); + queue.add(root); + //ÿһֵ + while (!queue.isEmpty()){ + int maxValue=Integer.MIN_VALUE; + int size = queue.size(); + //ǰ + for (int i = 0; i < size; i++) { + TreeNode node = queue.poll(); + //־ӡӰ ִʱȥִ־ + //System.out.println(""); + //ȡǰֵ + if(node.val>maxValue) { + maxValue=node.val; + } + + //ȡһӽڵ + if(node.left!=null) {queue.add(node.left);} + if (node.right != null) {queue.add(node.right);} + + } + res.add(maxValue); + } + + return res; + } + + + /** + * ݹ鷨- + * ִʱ : 1 ms , Java ύл 100.00% û + * ڴ : 42.6 MB , Java ύл 5.13% û + * + * ο⣺ + * https://leetcode-cn.com/problems/find-largest-value-in-each-tree-row/solution/java-di-gui-xie-fa-hao-shi-2ms-by-ou-ran-zz/ + * https://leetcode.com/problems/find-largest-value-in-each-tree-row/discuss/98971/9ms-JAVA-DFS-solution + * + */ + public List largestValues2(TreeNode root) { + List res=new ArrayList<>(); + if (root == null) { + return res; + } + + dfs(res,root,0); + + return res; + } + + private void dfs(List res, TreeNode root, int level) { + if(root==null){ + return; + } + if(level==res.size()){ + res.add(root.val); + }else{ + res.set(level,Math.max(res.get(level),root.val)); + } + + if(root.left!=null){ + dfs(res,root.left,level+1); + } + if(root.right!=null){ + dfs(res,root.right,level+1); + } + } + + +} diff --git a/Week_03/G20200343030379/LeetCode_51_379_0.java b/Week_03/G20200343030379/LeetCode_51_379_0.java new file mode 100644 index 00000000..f43d4f08 --- /dev/null +++ b/Week_03/G20200343030379/LeetCode_51_379_0.java @@ -0,0 +1,168 @@ +package G20200343030379; + + +import java.util.ArrayList; +import java.util.List; + +/** + * 51. Nʺ + * n ʺоν n ʺ nn ϣʹʺ˴֮䲻໥ + * ͼΪ 8 ʺһֽⷨ + * + * һ nвͬ?n?ʺĽ + * + * ÿһֽⷨһȷ?n ʺӷ÷÷ 'Q' '.' ֱ˻ʺͿλ + * + * : 4 + * : [ + * [".Q..", // ⷨ 1 + * "...Q", + * "Q...", + * "..Q."], + * + * ["..Q.", // ⷨ 2 + * "Q...", + * "...Q", + * ".Q.."] + * ] + * : 4 ʺͬĽⷨ + * + * ԴۣLeetCode + * ӣhttps://leetcode-cn.com/problems/n-queens + * ȨСҵתϵٷȨҵתע + * + * ο⣺ + */ +public class LeetCode_51_379_0 { + public static void main(String[] args) { + List> strings = new LeetCode_51_379_0().solveNQueens(4); + System.out.println(strings); + new LeetCode_51_379_0().construct(new char[][]{{'1','2'}}); + + + } + + /** + * ִʱ : 17 ms , Java ύл 9.57% û + * ڴ : 41.4 MB , Java ύл 5.86% û + * + * ȱ㣺1ṹװȽϻ + * 2ȥǷѡ㷨Ż + * @param n + * @return + */ + public List> solveNQueens(int n) { + //Nʺṹ + List> nStrut=new ArrayList<>(); + for (int i = 1; i <=n; i++) { + List list = new ArrayList<>(n); + for (int j = 1; j <= n; j++) { + list.add("."); + } + nStrut.add(list); + } + + //洢ܵн + List> res=new ArrayList<>(); + boardtrack(res,nStrut,0); + + return res; + } + + //ֶ + + /** + * + * @param res ǰʼNʺṹÿӶǡ. + * @param nStrut ѡн + * @param row + */ + private void boardtrack(List> res,List> nStrut, + int row) { + //1˳־ + if(row==nStrut.size()){ + res.add(construct(nStrut)); + return; + } + + //2ִ߼ + //2 + for (int i = 0; i < nStrut.size(); i++) { + //2.1ǷڹΧ + if(!isVaild(nStrut,row,i)){ + continue; + } + //2.2һ + List strings = nStrut.get(row); + strings.set(i,"Q"); + boardtrack(res,nStrut,row+1); + //2.3βһ + strings.set(i,"."); + } + } + + /** + * У鵱ǰλǷãΧ + * true false ǿãᱻ + * @param list ǰѡĽ + * @param row + * @param col + * @return + */ + private boolean isVaild(List> list, int row, int col) { + //鵱ǰǷΧ + for (int i = 0; i < list.size(); i++) { + String s = list.get(i).get(col); + if(s.equals("Q")){ + return false; + } + } + + //ǷΧų + for(int i=row-1,j=col-1; i>=0 && j>=0;i--,j--){ + //ȡij + String s = list.get(i).get(j); + if(s.equals("Q")){ + return false; + } + } + + //ϷǷΧų + for(int i=row-1,j=col+1;i>=0 && j Ϊ[{"..Q.","...Q"}] + private List construct(List> board) { + List list=new ArrayList<>(); + for (int i = 0; i < board.size(); i++) { + StringBuilder sb=new StringBuilder(); + List s = board.get(i); + for (int j = 0; j < s.size(); j++) { + sb.append(s.get(j)); + } + list.add(sb.toString()); + } + return list; + } + + + /****/ + private List construct(char[][] board) { + List list=new ArrayList<>(); + for (int i = 0; i < board.length; i++) { + String s = new String(board[i]); + list.add(s); + } + return list; + } + + + +} diff --git a/Week_03/G20200343030379/LeetCode_51_379_2.java b/Week_03/G20200343030379/LeetCode_51_379_2.java new file mode 100644 index 00000000..f54fe4b5 --- /dev/null +++ b/Week_03/G20200343030379/LeetCode_51_379_2.java @@ -0,0 +1,141 @@ +package G20200343030379; + + + +import java.util.ArrayList; +import java.util.List; + +/** + * Ż + * 51. Nʺ + * n ʺоν n ʺ nn ϣʹʺ˴֮䲻໥ + * ͼΪ 8 ʺһֽⷨ + * + * һ nвͬ?n?ʺĽ + * + * ÿһֽⷨһȷ?n ʺӷ÷÷ 'Q' '.' ֱ˻ʺͿλ + * + * : 4 + * : [ + * [".Q..", // ⷨ 1 + * "...Q", + * "Q...", + * "..Q."], + * + * ["..Q.", // ⷨ 2 + * "Q...", + * "...Q", + * ".Q.."] + * ] + * : 4 ʺͬĽⷨ + * + * ԴۣLeetCode + * ӣhttps://leetcode-cn.com/problems/n-queens + * ȨСҵתϵٷȨҵתע + * + * ο⣺ + */ +public class LeetCode_51_379_2 { + public static void main(String[] args) { + List> strings = new LeetCode_51_379_3().solveNQueens(4); + System.out.println(strings); + new LeetCode_51_379_2().construct(new char[][]{{'1','2'}}); + + + } + + /** + * ִʱ : 3 ms , Java ύл 90.88% û + * ڴ : 41.5 MB , Java ύл 5.58% û + * @param n + * @return + */ + public List> solveNQueens(int n) { + List> res=new ArrayList<>(); + char[][] board=new char[n][n]; + for (int i = 0; i < board.length; i++) { + for (int j = 0; j < board.length; j++) { + board[i][j]='.'; + } + } + dfs(res,board,0); + return res; + } + + + /** + * + * @param res ǰʼNʺṹÿӶǡ. + * @param nStrut ѡн + * @param row + */ + private void dfs(List> res,char[][] nStrut,int row) { + //˳ + if(nStrut.length==row){ + res.add(construct(nStrut)); + return ; + } + //ִ߼ + // + for (int col = 0; col < nStrut.length; col++) { + //УǷ + if(!validate(nStrut,row,col)){ + continue; + } + + //ѡ + nStrut[row][col]='Q'; + //ݹ + dfs(res,nStrut,row+1); + //ѡ + nStrut[row][col]='.'; + } + } + + /** + * У鵱ǰλǷãΧ + * true false ǿãᱻ + * @param broad ǰѡĽ + * @param row + * @param col + * @return + */ + private boolean validate(char[][] broad, int row, int col) { + //УеĵǰУǷڻʺ i == col,ﴫcolΪǻ + //broad.length ʵԸΪ rowΪĿ϶ǿյݣܴڹΧ + //for (int i = 0; i < broad.length; i++) { + for (int i = 0; i < row; i++) { + if(broad[i][col]=='Q'){ + return false; + } + } + + //УϽǣų row-- ,col-- + for (int i = row-1,j = col-1; i>=0 && j>=0 ; i--,j--) { + if(broad[i][j]=='Q'){ + return false; + } + } + + //УϽǣų row-- , col++ + for (int i = row-1,j = col+1; i>=0 && j construct(char[][] board) { + List list = new ArrayList<>(); + for (int i = 0; i < board.length; i++) { + String s = new String(board[i]); + list.add(s); + } + return list; + } + + + +} diff --git a/Week_03/G20200343030379/LeetCode_55_379.java b/Week_03/G20200343030379/LeetCode_55_379.java new file mode 100644 index 00000000..afae0870 --- /dev/null +++ b/Week_03/G20200343030379/LeetCode_55_379.java @@ -0,0 +1,58 @@ +package G20200343030379; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +/** + * 55. ԾϷ + * + * һǸ飬λĵһλá + * + * еÿԪشڸλÿԾ󳤶ȡ + * + * жǷܹһλá + * + * ʾ?1: + * + * : [2,3,1,1,4] + * : true + * : ǿ 1 λ 0 λ 1, Ȼٴλ 1 3 һλá + * ʾ?2: + * + * : [3,2,1,0,4] + * : false + * : ܻᵽΪ 3 λáλõԾ 0 Զܵһλá + * + * ԴۣLeetCode + * ӣhttps://leetcode-cn.com/problems/jump-game + * ȨСҵתϵٷȨҵתע + * + * ⣺ + * + * + */ + + + +public class LeetCode_55_379 { + + /** + * ִʱ : 1 ms , Java ύл 99.96% û + * ڴ : 41.1 MB , Java ύл 22.40% û + * @param nums + * @return + */ + public boolean canJump(int[] nums) { + int lastIndex=nums.length-1; + for (int i = lastIndex-1; i >= 0; i--) { + if(i+nums[i]>=lastIndex){ + lastIndex=i; + } + + } + return lastIndex==0; + } + +} diff --git a/Week_03/G20200343030379/LeetCode_69_379.java b/Week_03/G20200343030379/LeetCode_69_379.java new file mode 100644 index 00000000..1b3f7cb6 --- /dev/null +++ b/Week_03/G20200343030379/LeetCode_69_379.java @@ -0,0 +1,79 @@ +package G20200343030379; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 69. x ƽ + * ʵ?int sqrt(int x)? + * + * 㲢?x?ƽ?x ǷǸ + * + * ڷֻIJ֣Сֽȥ + * + * ʾ 1: + * + * : 4 + * : 2 + * ʾ 2: + * + * : 8 + * : 2 + * ˵: 8 ƽ 2.82842..., + * ? ڷСֽȥ + * + * ԴۣLeetCode + * ӣhttps://leetcode-cn.com/problems/sqrtx + * ȨСҵתϵٷȨҵתע + * + * ο⣺ + */ +public class LeetCode_69_379 { + public static void main(String[] args) { + } + + /** + * ֲҷ + * + * ִʱ : 2 ms , Java ύл 79.94% û + * ڴ : 36.9 MB , Java ύл 5.12% û + * @param x + * @return + */ + public int mySqrt(int x) { + long left=0,right=x; + long mid=0; + + while (left<=right){ + mid=(left+right)/2; + if(mid*mid==x){ + return (int) mid; + }else if(mid*mid>x){ + right=mid-1; + }else{ + left=mid+1; + } + } + return (int) right; + } + + /** + * ţٵ + * + * ִʱ : 2 ms , Java ύл 79.94% û + * ڴ : 36.7 MB , Java ύл 5.12% û + * @param x + * @return + */ + public int mySqrt2(int x) { + long a=x; + while (a*a>x){ + a = (a + x / a) / 2; + } + return (int) a; + } + + +} diff --git a/Week_03/G20200343030379/LeetCode_74_379.java b/Week_03/G20200343030379/LeetCode_74_379.java new file mode 100644 index 00000000..653ee845 --- /dev/null +++ b/Week_03/G20200343030379/LeetCode_74_379.java @@ -0,0 +1,113 @@ +package G20200343030379; + +/** + * 74. ά + * + * дһЧ㷨ж?m x n?УǷһĿֵþԣ + * + * ÿеҰС + * ÿеĵһǰһеһ + * ʾ?1: + * + * : + * matrix = [ + * [1, 3, 5, 7], + * [10, 11, 16, 20], + * [23, 30, 34, 50] + * ] + * target = 3 + * : true + * ʾ?2: + * + * : + * matrix = [ + * [1, 3, 5, 7], + * [10, 11, 16, 20], + * [23, 30, 34, 50] + * ] + * target = 13 + * : false + * + * ԴۣLeetCode + * ӣhttps://leetcode-cn.com/problems/search-a-2d-matrix + * ȨСҵתϵٷȨҵתע + * + * ο⣺ + * + */ +public class LeetCode_74_379 { + + /** + * ֲҷ + * + * ִʱ : 0 ms , Java ύл 100.00% û + * ڴ : 41.5 MB , Java ύл 47.05% û + * + * ⣺https://leetcode-cn.com/problems/search-a-2d-matrix/solution/sou-suo-er-wei-ju-zhen-by-leetcode/ + * @param matrix + * @param target + * @return + */ + public boolean searchMatrix(int[][] matrix, int target) { + int rowN = matrix.length; + if(rowN == 0) return false; + + //ж + int colM=matrix[0].length; + + + int left=0,right=rowN * colM - 1; + //洢У + int row=0,col=0; + int mid=0; + while (left <= right){ + mid=(left + right)/2; + row = mid / colM; + col = mid % colM; + + if(matrix[row][col] == target){ + return true; + }else if(matrix[row][col] > target){ + right = mid - 1; + }else{ + left = mid + 1; + } + + } + return false; + } + + /** + * Ͻǿʼ + * + * ִʱ : 1 ms , Java ύл 39.32% û + * ڴ : 41.5 MB , Java ύл 48.48% û + * + * ⣺https://leetcode.com/problems/search-a-2d-matrix/discuss/26215/An-Easy-Solution-in-Java + * @param matrix + * @param target + * @return + */ + public boolean searchMatrix2(int[][] matrix, int target) { + int row=0; + if(matrix.length==0) return false; + int col=matrix[0].length-1; + + while(row < matrix.length && col >= 0){ + System.out.println(row+"--"+col+"=="+matrix[row][col]); + if(matrix[row][col] == target){ + return true; + }else if(matrix[row][col] > target){ + //Ŀֵ + col --; + }else{ + //СĿֵһ + row ++; + } + } + //ʧܣfalse + return false; + } + + +} diff --git a/Week_03/G20200343030379/LeetCode_78_379.java b/Week_03/G20200343030379/LeetCode_78_379.java new file mode 100644 index 00000000..ae0f55cf --- /dev/null +++ b/Week_03/G20200343030379/LeetCode_78_379.java @@ -0,0 +1,130 @@ +package G20200343030379; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Stack; + +/** + * 78. Ӽ + * һ鲻ظԪص numsظпܵӼݼ + * ⼯ܰظӼ + * + * : nums = [1,2,3] + * : + * [ + * [3], + * [1], + * [2], + * [1,2,3], + * [1,3], + * [2,3], + * [1,2], + * [] + * ] + * + * + * ο˼·https://u.geekbang.org/lesson/10?article=199750 + * ע⣺пܶѡ + */ +public class LeetCode_78_379 { + public static void main(String[] args) { + + } + /******һַ񣺵ݹ*************/ + public List> subsets(int[] nums) { + Stack stack=new Stack<>(); + return dsf(nums,new ArrayList<>(),stack,0); + } + + /** + * һַһַд + * @param nums Ԫ + * @param list շ + * @param stack ǰ + * @param index ǰڼ + * @return + */ + public List> dsf(int[] nums,List> list, Stack stack, int index){ + //˳һ㼴˳ + if(index==nums.length){ + list.add(new ArrayList(stack)); + return list; + } + + //ִеݹ + //ѡǰԪأֱһ + //stack.add(nums[index]); + dsf(nums,list, stack, index+1); + //ѡǰԪأһ + stack.add(nums[index]); + dsf(nums,list, stack, index+1); + + // + stack.pop(); + return list; + } + + /******һַڶַ񣺵ݹ*************/ + public List> subsets2(int[] nums) { + Stack stack=new Stack<>(); + List> list=new ArrayList<>(); + dsf2(nums,list,stack,0); + return list; + } + + /** + * ڶַд + * @param nums Ԫ + * @param list շ + * @param stack ǰ + * @param index ǰڼ + * @return + */ + public void dsf2(int[] nums,List> list, Stack stack, int index){ + //˳һ㼴˳ + if(index==nums.length){ + list.add(new ArrayList(stack)); + return ; + } + + //ִеݹ + //ѡǰԪأֱһ + //stack.add(nums[index]); + dsf2(nums,list, stack, index+1); + //ѡǰԪأһ + stack.add(nums[index]); + dsf2(nums,list, stack, index+1); + + // + stack.pop(); + } + + /******ڶ˼·*************/ + public List> subsets3(int[] nums) { + //[1,2,3] + //ṹÿ[]һlistϣͺ + //{[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]} + //ӼʼһΪ + List> res=new ArrayList<>(); + res.add(new ArrayList<>()); + + //nums + for (int num : nums) { + //洢ÿһļ + List> bigList=new ArrayList(); + //Ӽ + for (List re : res) { + //洢ÿԪصļϣ˵[1,2][2,3] + List list = new ArrayList<>(re); + list.add(num); + bigList.add(list); + } + //ÿһļϣ׷ӵԪء + res.addAll(bigList); + } + + return res; + } + +} diff --git a/Week_03/G20200343030379/LeetCode_860_379.java b/Week_03/G20200343030379/LeetCode_860_379.java new file mode 100644 index 00000000..e79ec71c --- /dev/null +++ b/Week_03/G20200343030379/LeetCode_860_379.java @@ -0,0 +1,101 @@ +package G20200343030379; + +import java.util.Arrays; + +/** + * 860. ˮ + * + * ˮ̯ϣÿһˮۼΪ?5?Ԫ + * + * ˿ŶӹIJƷ˵ bills ֧˳һιһ + * + * ÿλ˿ֻһˮȻ㸶 5 Ԫ10 Ԫ 20 Ԫÿ˿ȷ㣬Ҳ˵ÿλ˿֧ 5 Ԫ + * + * ע⣬һʼͷûκǮ + * + * ܸÿλ˿ȷ㣬?true?򷵻 false? + * + * ʾ 1 + * + * 룺[5,5,5,10,20] + * true + * ͣ + * ǰ 3 λ˿ǰ˳ȡ 3 5 ԪijƱ + * 4 λ˿ȡһ 10 ԪijƱ 5 Ԫ + * 5 λ˿һһ 10 ԪijƱһ 5 ԪijƱ + * пͻõȷ㣬 true + * ʾ 2 + * + * 룺[5,5,10] + * true + * ʾ 3 + * + * 룺[10,10] + * false + * ʾ 4 + * + * 룺[5,5,10,10,20] + * false + * ͣ + * ǰ 2 λ˿ǰ˳ȡ 2 5 ԪijƱ + * ڽ 2 λ˿ͣȡһ 10 ԪijƱȻ󷵻 5 Ԫ + * һλ˿ͣ޷˻ 15 ԪΪֻ 10 ԪijƱ + * ڲÿλ˿Ͷõȷ㣬Դ false + * ? + * + * ʾ + * + * 0 <= bills.length <= 10000 + * bills[i]??5??10??20? + * + * ԴۣLeetCode + * ӣhttps://leetcode-cn.com/problems/lemonade-change + * ȨСҵתϵٷȨҵתע + * + * ⣺https://leetcode-cn.com/problems/lemonade-change/solution/lemonade-change-tan-xin-suan-fa-by-jyd/ + * + * + */ + + + +public class LeetCode_860_379 { + + public static void main(String[] args) { + new LeetCode_860_379().lemonadeChange(new int[]{5,5,5,10,20}); + } + + /** + * ִʱ : 2 ms , Java ύл 99.92% û + * ڴ : 41.8 MB , Java ύл 5.15% û + * @param bills + * @return + */ + public boolean lemonadeChange(int[] bills) { + int five=0,ten=0; + for (int bill : bills) { + if(bill==5){ + five++; + }else if(bill==10){ + if(five==0){ + return false; + } + five--; + ten++; + //20==10+5+5 + // 5+5+5+5 + }else{ + if(five>0 && ten>0){ + five--; + ten--; + }else if(five>2){ + five-=3; + }else{ + return false; + } + } + } + return true; + } + +} diff --git a/Week_03/G20200343030379/LeetCode_874_379.java b/Week_03/G20200343030379/LeetCode_874_379.java new file mode 100644 index 00000000..8d01436e --- /dev/null +++ b/Week_03/G20200343030379/LeetCode_874_379.java @@ -0,0 +1,191 @@ +package G20200343030379; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +/** + * 874. ģ߻ + * + * һ޴Сߣӵ?(0, 0) ʼ򱱷û˿Խ͵ + * + * -2ת?90 + * -1ת 90 + * 1 <= x <= 9ǰƶ?x?λ + * һЩӱΪϰ + * + * i?ϰλ ?(obstacles[i][0], obstacles[i][1]) + * + * ͼߵϰϷôͣϰǰһ񷽿ϣȻԼ·ߵಿ֡ + * + * شԭ㵽˵ŷʽƽ + * + * ? + * + * ʾ 1 + * + * : commands = [4,-1,3], obstacles = [] + * : 25 + * : ˽ᵽ (3, 4) + * ʾ?2 + * + * : commands = [4,-1,4,-2,4], obstacles = [[2,4]] + * : 65 + * : תߵ (1, 8) ֮ǰ (1, 4) + * ? + * + * ʾ + * + * 0 <= commands.length <= 10000 + * 0 <= obstacles.length <= 10000 + * -30000 <= obstacle[i][0] <= 30000 + * -30000 <= obstacle[i][1] <= 30000 + * 𰸱֤С?2 ^ 31 + * + * ԴۣLeetCode + * ӣhttps://leetcode-cn.com/problems/walking-robot-simulation + * ȨСҵתϵٷȨҵתע + * + * ⣺ + * https://leetcode-cn.com/problems/walking-robot-simulation/solution/mo-ni-xing-zou-ji-qi-ren-by-gpe3dbjds1/ + * https://leetcode.com/problems/walking-robot-simulation/discuss/152412/Concise-JavaScript-solution + * + * + * ע㡰עʹ Set ΪϰʹõݽṹԱǿЧؼһǷ衣 + * Ǽ õϰ ܻԼ 10000 + * + */ + + + +public class LeetCode_874_379 { + + /** + * ִʱ : 18 ms , Java ύл 92.95% û + * ڴ : 51.2 MB , Java ύл 96.15% û + * @param commands + * @param obstacles + * @return + */ + public int robotSim(int[] commands, int[][] obstacles) { + //ÿ,Ϊ׼ + int dx[]={0,1,0,-1}; + int dy[]={1,0,-1,0}; + + // + int x=0,y=0; + //ʶ + int di=0; + int maxValue=0; + + //ϰ浽setϣƥ + //obstacles[i][] iʾڼ obstacles[i][0] x ,obstacles[i][1] y + //xܴڶyֵԴ洢ʹ Map> 洢key:xᣬvalueyб + Map> obstaceleMap=new HashMap<>(); + for (int i = 0; i < obstacles.length; i++) { + //x + int ox=obstacles[i][0]; + //y + int oy=obstacles[i][1]; + if(!obstaceleMap.containsKey(ox)){ + HashSet set = new HashSet<>(); + set.add(oy); + obstaceleMap.put(ox,set); + }else{ + obstaceleMap.get(ox).add(oy); + } + } + + + //-2 -1 n ǰ + for (int command : commands) { + if(command==-2){ + //ȡ + di=(di+3)%4; + }else if(command==-1){ + //ȡ + di=(di+1)%4; + }else{//ǰ + //ҪһһǰжǷϰ + for (int n = 0; n < command; n++) { + //ȡǰ,ԭۼӣνж + x+=dx[di]; + y+=dy[di]; + + //жǷϰϰִ + //obstaceleMap.get(x) ֵһyļ + if(obstaceleMap.containsKey(x) && obstaceleMap.get(x).contains(y)){ + //˻ԭλ + x-=dx[di]; + y-=dy[di]; + //System.out.println("ϰֹͣǰx y"+x+"__"+y); + break; + } + + //System.out.println(x+"___"+y+"_____"+(x*x+y*y)); + + //شԭ㵽˵ŷʽƽÿһʱֵ + maxValue=Math.max(maxValue,x*x+y*y); + } + } + } + return maxValue; + } + + + /** + * Լһ + * @param commands + * @param obstacles + * @return + */ + public int robotSim2(int[] commands, int[][] obstacles) { + // + int[] dx={0,1,0,-1}; + int[] dy={1,0,-1,0}; + + int x=0,y=0; + int di=0; + int maxvale=0; + Map> obstaceleMap=new HashMap<>(); + for (int i = 0; i < obstacles.length; i++) { + int ox=obstacles[i][0]; + int oy=obstacles[i][1]; + + if(!obstaceleMap.containsKey(ox)){ + Set set=new HashSet<>(); + set.add(oy); + obstaceleMap.put(ox,set); + + }else{ + obstaceleMap.get(ox).add(oy); + } + + } + + for (int command : commands) { + if(command==-2){ + di=(di+3)%4; + }else if(command==-1){ + di=(di+1)%4; + }else{ + for (int i = 0; i < command; i++) { + x+=dx[di]; + y+=dy[di]; + + if(obstaceleMap.containsKey(x) && obstaceleMap.get(x).contains(y)){ + x-=dx[di]; + y-=dy[di]; + break; + } + maxvale=Math.max(maxvale,x*x+y*y); + } + + } + } + return maxvale; + } + +} diff --git a/Week_03/G20200343030379/NOTE.md b/Week_03/G20200343030379/NOTE.md index 50de3041..3c125488 100644 --- a/Week_03/G20200343030379/NOTE.md +++ b/Week_03/G20200343030379/NOTE.md @@ -1 +1,5 @@ -学习笔记 \ No newline at end of file +学习笔记 + +这周的难度加多了很多,有点措手不及,开始花了3、4天的时间,搞定了回溯和分治,信心影响很大. + +而后又学习广度优先搜索和深度优先搜索,更受打击,题目都看不懂,甚至看题目都看不懂,咬咬牙刷了一部分题目,这周有点吃力。 \ No newline at end of file diff --git a/Week_03/G20200343030383/LeetCode_33_383.go b/Week_03/G20200343030383/LeetCode_33_383.go new file mode 100644 index 00000000..332afb75 --- /dev/null +++ b/Week_03/G20200343030383/LeetCode_33_383.go @@ -0,0 +1,26 @@ +/* https://leetcode-cn.com/problems/search-in-rotated-sorted-array/ + * 33. 搜索旋转排序数组 +*/ +package leetcode + +func search(nums []int, target int) int { + start, end := 0, len(nums)-1 + for start <= end { + mid := (start + end) / 2 + if nums[mid] == target { + return mid + } else if targetInLeft(nums, start, mid, end, target) { + end = mid - 1 + } else { + start = mid + 1 + } + } + return -1 +} + +func targetInLeft(nums []int, start, mid, end, target int) bool { + if nums[start] <= nums[mid] { + return target <= nums[mid] && nums[start] <= target + } + return !(target <= nums[end] && nums[mid] <= target) +} diff --git a/Week_03/G20200343030383/LeetCode_55_383.go b/Week_03/G20200343030383/LeetCode_55_383.go new file mode 100644 index 00000000..070acef7 --- /dev/null +++ b/Week_03/G20200343030383/LeetCode_55_383.go @@ -0,0 +1,15 @@ +/* + * https://leetcode-cn.com/problems/jump-game/submissions/ + * 55. 跳跃游戏 + */ +package leetcode + +func canJump(nums []int) bool { + point := len(nums) - 1 + for i := point - 1; i >= 0; i-- { + if nums[i]+i >= point { + point = i + } + } + return point == 0 +} diff --git a/Week_03/G20200343030383/LeetCode_74_383.go b/Week_03/G20200343030383/LeetCode_74_383.go new file mode 100644 index 00000000..2d0de5c7 --- /dev/null +++ b/Week_03/G20200343030383/LeetCode_74_383.go @@ -0,0 +1,27 @@ +/* + * https://leetcode-cn.com/problems/search-a-2d-matrix/submissions/ + * 74. 搜索二维矩阵 + */ +package leetcode + +func searchMatrix(matrix [][]int, target int) bool { + if len(matrix) == 0 || len(matrix[0]) == 0 { + return false + } + for start, end := 0, len(matrix)*len(matrix[0])-1; start <= end; { + mid := (start + end) / 2 + if v := getMidVal(matrix, mid); v == target { + return true + } else if v < target { + start = mid + 1 + } else { + end = mid - 1 + } + } + return false +} + +func getMidVal(matrix [][]int, i int) int { + j := i / len(matrix[0]) + return matrix[j][i%len(matrix[0])] +} diff --git a/Week_03/G20200343030387/LeetCode_127_387.js b/Week_03/G20200343030387/LeetCode_127_387.js new file mode 100644 index 00000000..16666ace --- /dev/null +++ b/Week_03/G20200343030387/LeetCode_127_387.js @@ -0,0 +1,59 @@ +/** + * @param {string} beginWord + * @param {string} endWord + * @param {string[]} wordList + * @return {number} + */ +// 求最短距离,一般用广度优先比较合适,深度优先需要将所有可能情况都遍历到,然后比较最优; +// 从bgeinWord开始,每一层尝试转换成wordList里的单词,走到转换成enwWord,当前层就是最短距离; +// 中间需要存储访问过的单词,防止出来环路; +// 如果最终wordList里的都访问过了,还是没能转成endWord,则说明无法转换,返回0; +// 为加快找到能转换的单词,这里将wordList的单词用hash表存储对应的转换规则中,如'd*g' => ['dog', 'dug'] +var ladderLength = function (beginWord, endWord, wordList) { + const wordHash = new Map() + const wordLength = beginWord.length + const replaceCharByIndex = function (str, index) { + return str.substring(0, index) + "*" + str.substring(index + 1) + } + const buildWordHash = function () { + let key = '' + let val = [] + wordList.forEach(word => { + for (let i = 0; i < wordLength; i++) { + key = replaceCharByIndex(word, i) + val = wordHash.get(key) || [] + val.push(word) + wordHash.set(key, val) + } + }) + } + const bfs = function () { + const queues = [{node: beginWord, level: 1}] + const visited = new Set() + let current = '' + let level = 0 + let childNodes = [] + visited.add(beginWord) + while (queues.length) { + current = queues.shift() + level = current.level + for (let wi = 0; wi < wordLength; wi++) { + childNodes = wordHash.get(replaceCharByIndex(current.node, wi)) + if (childNodes) { + for (let i = 0; i < childNodes.length; i++) { + if (childNodes[i] === endWord) { + return current.level + 1 + } + if (!visited.has(childNodes[i])) { + visited.add(childNodes[i]) + queues.push({node: childNodes[i], level: level + 1}) + } + } + } + } + } + return 0 + } + buildWordHash() + return bfs() +}; \ No newline at end of file diff --git a/Week_03/G20200343030387/LeetCode_153_387.js b/Week_03/G20200343030387/LeetCode_153_387.js new file mode 100644 index 00000000..a97471cd --- /dev/null +++ b/Week_03/G20200343030387/LeetCode_153_387.js @@ -0,0 +1,25 @@ +/** + * @param {number[]} nums + * @return {number} + */ +// 二分法 +// 旋转后的数组,最小值在递增转变处; +// 如果找到整个是单调递增的,说明左边界即为最小值; +// 如果mid右边是单调递增,则最小值在mid的左边,否则在mid的右边; +var findMin = function (nums) { + let left = 0 + let right = nums.length - 1 + let mid = 0 + while (left < right) { + if (nums[left] < nums[right]) { + return nums[left] + } + mid = parseInt((left + right) / 2) + if (nums[mid] < nums[right]) { + right = mid + } else { + left = mid + 1 + } + } + return nums[right] +}; \ No newline at end of file diff --git a/Week_03/G20200343030387/LeetCode_17_387.js b/Week_03/G20200343030387/LeetCode_17_387.js new file mode 100644 index 00000000..795d895a --- /dev/null +++ b/Week_03/G20200343030387/LeetCode_17_387.js @@ -0,0 +1,35 @@ +/** + * @param {string} digits + * @return {string[]} + */ +// digits.length个格子,放置phone的数字对应的字母; +// 每个数字有三个字母,相当于每个格子有三种可能(三叉树); +const buildPhone = function () { + const phone = new Map() + phone.set("2", "abc") + phone.set("3", "def") + phone.set("4", "ghi") + phone.set("5", "jkl") + phone.set("6", "mno") + phone.set("7", "pqrs") + phone.set("8", "tuv") + phone.set("9", "wxyz") + return phone +} +var letterCombinations = function (digits) { + if (!digits.length) return [] + const phone = buildPhone() + const res = [] + const size = digits.length + const reversion = function (level, str) { + if (level >= size) { + res.push(str) + return + } + phone.get(digits[level]).split('').forEach(c => { + reversion(level + 1, str + c) + }) + } + reversion(0, '') + return res +}; \ No newline at end of file diff --git a/Week_03/G20200343030387/LeetCode_22_387.js b/Week_03/G20200343030387/LeetCode_22_387.js new file mode 100644 index 00000000..4f090284 --- /dev/null +++ b/Week_03/G20200343030387/LeetCode_22_387.js @@ -0,0 +1,26 @@ +/** + * @param {number} n + * @return {string[]} + */ +// 想象有2n个格式,每个格子放一个左或右括号,并且满足成对的形式 +// 最近重复性是放左格号或右括号 +var generateParenthesis = function (n) { + const res = [] + const recursion = function (left, right, n, str) { + if (left >= n && right >= n) { + res.push(str) + return + } + // 剪枝 + // 左括号不超限 + if (left < n) { + recursion(left + 1, right, n, str + '(') + } + // 已经有左括号,且右括号数量少于左括号数量 + if (left > right) { + recursion(left, right + 1, n, str + ')') + } + } + recursion(0, 0, n, '') + return res +}; \ No newline at end of file diff --git a/Week_03/G20200343030387/LeetCode_33_387.js b/Week_03/G20200343030387/LeetCode_33_387.js new file mode 100644 index 00000000..5a7b2c98 --- /dev/null +++ b/Week_03/G20200343030387/LeetCode_33_387.js @@ -0,0 +1,33 @@ +/** + * @param {number[]} nums + * @param {number} target + * @return {number} + */ +// 二分查找 +// 元素经过旋转后,不再是全局单调递增,但旋转点的左右部分还是递增的,且递增方向一致; +// [nums[left], mid] +// 如果 nums[left] < mid,表示这部分递增,target < nums[left] 或 target > mid,命中后半部分; +// 如果 nums[left] > mid,表示这部分不是递增,target < nums[left] 且 target > mid,命中后半部分; +// 否则,命中前半部分; +// 每次需要判断mid是否等于target,是则返回其索引,否则返回-1 +// 遍历结束也没找到符合条件的,返回-1 +var search = function (nums, target) { + if (!nums.length) return -1 + let left = 0 + let right = nums.length - 1 + let mid = 0 + while (left <= right) { + mid = parseInt((left + right) / 2) + if (nums[mid] === target) { + return mid + } + if (nums[left] <= nums[mid] && (target < nums[left] || target > nums[mid])) { + left = mid + 1 + } else if (nums[left] > target && target > nums[mid]) { + left = mid + 1 + } else { + right = mid - 1 + } + } + return -1 +}; \ No newline at end of file diff --git a/Week_03/G20200343030387/LeetCode_50_387.js b/Week_03/G20200343030387/LeetCode_50_387.js new file mode 100644 index 00000000..6bb3ffc0 --- /dev/null +++ b/Week_03/G20200343030387/LeetCode_50_387.js @@ -0,0 +1,53 @@ +/** + * @param {number} x + * @param {number} n + * @return {number} + */ + +// 暴力法 +// LeetCode校验会超时,可能是js运行太慢了 +const fastPow1 = function (x, n) { + let N = n + if (N < 0) { + N = -N + x = 1 / x + } + let res = 1 + for (let i = 0; i < N; i++) { + res *= x + } + return res +} + +// 快速幂算法(递归) +// n为偶数: +// x^n = x^(n/2) * x^(n/2) +// = x^(n/4) * x^(n/4) * x^(n/4) * x^(n/4) +// = ... +// 兼容奇数情况,n减半时要取整数,最后再乘多一个x: +// x^n = x^(n/2) * x^(n/2) * x +// = x^(n/4) * x^(n/4) * x^(n/4) * x^(n/4) * x +// = ... +// 找到重复性,进行递归 +const fastPow = function (x, n) { + if (n === 0) { + return 1 + } + const half = fastPow(x, parseInt(n / 2)) + if (n % 2 === 0) { + return half * half + } else { + return half * half * x + } +} +const myPow = function (x, n) { + let N = n + // 数学知识:指数小于0时,2^-2 = (1/2)^2 + if (N < 0) { + x = 1 / x + N = -N + } + + return fastPow(x, N) +}; + diff --git a/Week_03/G20200343030387/LeetCode_51_387.js b/Week_03/G20200343030387/LeetCode_51_387.js new file mode 100644 index 00000000..61d01034 --- /dev/null +++ b/Week_03/G20200343030387/LeetCode_51_387.js @@ -0,0 +1,52 @@ +/** + * @param {number} n + * @return {string[][]} + */ +// 递归法 +// 皇后在每一行都会有n个列可选,相当于状态树的每一层都有n个分叉; +// 走下一个分叉前需要判断攻击范围,每次成功都存储当前所在的列,行数则为当时遍历到的状态树层次,也是存入数组元素的序号; +// 若走到了最底层,则表示当前存储的状态符合条件; +var solveNQueens = function (n) { + const res = [] + const cols = new Set() // 垂直线的攻击位置 + const pies = new Set() // 向左对角线的攻击位置 + const nas = new Set() // 向右对角线的攻击位置 + // 递归生成皇后的位置 + const recurison = function (row, queens) { + if (row >= n) { + // 由于queens在reverse会被修改,所以这里clone一份 + res.push(queens.slice(0)) + return + } + // 遍历列 + for (let col = 0; col < n; col++) { + // 判断是否在攻击范围,是则continue + if (cols.has(col) || pies.has(col + row) || nas.has(col - row)) { + continue + } + cols.add(col) + pies.add(col + row) + nas.add(col - row) + queens.push(col) + + // drill down + recurison(row + 1, queens) + + // reverse status + queens.pop() + cols.delete(col) + pies.delete(col + row) + nas.delete(col - row) + } + } + // 生成棋盘 + const generateCheckerboard = function () { + return res.map(queens => { + return queens.map(q => { + return Array(n).fill().map((k, i) => {return i === q ? 'Q' : '.'}).join('') + }) + }) + } + recurison(0, []) + return generateCheckerboard() +}; \ No newline at end of file diff --git a/Week_03/G20200343030387/LeetCode_74_387.js b/Week_03/G20200343030387/LeetCode_74_387.js new file mode 100644 index 00000000..f279ed52 --- /dev/null +++ b/Week_03/G20200343030387/LeetCode_74_387.js @@ -0,0 +1,59 @@ +/** + * @param {number[][]} matrix + * @param {number} target + * @return {boolean} + */ +// 将二维数组降至一维; +// 因为其单调递增,所以用十分法求目标值; +// 找到则返回true, 遍历到最后返回false; +var searchMatrix1 = function (matrix, target) { + if (!matrix.length) return false + matrix.forEach(item => { + matrix[0] = matrix[0].concat(item) + }) + if (!matrix[0].length) return false + let left = 0 + let right = matrix[0].length - 1 + let mid = 0 + while (left <= right) { + mid = parseInt((left + right) / 2) + if (matrix[0][mid] === target) { + return true + } + if (matrix[0][mid] > target) { + right = mid - 1 + } else { + left = mid + 1 + } + } + return false +}; + + +// 想象所有元素拼接成虚拟数组; +// 虚拟数组元素的索引index转换为矩阵的行列位置; +// 行:index / n;列:index % n +var searchMatrix = function (matrix, target) { + const m = matrix.length + if (m === 0) return false + const n = matrix[0].length + let left = 0 + let right = m * n - 1 + let mid = 0 + let midx = 0 + let nidx = 0 + while (left <= right) { + mid = parseInt((left + right) / 2) + midx = parseInt(mid / n) + nidx = parseInt(mid % n) + if (matrix[midx][nidx] === target) { + return true + } + if (matrix[midx][nidx] > target) { + right = mid - 1 + } else { + left = mid + 1 + } + } + return false +} \ No newline at end of file diff --git a/Week_03/G20200343030387/LeetCode_78_387.js b/Week_03/G20200343030387/LeetCode_78_387.js new file mode 100644 index 00000000..4c731b75 --- /dev/null +++ b/Week_03/G20200343030387/LeetCode_78_387.js @@ -0,0 +1,26 @@ +/** + * @param {number[]} nums + * @return {number[][]} + */ +// 递归法 +// n(nums长度)个格子里放数值,可放可不放 +var subsets = function (nums) { + const res = [] + const recursion = function (level, max, list) { + // terminator + if (level >= max) { + res.push(list) + return + } + + // process current logic + // drill down + recursion(level + 1, max, list.slice(0)) + list.push(nums[level]) + recursion(level + 1, max, list.slice(0)) + + // restore current status + } + recursion(0, nums.length, []) + return res +}; diff --git a/Week_03/G20200343030387/LeetCode_860_387.js b/Week_03/G20200343030387/LeetCode_860_387.js new file mode 100644 index 00000000..ef15b2a3 --- /dev/null +++ b/Week_03/G20200343030387/LeetCode_860_387.js @@ -0,0 +1,33 @@ +/** + * @param {number[]} bills + * @return {boolean} + */ +// 贪心算法 +// 经过推断,每次找零都用最优,最后能得出全局最优 +var lemonadeChange = function (bills) { + let five = 0 + let ten = 0 + for (let i = 0; i < bills.length; i++) { + switch (bills[i]) { + case 5: + five++ + break + case 10: + five-- + ten++ + break + case 20: + if (ten > 0) { + five-- + ten-- + } else { + five -= 3 + } + break + } + if (five < 0) { + return false + } + } + return true +}; \ No newline at end of file diff --git a/Week_03/G20200343030387/NOTE.md b/Week_03/G20200343030387/NOTE.md index 50de3041..c0457c7f 100644 --- a/Week_03/G20200343030387/NOTE.md +++ b/Week_03/G20200343030387/NOTE.md @@ -1 +1,146 @@ -学习笔记 \ No newline at end of file +# 学习笔记 +## 递归、分治、回溯 +* 分解子问题 +* 找重复性 +* 三者的代码实现很相似 +* 用递归代码实现逻辑,可以类比n叉状态树的深度优先遍历 + +## 深度、广度优先搜索 +### 深度优先搜索(DFS) +* 比较反常识; +* 类比二叉树的遍历; +* 代码模板 +递归: +``` +visited = set() + +def dfs(node, visited): + if node in visited: # terminator + # already visited + return + + visited.add(node) + + # process current node here. + ... + for next_node in node.children(): + if next_node not in visited: + dfs(next_node, visited) +``` + +自定义栈 +``` +def DFS(self, tree): + + if tree.root is None: + return [] + + visited, stack = [], [tree.root] + + while stack: + node = stack.pop() + visited.add(node) + + process (node) + nodes = generate_related_nodes(node) + stack.push(nodes) + + # other processing work + ... +``` + +### 广度优先搜索(BFS) +* 符合常识 +* 类似公司、团体组织的职位分层 +* 代码模板 +``` +def BFS(graph, start, end): + visited = set() + queue = [] + queue.append([start]) + + while queue: + node = queue.pop() + visited.add(node) + + process(node) + nodes = generate_related_nodes(node) + queue.push(nodes) + + # other processing work + ... +``` + +## 贪心算法 +* 每一步都求局部最优,最终达到全局最优; +* 适用场景较少; +* 代码实现逻辑简单,判断是否可用贪心算法更重要; +* 与动态规划的区别在于,它不能回退中间结果,而动态规划可以; + +## 二分查找 +### 使用的前提 +1. 目标函数单调性(递增或递减); +2. 存在上下界; +3. 能够通过索引访问; + +### 代码模板 +``` +left, right = 0, len(array) - 1 +while left <= right: + mid = (left + right) / 2 + if array[mid] == target: + # find the target!! + break or return result + elif array[mid] < target: + left = mid + 1 + else: + right = mid - 1 +``` + +## 作业题 +> 使用二分查找,寻找一个半有序数组 [4, 5, 6, 7, 0, 1, 2] 中间无序的地方 + +### 解题思路 +1. 半有序数组相当于是一个升数组旋转一次得到; +2. 中间无序的地方相邻元素分别是该数组的最大与最小值,且与前后片段的单调性相反; +3. 用二分法查找数组的最大或最小值,则得到无序地方的位置; +4. 找最小值,如果mid右边是单调递增,则最小值在mid的左边,否则在mid的右边,一直二分下去直到左右边界重合则边界即是所求,或者中间出现左边界的值小于右边界的值,则左边界即是所求 + +* 代码实现 +```js +const solution = function (nums) { + let left = 0 + let right = nums.length - 1 + let mid = 0 + while (left < right) { + if (nums[left] < nums[right]) { + return left + } + mid = parseInt((left + right) / 2) + if (nums[mid] > nums[right]) { + left = mid + 1 + } else { + right = mid + } + } + return left +} + +const test = function () { + if (solution([4, 5, 6, 7, 0, 1, 2]) !== 4) { + throw new Error('error') + } + if (solution([4, 5, 6, 0, 1, 2]) !== 3) { + throw new Error('error') + } + if (solution([4, 1, 2]) !== 1) { + throw new Error('error') + } + if (solution([4, 5, 1, 2]) !== 2) { + throw new Error('error') + } + console.log('success') +} +test() +``` + diff --git a/Week_03/G20200343030389/JumpGame.java b/Week_03/G20200343030389/JumpGame.java new file mode 100644 index 00000000..52538d5f --- /dev/null +++ b/Week_03/G20200343030389/JumpGame.java @@ -0,0 +1,19 @@ +package follow.ice.phenix.leecode.week03; + +public class JumpGame { + + private boolean jump(int position, int[] nums) { + if (position == nums.length - 1) { + return true; + } + + int furthestJump = Math.min(position + nums[position], nums.length - 1); + for (int nextPosition = position + 1; nextPosition <= furthestJump; nextPosition++) { + if (jump(nextPosition, nums)) { + return true; + } + } + + return false; + } +} diff --git a/Week_03/G20200343030389/LemonadeChange.java b/Week_03/G20200343030389/LemonadeChange.java new file mode 100644 index 00000000..1a32f303 --- /dev/null +++ b/Week_03/G20200343030389/LemonadeChange.java @@ -0,0 +1,34 @@ +package follow.ice.phenix.leecode.week03; + +/** + * 柠檬水找零 + */ +public class LemonadeChange { + + public boolean lemonadeChange(int[] bills) { + int fiveCount = 0; + int tenCount = 0; + for (int bill : bills) { + if (bill == 5) { + fiveCount++; + } else if (bill == 10) { + if (fiveCount >= 1) { + fiveCount--; + tenCount++; + } else { + return false; + } + } else { + if (fiveCount >= 1 && tenCount >= 1) { + fiveCount--; + tenCount--; + } else if (fiveCount >= 3) { + fiveCount = fiveCount - 3; + } else { + return false; + } + } + } + return true; + } +} diff --git a/Week_03/G20200343030389/MaxProfit.java b/Week_03/G20200343030389/MaxProfit.java new file mode 100644 index 00000000..ede3af79 --- /dev/null +++ b/Week_03/G20200343030389/MaxProfit.java @@ -0,0 +1,18 @@ +package follow.ice.phenix.leecode.week03; + +/** + * 买卖股票的最佳时机 + */ +public class MaxProfit { + + public int maxProfit(int[] prices) { + int result = 0; + for (int i = 0; i < prices.length - 1; i++) { + int money = prices[i] - prices[i + 1]; + if (money > 0) { + result = result + money; + } + } + return result; + } +} diff --git a/Week_03/G20200343030391/LeetCode_102_391.java b/Week_03/G20200343030391/LeetCode_102_391.java new file mode 100644 index 00000000..ebbd547c --- /dev/null +++ b/Week_03/G20200343030391/LeetCode_102_391.java @@ -0,0 +1,76 @@ +package G20200343030391; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; + +public class LeetCode_102_391 { + + public static void main(String[] args) { + TreeNode node1 = new TreeNode(1); + TreeNode node2 = new TreeNode(2); + TreeNode node3 = new TreeNode(3); + TreeNode node4 = new TreeNode(4); + TreeNode node5 = new TreeNode(5); + TreeNode node6 = new TreeNode(6); + TreeNode node7 = new TreeNode(7); + node1.right = node2; + node2.left = node3; + node3.left = node4; + node4.right = node5; + node5.right = node6; + node5.left = node7; + List> lists = new LeetCode_102_391().levelOrderByRecursion(node1); + System.out.println(lists); + } + + public List> levelOrderByRecursion(TreeNode root) { + List> result = new ArrayList<>(); + help(result, root, 0); + return result; + } + + private void help(List> result, TreeNode root, int depth) { + if (root == null) { + return; + } + if (result.size() == depth) { + result.add(new LinkedList<>()); + } + result.get(depth).add(root.val); + help(result, root.left, depth + 1); + help(result, root.right, depth + 1); + + } + + public List> levelOrderByLoop(TreeNode root) { + List> result = new ArrayList<>(); + LinkedList queue = new LinkedList<>(); + queue.push(root); + int level = 0; + while (!queue.isEmpty()) { + //start the current level + result.add(new ArrayList<>()); + + int levelSize = queue.size(); + for (int i = 0; i < levelSize; i++) { + TreeNode poll = queue.poll(); + result.get(level).add(poll.val); + if (poll.left != null) queue.add(poll.left); + if (poll.right != null) queue.add(poll.right); + } + level++; + } + return result; + } + + public static class TreeNode { + int val; + TreeNode left; + TreeNode right; + + TreeNode(int x) { + val = x; + } + } +} diff --git a/Week_03/G20200343030391/LeetCode_122_391.java b/Week_03/G20200343030391/LeetCode_122_391.java new file mode 100644 index 00000000..d86abe4b --- /dev/null +++ b/Week_03/G20200343030391/LeetCode_122_391.java @@ -0,0 +1,35 @@ +package G20200343030391; + +public class LeetCode_122_391 { + + public static void main(String[] args) { + int[] prices = {7, 1, 5, 3, 6, 4}; + int i = new LeetCode_122_391().maxProfit(prices); + System.out.println(i); + + int[] prices1 = {1, 2, 3, 4, 5}; + int i1 = new LeetCode_122_391().maxProfit(prices1); + System.out.println(i1); + + int[] prices3 = {7, 6, 3, 2}; + int i3 = new LeetCode_122_391().maxProfit(prices3); + System.out.println(i3); + } + + /** + * 贪心 + * + * @param prices + * @return + */ + public int maxProfit(int[] prices) { + int profit = 0; + for (int i = 1; i < prices.length; i++) { + //卖出 + if (prices[i] > prices[i - 1]) { + profit += prices[i] - prices[i - 1]; + } + } + return profit; + } +} diff --git a/Week_03/G20200343030391/LeetCode_126_391.java b/Week_03/G20200343030391/LeetCode_126_391.java new file mode 100644 index 00000000..7ba834bd --- /dev/null +++ b/Week_03/G20200343030391/LeetCode_126_391.java @@ -0,0 +1,93 @@ +package G20200343030391; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; +import java.util.Set; + +public class LeetCode_126_391 { + + public static void main(String[] args) { + String beginWord = "hit"; + String endWord = "cog"; + List wordList = new ArrayList<>( + Arrays.asList("hot", "dot", "dog", "lot", "log", "cog")); + long start = System.currentTimeMillis(); + List> list = new LeetCode_126_391().findLadders(beginWord, endWord, wordList); + System.out.println("耗时:" + (System.currentTimeMillis() - start) + " 结果:" + list); + } + + /** + * BFS + * + * @param beginWord + * @param endWord + * @param wordList + * @return + */ + public List> findLadders(String beginWord, String endWord, List wordList) { + // 结果集 + List> res = new ArrayList<>(); + Set distSet = new HashSet<>(wordList); + // 字典中不包含目标单词 + if (!distSet.contains(endWord)) { + return res; + } + // 已经访问过的单词集合:只找最短路径,所以之前出现过的单词不用出现在下一层 + Set visited = new HashSet<>(); + // 累积每一层的结果队列 + Queue> queue= new LinkedList<>(); + List list = new ArrayList<>(Arrays.asList(beginWord)); + queue.add(list); + visited.add(beginWord); + // 是否到达符合条件的层:如果该层添加的某一单词符合目标单词,则说明截止该层的所有解为最短路径,停止循环 + boolean flag = false; + while (!queue.isEmpty() && !flag) { + // 上一层的结果队列 + int size = queue.size(); + // 该层添加的所有元素:每层必须在所有结果都添加完新的单词之后,再将这些单词统一添加到已使用单词集合 + // 如果直接添加到 visited 中,会导致该层本次结果添加之后的相同添加行为失败 + // 如:该层遇到目标单词,有两条路径都可以遇到,但是先到达的将该单词添加进 visited 中,会导致第二条路径无法添加 + Set subVisited = new HashSet<>(); + for (int i = 0; i < size; i++) { + List path = queue.poll(); + // 获取该路径上一层的单词 + String word = path.get(path.size() - 1); + char[] chars = word.toCharArray(); + // 寻找该单词的下一个符合条件的单词 + for (int j = 0; j < chars.length; j++) { + char temp = chars[j]; + for (char ch = 'a'; ch <= 'z'; ch++) { + chars[j] = ch; + if (temp == ch) { + continue; + } + String str = new String(chars); + // 符合条件:在 wordList 中 && 之前的层没有使用过 + if (distSet.contains(str) && !visited.contains(str)) { + // 生成新的路径 + List pathList = new ArrayList<>(path); + pathList.add(str); + // 如果该单词是目标单词:将该路径添加到结果集中,查询截止到该层 + if (str.equals(endWord)) { + flag = true; + res.add(pathList); + } + // 将该路径添加到该层队列中 + queue.add(pathList); + // 将该单词添加到该层已访问的单词集合中 + subVisited.add(str); + } + } + chars[j] = temp; + } + } + // 将该层所有访问的单词添加到总的已访问集合中 + visited.addAll(subVisited); + } + return res; + } +} diff --git a/Week_03/G20200343030391/LeetCode_127_391.java b/Week_03/G20200343030391/LeetCode_127_391.java new file mode 100644 index 00000000..dd6c1627 --- /dev/null +++ b/Week_03/G20200343030391/LeetCode_127_391.java @@ -0,0 +1,286 @@ +package G20200343030391; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; +import java.util.Set; + +public class LeetCode_127_391 { + + public static void main(String[] args) { + + String beginWord = "hit"; + String endWord = "cog"; + List wordList = new ArrayList<>( + Arrays.asList("hot", "dot", "dog", "lot", "log", "cog")); + long start = System.currentTimeMillis(); + int length = new LeetCode_127_391().ladderLengthByBFS(beginWord, endWord, wordList); + System.out.println("耗时:" + (System.currentTimeMillis() - start) + " 结果:" + length); + } + + public int ladderLength(String beginWord, String endWord, List wordList) { + int end = wordList.indexOf(endWord); + if (end == -1) { + return 0; + } + wordList.add(beginWord); + + // 从两端BFS遍历要用的队列 + Queue startQueue = new LinkedList<>(); + Queue endQueue = new LinkedList<>(); + // 两端已经遍历过的节点 + Set startWayVisited = new HashSet<>(); + Set endWayVisited = new HashSet<>(); + startQueue.offer(beginWord); + endQueue.offer(endWord); + startWayVisited.add(beginWord); + endWayVisited.add(endWord); + + int count = 0; + Set allWordSet = new HashSet<>(wordList); + + while (!startQueue.isEmpty() && !endQueue.isEmpty()) { + count++; + if (startQueue.size() > endQueue.size()) { + Queue tmp = startQueue; + startQueue = endQueue; + endQueue = tmp; + Set t = startWayVisited; + startWayVisited = endWayVisited; + endWayVisited = t; + } + int size1 = startQueue.size(); + while (size1-- > 0) { + String s = startQueue.poll(); + char[] chars = s.toCharArray(); + for (int j = 0; j < s.length(); ++j) { + // 保存第j位的原始字符 + char c0 = chars[j]; + for (char c = 'a'; c <= 'z'; ++c) { + chars[j] = c; + String newString = new String(chars); + // 已经访问过了,跳过 + if (startWayVisited.contains(newString)) { + continue; + } + // 两端遍历相遇,结束遍历,返回count + if (endWayVisited.contains(newString)) { + return count + 1; + } + // 如果单词在列表中存在,将其添加到队列,并标记为已访问 + if (allWordSet.contains(newString)) { + startQueue.offer(newString); + startWayVisited.add(newString); + } + } + // 恢复第j位的原始字符 + chars[j] = c0; + } + } + } + return 0; + } + + + public int ladderLengthTowWayBFS_2(String beginWord, String endWord, List wordList) { + int end = wordList.indexOf(endWord); + if (end == -1) { + return 0; + } + wordList.add(beginWord); + int start = wordList.size() - 1; + Queue queue1 = new LinkedList<>(); + Queue queue2 = new LinkedList<>(); + Set visited1 = new HashSet<>(); + Set visited2 = new HashSet<>(); + queue1.offer(start); + queue2.offer(end); + visited1.add(start); + visited2.add(end); + int count = 0; + while (!queue1.isEmpty() && !queue2.isEmpty()) { + count++; + if (queue1.size() > queue2.size()) { + Queue tmp = queue1; + queue1 = queue2; + queue2 = tmp; + Set t = visited1; + visited1 = visited2; + visited2 = t; + } + int size1 = queue1.size(); + while (size1-- > 0) { + String s = wordList.get(queue1.poll()); + for (int i = 0; i < wordList.size(); ++i) { + if (visited1.contains(i)) { + continue; + } + if (!canConvert(s, wordList.get(i))) { + continue; + } + if (visited2.contains(i)) { + return count + 1; + } + visited1.add(i); + queue1.offer(i); + } + } + } + return 0; + } + + /** + * 双向BFS + * + * @param beginWord + * @param endWord + * @param wordList + * @return + */ + public int ladderLengthTowWayBFS_1(String beginWord, String endWord, List wordList) { + // endWord在字典中的下标 + int endWordIndex = wordList.indexOf(endWord); + if (endWordIndex == -1) { + return 0; + } + //添加startWord到字典,为endWord为起点的广度优先搜索准备数据 + wordList.add(beginWord); + //startWord 下标 + int startWordIndex = wordList.size() - 1; + // 用于BFS遍历的队列 + Queue startWayQueue = new LinkedList<>(); + Queue endWayQueue = new LinkedList<>(); + // 用于保存已访问的单词下标 + Set startWayVisited = new HashSet<>(); + Set endWayVisited = new HashSet<>(); + //入队 + startWayQueue.offer(startWordIndex); + endWayQueue.offer(endWordIndex); + //标记访问 + startWayVisited.add(startWordIndex); + endWayVisited.add(endWordIndex); + // + int count1 = 0; + int count2 = 0; + + + while (!startWayQueue.isEmpty() && !endWayQueue.isEmpty()) { + count1++; + int startWayQueueSize = startWayQueue.size(); + while (startWayQueueSize-- > 0) { + String s = wordList.get(startWayQueue.poll()); + for (int i = 0; i < wordList.size(); ++i) { + //start方向已经使用过 + if (startWayVisited.contains(i)) { + continue; + } + if (!canConvert(s, wordList.get(i))) { + continue; + } + //end方向已经使用过 + if (endWayVisited.contains(i)) { + return count1 + count2 + 1; + } + startWayVisited.add(i); + startWayQueue.offer(i); + } + } + count2++; + int size2 = endWayQueue.size(); + while (size2-- > 0) { + String s = wordList.get(endWayQueue.poll()); + for (int i = 0; i < wordList.size(); ++i) { + if (endWayVisited.contains(i)) { + continue; + } + if (!canConvert(s, wordList.get(i))) { + continue; + } + if (startWayVisited.contains(i)) { + return count1 + count2 + 1; + } + endWayVisited.add(i); + endWayQueue.offer(i); + } + } + } + return 0; + } + + /** + * 单向广度优先搜索 + * + * @param beginWord + * @param endWord + * @param wordList + * @return + */ + public int ladderLengthByBFS(String beginWord, String endWord, List wordList) { + if (!wordList.contains(endWord)) { + return 0; + } + boolean[] visited = new boolean[wordList.size()]; + + int beginWordIndex = wordList.indexOf(beginWord); + if (beginWordIndex != -1) { + visited[beginWordIndex] = true; + } + Queue queue = new LinkedList<>(); + queue.offer(beginWord); + int count = 0; + while (!queue.isEmpty()) { + //当前层数量 + int size = queue.size(); + // + count++; + for (int i = 0; i < size; i++) { + String start = queue.poll(); + for (int j = 0; j < wordList.size(); j++) { + //字典中的j元素已经使用过 + if (visited[j]) { + continue; + } + String s = wordList.get(j); + //是否相差一个字母 + if (!canConvert(start, s)) { + continue; + } + //破案:字典中已经找到endWord + if (s.equals(endWord)) { + return count + 1; + } + //标记已经使用过 + visited[j] = true; + //入队:加入下一层 + queue.offer(s); + } + } + } + return 0; + } + + /** + * 判断是否符合规则,只改变一个字母 + * + * @param s1 + * @param s2 + * @return + */ + public boolean canConvert(String s1, String s2) { + int diffCount = 0; + for (int i = 0; i < s1.length(); ++i) { + if (s1.charAt(i) != s2.charAt(i)) { + ++diffCount; + if (diffCount > 1) { + return false; + } + } + } + return diffCount == 1; + } + + +} diff --git a/Week_03/G20200343030391/LeetCode_153_391.java b/Week_03/G20200343030391/LeetCode_153_391.java new file mode 100644 index 00000000..aa1dd0bc --- /dev/null +++ b/Week_03/G20200343030391/LeetCode_153_391.java @@ -0,0 +1,27 @@ +package G20200343030391; + +public class LeetCode_153_391 { + + public static void main(String[] args) { + int[] nums = {4, 5, 6, 7, 0, 1, 2}; + int min = new LeetCode_153_391().findMin(nums); + System.out.println(min); + } + + public int findMin(int[] nums) { + int left = 0; + int right = nums.length - 1; + int mid; + + while (left < right) { + mid = left + (right - left) / 2; + if (nums[mid] <= nums[right]) { + right = mid; + } else { + left = mid + 1; + } + } + return nums[right]; + } + +} diff --git a/Week_03/G20200343030391/LeetCode_169_391.java b/Week_03/G20200343030391/LeetCode_169_391.java new file mode 100644 index 00000000..e6373382 --- /dev/null +++ b/Week_03/G20200343030391/LeetCode_169_391.java @@ -0,0 +1,100 @@ +package G20200343030391; + +import java.util.Arrays; +import java.util.HashMap; + +public class LeetCode_169_391 { + + public static void main(String[] args) { + int[] nums = {3, 2, 3, 4}; + int i = new LeetCode_169_391().majorityElement_3(nums); + System.out.println(i); + } + + /** + * 众数 + * + * @param nums + * @return + */ + public int majorityElement_1(int[] nums) { + Arrays.sort(nums); + return nums[nums.length / 2]; + } + + + /** + * 哈希表 + * + * @param nums + * @return + */ + public int majorityElement_2(int[] nums) { + if (nums.length == 1) { + return nums[0]; + } + HashMap map = new HashMap<>(); + for (int i = 0; i < nums.length; i++) { + Integer count = map.putIfAbsent(nums[i], 1); + if (count != null) { + count++; + if (count >= 1.0 * nums.length / 2) { + return nums[i]; + } else { + map.put(nums[i], count); + } + } + } + return 0; + } + + /** + * 分治 + * + * @param nums + * @return + */ + public int majorityElement_3(int[] nums) { + return divide_conquer(nums, 0, nums.length - 1); + } + + /** + * 拆分数组,一个元素的数组直接返回唯一元素,两个子数组取到各自的组内的众数, + * + * @param nums + * @param start + * @param end + * @return + */ + private int divide_conquer(int[] nums, int start, int end) { + //terminator + if (start == end) { + return nums[start]; + } + //prepare data + int mid = (end - start) / 2 + start; + //split problem + int leftMost = divide_conquer(nums, start, mid); + int rightMost = divide_conquer(nums, mid + 1, end); + + if (leftMost == rightMost) { + return leftMost; + } + //merge result + int leftCount = countInRange(nums, leftMost, start, mid); + int rightCount = countInRange(nums, rightMost, mid + 1, end); + return leftCount > rightCount ? leftMost : rightMost; + } + + private int countInRange(int[] nums, int num, int lo, int hi) { + int count = 0; + for (int i = lo; i <= hi; i++) { + if (nums[i] == num) { + count++; + } + } + return count; + } + + +} diff --git a/Week_03/G20200343030391/LeetCode_17_391.java b/Week_03/G20200343030391/LeetCode_17_391.java new file mode 100644 index 00000000..af667a01 --- /dev/null +++ b/Week_03/G20200343030391/LeetCode_17_391.java @@ -0,0 +1,114 @@ +package G20200343030391; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +public class LeetCode_17_391 { + + public static void main(String[] args) { + String digits = "23"; + List strings = new LeetCode_17_391().letterCombinations_2(digits); + System.out.println(strings); + } + /** + * 递归 + * @param digits + * @return + */ + public List letterCombinations_1(String digits) { + if (digits == null || digits.isEmpty()) { + return new ArrayList<>(); + } + HashMap map = new HashMap<>(); + map.put('2', new char[]{'a', 'b', 'c'}); + map.put('3', new char[]{'d', 'e', 'f'}); + map.put('4', new char[]{'g', 'h', 'i'}); + map.put('5', new char[]{'j', 'k', 'l'}); + map.put('6', new char[]{'m', 'n', 'o'}); + map.put('7', new char[]{'p', 'q', 'r', 's'}); + map.put('8', new char[]{'t', 'u', 'v'}); + map.put('9', new char[]{'w', 'x', 'y', 'z'}); + ArrayList result = new ArrayList<>(); + + combine("", digits.toCharArray(), 0, result, map); + + return result; + } + + /** + * 回溯 + * @param str + * @param input + * @param index + * @param result + * @param directory + */ + private void combine(String str, char[] input, int index, List result, HashMap directory) { + //terminator + if (str.length() == input.length) { + result.add(str); + return; + } + char[] chars = directory.get(input[index]); + + //process logic + for (int i = 0; i < chars.length; i++) { + //drill down + combine(str + chars[i], input, index + 1, result, directory); + } + + //reverse + } + + /** + * 递归 + * @param digits + * @return + */ + public List letterCombinations_2(String digits) { + if (digits == null || digits.isEmpty()) { + return new ArrayList<>(); + } + HashMap map = new HashMap<>(); + map.put('2', new char[]{'a', 'b', 'c'}); + map.put('3', new char[]{'d', 'e', 'f'}); + map.put('4', new char[]{'g', 'h', 'i'}); + map.put('5', new char[]{'j', 'k', 'l'}); + map.put('6', new char[]{'m', 'n', 'o'}); + map.put('7', new char[]{'p', 'q', 'r', 's'}); + map.put('8', new char[]{'t', 'u', 'v'}); + map.put('9', new char[]{'w', 'x', 'y', 'z'}); + ArrayList result = new ArrayList<>(); + + combine_2(new StringBuilder(), digits.toCharArray(), 0, result, map); + + return result; + } + + /** + * 回溯 + * @param str + * @param input + * @param index + * @param result + * @param directory + */ + private void combine_2(StringBuilder str, char[] input, int index, List result, HashMap directory) { + //terminator + if (str.length() == input.length) { + result.add(str.toString()); + return; + } + char[] chars = directory.get(input[index]); + + //process logic + for (int i = 0; i < chars.length; i++) { + //drill down + combine_2(str.append(chars[i]), input, index + 1, result, directory); + str.deleteCharAt(str.length() - 1); + } + + //reverse + } +} diff --git a/Week_03/G20200343030391/LeetCode_200_391.java b/Week_03/G20200343030391/LeetCode_200_391.java new file mode 100644 index 00000000..e79133a9 --- /dev/null +++ b/Week_03/G20200343030391/LeetCode_200_391.java @@ -0,0 +1,223 @@ +package G20200343030391; + +import java.util.LinkedList; + +public class LeetCode_200_391 { + + public static void main(String[] args) { + LeetCode_200_391 solution = new LeetCode_200_391(); + char[][] grid1 = { + {'1', '1', '1'}, + {'0', '0', '0'}, + {'1', '1', '1'}}; + int numIslands1 = solution.numIslands_UF(grid1); + System.out.println(numIslands1); + +// char[][] grid2 = { +// {'1', '1', '0', '0', '0'}, +// {'1', '1', '0', '0', '0'}, +// {'0', '0', '1', '0', '0'}, +// {'0', '0', '0', '1', '1'}}; +// int numIslands2 = solution.numIslands_DFS(grid2); +// System.out.println(numIslands2); + } + + /** + * 深度优先 + * + * @param grid + * @return + */ + public int numIslands_DFS(char[][] grid) { + if (grid == null || grid.length == 0) { + return 0; + } + int row = grid.length; + int col = grid[0].length; + int island = 0; + boolean[][] visited = new boolean[row][col]; + for (int r = 0; r < row; r++) { + for (int c = 0; c < col; c++) { + if (!visited[r][c] && grid[r][c] == '1') { + island++; + dfs(grid, visited, r, c); + } + } + } + return island; + } + + /** + * 查找四个方向关联的陆地 + * + * @param grid + * @param visited + * @param r + * @param c + */ + private void dfs(char[][] grid, boolean[][] visited, int r, int c) { + //标记已访问 + visited[r][c] = true; + //上 + if (r - 1 >= 0 && grid[r - 1][c] == '1' && !visited[r - 1][c]) { + dfs(grid, visited, r - 1, c); + } + //下 + if (r + 1 < grid.length && grid[r + 1][c] == '1' && !visited[r + 1][c]) { + dfs(grid, visited, r + 1, c); + } + //左 + if (c - 1 >= 0 && grid[r][c - 1] == '1' && !visited[r][c - 1]) { + dfs(grid, visited, r, c - 1); + } + //右 + if (c + 1 < grid[0].length && grid[r][c + 1] == '1' && !visited[r][c + 1]) { + dfs(grid, visited, r, c + 1); + } + } + + /** + * 广度优先 + * + * @param grid + * @return + */ + public int numIslands_BFS(char[][] grid) { + // x-1,y + // x,y-1 x,y x,y+1 + // x+1,y + int[][] directions = {{-1, 0}, {0, -1}, {1, 0}, {0, 1}}; + + int rows = grid.length; + if (rows == 0) { + return 0; + } + int cols = grid[0].length; + boolean[][] marked = new boolean[rows][cols]; + int count = 0; + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + // 如果是岛屿中的一个点,并且没有被访问过 + // 从坐标为 (i,j) 的点开始进行广度优先遍历 + if (!marked[i][j] && grid[i][j] == '1') { + count++; + LinkedList queue = new LinkedList<>(); + // 小技巧:把坐标转换为一个数字 + // 否则,得用一个数组存,在 Python 中,可以使用 tuple 存 + queue.addLast(i * cols + j); + // 注意:这里要标记上已经访问过 + marked[i][j] = true; + while (!queue.isEmpty()) { + int cur = queue.removeFirst(); + int curX = cur / cols; + int curY = cur % cols; + // 得到 4 个方向的坐标 + for (int k = 0; k < 4; k++) { + int newX = curX + directions[k][0]; + int newY = curY + directions[k][1]; + // 如果不越界、没有被访问过、并且还要是陆地,我就继续放入队列,放入队列的同时,要记得标记已经访问过 + if ((newX >= 0 && newX < rows && newY >= 0 && newY < cols) && grid[newX][newY] == '1' && !marked[newX][newY]) { + queue.addLast(newX * cols + newY); + // 【特别注意】在放入队列以后,要马上标记成已经访问过,语义也是十分清楚的:反正只要进入了队列,你迟早都会遍历到它 + // 而不是在出队列的时候再标记 + // 【特别注意】如果是出队列的时候再标记,会造成很多重复的结点进入队列,造成重复的操作,这句话如果你没有写对地方,代码会严重超时的 + marked[newX][newY] = true; + } + } + } + } + } + + } + return count; + } + + /** + * 并查集 + * + * @param grid + * @return + */ + public int numIslands_UF(char[][] grid) { + if (grid == null || grid.length == 0) { + return 0; + } + int row = grid.length; + int col = grid[0].length; + int[][] directions = {{1, 0}, {0, 1}}; + int dummy_node = row * col; + UF uf = new UF(dummy_node + 1); + for (int i = 0; i < row; i++) { + for (int j = 0; j < col; j++) { + if (grid[i][j] == '1') { + for (int k = 0; k < directions.length; k++) { + int newX = i + directions[k][0]; + int newY = j + directions[k][1]; + if (newX < row && newY < col && grid[newX][newY] == '1') { + uf.union(newX * col + newY, i * col + j); + } + } + } else { + uf.union(i * col + j, dummy_node); + } + } + } + return uf.count - 1; + + } + + class UF { + // 连通分量个数 + private int count; + // 存储一棵树 + private int[] parent; + // 记录树的“重量” + private int[] size; + + public UF(int n) { + this.count = n; + parent = new int[n]; + size = new int[n]; + for (int i = 0; i < n; i++) { + parent[i] = i; + size[i] = 1; + } + } + + public void union(int p, int q) { + int rootP = find(p); + int rootQ = find(q); + if (rootP == rootQ) + return; + + // 小树接到大树下面,较平衡 + if (size[rootP] > size[rootQ]) { + parent[rootQ] = rootP; + size[rootP] += size[rootQ]; + } else { + parent[rootP] = rootQ; + size[rootQ] += size[rootP]; + } + count--; + } + + public boolean connected(int p, int q) { + int rootP = find(p); + int rootQ = find(q); + return rootP == rootQ; + } + + private int find(int x) { + while (parent[x] != x) { + // 进行路径压缩 + parent[x] = parent[parent[x]]; + x = parent[x]; + } + return x; + } + + public int count() { + return count; + } + } +} diff --git a/Week_03/G20200343030391/LeetCode_22_391.java b/Week_03/G20200343030391/LeetCode_22_391.java new file mode 100644 index 00000000..de3e82eb --- /dev/null +++ b/Week_03/G20200343030391/LeetCode_22_391.java @@ -0,0 +1,41 @@ +package G20200343030391; + +import java.util.ArrayList; +import java.util.List; + +public class LeetCode_22_391 { + + public static void main(String[] args) { + int n = 3; + List strings = new LeetCode_22_391().generateParenthesis(n); + System.out.println(strings); + } + + public List generateParenthesis(int n) { + List result = new ArrayList<>(); + generate("", result, n, n); + return result; + } + + /** + * 递归剪枝 + * + * @param str + * @param result + * @param left + * @param right + */ + private void generate(String str, List result, int left, int right) { + if (left == 0 && right == 0) { + result.add(str); + return; + } + if (left > 0) { + generate(str + "(", result, left - 1, right); + } + if (right > left) { + generate(str + ")", result, left, right - 1); + } + } + +} diff --git a/Week_03/G20200343030391/LeetCode_322_391.java b/Week_03/G20200343030391/LeetCode_322_391.java new file mode 100644 index 00000000..5bf83c58 --- /dev/null +++ b/Week_03/G20200343030391/LeetCode_322_391.java @@ -0,0 +1,102 @@ +package G20200343030391; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class LeetCode_322_391 { + + public static void main(String[] args) { + int[] coins = {186, 419, 83, 408}; + + int amount = 1234; + int i = new LeetCode_322_391().coinChange(coins, amount); + System.out.println(i); + } + + /** + * 傻递归 + * + * @param coins + * @param amount + * @return + */ + public int coinChange_0(int[] coins, int amount) { + help(0, coins, amount); + return foolish == Integer.MAX_VALUE ? -1 : foolish; + } + + int foolish = Integer.MAX_VALUE; + + private void help(int count, int[] coins, int amount) { + //有效路径,更新次数 + if (amount == 0) { + foolish = Math.min(foolish, count); + return; + } + //无效路径,丢弃 + if (amount < 0) { + return; + } + for (int j = 0; j < coins.length; j++) { + help(count + 1, coins, amount - coins[j]); + } + } + + /** + * 自底向上的动态规划 + * + * @param coins + * @param amount + * @return + */ + public int coinChange_1(int[] coins, int amount) { + // 特例 + if (coins.length == 0) { + return -1; + } + Arrays.sort(coins); + // dp[n]的值: 表示的凑成总金额为n所需的最少的硬币个数 + int[] dp = new int[amount + 1]; + Arrays.fill(dp, amount + 1); + dp[0] = 0; + for (int i = 1; i <= amount; i++) { + for (int j = 0; j < coins.length; j++) { + if (coins[j] <= i) { + dp[i] = Math.min(dp[i], dp[i - coins[j]] + 1); + } + } + } + + return dp[amount] > amount ? -1 : dp[amount]; + } + + /** + * 贪心 + * @param coins + * @param amount + * @return + */ + public int coinChange(int[] coins, int amount) { + Arrays.sort(coins); + coinChange(coins.length - 1, coins, 0, amount); + return ans == Integer.MAX_VALUE ? -1 : ans; + } + int ans = Integer.MAX_VALUE; + + private void coinChange(int index, int[] coins, int count, int needAmount) { + if (needAmount == 0) { + ans = Math.min(count, ans); + return; + } + if (index < 0) { + return; + } + + int i = needAmount / coins[index]; + for (int k = i; k >= 0 && count + k < ans; k--) { + coinChange(index - 1, coins, count + k, needAmount - k * coins[index]); + } + } + +} diff --git a/Week_03/G20200343030391/LeetCode_33_391.java b/Week_03/G20200343030391/LeetCode_33_391.java new file mode 100644 index 00000000..b9a8d584 --- /dev/null +++ b/Week_03/G20200343030391/LeetCode_33_391.java @@ -0,0 +1,49 @@ +package G20200343030391; + +import java.util.List; + +public class LeetCode_33_391 { + + public static void main(String[] args) { + int[] nums = {4, 5, 6, 7, 0, 1, 2}; + int target = 0; + int search = new LeetCode_33_391().search(nums, target); + System.out.println(search); + } + + public int search(int[] nums, int target) { + if (nums.length == 0) { + return -1; + } + if (nums.length == 1) { + return nums[0] == target ? 0 : -1; + } + int left = 0; + int right = nums.length - 1; + int mid ; + while (left <= right) { + mid = left + (right - left) / 2; + if (nums[mid] == target) { + return mid; + } + //左侧有序 + if (nums[left] <= nums[mid]) { + //target 在左侧 + if (target >= nums[left] && target < nums[mid]) { + right = mid - 1; + } else { + left = mid + 1; + } + } else { + if (target > nums[mid] && target <= nums[right]) { + left = mid + 1; + } else { + right = mid - 1; + } + } + } + return -1; + } + + +} diff --git a/Week_03/G20200343030391/LeetCode_367_391.java b/Week_03/G20200343030391/LeetCode_367_391.java new file mode 100644 index 00000000..4ce81b36 --- /dev/null +++ b/Week_03/G20200343030391/LeetCode_367_391.java @@ -0,0 +1,36 @@ +package G20200343030391; + +public class LeetCode_367_391 { + + public static void main(String[] args) { +// for (int i = 0; i < Integer.MAX_VALUE; i++) { + System.out.println(new LeetCode_367_391().isPerfectSquare(808201)); +// } + } + + /** + * 二分 + * + * @param num + * @return + */ + public boolean isPerfectSquare(int num) { + if (num < 2) { + return true; + } + long left = 2, right = num / 2; + while (left <= right) { + long x = left + (right - left) / 2; + long square = x * x; + if (square == num) { + return true; + } + if (square > num) { + right = x - 1; + } else { + left = x + 1; + } + } + return false; + } +} diff --git a/Week_03/G20200343030391/LeetCode_433_391.java b/Week_03/G20200343030391/LeetCode_433_391.java new file mode 100644 index 00000000..22c293ad --- /dev/null +++ b/Week_03/G20200343030391/LeetCode_433_391.java @@ -0,0 +1,58 @@ +package G20200343030391; + +import java.util.HashSet; + +public class LeetCode_433_391 { + + public static void main(String[] args) { + + String start = "AACCGGTT"; + String end = "AAACGGTA"; + String[] bank = {"AACCGGTA", "AACCGCTA", "AAACGGTA"}; + + int minMutation = new LeetCode_433_391().minMutation(start, end, bank); + System.out.println(minMutation); + } + + int minStep = Integer.MAX_VALUE; + + public int minMutation(String start, String end, String[] bank) { + HashSet changedStep = new HashSet<>(); + changeToNext(changedStep, 0, start, end, bank); + return (minStep == Integer.MAX_VALUE) ? -1 : minStep; + } + + /** + * @param changedStep + * @param step + * @param current + * @param end + * @param bank + * @return + */ + private void changeToNext(HashSet changedStep, int step, String current, String end, String[] bank) { + //terminator + if (current.equals(end)) { + minStep = Math.min(minStep, step); + } + for (int i = 0; i < bank.length; i++) { + String str = bank[i]; + int diffCharCount = 0; + for (int j = 0; j < str.length(); j++) { + if (current.charAt(j) != str.charAt(j)) { + diffCharCount++; + if (diffCharCount > 1) { + break; + } + } + } + if (diffCharCount == 1 && !changedStep.contains(str)) { + changedStep.add(str); + changeToNext(changedStep, step + 1, str, end, bank); + changedStep.remove(str); + } + } + } + + +} diff --git a/Week_03/G20200343030391/LeetCode_455_391.java b/Week_03/G20200343030391/LeetCode_455_391.java new file mode 100644 index 00000000..f0d7b7e3 --- /dev/null +++ b/Week_03/G20200343030391/LeetCode_455_391.java @@ -0,0 +1,37 @@ +package G20200343030391; + +import java.util.Arrays; + +public class LeetCode_455_391 { + + public static void main(String[] args) { + int[] g = {1, 2, 3}; + int[] s = {1, 1}; + int contentChildren = new LeetCode_455_391().findContentChildren_1(g, s); + System.out.println(contentChildren); + } + + /** + * 贪心,最小饼干分给胃口最小的 + * @param g + * @param s + * @return + */ + public int findContentChildren_1(int[] g, int[] s) { + if (g == null || g.length == 0 || s == null || s.length == 0) { + return 0; + } + Arrays.sort(g); + Arrays.sort(s); + int gi = 0, si = 0; + while(gi < g.length && si < s.length){ + //满足一个 + if (g[gi] <= s[si]) { + gi++; + } + si++; + } + return gi; + } + +} diff --git a/Week_03/G20200343030391/LeetCode_45_391.java b/Week_03/G20200343030391/LeetCode_45_391.java new file mode 100644 index 00000000..3d2d6722 --- /dev/null +++ b/Week_03/G20200343030391/LeetCode_45_391.java @@ -0,0 +1,26 @@ +package G20200343030391; + +public class LeetCode_45_391 { + + public static void main(String[] args) { + int[] nums = {2, 3, 1, 1, 4}; + int b = new LeetCode_45_391().jump(nums); + System.out.println(b); + } + + public int jump(int[] nums) { + int end = 0; + int maxPosition = 0; + int step = 0; + for (int i = 0; i < nums.length - 1; i++) { + //最大跳跃位置 + maxPosition = Math.max(maxPosition, nums[i] + i); + if (i == end) { + //更新边界 + end = maxPosition; + step++; + } + } + return step; + } +} diff --git a/Week_03/G20200343030391/LeetCode_509_391.java b/Week_03/G20200343030391/LeetCode_509_391.java new file mode 100644 index 00000000..f4e94b89 --- /dev/null +++ b/Week_03/G20200343030391/LeetCode_509_391.java @@ -0,0 +1,61 @@ +package G20200343030391; + +public class LeetCode_509_391 { + + public static void main(String[] args) { + long start = System.currentTimeMillis(); + int n = 999; + int[] memo = new int[n + 1]; + memo[1] = 1; + int fib1 = new LeetCode_509_391().fib_1(n); +// int fib2 = new LeetCode_509_391_DP().fib_2(n); +// int fib3 = new LeetCode_509_391_DP().fib_3(n, memo); + + long end = System.currentTimeMillis(); + System.out.println("结果:" + fib1 + " 耗时:" + (end - start)); + + } + + /** + * 傻递归 + * @param N + * @return + */ + public int fib_1(int N) { + return N <= 1 ? N : fib_1(N - 1) + fib_1(N - 2); + } + + /** + * 自底向上 + * @param N + * @return + */ + public int fib_2(int N) { + if (N <= 1) { + return N; + } + int[] memo = new int[N + 1]; + memo[1] = 1; + for (int i = 2; i <= N; i++) { + memo[i] = memo[i - 1] + memo[i - 2]; + } + return memo[N]; + } + + /** + * 自顶向下 + * + * @param N + * @return + */ + public int fib_3(int N, int[] memo) { + if (N <= 1) { + return N; + } + if (memo[N] == 0) { + memo[N] = fib_3(N - 1, memo) + fib_3(N - 2, memo); + } + return memo[N]; + } + +} diff --git a/Week_03/G20200343030391/LeetCode_50_391.java b/Week_03/G20200343030391/LeetCode_50_391.java new file mode 100644 index 00000000..d0116afa --- /dev/null +++ b/Week_03/G20200343030391/LeetCode_50_391.java @@ -0,0 +1,46 @@ +package G20200343030391; + +import java.util.List; + +public class LeetCode_50_391 { + + public static void main(String[] args) { + double x = -2.123; + int n = -10; + double pow = new LeetCode_50_391().myPow(x, n); + assert pow == Math.pow(x, n); + } + + /** + * 分治 + * @param x + * @param n + * @return + */ + public double myPow(double x, int n) { + if (n < 0) { + x = 1 / x; + n = -n; + } + return fastPow(x, n); + } + + private double fastPow(double x, int n) { + //terminator + if (n == 0) { + return 1.0; + } + //process(split the big problem) + //drill down + double pow = fastPow(x, n / 2); + //merge(subResult) + if (n % 2 == 0) { + pow *= pow; + } else { + pow = pow * pow * x; + } + //reverse states + return pow; + } + +} diff --git a/Week_03/G20200343030391/LeetCode_515_391.java b/Week_03/G20200343030391/LeetCode_515_391.java new file mode 100644 index 00000000..a0730a13 --- /dev/null +++ b/Week_03/G20200343030391/LeetCode_515_391.java @@ -0,0 +1,65 @@ +package G20200343030391; + +import java.util.ArrayList; +import java.util.List; + +public class LeetCode_515_391 { + + public static void main(String[] args) { + TreeNode node1 = new TreeNode(1); + TreeNode node2 = new TreeNode(2); + TreeNode node3 = new TreeNode(3); + TreeNode node4 = new TreeNode(4); + TreeNode node5 = new TreeNode(5); + TreeNode node6 = new TreeNode(6); + TreeNode node7 = new TreeNode(9); + node1.left = node3; + node1.right = node2; + node3.left = node5; + node3.right = node4; + node2.right = node7; + List list = new LeetCode_515_391().largestValues(node1); + System.out.println(list); + } + + public List largestValues(TreeNode root) { + ArrayList list = new ArrayList<>(); + currentLevelMax(root, 0, list); + return list; + } + + private void currentLevelMax(TreeNode root, int level, ArrayList list) { + //terminator + if (root == null) { + return; + } + //process logic + if (list.size() == level) { + list.add(root.val); + } else { + Integer current = list.get(level); + if (current == null) { + list.add(root.val); + } else { + list.set(level, Math.max(current, root.val)); + } + } + //drill down + if (root.left != null) { + currentLevelMax(root.left, level + 1, list); + } + if (root.right != null) { + currentLevelMax(root.right, level + 1, list); + } + } + + public static class TreeNode { + int val; + TreeNode left; + TreeNode right; + + TreeNode(int x) { + val = x; + } + } +} diff --git a/Week_03/G20200343030391/LeetCode_51_391.java b/Week_03/G20200343030391/LeetCode_51_391.java new file mode 100644 index 00000000..d6b7acaa --- /dev/null +++ b/Week_03/G20200343030391/LeetCode_51_391.java @@ -0,0 +1,139 @@ +package G20200343030391; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.Stack; + +public class LeetCode_51_391 { + + public static void main(String[] args) { + int digits = 4; + List> lists = new LeetCode_51_391().solveNQueens(digits); + System.out.println(lists); + } + + /** + * 实时计算位置 + * @param n + * @return + */ + public List> solveNQueens(int n) { + List> result = new ArrayList<>(); + if (n == 0) { + return result; + } + char[][] board = new char[n][n]; + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + board[i][j] = '.'; + } + } + int[] cols = new int[n]; + int[] fls = new int[2 * n - 1]; + int[] rls = new int[2 * n - 1]; + solve(0, n, board, cols, fls, rls, result); + return result; + } + + private void solve(int i, int n, char[][] board, int[] cols, int[] fls, int[] rls, List> ans) { + if (i == n) { + List strs = new ArrayList<>(); + for (int k = 0; k < n; k++) { + strs.add(String.valueOf(board[k])); + } + ans.add(strs); + return; + } + for (int j = 0; j < n; j++) { + if (cols[j] == 0 && fls[i + j] == 0 && rls[n - 1 - i + j] == 0) { + board[i][j] = 'Q'; + cols[j] = 1; + fls[i + j] = 1; + rls[n - 1 - i + j] = 1; + solve(i + 1, n, board, cols, fls, rls, ans); + board[i][j] = '.'; + cols[j] = 0; + fls[i + j] = 0; + rls[n - 1 - i + j] = 0; + } + } + } + + + /** + * @param n + * @return + */ + public List> solveNQueensByBacktrack(int n) { + List> result = new ArrayList<>(); + if (n == 0) { + return result; + } + Set col = new HashSet<>(); + Set pie = new HashSet<>(); + Set na = new HashSet<>(); + Stack stack = new Stack<>(); + backtrack(0, n, col, pie, na, stack, result); + return result; + } + + /** + * 回溯 + * + * @param row + * @param n + * @param col + * @param pie + * @param na + * @param stack + * @param result + */ + private void backtrack(int row, int n, Set col, Set pie, Set na, Stack stack, List> result) { + //terminator + if (row == n) { + List board = convert2board(stack, n); + result.add(board); + return; + } + //process logic 遍历棋盘每一行 + for (int i = 0; i < n; i++) { + //行,/ , \ 处于未被攻击到的位置 + if (!col.contains(i) && !pie.contains(row - i) && !na.contains(row + i)) { + //放置queen + stack.add(i); + //攻击范围 + col.add(i); + pie.add(row - i); + na.add(row + i); + + //drill down + backtrack(row + 1, n, col, pie, na, stack, result); + //回溯 重置 + col.remove(i); + pie.remove(row - i); + na.remove(row + i); + stack.pop(); + } + } + //reverse + } + + private List convert2board(Stack stack, int n) { + ArrayList board = new ArrayList<>(); + for (Integer queen : stack) { + StringBuilder builder = new StringBuilder(); + for (int i = 0; i < n; i++) { + if (i == queen) { + builder.append("Q"); + } else { + builder.append("."); + } + } + board.add(builder.toString()); + } + return board; + } + +} diff --git a/Week_03/G20200343030391/LeetCode_529_391.java b/Week_03/G20200343030391/LeetCode_529_391.java new file mode 100644 index 00000000..64e3fb36 --- /dev/null +++ b/Week_03/G20200343030391/LeetCode_529_391.java @@ -0,0 +1,65 @@ +package G20200343030391; + +import java.util.Arrays; + +public class LeetCode_529_391 { + + public static void main(String[] args) throws InterruptedException { + char[][] board = { + {'E', 'E', 'E', 'E', 'E'}, + {'E', 'E', 'M', 'E', 'E'}, + {'E', 'E', 'E', 'E', 'E'}, + {'E', 'E', 'E', 'E', 'E'} + }; + int[] click = {3, 0}; + + + char[][] chars = new LeetCode_529_391().updateBoard(board, click); + System.out.println(Arrays.deepToString(chars)); + int[] click2 = {1, 2}; + char[][] chars2 = new LeetCode_529_391().updateBoard(chars, click2); + System.out.println(Arrays.deepToString(chars2)); + } + + public char[][] updateBoard(char[][] board, int[] click) { + if (board[click[0]][click[1]] == 'M') { + board[click[0]][click[1]] = 'X'; + return board; + } + int[][] round = {{-1, 0}, {-1, 1}, {0, 1}, {1, 1}, {1, 0}, {1, -1}, {0, -1}, {-1, -1}}; + dfs(click[0], click[1], board, round); + return board; + } + + private void dfs(int r, int c, char[][] board, int[][] round) { + if (r < 0 || c < 0 || r >= board.length || c >= board[0].length) { + return; + } + if (board[r][c] == 'E') { + board[r][c] = 'B'; + //查周围的雷 + int minesCount = 0; + for (int i = 0; i < round.length; i++) { + int newR = r + round[i][0]; + int newC = c + round[i][1]; + if (newR < 0 || newR >= board.length || newC < 0 || newC >= board[0].length) { + continue; + } + if (board[newR][newC] == 'M') { + minesCount++; + } + } + if (minesCount == 0) { + for (int i = 0; i < round.length; i++) { + int newR = r + round[i][0]; + int newC = c + round[i][1]; + dfs(newR, newC, board, round); + } + } else { + board[r][c] = (char) (minesCount + '0'); + } + } else if (board[r][c] == 'M') { + board[r][c] = 'X'; + } + } +} diff --git a/Week_03/G20200343030391/LeetCode_55_391.java b/Week_03/G20200343030391/LeetCode_55_391.java new file mode 100644 index 00000000..aafcf3d8 --- /dev/null +++ b/Week_03/G20200343030391/LeetCode_55_391.java @@ -0,0 +1,22 @@ +package G20200343030391; + +import java.util.List; + +public class LeetCode_55_391 { + + public static void main(String[] args) { + int[] nums = {2, 3, 1, 1, 4}; + boolean b = new LeetCode_55_391().canJump(nums); + System.out.println(b); + } + + public boolean canJump(int[] nums) { + int canJump = nums.length - 1; + for (int i = nums.length - 1; i >= 0; i--) { + if (nums[i] + i >= canJump) { + canJump = i; + } + } + return canJump == 0; + } +} diff --git a/Week_03/G20200343030391/LeetCode_69_391.java b/Week_03/G20200343030391/LeetCode_69_391.java new file mode 100644 index 00000000..3f16ccd7 --- /dev/null +++ b/Week_03/G20200343030391/LeetCode_69_391.java @@ -0,0 +1,31 @@ +package G20200343030391; + +public class LeetCode_69_391 { + + public static void main(String[] args) { + int i = new LeetCode_69_391().mySqrt(36); + System.out.println(i); + } + + /** + * 二分查找 + * @param x + * @return + */ + public int mySqrt(int x) { + if (x == 0 || x == 1) { + return x; + } + long left = 0, right = x; + long mid; + while (left <= right) { + mid = left + (right - left) / 2; + if (mid * mid > x) { + right = mid - 1; + } else { + left = mid + 1; + } + } + return (int) right; + } +} diff --git a/Week_03/G20200343030391/LeetCode_74_391.java b/Week_03/G20200343030391/LeetCode_74_391.java new file mode 100644 index 00000000..c19b400b --- /dev/null +++ b/Week_03/G20200343030391/LeetCode_74_391.java @@ -0,0 +1,35 @@ +package G20200343030391; + +public class LeetCode_74_391 { + + public static void main(String[] args) { + int[][] matrix = { + {1, 1} + }; + int target = 3; + boolean b = new LeetCode_74_391().searchMatrix(matrix, target); + System.out.println(b); + } + + public boolean searchMatrix(int[][] matrix, int target) { + if (matrix == null || matrix.length == 0) { + return false; + } + int row = matrix.length; + int col = matrix[0].length; + int start = 0; + int end = row * col - 1; + while (start <= end) { + int mid = start + (end - start) / 2; + if (matrix[mid / col][mid % col] == target) { + return true; + } else if (matrix[mid / col][mid % col] > target) { + end = mid - 1; + } else { + start = mid + 1; + } + } + return false; + } + +} diff --git a/Week_03/G20200343030391/LeetCode_78_391.java b/Week_03/G20200343030391/LeetCode_78_391.java new file mode 100644 index 00000000..1dba0eb7 --- /dev/null +++ b/Week_03/G20200343030391/LeetCode_78_391.java @@ -0,0 +1,75 @@ +package G20200343030391; + +import java.util.ArrayList; +import java.util.List; + +public class LeetCode_78_391 { + + public static void main(String[] args) { + int[] nums = {1, 2, 3}; + List> subsets = new LeetCode_78_391().subsetsByLoop(nums); + System.out.println(subsets); + + } + + /** + * 1 递归解法,每层分为选和不选两个逻辑分支 + * + * @param nums + * @return + */ + public List> subsets(int[] nums) { + List> result = new ArrayList<>(); + if (nums == null || nums.length == 0) { + return result; + } + recursion(result, nums, new ArrayList<>(), 0); + return result; + } + + /** + * 递归 + * + * @param result + * @param nums + * @param list + * @param index + */ + private void recursion(List> result, int[] nums, ArrayList list, int index) { + //terminator + if (index == nums.length) { + result.add(new ArrayList<>(list)); + return; + } + //不使用下标index元素 + recursion(result, nums, list, index + 1); + //使用下标index元素 + list.add(nums[index]); + recursion(result, nums, list, index + 1); + + //回溯 + list.remove(list.size() - 1); + } + /** + * 2 循环遍历 + * + * @param nums + * @return + */ + public List> subsetsByLoop(int[] nums) { + List> res = new ArrayList<>(); + res.add(new ArrayList<>()); + for (int j = 0; j < nums.length; j++) { + int n = nums[j]; + int size = res.size(); + for (int i = 0; i < size; i++) { + List newSub = new ArrayList<>(res.get(i)); + newSub.add(n); + res.add(newSub); + } + } + return res; + } + + +} diff --git a/Week_03/G20200343030391/LeetCode_860_391.java b/Week_03/G20200343030391/LeetCode_860_391.java new file mode 100644 index 00000000..ea622949 --- /dev/null +++ b/Week_03/G20200343030391/LeetCode_860_391.java @@ -0,0 +1,48 @@ +package G20200343030391; + +public class LeetCode_860_391 { + + public static void main(String[] args) { + int[] bills = {5, 5, 5, 10, 20}; + boolean b = new LeetCode_860_391().lemonadeChange(bills); + System.out.println(b); + + } + + /** + * 贪心算法 + * @param bills + * @return + */ + public boolean lemonadeChange(int[] bills) { + int five = 0, ten = 0; + for (int i = 0; i < bills.length; i++) { + switch (bills[i]) { + case 5: + five++; + break; + case 10: + if (five > 0) { + five--; + ten++; + } else { + return false; + } + break; + case 20: + if (five > 0 && ten > 0) { + five--; + ten--; + } else if (five >= 3) { + five -= 3; + } else { + return false; + } + break; + default: + return false; + } + } + return true; + } +} diff --git a/Week_03/G20200343030391/LeetCode_874_391.java b/Week_03/G20200343030391/LeetCode_874_391.java new file mode 100644 index 00000000..ae7bd620 --- /dev/null +++ b/Week_03/G20200343030391/LeetCode_874_391.java @@ -0,0 +1,52 @@ +package G20200343030391; + +import java.util.HashSet; + +public class LeetCode_874_391 { + + public static void main(String[] args) { + int[] commands = {4,-1,4,-2,4}; + int[][] obstacles = {{2,4}}; + int i = new LeetCode_874_391().robotSim(commands, obstacles); + System.out.println(i); + + } + + public int robotSim(int[] commands, int[][] obstacles) { + //定义方向,初始方向为北,以顺时针方向依次定义: 北 0,东 1,南 2,西 3 + int direction = 0; + // 定义数组,x轴或者y轴在每个方向前进一步走的距离,四个值分别对应北、东、南、西 + int[] dx = {0, 1, 0, -1}; + int[] dy = {1, 0, -1, 0}; + //初始坐标 + int x = 0, y = 0; + //障碍物存储 + HashSet obstacleSet = new HashSet<>(); + for (int i = 0; i < obstacles.length; i++) { + obstacleSet.add(obstacles[i][0] + "-" + obstacles[i][1]); + } + int max = 0; + for (int i = 0; i < commands.length; i++) { + if (commands[i] == -1) { + //右转,顺时针+1取模 + direction = (direction + 1) % 4; + } else if (commands[i] == -2) { + //左转,顺时针+3取模 + direction = (direction + 3) % 4; + } else { + //行进 + for (int j = 0; j < commands[i]; j++) { + int newX = x + dx[direction]; + int newY = y + dy[direction]; + if (!obstacleSet.contains(newX + "-" + newY)) { + //没有障碍 + x = newX; + y = newY; + max = Math.max(max, x * x + y * y); + } + } + } + } + return max; + } +} diff --git a/Week_03/G20200343030391/NOTE.md b/Week_03/G20200343030391/NOTE.md index 50de3041..b880aac4 100644 --- a/Week_03/G20200343030391/NOTE.md +++ b/Week_03/G20200343030391/NOTE.md @@ -1 +1,118 @@ -学习笔记 \ No newline at end of file +学习笔记 +# 分治 + - 代码模板 + ```java + public void divide_cpnquer(int lever,int[] param) { + // terminator + if(leverl > max_level){ + // process result + return; + } + // prepare data + int num1=prepare_data(parm) + // divide + int []sub_problems = split_problem(param,num1) + // cpnquer subproblems + + int sub_result1 = diver_conquer(sub_problems[0]); + int sub_result2 = diver_conquer(sub_problems[1]); + int sub_result3 = diver_conquer(sub_problems[2]); + + //process and generate the final result + result = process_result(sub_result1,sub_result2,sub_result3) + + //restore current status + } + ``` +# 回溯 + - 模板 + ```java + public void recur(int lever,int param) { + // terminator + if(leverl > max_level){ + // process result + return; + } + //process current logic + process(level,param); + + //drill down + recur(level:level+1,newParam); + // backtrack + level--; + + //restore current status + } + ``` +# 深度优先 + - 模板 + - 递归写法 + ```java + public void dfs(visited,node){ + //terminator + if (visited.contains(node)) { + return; + } + visited.add(node); + //process current node here + for(Node child : node.children()){ + if (!visited.contains(child)) { + dfs(visited,child) + } + } + } + ``` + - 循环写法 + ```java + public void dfs(node){ + if(node==null){ + return; + } + Stack stack = new Stack(); + stack.push(node); + while(!stack.isEmpty){ + node = stack.pop(); + process(node); + nodes = generate_related_node(node); + stack.push(nodes) + } + } + ``` + +# 广度优先 + - 模板 + ```java + public void bfs(node){ + Set visited = new HashSet(); + Deque queue = new Deque(); + queue.push([start]); + while (!queue.isEmpty()){ + node = queue.pop() + visited.add(node) + + process(node) + nodes = generate_related_nodes(node) + queue.push(nodes) + } + # other processing work + ... + } + ``` +# 二分查找 + - 模板 + ```java + public int bs(int [] array,int target){ + int left=0; + int right=array.length-1; + while left <= right: + int mid = (left + ritht) / 2; + if (array[mind]==target){ + //find the target + return mid; + } else if(array[mid] < target){ + left = mid+1; + }elset{ + ritht = mid - 1; + } + } + ``` \ No newline at end of file diff --git a/Week_03/G20200343030393/LeetCode_127_393.py b/Week_03/G20200343030393/LeetCode_127_393.py new file mode 100644 index 00000000..8afd6910 --- /dev/null +++ b/Week_03/G20200343030393/LeetCode_127_393.py @@ -0,0 +1,60 @@ +from collections import defaultdict + + +class Solution(object): + def __init__(self): + self.lenght = 0 + self.all_combo_dict = defaultdict(list) + + def ladderLength(self, beginWord, endWord, wordList): + """ + :type beginWord: str + :type endWord: str + :type wordList: List[str] + :rtype: int + """ + if endWord not in wordList or not beginWord or not endWord or not wordList: + return 0 + + self.lenght = len(beginWord) + for word in set(wordList): + for i in range(self.lenght): + self.all_combo_dict[word[:i] + "*" + word[i+1:]].append(word) + + queue_begin = [(beginWord, 1)] + queue_end = [(endWord, 1)] + + visited_begin = {beginWord: 1} + visited_end = {endWord: 1} + ans = 0 + + while queue_begin and queue_end: + ans = self.visitedWordNode(queue_begin, visited_begin, visited_end) + if ans: + return ans + + ans = self.visitedWordNode(queue_end, visited_end, visited_begin) + if ans: + return ans + return ans + + def visitedWordNode(self, queue, visited, orther_cisited): + current_word, level = queue.pop(0) + + for i in range(self.lenght): + intermediate = current_word[:i] + "*" + current_word[i+1:] + for word in self.all_combo_dict[intermediate]: + if word in orther_cisited: + return level + orther_cisited[word] + + if word not in visited: + visited[word] = level + 1 + queue.append((word, level+1)) + return 0 + + +beginWord = "hot" +endWord = "dog" +wordList = ["hot", "dog"] +run = Solution() +print(run.ladderLength(beginWord, endWord, wordList)) \ No newline at end of file diff --git a/Week_03/G20200343030393/LeetCode_169_393.py b/Week_03/G20200343030393/LeetCode_169_393.py new file mode 100644 index 00000000..27c0908a --- /dev/null +++ b/Week_03/G20200343030393/LeetCode_169_393.py @@ -0,0 +1,15 @@ +class Solution(object): + def majorityElement(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + n = len(nums) / 2 + for i in set(nums): + if nums.count(i) > n: + return i + + +nums = [2, 2, 1, 1, 1, 2, 2] +aa = Solution() +print(aa.majorityElement(nums)) \ No newline at end of file diff --git a/Week_03/G20200343030393/LeetCode_17_393.py b/Week_03/G20200343030393/LeetCode_17_393.py new file mode 100644 index 00000000..d5f423ed --- /dev/null +++ b/Week_03/G20200343030393/LeetCode_17_393.py @@ -0,0 +1,51 @@ +class Solution(object): + def letterCombinations(self, digits): + """ + :type digits: str + :rtype: List[str] + """ + # execution time: 12 ms; memory consumption: 11.7MB + phone = {'2': ['a', 'b', 'c'], + '3': ['d', 'e', 'f'], + '4': ['g', 'h', 'i'], + '5': ['j', 'k', 'l'], + '6': ['m', 'n', 'o'], + '7': ['p', 'q', 'r', 's'], + '8': ['t', 'u', 'v'], + '9': ['w', 'x', 'y', 'z']} + + def __combination(string_combination, next_digits): + if len(next_digits) == 0: + return result.append(string_combination) + else: + for i in phone[next_digits[0]]: + __combination(string_combination+i, next_digits[1:]) + + result = [] + if digits: + __combination("", digits) + return result + + # execution time: 28 ms; memory consumption: 11.6MB + # dict = {'2': "abc", '3': "def", '4': "ghi", '5': "jkl", '6': "mno", '7': "pqrs", + # '8': "tuv", '9': "wxyz"} + # cmb = [''] if digits else [] + # for d in digits: + # cmb = [p + q for p in cmb for q in dict[d]] + # return cmb + + # execution time: 24 ms; memory consumption: 11.6MB + # mapping = {'2': 'abc', '3': 'def', '4': 'ghi', '5': 'jkl', + # '6': 'mno', '7': 'pqrs', '8': 'tuv', '9': 'wxyz'} + # if len(digits) == 0: + # return [] + # if len(digits) == 1: + # return list(mapping[digits[0]]) + # prev = self.letterCombinations(digits[:-1]) + # additional = mapping[digits[-1]] + # return [s + c for s in prev for c in additional] + + +digits = "234" +aa = Solution() +print(aa.letterCombinations(digits)) \ No newline at end of file diff --git a/Week_03/G20200343030393/LeetCode_455_393.py b/Week_03/G20200343030393/LeetCode_455_393.py new file mode 100644 index 00000000..e4c19365 --- /dev/null +++ b/Week_03/G20200343030393/LeetCode_455_393.py @@ -0,0 +1,25 @@ +class Solution(object): + def findContentChildren(self, g, s): + """ + :type g: List[int] + :type s: List[int] + :rtype: int + """ + if g is None or s is None: + return 0 + + g.sort() + s.sort() + + gi, si = 0, 0 + while gi < len(g) and si < len(s): + if g[gi] <= s[si]: + gi += 1 + si += 1 + return gi + + +g = [10, 9, 8, 7] +s = [5, 6, 7, 8] +aa = Solution() +print(aa.findContentChildren(g, s)) \ No newline at end of file diff --git a/Week_03/G20200343030393/LeetCode_50_393.py b/Week_03/G20200343030393/LeetCode_50_393.py new file mode 100644 index 00000000..ccd5c563 --- /dev/null +++ b/Week_03/G20200343030393/LeetCode_50_393.py @@ -0,0 +1,32 @@ +class Solution: + # def myPow(self, x: float, n: int) -> float: + # if n > 0: + # return self.__help(x, n) + # elif n == 0: + # return 1 + # else: + # return self.__help(1/x, -n) + # + # def __help(self, x: float, n: int) -> float: + # if n == 1: + # return x + # elif n & 1: + # return x * self.__help(x, n - 1) + # elif not n & 1: + # return self.__help(x * x, n //2) + + def myPow(self, x: float, n: int) -> float: + return x ** n + # if not n: + # return 1 + # if n < 0: + # return 1 / self.myPow(x, -n) + # if n % 2: + # return x * self.myPow(x, n - 1) + # return self.myPow(x * x, n // 2) + + +x = 2.1 +n = 3 +aa = Solution() +print(aa.myPow(x, n)) \ No newline at end of file diff --git a/Week_03/G20200343030393/LeetCode_74_393.py b/Week_03/G20200343030393/LeetCode_74_393.py new file mode 100644 index 00000000..366ef638 --- /dev/null +++ b/Week_03/G20200343030393/LeetCode_74_393.py @@ -0,0 +1,31 @@ +class Solution(object): + def searchMatrix(self, matrix, target): + """ + :type matrix: List[List[int]] + :type target: int + :rtype: bool + """ + combination = [] + for i in matrix: + combination += i + + left, right = 0, len(combination) - 1 + while left <= right: + mid = (left + right) // 2 + if combination[mid] == target: + return True + elif combination[mid] < target: + left = mid + 1 + else: + right = mid - 1 + return False + + +matrix = [ + [1, 3, 5, 7], + [10, 11, 16, 20], + [23, 30, 34, 50] +] +target = 13 +aa = Solution() +print(aa.searchMatrix(matrix, target)) \ No newline at end of file diff --git a/Week_03/G20200343030393/LeetCode_78_393.py b/Week_03/G20200343030393/LeetCode_78_393.py new file mode 100644 index 00000000..a9461818 --- /dev/null +++ b/Week_03/G20200343030393/LeetCode_78_393.py @@ -0,0 +1,26 @@ +class Solution(object): + def subsets(self, nums): + """ + :type nums: List[int] + :rtype: List[List[int]] + """ + res = [] + n = len(nums) + + def helper(i, tmp): + res.append(tmp) + for j in range(i, n): + helper(j + 1, tmp + [nums[j]]) + + helper(0, []) + return res + + # res = [[]] + # for i in nums: + # res += [[i] + num for num in res] + # return res + + +nums = [1, 2, 3] +aa = Solution() +print(aa.subsets(nums)) \ No newline at end of file diff --git a/Week_03/G20200343030395/LeetCode_1_395.java b/Week_03/G20200343030395/LeetCode_1_395.java new file mode 100644 index 00000000..2e2ecdea --- /dev/null +++ b/Week_03/G20200343030395/LeetCode_1_395.java @@ -0,0 +1,33 @@ +package Week_03.G20200343030395; + +public class LeetCode_1_395 { + public boolean lemonadeChange(int[] bills) { + int five = 0, ten = 0; + for (int bill : bills) { + //5块钱,不用找,获得5块钱零钱 + if(bill == 5) { + five++; + } else if (bill == 10) { + //10块,找5块;如果没有5块的,就完犊子了 + if(five == 0) { + return false; + } + + five --; + ten ++; + } else { + //20的,有10+5就找10+5,没有全5,还是没有完犊子 + if (five > 0 && ten > 0) { + five--; + ten--; + } else if (five >= 3) { + five -= 3; + } else { + return false; + } + } + } + + return true; + } +} diff --git a/Week_03/G20200343030395/LeetCode_3_395.java b/Week_03/G20200343030395/LeetCode_3_395.java new file mode 100644 index 00000000..ec0a8acd --- /dev/null +++ b/Week_03/G20200343030395/LeetCode_3_395.java @@ -0,0 +1,21 @@ +package Week_03.G20200343030395; + +import java.util.Arrays; + +public class LeetCode_3_395 { + public int findContentChildren(int[] g, int[] s) { + int child = 0, cookie = 0; + Arrays.sort(g); + Arrays.sort(s); + + while(child < g.length && cookie < s.length) { + if(g[child] <= s[cookie]) { + child++; + } + + cookie ++; + } + + return child; + } +} diff --git a/Week_03/G20200343030395/LeetCode_5_395.java b/Week_03/G20200343030395/LeetCode_5_395.java new file mode 100644 index 00000000..88d341ce --- /dev/null +++ b/Week_03/G20200343030395/LeetCode_5_395.java @@ -0,0 +1,72 @@ +package Week_03.G20200343030395; + +public class LeetCode_5_395 { + int[] nums; + int target; + + public int find_rotate_index(int left, int right) { + if (nums[left] < nums[right]) { + return 0; + } + + while (left <= right) { + int pivot = (left + right) / 2; + if (nums[pivot] > nums[pivot + 1]) { + return pivot + 1; + } else { + if(nums[pivot] < nums[left]) { + right = pivot - 1; + } else { + left = pivot + 1; + } + } + + } + + return 0; + } + + public int search(int left, int right) + { + while (left <= right) { + int pivot = (left + right) / 2; + if (nums[pivot] == target) + return pivot; + else { + if (target < nums[pivot]) + right = pivot - 1; + else + left = pivot + 1; + } + } + return -1; + } + + public int search(int[] nums, int target) { + this.nums = nums; + this.target = target; + + int n = nums.length; + + if (n == 0) { + return -1; + } + if (n == 1) { + return this.nums[0] == target ? 0 : -1; + } + + int rotate_index = find_rotate_index(0, n - 1); + + if (nums[rotate_index] == target) { + return rotate_index; + } + if (rotate_index == 0) { + return search(0, n - 1); + } + if (target < nums[0]) { + return search(rotate_index, n - 1); + } + + return search(0, rotate_index); + } +} diff --git a/Week_03/G20200343030395/LeetCode_6_395.java b/Week_03/G20200343030395/LeetCode_6_395.java new file mode 100644 index 00000000..9d6fe009 --- /dev/null +++ b/Week_03/G20200343030395/LeetCode_6_395.java @@ -0,0 +1,46 @@ +package Week_03.G20200343030395; + +public class LeetCode_6_395 { + + public int numIslands(char[][] grid) { + if(grid == null || grid.length == 0) { + return 0; + } + + int nr = grid.length; + int nc = grid[0].length; + + int nums = 0; + //遍历整个图 + for (int r = 0; r < nr; ++r) { + for (int c = 0;c < nc; ++c) { + //如果是1,从这里开始深度遍历,并设置为一个岛屿 + if(grid[r][c] == '1') { + nums ++; + dfs(grid, r, c); + } + } + } + + return nums; + } + + void dfs(char[][] grid, int r, int c) { + int nr = grid.length; + int nc = grid[0].length; + + //边界条件和已遍历判断 + if(r < 0 || c < 0 || r >= nr || c >= nc || grid[r][c] == '0') { + return; + } + + //当前节点设置为已遍历 + grid[r][c] = '0'; + + //四个方向扩深度遍历 + dfs(grid, r-1, c); + dfs(grid, r+1, c); + dfs(grid, r, c-1); + dfs(grid, r, c+1); + } +} diff --git a/Week_03/G20200343030395/LeetCode_powxn.java b/Week_03/G20200343030395/LeetCode_powxn.java new file mode 100644 index 00000000..065de3c6 --- /dev/null +++ b/Week_03/G20200343030395/LeetCode_powxn.java @@ -0,0 +1,34 @@ +package Week_03.G20200343030395; + +public class LeetCode_powxn { + + public double myPow(double x, int n) { + long N = n; + if(n < 0) { + x = 1/x; + N = -N; + } + + return fastPow(x, N); + } + + private double fastPow(double x, long n) { + //结束 + if(n == 0) { + return 1.0; + } + + //子问题处理 + double helf = fastPow(x, n/2); + + //处理当前层 + if(n%2 == 0) { + return helf * helf; + } else { + return helf * helf * x; + } + + + + } +} diff --git a/Week_03/G20200343030395/NOTE.md b/Week_03/G20200343030395/NOTE.md index 50de3041..9a019814 100644 --- a/Week_03/G20200343030395/NOTE.md +++ b/Week_03/G20200343030395/NOTE.md @@ -1 +1,39 @@ -学习笔记 \ No newline at end of file +学习笔记 +## 2020/2/24 +* 分治回溯本质上也是递归 +* 当前层考虑当前层的问题 +* 回溯采用试错的方法,分步解决问题 + +## 2020/2/27 +* 贪心:当下局部最优 +* 回溯:尝试后回退 +* 动态规划:最优+回退 +适用贪心: +1. 问题能够分解成子问题 +2. 子问题最优解能够推理出最终问题的最优解 + +动态规划和贪心的区别: +贪心:每个子问题选择最优并得到最终问题的最优 +动态规划:保存每个子问题的解,最后再选择 + +贪心的关键点: +1. 证明贪心是适用的 +2. 贪心的角度(从后?从前?转换? + +二分查找前提: +1. 单调性(确定左右) +2. 存在上下界 +3. 能够通过索引访问 +``` +left,right = 0, len(array) -1 +while left <= right: + mid = (left + right)/2 + if(array[mid]) == target: + //找到 + break or return result + elif array[mid] < target: + left = mid+1 + else: + right = mid+1 +``` + diff --git a/Week_03/G20200343030401/LeetCode_122_401.java b/Week_03/G20200343030401/LeetCode_122_401.java new file mode 100644 index 00000000..81197f70 --- /dev/null +++ b/Week_03/G20200343030401/LeetCode_122_401.java @@ -0,0 +1,63 @@ +//题目链接:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/ +class Solution { + /** + * 方法1: 暴力法; 计算与所有可能的交易组合相对应的利润,并找出它们中的最大利润 + * 时间复杂度: 时间复杂度:O(n^n),调用递归函数 n^n次 + * 空间复杂度: O(n),递归的深度为 n + */ + public int maxProfit1(int[] prices, int s) { + if (s >= prices.length) + return 0; + int max = 0; + for (int start = s; start < prices.length; start++) { + int maxprofit = 0; + for (int i = start + 1; i < prices.length; i++) { + if (prices[start] < prices[i]) { + int profit = calculate(prices, i + 1) + prices[i] - prices[start]; + if (profit > maxprofit) + maxprofit = profit; + } + } + if (maxprofit > max) + max = maxprofit; + } + return max; + } + + /** + * 方法2: 峰谷法 + * 时间复杂度: 时间复杂度:O(n),遍历一次 + * 空间复杂度: O(1),需要常量的空间 + */ + public int maxProfit2(int[] prices) { + int i = 0; + int valley = prices[0]; + int peak = prices[0]; + int maxprofit = 0; + while (i < prices.length - 1) { + while (i < prices.length - 1 && prices[i] >= prices[i + 1]) + i++; + valley = prices[i]; + while (i < prices.length - 1 && prices[i] <= prices[i + 1]) + i++; + peak = prices[i]; + maxprofit += peak - valley; + } + return maxprofit; + } + + + /** + * 方法2: 简单的一次遍历; 第二个数字大于第一个数字,获得的总和将是最大利润 + * 时间复杂度: 时间复杂度:O(n),遍历一次 + * 空间复杂度: O(1),需要常量的空间 + */ + public int maxProfit3(int[] prices) { + int maxprofit = 0; + for (int i = 1; i < prices.length; i++) { + if (prices[i] > prices[i - 1]) + maxprofit += prices[i] - prices[i - 1]; + } + return maxprofit; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030401/LeetCode_860_401.java b/Week_03/G20200343030401/LeetCode_860_401.java new file mode 100644 index 00000000..91ff630f --- /dev/null +++ b/Week_03/G20200343030401/LeetCode_860_401.java @@ -0,0 +1,60 @@ +// 题目连接: https://leetcode-cn.com/problems/lemonade-change/ +class Solution { + /** + * 方法1: 暴力求解法 + * 时间复杂度: O(N), 其中N是bills的长度 + * 空间复杂度: O(1) + */ + public boolean lemonadeChange1(int[] bills) { + int five = 0, ten = 0; + for (int bill: bills) { + if (bill == 5) + five++; + else if (bill == 10) { + if (five == 0) return false; + five--; + ten++; + } else { + if (five > 0 && ten > 0) { + five--; + ten--; + } else if (five >= 3) { + five -= 3; + } else { + return false; + } + } + } + + return true; + } + + /** + * 方法1: 贪心算法 + * 时间复杂度: O(N) + * 空间复杂度: O(1), 没有用到额外空间 + */ + public boolean lemonadeChange2(int[] bills) { + int fives = 0, tens = 0; + if (bills.length < 1) return true; + if (bills[0] != 5) return false; + for (int index = 0; index < bills.length; ++index) { + if (bills[index] == 5) + fives++; + else if (bills[index] == 10) { + if (fives < 1) + return false; + fives--; + tens++; + } else { + if (tens > 0 && fives > 0) { + tens--; + fives--; + } else if (fives > 2) + fives -= 3; + else return false; + } + } + return true; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030401/LeetCode_874_401.java b/Week_03/G20200343030401/LeetCode_874_401.java new file mode 100644 index 00000000..673557dd --- /dev/null +++ b/Week_03/G20200343030401/LeetCode_874_401.java @@ -0,0 +1,39 @@ +//题目链接: https://leetcode-cn.com/problems/walking-robot-simulation/description/ + +class Solution { + public int robotSim(int[] commands, int[][] obstacles) { + int[] dx = new int[]{0, 1, 0, -1}; + int[] dy = new int[]{1, 0, -1, 0}; + int x = 0, y = 0, di = 0; + + // Encode obstacles (x, y) as (x+30000) * (2^16) + (y+30000) + Set obstacleSet = new HashSet(); + for (int[] obstacle: obstacles) { + long ox = (long) obstacle[0] + 30000; + long oy = (long) obstacle[1] + 30000; + obstacleSet.add((ox << 16) + oy); + } + + int ans = 0; + for (int cmd: commands) { + if (cmd == -2) //left + di = (di + 3) % 4; + else if (cmd == -1) //right + di = (di + 1) % 4; + else { + for (int k = 0; k < cmd; ++k) { + int nx = x + dx[di]; + int ny = y + dy[di]; + long code = (((long) nx + 30000) << 16) + ((long) ny + 30000); + if (!obstacleSet.contains(code)) { + x = nx; + y = ny; + ans = Math.max(ans, x*x + y*y); + } + } + } + } + + return ans; + } +} \ No newline at end of file diff --git "a/Week_03/G20200343030407/[122]\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272 II.py" "b/Week_03/G20200343030407/[122]\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272 II.py" new file mode 100644 index 00000000..cdf811e7 --- /dev/null +++ "b/Week_03/G20200343030407/[122]\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272 II.py" @@ -0,0 +1,72 @@ +# 给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。 +# +# 设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。 +# +# 注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。 +# +# 示例 1: +# +# 输入: [7,1,5,3,6,4] +# 输出: 7 +# 解释: 在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。 +#   随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6-3 = 3 。 +# +# +# 示例 2: +# +# 输入: [1,2,3,4,5] +# 输出: 4 +# 解释: 在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。 +#   注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。 +#   因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。 +# +# +# 示例 3: +# +# 输入: [7,6,4,3,1] +# 输出: 0 +# 解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。 +# Related Topics 贪心算法 数组 +from typing import List + + +# leetcode submit region begin(Prohibit modification and deletion) +class Solution: + def maxProfit(self, prices: List[int]) -> int: + #return violence(prices, 0) + if len(prices) == 0: + return 0 + max_profit = 0 + current_low_price = prices[0] + for index, price in enumerate(prices): + if index == 0: + continue + if price < prices[index - 1]: + max_profit += prices[index - 1] - current_low_price + current_low_price = price + elif index == prices.__len__() - 1: + max_profit += price - current_low_price + return max_profit + + + +def violence(prices: List[int], s_index): + l = prices.__len__() + if s_index > l: + return 0 + final_max = 0 + for i in range(s_index, l): + max_profit = 0 + for k in range(i + 1, l): + if prices[i] < prices[k]: + profit = violence(prices, k + 1) + prices[k] - prices[i] + if profit > max_profit: + max_profit = profit + if max_profit > final_max: + final_max = max_profit + return final_max + + +# leetcode submit region end(Prohibit modification and deletion) +a = [1,2,3,4,5] +print(Solution().maxProfit(a)) diff --git "a/Week_03/G20200343030407/[127]\345\215\225\350\257\215\346\216\245\351\276\231.py" "b/Week_03/G20200343030407/[127]\345\215\225\350\257\215\346\216\245\351\276\231.py" new file mode 100644 index 00000000..985b329c --- /dev/null +++ "b/Week_03/G20200343030407/[127]\345\215\225\350\257\215\346\216\245\351\276\231.py" @@ -0,0 +1,79 @@ +# 给定两个单词(beginWord 和 endWord)和一个字典,找到从 beginWord 到 endWord 的最短转换序列的长度。转换需遵循如下规则: +# +# +# +# 每次转换只能改变一个字母。 +# 转换过程中的中间单词必须是字典中的单词。 +# +# +# 说明: +# +# +# 如果不存在这样的转换序列,返回 0。 +# 所有单词具有相同的长度。 +# 所有单词只由小写字母组成。 +# 字典中不存在重复的单词。 +# 你可以假设 beginWord 和 endWord 是非空的,且二者不相同。 +# +# +# 示例 1: +# +# 输入: +# beginWord = "hit", +# endWord = "cog", +# wordList = ["hot","dot","dog","lot","log","cog"] +# +# 输出: 5 +# +# 解释: 一个最短转换序列是 "hit" -> "hot" -> "dot" -> "dog" -> "cog", +# 返回它的长度 5。 +# +# +# 示例 2: +# +# 输入: +# beginWord = "hit" +# endWord = "cog" +# wordList = ["hot","dot","dog","lot","log"] +# +# 输出: 0 +# +# 解释: endWord "cog" 不在字典中,所以无法进行转换。 +# Related Topics 广度优先搜索 +from collections import defaultdict +from typing import List + + +# leetcode submit region begin(Prohibit modification and deletion) +class Solution: + def ladderLength(self, beginWord: str, endWord: str, wordList: List[str]) -> int: + length = len(beginWord) + all_dict = defaultdict(list) + for word in wordList: + for i in range(length): + all_dict[word[:i] + '*' + word[i + 1:]].append(word) + + queue = [(beginWord, 1)] + visited = {beginWord: True} + while queue: + current_word, level = queue.pop(0) + for i in range(length): + intermediate_word = current_word[:i] + "*" + current_word[i + 1:] + + for word in all_dict[intermediate_word]: + if word == endWord: + return level + 1 + if word not in visited: + visited[word] = True + queue.append((word, level + 1)) + all_dict[intermediate_word] = [] + return 0 + + +# leetcode submit region end(Prohibit modification and deletion) + + +beginWord = 'hit' +endWord = 'cog' +wordList = ["hot","dot","dog","lot","log"] +print(Solution().ladderLength(beginWord, endWord, wordList)) diff --git "a/Week_03/G20200343030407/[455]\345\210\206\345\217\221\351\245\274\345\271\262.py" "b/Week_03/G20200343030407/[455]\345\210\206\345\217\221\351\245\274\345\271\262.py" new file mode 100644 index 00000000..088aefb5 --- /dev/null +++ "b/Week_03/G20200343030407/[455]\345\210\206\345\217\221\351\245\274\345\271\262.py" @@ -0,0 +1,58 @@ +# 假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。对每个孩子 i ,都有一个胃口值 gi ,这是能让孩子们满足胃口的饼干 +# 的最小尺寸;并且每块饼干 j ,都有一个尺寸 sj 。如果 sj >= gi ,我们可以将这个饼干 j 分配给孩子 i ,这个孩子会得到满足。你的目标是尽可能满 +# 足越多数量的孩子,并输出这个最大数值。 +# +# 注意: +# +# 你可以假设胃口值为正。 +# 一个小朋友最多只能拥有一块饼干。 +# +# 示例 1: +# +# +# 输入: [1,2,3], [1,1] +# +# 输出: 1 +# +# 解释: +# 你有三个孩子和两块小饼干,3个孩子的胃口值分别是:1,2,3。 +# 虽然你有两块小饼干,由于他们的尺寸都是1,你只能让胃口值是1的孩子满足。 +# 所以你应该输出1。 +# +# +# 示例 2: +# +# +# 输入: [1,2], [1,2,3] +# +# 输出: 2 +# +# 解释: +# 你有两个孩子和三块小饼干,2个孩子的胃口值分别是1,2。 +# 你拥有的饼干数量和尺寸都足以让所有孩子满足。 +# 所以你应该输出2. +# +# Related Topics 贪心算法 +from typing import List + +# leetcode submit region begin(Prohibit modification and deletion) +class Solution: + def findContentChildren(self, g: List[int], s: List[int]) -> int: + if g.__len__() == 0 or s.__len__() == 0: + return 0 + g.sort() + s.sort() + feed_num = 0 + g_index = 0 + s_index = 0 + while g_index < g.__len__() and s_index < s.__len__(): + if g[g_index] <= s[s_index]: + g_index += 1 + s_index += 1 + return g_index + + +# leetcode submit region end(Prohibit modification and deletion) +g = [1,2,3,1] +s = [1,1] +print(Solution().findContentChildren(g, s)) \ No newline at end of file diff --git "a/Week_03/G20200343030407/[860]\346\237\240\346\252\254\346\260\264\346\211\276\351\233\266.py" "b/Week_03/G20200343030407/[860]\346\237\240\346\252\254\346\260\264\346\211\276\351\233\266.py" new file mode 100644 index 00000000..2943a17c --- /dev/null +++ "b/Week_03/G20200343030407/[860]\346\237\240\346\252\254\346\260\264\346\211\276\351\233\266.py" @@ -0,0 +1,79 @@ +# 在柠檬水摊上,每一杯柠檬水的售价为 5 美元。 +# +# 顾客排队购买你的产品,(按账单 bills 支付的顺序)一次购买一杯。 +# +# 每位顾客只买一杯柠檬水,然后向你付 5 美元、10 美元或 20 美元。你必须给每个顾客正确找零,也就是说净交易是每位顾客向你支付 5 美元。 +# +# 注意,一开始你手头没有任何零钱。 +# +# 如果你能给每位顾客正确找零,返回 true ,否则返回 false 。 +# +# 示例 1: +# +# 输入:[5,5,5,10,20] +# 输出:true +# 解释: +# 前 3 位顾客那里,我们按顺序收取 3 张 5 美元的钞票。 +# 第 4 位顾客那里,我们收取一张 10 美元的钞票,并返还 5 美元。 +# 第 5 位顾客那里,我们找还一张 10 美元的钞票和一张 5 美元的钞票。 +# 由于所有客户都得到了正确的找零,所以我们输出 true。 +# +# +# 示例 2: +# +# 输入:[5,5,10] +# 输出:true +# +# +# 示例 3: +# +# 输入:[10,10] +# 输出:false +# +# +# 示例 4: +# +# 输入:[5,5,10,10,20] +# 输出:false +# 解释: +# 前 2 位顾客那里,我们按顺序收取 2 张 5 美元的钞票。 +# 对于接下来的 2 位顾客,我们收取一张 10 美元的钞票,然后返还 5 美元。 +# 对于最后一位顾客,我们无法退回 15 美元,因为我们现在只有两张 10 美元的钞票。 +# 由于不是每位顾客都得到了正确的找零,所以答案是 false。 +# +# +# +# +# 提示: +# +# +# 0 <= bills.length <= 10000 +# bills[i] 不是 5 就是 10 或是 20 +# +# Related Topics 贪心算法 +from typing import List + +# leetcode submit region begin(Prohibit modification and deletion) +class Solution: + def lemonadeChange(self, bills: List[int]) -> bool: + five = 0 + ten = 0 + for bill in bills: + if bill == 5: + five += 1 + if bill == 10: + five -= 1 + ten += 1 + if bill == 20: + if ten > 0: + ten -= 1 + five -= 1 + else: + five -= 3 + if five < 0: + return False + return True + + + +# leetcode submit region end(Prohibit modification and deletion) diff --git "a/Week_03/G20200343030407/[874]\346\250\241\346\213\237\350\241\214\350\265\260\346\234\272\345\231\250\344\272\272.py" "b/Week_03/G20200343030407/[874]\346\250\241\346\213\237\350\241\214\350\265\260\346\234\272\345\231\250\344\272\272.py" new file mode 100644 index 00000000..82e423c7 --- /dev/null +++ "b/Week_03/G20200343030407/[874]\346\250\241\346\213\237\350\241\214\350\265\260\346\234\272\345\231\250\344\272\272.py" @@ -0,0 +1,70 @@ +# 机器人在一个无限大小的网格上行走,从点 (0, 0) 处开始出发,面向北方。该机器人可以接收以下三种类型的命令: +# +# +# -2:向左转 90 度 +# -1:向右转 90 度 +# 1 <= x <= 9:向前移动 x 个单位长度 +# +# +# 在网格上有一些格子被视为障碍物。 +# +# 第 i 个障碍物位于网格点 (obstacles[i][0], obstacles[i][1]) +# +# 如果机器人试图走到障碍物上方,那么它将停留在障碍物的前一个网格方块上,但仍然可以继续该路线的其余部分。 +# +# 返回从原点到机器人的最大欧式距离的平方。 +# +# +# +# 示例 1: +# +# 输入: commands = [4,-1,3], obstacles = [] +# 输出: 25 +# 解释: 机器人将会到达 (3, 4) +# +# +# 示例 2: +# +# 输入: commands = [4,-1,4,-2,4], obstacles = [[2,4]] +# 输出: 65 +# 解释: 机器人在左转走到 (1, 8) 之前将被困在 (1, 4) 处 +# +# +# +# +# 提示: +# +# +# 0 <= commands.length <= 10000 +# 0 <= obstacles.length <= 10000 +# -30000 <= obstacle[i][0] <= 30000 +# -30000 <= obstacle[i][1] <= 30000 +# 答案保证小于 2 ^ 31 +# +# Related Topics 贪心算法 + + +# leetcode submit region begin(Prohibit modification and deletion) +class Solution: + def robotSim(self, commands: List[int], obstacles: List[List[int]]) -> int: + dx = [0, 1, 0, -1] + dy = [1, 0, -1, 0] + x = y = di = 0 # x,y为当前坐标,di为当前方向 + obstacle_set = set(map(tuple, obstacles)) + ans = 0 + for command in commands: + if command == -1: + di = (di + 1) % 4 + elif command == -2: + di = (di - 1) % 4 + else: + for i in range(command): + if (x + dx[di], y + dy[di]) in obstacle_set: + break + else: + x += dx[di] + y += dy[di] + ans = max(ans, x * x + y * y) + return ans + +# leetcode submit region end(Prohibit modification and deletion) diff --git a/Week_03/G20200343030409/LeetCode_122_409.java b/Week_03/G20200343030409/LeetCode_122_409.java new file mode 100644 index 00000000..ef82ffa1 --- /dev/null +++ b/Week_03/G20200343030409/LeetCode_122_409.java @@ -0,0 +1,16 @@ +/* + greedy + + time complexity: O(n), space complexity:O(1) +*/ +class Solution { + public int maxProfit(int[] prices) { + int profit = 0; + for (int i = 0; i < prices.length - 1; i++) { // or add i+1 < prices.length && in if statement + if (prices[i+1] > prices[i]) { // found next price is bigger, add it to profit + profit += prices[i+1] - prices[i]; + } + } + return profit; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030409/LeetCode_200_409.java b/Week_03/G20200343030409/LeetCode_200_409.java new file mode 100644 index 00000000..0fd27dfc --- /dev/null +++ b/Week_03/G20200343030409/LeetCode_200_409.java @@ -0,0 +1,46 @@ +/* + use flood fill, use dfs to traverse all island, and mark vistied + + time complexity: O(n*m), space complexity: O(1), n is grid's height, m is grid's width + +*/ +class Solution { + private int n; //grid's height + private int m; //grid's width + public int numIslands(char[][] grid) { + n = grid.length; + if (n == 0) return 0; + + m = grid[0].length; + + int count = 0; + + // loop grid[][] + for (int i = 0; i < n; i ++) { + for (int j = 0; j < m; j++) { + if (grid[i][j] == '1') { //if touch the land, do dfs traverser + dfs(grid, i, j); + count++; //find island, count++ + } + } + } + return count; + } + + private void dfs(char[][] grid, int i, int j) { + // terminator + // out of bound or it's water + if (i < 0 || j < 0 || i >= n || j >=m || grid[i][j] == '0') return; + + //drill down + // an islan to be sinked, visited, island becomes water + grid[i][j] = '0'; + + // traverse all surrouding area + dfs(grid, i+1, j); + dfs(grid, i, j+1); + dfs(grid, i-1, j); + dfs(grid, i, j-1); + + } +} \ No newline at end of file diff --git a/Week_03/G20200343030409/LeetCode_33_409.java b/Week_03/G20200343030409/LeetCode_33_409.java new file mode 100644 index 00000000..803da79c --- /dev/null +++ b/Week_03/G20200343030409/LeetCode_33_409.java @@ -0,0 +1,48 @@ +/* + there is two part are ordered. + + use nested binary search to find + + if (nums[mid] == target) { + return mid; + } else if (nums[mid] >= nums[left]) { + + //check target in which part, then to adjust right or left index + } else { + + //check target in which part, then to adjust right or left index + } + + time complexity: O(logn), space complexity: O(1) +*/ + +class Solution { + public int search(int[] nums, int target) { + int left = 0; + int right = nums.length - 1; + + while (left <= right) { + int mid = left + (right - left)/2; + if (nums[mid] == target) { + return mid; + + } else if (nums[mid] >= nums[left]) { //first, try to assure which part is we want (left part) + + if (nums[mid] >= target && target >= nums[left]) { // then try to find target in this part + right = mid - 1; // this means target is really in left part + } else { + left = mid + 1; // means not in left part, it should be in right part + } + + } else { // assure which part is we want (right part) + + if (nums[right] >= target && target >= nums[mid]) { + left = mid + 1; + } else { + right = mid - 1; + } + } + } + return -1; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030409/LeetCode_455_409.java b/Week_03/G20200343030409/LeetCode_455_409.java new file mode 100644 index 00000000..81d2c900 --- /dev/null +++ b/Week_03/G20200343030409/LeetCode_455_409.java @@ -0,0 +1,19 @@ +/* + greedy + + time complexity: O(nlogn), space complexity: O(1) +*/ +class Solution { + public int findContentChildren(int[] g, int[] s) { + Arrays.sort(g); //both need to sort first, because we will compare one by one from beginning + Arrays.sort(s); + + int i = 0; + for (int cookies: s) { + if (i < g.length && g[i] <= cookies) { //if it matches content, increment count + i++; + } + } + return i; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030409/LeetCode_74_409.java b/Week_03/G20200343030409/LeetCode_74_409.java new file mode 100644 index 00000000..3c8af034 --- /dev/null +++ b/Week_03/G20200343030409/LeetCode_74_409.java @@ -0,0 +1,32 @@ +/* + use binary search + + time complexity: O(log(m*n)) space complexity: O(1) +*/ +class Solution { + public boolean searchMatrix(int[][] matrix, int target) { + if (matrix == null || matrix.length == 0) return false; + + int m = matrix.length; // 2d -> look as a 1-d array, matrix[m][n] looks like a[m*n] + int n = matrix[0].length; + + int left = 0; + int right = m*n - 1; + + while (left <= right) { + int mid = left + (right - left)/2; + int matrixVal = matrix[mid/n][mid%n]; // 1d index + + if (matrixVal == target) { + return true; + } + + if (matrixVal > target) { + right = mid - 1; + } else { + left = mid + 1; + } + } + return false; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030409/LeetCode_860_409.java b/Week_03/G20200343030409/LeetCode_860_409.java new file mode 100644 index 00000000..a014adb1 --- /dev/null +++ b/Week_03/G20200343030409/LeetCode_860_409.java @@ -0,0 +1,31 @@ +/* + greedy algo, becasue if we have $10, we use combination of $5 & $10 first + + time complexity: O(n) , space complecity: O(1) +*/ +class Solution { + public boolean lemonadeChange(int[] bills) { + int five = 0; + int ten = 0; + + for (int bill : bills) { + + if (bill == 5) { + five++; //$5 number ++ + } else if (bill == 10) { //$10 number ++, and changing $5 back + five--; + ten++; + + } else if (ten > 0) { // 20 dollars case, if we have ten coins, use combination of $5 & $10 first + five--; + ten--; + + } else { + five -= 3; //not enough $10, so using 3 $5 + } + + if (five < 0) return false; // in loop, we found not enough change + } + return true; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030409/LeetCode_874_409.java b/Week_03/G20200343030409/LeetCode_874_409.java new file mode 100644 index 00000000..8a2471b3 --- /dev/null +++ b/Week_03/G20200343030409/LeetCode_874_409.java @@ -0,0 +1,59 @@ +/* + W + S -|- N + E + according to the question, the robot faces north + + general case: + use directions[direction] to caculate x,y + + North, direction = 0, directions[direction] = {0, 1} + East, direction = 1, directions[direction] = {1, 0} + South, direction = 2, directions[direction] = {0, -1} + West, direction = 3, directions[direction] = {-1, 0} + + time conplexity: O(n+k), space complexity:O(k), n is commands array size, k is obstacles array size +*/ +class Solution { + public static final int[][] directions = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}}; // north, east, south, west + + public int robotSim(int[] commands, int[][] obstacles) { + Set obsMap = new HashSet<>(); + for (int[] o : obstacles) { + long code = encode(o[0], o[1]); + obsMap.add(code); + } + + int x = 0; + int y = 0; + int direction = 0; + int maxSquare = 0; + + for (int cmd : commands) { + if (cmd == -2) { // turn left, then caculate the direction + direction = (direction + 3) % 4; // (direction - 1) % 4 = -1 => so use (direction + 3)%4 + } else if (cmd == -1) { // turn right, then caculate the direction + direction = (direction + 1) % 4; + } else { + for (int step = 0; step < cmd; step++) { + int nx = x + directions[direction][0]; // new x value, because if it has obstacles, remain old x value + int ny = y + directions[direction][1]; + + long code = encode(nx, ny); + if (!obsMap.contains(code)) { // no obstacles, caculate the max result + x = nx; // update new value + y = ny; + maxSquare = Math.max(maxSquare, x*x + y*y); + } + } + } + } + return maxSquare; + } + + // encoding: access set fast! + // enocde obstacles(x,y) to (((long)x + 300000) << 16) + (long)y + 30000 + private long encode(int x, int y) { + return (((long)x + 300000) << 16) + (long)y + 30000; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030413/LeetCode_122_413.java b/Week_03/G20200343030413/LeetCode_122_413.java new file mode 100644 index 00000000..dc690b46 --- /dev/null +++ b/Week_03/G20200343030413/LeetCode_122_413.java @@ -0,0 +1,28 @@ +package com.kidand.homework.week03; +/** +* +* ██╗ ██╗██╗██████╗ █████╗ ███╗ ██╗██████╗ +* ██║ ██╔╝██║██╔══██╗██╔══██╗████╗ ██║██╔══██╗ +* █████╔╝ ██║██║ ██║███████║██╔██╗ ██║██║ ██║ +* ██╔═██╗ ██║██║ ██║██╔══██║██║╚██╗██║██║ ██║ +* ██║ ██╗██║██████╔╝██║ ██║██║ ╚████║██████╔╝ +* ╚═╝ ╚═╝╚═╝╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═══╝╚═════╝ +* +* @description:LeetCode_122_413 +* @author: Kidand +* @date: 2020/2/29 5:40 下午 +* Copyright © 2019-Kidand. +*/ +public class LeetCode_122_413 { + public int maxProfit(int[] prices) { + int ans=0; + for(int i=1;i<=prices.length-1;i++) + { + if(prices[i]>prices[i-1]) + { + ans+=prices[i]-prices[i-1]; + } + } + return ans; + } +} diff --git a/Week_03/G20200343030413/LeetCode_860_413.java b/Week_03/G20200343030413/LeetCode_860_413.java new file mode 100644 index 00000000..c15361de --- /dev/null +++ b/Week_03/G20200343030413/LeetCode_860_413.java @@ -0,0 +1,41 @@ +package com.kidand.homework.week03; +/** +* +* ██╗ ██╗██╗██████╗ █████╗ ███╗ ██╗██████╗ +* ██║ ██╔╝██║██╔══██╗██╔══██╗████╗ ██║██╔══██╗ +* █████╔╝ ██║██║ ██║███████║██╔██╗ ██║██║ ██║ +* ██╔═██╗ ██║██║ ██║██╔══██║██║╚██╗██║██║ ██║ +* ██║ ██╗██║██████╔╝██║ ██║██║ ╚████║██████╔╝ +* ╚═╝ ╚═╝╚═╝╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═══╝╚═════╝ +* +* @description:LeetCode_860_413 +* @author: Kidand +* @date: 2020/2/28 5:38 下午 +* Copyright © 2019-Kidand. +*/ +public class LeetCode_860_413 { + public boolean lemonadeChange(int[] bills) { + int five=0,ten=0,back=0; + for(int i=0;i=10&&ten>0){ + back-=10; + --ten; + } + while(back>=5&&five>0){ + back-=5; + --five; + } + if(back>0) { + return false; + } + } + return true; + } +} diff --git a/Week_03/G20200343030415/LeetCode-127-415.java b/Week_03/G20200343030415/LeetCode-127-415.java new file mode 100644 index 00000000..f8f2b854 --- /dev/null +++ b/Week_03/G20200343030415/LeetCode-127-415.java @@ -0,0 +1,46 @@ +class Solution { + public int ladderLength(String beginWord, String endWord, List wordList) { + Set visited = new HashSet<>(); + Queue queue = new LinkedList<>(); + queue.offer(beginWord); + visited.add(beginWord); + int count = 0; + while (!queue.isEmpty()){ + int size = queue.size(); + ++count; + for (int i = 0; i < size; i++) { + String start = queue.poll(); + for (String s : wordList){ + if(!canCovert(start,s)){ + continue; + } + if(visited.contains(s)){ + continue; + } + if(s.equals(endWord)){ + return count + 1; + } + visited.add(s); + queue.offer(s); + } + } + } + return 0; + } + + public boolean canCovert(String s1, String s2){ + if(s1.length() != s2.length()){ + return false; + } + int count = 0; + for (int i = 0; i < s1.length(); i++) { + if(s1.charAt(i) != s2.charAt(i)){ + ++count; + if(count > 1){ + return false; + } + } + } + return count == 1; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030415/LeetCode-153-415.java b/Week_03/G20200343030415/LeetCode-153-415.java new file mode 100644 index 00000000..6fb05de3 --- /dev/null +++ b/Week_03/G20200343030415/LeetCode-153-415.java @@ -0,0 +1,15 @@ +class Solution { + public int findMin(int[] nums) { + int left = 0; + int right = nums.length - 1; + while (left < right){ + int mid = left + (right -left) / 2; + if(nums[mid] > nums[right]){ + left = mid + 1; + }else { + right = mid; + } + } + return nums[left]; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030415/LeetCode-200-415.java b/Week_03/G20200343030415/LeetCode-200-415.java new file mode 100644 index 00000000..27097730 --- /dev/null +++ b/Week_03/G20200343030415/LeetCode-200-415.java @@ -0,0 +1,33 @@ + + +class Solution { + int[] dx = {-1,1,0,0}; + int[] dy = {0,0,-1,1}; + char[][] g; + public int numIslands(char[][] grid) { + int islands = 0; + g = grid; + for (int i = 0; i < g.length; i++) { + for (int j = 0; j < g[i].length; j++) { + islands += sink(i,j); + } + } + return islands; + } + + public int sink(int i, int j){ + if(g[i][j] == '0'){ + return 0; + } + g[i][j] = '0'; + + for (int k = 0; k < dx.length; k++) { + int x = i + dx[k]; + int y = j + dy[k]; + if(x >= 0 && x < g.length && y >=0 && y < g[i].length){ + sink(x,y); + } + } + return 1; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030415/LeetCode-33-415.java b/Week_03/G20200343030415/LeetCode-33-415.java new file mode 100644 index 00000000..3cba08fb --- /dev/null +++ b/Week_03/G20200343030415/LeetCode-33-415.java @@ -0,0 +1,19 @@ +class Solution { + + public int search(int[] nums, int target) { + int left = 0; + int right = nums.length - 1; + while (left < right){ + int mid = (left + right) / 2; + if(nums[0] <= nums[mid] && (target < nums[0] || target > nums[mid])){ + left = mid + 1; + }else if(target < nums[0] && target > nums[mid]){ + left = mid + 1; + }else { + right = mid; + } + } + return left == right && nums[left] == target ? left : -1; + } + +} \ No newline at end of file diff --git a/Week_03/G20200343030415/LeetCode-529-415.java b/Week_03/G20200343030415/LeetCode-529-415.java new file mode 100644 index 00000000..4c544bc2 --- /dev/null +++ b/Week_03/G20200343030415/LeetCode-529-415.java @@ -0,0 +1,49 @@ +class Solution { + + int[] dx = {-1,-1,0,1,1,1,0,-1}; + int[] dy = {0,1,1,1,0,-1,-1,-1}; + + public char[][] updateBoard(char[][] board, int[] click) { + dfs(board,click[0],click[1]); + return board; + } + + public void dfs(char[][] board, int x, int y){ + int r = board.length; + int c = board[0].length; + if(x >= 0 && x < r && y >=0 && y < c){ + if(board[x][y] == 'E'){ + board[x][y] = 'B'; + int count = judge(board,x,y); + //周围没有地雷 + if(count == 0){ + for (int i = 0; i < 8; i++) { + dfs(board,x + dx[i],y + dy[i]); + } + }else { + //有地雷,显示地雷个数 + board[x][y] = (char) (count + '0'); + } + }else if(board[x][y] == 'M'){ + board[x][y] = 'X'; + } + } + + } + + public int judge(char[][] board, int x, int y){ + int r = board.length; + int c = board[0].length; + int count = 0; + for (int i = 0; i < dx.length; i++) { + int newX= x + dx[i]; + int newY = y + dy[i]; + if(newX >=0 && newX < r && newY >=0 && newY < c){ + if(board[newX][newY] == 'M'){ + count++; + } + } + } + return count; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030415/LeetCode-55-415.java b/Week_03/G20200343030415/LeetCode-55-415.java new file mode 100644 index 00000000..bb3cac38 --- /dev/null +++ b/Week_03/G20200343030415/LeetCode-55-415.java @@ -0,0 +1,10 @@ +class Solution { + public boolean canJump(int[] nums) { + int lastPos = nums.length - 1; + for (int i = nums.length - 1; i >= 0; i--) { + if(nums[i] + i >= lastPos){ + lastPos = i; + } + } + return lastPos == 0; + } \ No newline at end of file diff --git a/Week_03/G20200343030415/LeetCode-74-415.java b/Week_03/G20200343030415/LeetCode-74-415.java new file mode 100644 index 00000000..fd117a9d --- /dev/null +++ b/Week_03/G20200343030415/LeetCode-74-415.java @@ -0,0 +1,28 @@ +class Solution { + + + public boolean searchMatrix(int[][] matrix, int target){ + int m = matrix.length; + if(m == 0){ + return false; + } + int n = matrix[0].length; + int left = 0; + int right = m * n - 1; + int pivotIdx,pivotElement; + while (left <= right){ + pivotIdx = (left + right) / 2; + pivotElement = matrix[pivotIdx / n][pivotIdx % n]; + if(target == pivotElement){ + return true; + }else { + if(target > pivotElement){ + left = pivotIdx + 1; + }else { + right = pivotIdx - 1; + } + } + } + return false; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030417/417-week03-homework.py b/Week_03/G20200343030417/417-week03-homework.py new file mode 100644 index 00000000..4bc4c5c1 --- /dev/null +++ b/Week_03/G20200343030417/417-week03-homework.py @@ -0,0 +1,35 @@ + +# 200 岛屿数量 +class Solution(object): + # 深度优先算法 + def numIslands(self, grid): + # 记录岛屿的数量 + island_count = 0 + + # 深度优先遍历函数 + def dfs(row, col): + if row not in range(len(grid)) or col not in range(len(grid[0])) or\ + grid[row][col] == "0": + return + + # 当前位置为“1”的话,遍历完改为“0” + grid[row][col] = "0" + + # 上下左右四个方向遍历 + dfs(row, col-1) + dfs(row+1, col) + dfs(row, col+1) + dfs(row-1, col) + + for row in range(len(grid)): + for col in range(len(grid[0])): + if grid[row][col] == "1": + island_count += 1 + dfs(row, col) + + return island_count + + + + + diff --git a/Week_03/G20200343030417/homewok2.py b/Week_03/G20200343030417/homewok2.py new file mode 100644 index 00000000..e3862e2d --- /dev/null +++ b/Week_03/G20200343030417/homewok2.py @@ -0,0 +1,10 @@ +# 55.跳跃游戏 +# 贪心算法完成跳跃游戏 +class Solution(object): + def canJump(self,nums): + max_i = 0 # 初始化当然爱安能到达的最远的位置 + for i,jump in enumerate(nums): # i为当前位置,jump是当前未知的跳数 + if max_i >= i and i+jump > max_i: #如果当前位置能够到达,并且当前位置+跳数>最远距离 + max_i = i+jump # 更新最远能够到达的位置 + + return max_i >= i \ No newline at end of file diff --git a/Week_03/G20200343030423/LeetCode_74_423.java b/Week_03/G20200343030423/LeetCode_74_423.java new file mode 100644 index 00000000..1a88bcff --- /dev/null +++ b/Week_03/G20200343030423/LeetCode_74_423.java @@ -0,0 +1,27 @@ +public class LeetCode_74_423 { + +} + +class Solution74 { + public boolean searchMatrix(int[][] matrix, int target) { + if (matrix != null && matrix.length > 0) { + int left = 0; + int row = matrix.length; + int clo = matrix[0].length; + int right = row * clo - 1; + int mid ; + while (left <= right) { + mid = left + (right-left)/2; + if (matrix[(mid)/clo][(mid%clo)] == target) { + return true; + } + if (matrix[(mid)/clo][(mid%clo)] < target) { + left = mid + 1; + } else { + right = mid - 1; + } + } + } + return false; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030423/LeetCode_860_423.java b/Week_03/G20200343030423/LeetCode_860_423.java new file mode 100644 index 00000000..4570f54c --- /dev/null +++ b/Week_03/G20200343030423/LeetCode_860_423.java @@ -0,0 +1,35 @@ +public class LeetCode_860_423 { + +} + +class Solution860 { + public boolean lemonadeChange(int[] bills) { + if (bills.length <= 0 || bills[0] != 5) { + return false; + } + int fiveCount = 0; + int tenCount = 0; + for (int i = 0; i < bills.length; i++) { + if (bills[i] == 5) { + fiveCount++; + } else if (bills[i] == 10) { + if (fiveCount > 0) { + fiveCount--; + tenCount++; + } else { + return false; + } + } else if (bills[i] == 20) { + if (tenCount > 0 && fiveCount > 0) { + tenCount--; + fiveCount--; + } else if (fiveCount > 3) { + fiveCount = fiveCount-3; + } else { + return false; + } + } + } + return true; + } +} diff --git a/Week_03/G20200343030425/LeetCode_122_425/LeetCode_122_425.js b/Week_03/G20200343030425/LeetCode_122_425/LeetCode_122_425.js new file mode 100644 index 00000000..4425bbd8 --- /dev/null +++ b/Week_03/G20200343030425/LeetCode_122_425/LeetCode_122_425.js @@ -0,0 +1,23 @@ +/* +* address: https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/description/ +* */ +let input=[7,1,5,3,6,4]; +let result=7; + +/* +* Method 1: only using for loop +* */ +const maxProfit=(input)=>{ + let profit=0; + + for (let i = 0; i input[i]){ + profit+=input[i+1]-input[i]; + } + } + return profit; + +}; +/* +* Method 2: +* */ diff --git a/Week_03/G20200343030425/LeetCode_860_425/LeetCode_860_425.js b/Week_03/G20200343030425/LeetCode_860_425/LeetCode_860_425.js new file mode 100644 index 00000000..713791de --- /dev/null +++ b/Week_03/G20200343030425/LeetCode_860_425/LeetCode_860_425.js @@ -0,0 +1,35 @@ +/* +* address: https://leetcode-cn.com/problems/lemonade-change/ +* */ + +let input = [5, 5, 5, 10, 20]; +let result = true; + +/* +* 贪心:目前情况下最好的就是能用10元用10元,尽量少用5元; +* */ +let lemonadeChange = function (bills) { + let num5 = 0; + let num10 = 0; + for (let i = 0; i < bills.length; i++) { + switch (bills[i]) { + case 5: + num5++; + break; + case 10: + if (num5 === 0) return false; + num10++; + num5--; + break; + case 20: + if (num10 >= 1 && num5 >= 1) { + num10-- + num5-- + } else if (num10 === 0 && num5 >= 3) { + num5 -= 3 + } else return false; + break; + } + } + return true +}; diff --git a/Week_03/G20200343030429/LeetCode_1_429.java b/Week_03/G20200343030429/LeetCode_1_429.java new file mode 100644 index 00000000..38c47609 --- /dev/null +++ b/Week_03/G20200343030429/LeetCode_1_429.java @@ -0,0 +1,58 @@ +package com.study.week03; + +import com.study.Node; + +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; + +/** + * @author Abner + * @date 2020/3/3 20:25 + * @email songkd90@163.com + * @description 柠檬水找零 + * + */ +public class LeetCode_1_429 { + + // 1、暴力解法, 情景模拟 + // 记录手中5美元和10美元的数量 + // 找零后相应减去,20美元则优先找零10美元+5美元 + public boolean lemonChange(int[] bills) { + // 初始时5美元与10美元数量为0 + int five = 0; + int ten = 0; + + // 遍历购买单 + for (int bill : bills) { + // 如果是5美元,无需找零5美元数量增1 + if (bill == 5) { + five++; + } else if (bill == 10) { + // 如果顾客给10美元,则要找零五美元,看数量是否足够 + if (five == 0) { + return false; + } + // 找零,5美元数量少1,10美元增加了1 + five--; + ten++; + } else { + // 20美元的情况 + // 优先找零10美元 + if (ten > 0 && five > 0) { + five--; + ten--; + } else if(five >= 3) { + // 假如有3张五美元 + five -= 3; + } else { + return false; + } + } + } + + return true; + } +} + + diff --git a/Week_03/G20200343030429/LeetCode_2_429.java b/Week_03/G20200343030429/LeetCode_2_429.java new file mode 100644 index 00000000..d8d3cfc8 --- /dev/null +++ b/Week_03/G20200343030429/LeetCode_2_429.java @@ -0,0 +1,66 @@ +package com.study.week03; + +import com.study.Node; + +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; + +/** + * @author Abner + * @date 2020/3/1 21:15 + * @email songkd90@163.com + * @description 股票最佳时机 + */ +public class LeetCode_2_429 { + /** + * 解法一:暴力,计算所有可能性 + * @param prices + * @return 运行结果超出时间限制 + */ + public int maxProfit(int[] prices) { + return calculate(prices, 0); + } + + private int calculate(int[] prices, int s) { + // 递归终止条件 + if (s > prices.length) { + return 0; + } + + int max = 0; + for (int i = s; i < prices.length; i++) { + int maxprofit = 0; + for (int j = i+1; j < prices.length; j++) { + if (prices[i] < prices[j]) { + // 下潜 + int profit = calculate(prices, j + 1) + prices[j] - prices[i]; + if (profit > maxprofit) { + maxprofit = profit; + } + } + } + + if (maxprofit > max) { + max = maxprofit; + } + } + return max; + } + + + /** + * 解法二:贪心算法,后一天的股价减前一天的股价,结果只加正数 + * @param prices + * @return + */ + public int maxProfit1(int[] prices) { + int result = 0; + for (int i = 0; i < prices.length - 1; i++) { + if (prices[i + 1] > prices[i]) { + result += prices[i + 1] - prices[i]; + } + } + return result; + } +} diff --git a/Week_03/G20200343030429/LeetCode_3_429.java b/Week_03/G20200343030429/LeetCode_3_429.java new file mode 100644 index 00000000..c8d2e3b6 --- /dev/null +++ b/Week_03/G20200343030429/LeetCode_3_429.java @@ -0,0 +1,41 @@ +package com.study.week03; + +import java.util.Arrays; + +/** + * @author Abner + * @date 2020/3/1 22:15 + * @email songkd90@163.com + * @description 分发饼干 + */ +public class LeetCode_3_429 { + + /** + * 解法:贪心算法,胃口最小的先满足,留下份量大的来尽量满足胃口大的小朋友 + * @param s + * @param g + * @return + */ + public static int assignCookies(int[] g, int[] s) { + Arrays.sort(g); + Arrays.sort(s); + int gNum = 0; + int sNum = 0; + + while (gNum < g.length && sNum < s.length) { + // 分量大于胃口,满足,目标转移到下一个小朋友,同时也代表满足的数量 + if (s[sNum] >= g[gNum]) { + gNum++; + } + // 下一份饼干 + sNum++; + } + return gNum; + } + + public static void main(String[] args) { + int[] g = new int[]{1,2,3}; + int[] s = new int[]{1,1}; + System.out.println(assignCookies(g, s)); + } +} diff --git a/Week_03/G20200343030431/LeetCode_127_431.java b/Week_03/G20200343030431/LeetCode_127_431.java new file mode 100644 index 00000000..15f0ec62 --- /dev/null +++ b/Week_03/G20200343030431/LeetCode_127_431.java @@ -0,0 +1,50 @@ +package ThirdWork; + +import java.util.HashSet; +import java.util.List; + +public class Solution127 { + public int ladderLength(String beginWord, String endWord, List wordList) { + if (wordList == null || wordList.size() == 0) return 0; + HashSet start = new HashSet<>(); + HashSet end = new HashSet<>(); + HashSet dic = new HashSet<>(wordList); + start.add(beginWord); + end.add(endWord); + int step = 1; + if (!dic.contains(endWord)) return 0; + while (!start.isEmpty()) { + step++; + HashSet tmpSet = new HashSet<>(); + dic.removeAll(start); + for (String s : start) { + char[] arr = s.toCharArray(); + for (int i = 0; i < arr.length; i++) { + char tmp = arr[i]; + for (char c = 'a'; c <= 'z'; c++) { + if (tmp == c) continue; + arr[i] = c; + String strTmp = new String(arr); + if (dic.contains(strTmp)) { + if (end.contains(strTmp)) { + return step; + } else { + tmpSet.add(strTmp); + } + } + } + arr[i] = tmp; + } + } + if (tmpSet.size() < end.size()) { + start = tmpSet; + } else { + start = end; + end = tmpSet; + } + + } + return 0; + } + +} diff --git a/Week_03/G20200343030431/LeetCode_455_431.java b/Week_03/G20200343030431/LeetCode_455_431.java new file mode 100644 index 00000000..d60ebc1b --- /dev/null +++ b/Week_03/G20200343030431/LeetCode_455_431.java @@ -0,0 +1,20 @@ +package ThirdWork; + +import java.util.Arrays; + +class Solution455 { + //贪心的思想是,用尽量小的饼干去满足小需求的孩子,所以需要进行排序先 + public int findContentChildren(int[] g, int[] s) { + int child = 0; + int cookie = 0; + Arrays.sort(g); //先将饼干 和 孩子所需大小都进行排序 + Arrays.sort(s); + while (child < g.length && cookie < s.length ){ //当其中一个遍历就结束 + if (g[child] <= s[cookie]){ //当用当前饼干可以满足当前孩子的需求,可以满足的孩子数量+1 + child++; + } + cookie++; // 饼干只可以用一次,因为饼干如果小的话,就是无法满足被抛弃,满足的话就是被用了 + } + return child; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030431/NOTE.md b/Week_03/G20200343030431/NOTE.md index 50de3041..68bbca05 100644 --- a/Week_03/G20200343030431/NOTE.md +++ b/Week_03/G20200343030431/NOTE.md @@ -1 +1,39 @@ -学习笔记 \ No newline at end of file +学习笔记 +贪心算法: +一、基本概念: + 所谓贪心算法是指,在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,他所做出的仅是在某种意义上的局部最优解。 + 贪心算法没有固定的算法框架,算法设计的关键是贪心策略的选择。 + 必须注意的是,贪心算法不是对所有问题都能得到整体最优解,选择的贪心策略必须具备无后效性,即某个状态以后的过程不会影响以前的状态,只与当前状态有关。 + 所以对所采用的贪心策略一定要仔细分析其是否满足无后效性。 + +二、贪心算法的基本思路: + 1.建立数学模型来描述问题。 + 2.把求解的问题分成若干个子问题。 + 3.对每一子问题求解,得到子问题的局部最优解。 + 4.把子问题的解局部最优解合成原来解问题的一个解。 + +三、贪心算法适用的问题 + 贪心策略适用的前提是:局部最优策略能导致产生全局最优解。 + 实际上,贪心算法适用的情况很少。一般,对一个问题分析是否适用于贪心算法,可以先选择该问题下的几个实际数据进行分析,就可做出判断。 + 贪心算法的证明围绕着:整个问题的最优解一定由在贪心策略中存在的子问题的最优解得来的。 + + +二分查找: +二分查找算法思想 + +有序的序列,每次都是以序列的中间位置的数来与待查找的关键字进行比较,每次缩小一半的查找范围,直到匹配成功。 + + +一个情景:将表中间位置记录的关键字与查找关键字比较,如果两者相等,则查找成功; + 否则利用中间位置记录将表分成前、后两个子表,如果中间位置记录的关键字大于查找关键字,则进一步查找前一子表,否则进一步查找后一子表。 + 重复以上过程,直到找到满足条件的记录,使查找成功,或直到子表不存在为止,此时查找不成功。 + +二分查找优缺点 + + +优点是比较次数少,查找速度快,平均性能好; + +其缺点是要求待查表为有序表,且插入删除困难。 + +因此,折半查找方法适用于不经常变动而查找频繁的有序列表。 + diff --git a/Week_03/G20200343030433/Leetcode_455_433.py b/Week_03/G20200343030433/Leetcode_455_433.py new file mode 100644 index 00000000..f883cfab --- /dev/null +++ b/Week_03/G20200343030433/Leetcode_455_433.py @@ -0,0 +1,16 @@ +class Solution: + def findContentChildren(self, g, s): + """ + :type g: List[int] + :type s: List[int] + :rtype: int + """ + g.sort() # 对需求因子进行排序,从小到大 + s.sort() # 对糖果数组进行排序,从小到大 + child = 0 # 记录可以被满足孩子数 + cookie = 0 # 记录可以满足的糖果数 + while child 0: five, ten = five - 1, ten - 1 + else: five -= 3 + if five < 0: return False + return True diff --git a/Week_03/G20200343030435/LeetCode_122_435.js b/Week_03/G20200343030435/LeetCode_122_435.js new file mode 100644 index 00000000..9c914551 --- /dev/null +++ b/Week_03/G20200343030435/LeetCode_122_435.js @@ -0,0 +1,7 @@ +let maxProfit = function(prices) { + let profit = 0; + for (let i = 0; i < prices.length - 1; i++) { + if (prices[i + 1] > prices[i]) profit += prices[i + 1] - prices[i]; + } + return profit; +}; diff --git a/Week_03/G20200343030435/LeetCode_153_435.js b/Week_03/G20200343030435/LeetCode_153_435.js new file mode 100644 index 00000000..e39ea879 --- /dev/null +++ b/Week_03/G20200343030435/LeetCode_153_435.js @@ -0,0 +1,13 @@ +var findMin = function(nums) { + var low = 0; + var high = nums.length - 1; + while (low < high) { + var mid = (low + high) >> 1; + if (nums[mid] > nums[high]) { + low = mid + 1; + } else { + high = mid; + } + } + return nums[low]; +}; diff --git a/Week_03/G20200343030435/LeetCode_200_435.js b/Week_03/G20200343030435/LeetCode_200_435.js new file mode 100644 index 00000000..e3cd2d52 --- /dev/null +++ b/Week_03/G20200343030435/LeetCode_200_435.js @@ -0,0 +1,38 @@ +var numIslands = function(grid) { + if (!grid || grid.length == 0) { + return 0; + } + var len = grid.length; + var size = grid[0].length; + var island = 0; + function sink(i, j) { + // terminator + if (grid[i][j] == "0") { + return 0; + } + // process + grid[i][j] = "0"; + // drill down + if (i + 1 < len && grid[i + 1][j] == "1") { + sink(i + 1, j); + } + if (i - 1 >= 0 && grid[i - 1][j] == "1") { + sink(i - 1, j); + } + if (j + 1 < size && grid[i][j + 1] == "1") { + sink(i, j + 1); + } + if (j - 1 >= 0 && grid[i][j - 1] == "1") { + sink(i, j - 1); + } + return 1; + } + for (var i = 0; i < len; i++) { + for (var r = 0; r < grid[i].length; r++) { + if (grid[i][r] == "1") { + island += sink(i, r); + } + } + } + return island; +}; diff --git a/Week_03/G20200343030435/LeetCode_33_435.js b/Week_03/G20200343030435/LeetCode_33_435.js new file mode 100644 index 00000000..04fe7084 --- /dev/null +++ b/Week_03/G20200343030435/LeetCode_33_435.js @@ -0,0 +1,20 @@ +let search = function(nums, target) { + let left = 0, + right = nums.length - 1, + mid = 0; + while (left < right) { + mid = parseInt((left + right) / 2); + if (nums[0] > target && nums[mid] < target) { + left = mid + 1; + } else if ( + nums[0] <= nums[mid] && + (nums[0] > target || nums[mid] < target) + ) { + left = mid + 1; + } else { + right = mid; + } + } + + return left === right && nums[left] === target ? left : -1; +}; diff --git a/Week_03/G20200343030435/LeetCode_55_435.js b/Week_03/G20200343030435/LeetCode_55_435.js new file mode 100644 index 00000000..8bdf8252 --- /dev/null +++ b/Week_03/G20200343030435/LeetCode_55_435.js @@ -0,0 +1,9 @@ +var canJump = function(nums) { + var leftPos = nums.length - 1; + for (var left = nums.length - 1; left >= 0; left--) { + if (nums[left] + left >= leftPos) { + leftPos = left; + } + } + return leftPos == 0; +}; diff --git a/Week_03/G20200343030437/jump-game.java b/Week_03/G20200343030437/jump-game.java new file mode 100644 index 00000000..5acd349f --- /dev/null +++ b/Week_03/G20200343030437/jump-game.java @@ -0,0 +1,13 @@ +class Solution { + public boolean canJump(int[] nums) { + int n = 1; + for (int i = nums.length-2 ; i >= 0; i--) { + if (nums[i] >= n) { + n = 1; + } else { + n++; + } + if(i == 0 && nums[0] < n) return false; + } + return true; + } diff --git a/Week_03/G20200343030437/n-queens.java b/Week_03/G20200343030437/n-queens.java new file mode 100644 index 00000000..e69de29b diff --git a/Week_03/G20200343030437/search-in-rotated-sorted-array.java b/Week_03/G20200343030437/search-in-rotated-sorted-array.java new file mode 100644 index 00000000..5b752749 --- /dev/null +++ b/Week_03/G20200343030437/search-in-rotated-sorted-array.java @@ -0,0 +1,22 @@ +public int search(int[] nums, int target) { + int length = nums.length; + int left = 0; + int right = length-1; +//第一次靠自己写的击败100%的题目 + while (left <= right) { + int mid = (left + right) / 2; + if (target == nums[mid]) { + return mid; + } + else if((nums[mid] < nums[right] && !(target > nums[mid] + && target <= nums[right])) || (target >= nums[left] && target < nums[mid])) { + // 往左走 + right = mid - 1; + } + else { + // 往右走 + left = mid + 1; + } + } + return -1; + } diff --git a/Week_03/G20200343030439/LeetCode_122_439.java b/Week_03/G20200343030439/LeetCode_122_439.java new file mode 100644 index 00000000..73809d88 --- /dev/null +++ b/Week_03/G20200343030439/LeetCode_122_439.java @@ -0,0 +1,74 @@ +/* + * @lc app=leetcode.cn id=122 lang=java + * + * [122] 买卖股票的最佳时机 II + * + * https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/description/ + * + * algorithms + * Easy (56.82%) + * Likes: 608 + * Dislikes: 0 + * Total Accepted: 122.1K + * Total Submissions: 211.5K + * Testcase Example: '[7,1,5,3,6,4]' + * + * 给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。 + * + * 设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。 + * + * 注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。 + * + * 示例 1: + * + * 输入: [7,1,5,3,6,4] + * 输出: 7 + * 解释: 在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。 + * 随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6-3 = 3 。 + * + * + * 示例 2: + * + * 输入: [1,2,3,4,5] + * 输出: 4 + * 解释: 在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 + * 。 + * 注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。 + * 因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。 + * + * + * 示例 3: + * + * 输入: [7,6,4,3,1] + * 输出: 0 + * 解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。 + * + */ + +// @lc code=start +class Solution { + + public static void main(String[] args) { + int[] bills = { 7, 1, 5, 3, 6, 4 }; + int result = maxProfit(bills); + + System.out.println(result); + + } + + public static int maxProfit(int[] prices) { + int profit = 0; + if (prices.length < 2) { + return profit; + } + for (int i = 1; i < prices.length; i++) { + int tProfit = prices[i] - prices[i - 1]; + if (tProfit > 0) { + profit += tProfit; + } + } + return profit; + } +} +// @lc code=end + diff --git a/Week_03/G20200343030439/LeetCode_200_439.java b/Week_03/G20200343030439/LeetCode_200_439.java new file mode 100644 index 00000000..072591ae --- /dev/null +++ b/Week_03/G20200343030439/LeetCode_200_439.java @@ -0,0 +1,93 @@ +/* + * @lc app=leetcode.cn id=200 lang=java + * + * [200] 岛屿数量 + * + * https://leetcode-cn.com/problems/number-of-islands/description/ + * + * algorithms + * Medium (46.50%) + * Likes: 392 + * Dislikes: 0 + * Total Accepted: 59.1K + * Total Submissions: 125.4K + * Testcase Example: '[["1","1","1","1","0"],["1","1","0","1","0"],["1","1","0","0","0"],["0","0","0","0","0"]]' + * + * 给定一个由 '1'(陆地)和 + * '0'(水)组成的的二维网格,计算岛屿的数量。一个岛被水包围,并且它是通过水平方向或垂直方向上相邻的陆地连接而成的。你可以假设网格的四个边均被水包围。 + * + * 示例 1: + * + * 输入: + * 11110 + * 11010 + * 11000 + * 00000 + * + * 输出: 1 + * + * + * 示例 2: + * + * 输入: + * 11000 + * 11000 + * 00100 + * 00011 + * + * 输出: 3 + * + * + */ + +// @lc code=start +class Solution { + + public static void main(String[] args) { + char[][] bills = { { '1', '1', '1', '1', '0' }, { '1', '1', '0', '1', '0' }, { '1', '1', '0', '0', '0' }, + { '0', '0', '0', '0', '0' } }; + int result = numIslands(bills); + + System.out.println(result); + } + + private static int n; + private static int m; + + // depth-first-search + public static int numIslands(char[][] grid) { + int count = 0; + n = grid.length; + if (n == 0) { + return count; + } + m = grid[0].length; + for (int i = 0; i < n; i++) { + for (int j = 0; j < m; j++) { + if (grid[i][j] == '1') { + DFSMarking(grid, i, j); + count++; + } + + } + } + return count; + } + + private static void DFSMarking(char[][] grid, int i, int j) { + if (i < 0 || j < 0 || i >= n || j >= m || grid[i][j] != '1') { + return; + } + grid[i][j] = '0'; + DFSMarking(grid, i + 1, j); + DFSMarking(grid, i - 1, j); + DFSMarking(grid, i, j + 1); + DFSMarking(grid, i, j - 1); + } + + // breadth-first-search + // union-find + +} +// @lc code=end + diff --git a/Week_03/G20200343030439/LeetCode_50_439.java b/Week_03/G20200343030439/LeetCode_50_439.java new file mode 100644 index 00000000..83bd7b85 --- /dev/null +++ b/Week_03/G20200343030439/LeetCode_50_439.java @@ -0,0 +1,89 @@ +/* + * @lc app=leetcode.cn id=50 lang=java + * + * [50] Pow(x, n) + * + * https://leetcode-cn.com/problems/powx-n/description/ + * + * algorithms + * Medium (33.64%) + * Likes: 270 + * Dislikes: 0 + * Total Accepted: 54.2K + * Total Submissions: 159.3K + * Testcase Example: '2.00000\n10' + * + * 实现 pow(x, n) ,即计算 x 的 n 次幂函数。 + * + * 示例 1: + * + * 输入: 2.00000, 10 + * 输出: 1024.00000 + * + * + * 示例 2: + * + * 输入: 2.10000, 3 + * 输出: 9.26100 + * + * + * 示例 3: + * + * 输入: 2.00000, -2 + * 输出: 0.25000 + * 解释: 2^-2 = 1/2^2 = 1/4 = 0.25 + * + * 说明: + * + * + * -100.0 < x < 100.0 + * n 是 32 位有符号整数,其数值范围是 [−2^31, 2^31 − 1] 。 + * + * + */ + +// @lc code=start +class Solution { + + public static void main(String[] args) { + double result = myPow2(2, 13); + System.out.println(result); + } + + public static double myPow(double x, int n) { + long copyN = n; + if (copyN < 0) { + x = 1 / x; + copyN = -n; + } + double result = 1; + for (int i = 0; i < copyN; i++) { + result *= x; + } + return result; + } + + + // 分治 + private static double myPow2(double x, int n) { + long copyN = n; + if (copyN < 0) { + x = 1 / x; + copyN = -n; + } + return fastPow(x, copyN); + } + + private static double fastPow(double x, long n) { + if (n == 0) { + return 1; + } + double half = fastPow(x, n / 2); + if (n % 2 == 1) { + return half * half * x; + } else { + return half * half; + } + } +} +// @lc code=end diff --git a/Week_03/G20200343030439/LeetCode_860_439.java b/Week_03/G20200343030439/LeetCode_860_439.java new file mode 100644 index 00000000..3f21f649 --- /dev/null +++ b/Week_03/G20200343030439/LeetCode_860_439.java @@ -0,0 +1,107 @@ +/* + * @lc app=leetcode.cn id=860 lang=java + * + * [860] 柠檬水找零 + * + * https://leetcode-cn.com/problems/lemonade-change/description/ + * + * algorithms + * Easy (53.33%) + * Likes: 96 + * Dislikes: 0 + * Total Accepted: 16.3K + * Total Submissions: 30.2K + * Testcase Example: '[5,5,5,10,20]' + * + * 在柠檬水摊上,每一杯柠檬水的售价为 5 美元。 + * + * 顾客排队购买你的产品,(按账单 bills 支付的顺序)一次购买一杯。 + * + * 每位顾客只买一杯柠檬水,然后向你付 5 美元、10 美元或 20 美元。你必须给每个顾客正确找零,也就是说净交易是每位顾客向你支付 5 美元。 + * + * 注意,一开始你手头没有任何零钱。 + * + * 如果你能给每位顾客正确找零,返回 true ,否则返回 false 。 + * + * 示例 1: + * + * 输入:[5,5,5,10,20] + * 输出:true + * 解释: + * 前 3 位顾客那里,我们按顺序收取 3 张 5 美元的钞票。 + * 第 4 位顾客那里,我们收取一张 10 美元的钞票,并返还 5 美元。 + * 第 5 位顾客那里,我们找还一张 10 美元的钞票和一张 5 美元的钞票。 + * 由于所有客户都得到了正确的找零,所以我们输出 true。 + * + * + * 示例 2: + * + * 输入:[5,5,10] + * 输出:true + * + * + * 示例 3: + * + * 输入:[10,10] + * 输出:false + * + * + * 示例 4: + * + * 输入:[5,5,10,10,20] + * 输出:false + * 解释: + * 前 2 位顾客那里,我们按顺序收取 2 张 5 美元的钞票。 + * 对于接下来的 2 位顾客,我们收取一张 10 美元的钞票,然后返还 5 美元。 + * 对于最后一位顾客,我们无法退回 15 美元,因为我们现在只有两张 10 美元的钞票。 + * 由于不是每位顾客都得到了正确的找零,所以答案是 false。 + * + * + * + * + * 提示: + * + * + * 0 <= bills.length <= 10000 + * bills[i] 不是 5 就是 10 或是 20  + * + * + */ + +// @lc code=start +class Solution { + public static void main(String[] args) { + int[] bills = { 5, 5, 10 }; + boolean result = lemonadeChange(bills); + + System.out.println(result); + } + + public static boolean lemonadeChange(int[] bills) { + int five = 0; + int ten = 0; + for (int i : bills) { + if (i == 5) { + five++; + } else if (i == 10) { + if (five == 0) { + return false; + } + five--; + ten++; + } else { + if (five >= 1 && ten >= 1) { + five--; + ten--; + } else if (five >= 3) { + five -= 3; + } else { + return false; + } + } + } + return true; + } +} +// @lc code=end + diff --git a/Week_03/G20200343030441/LeetCode_102_441.java b/Week_03/G20200343030441/LeetCode_102_441.java new file mode 100644 index 00000000..8ec179a3 --- /dev/null +++ b/Week_03/G20200343030441/LeetCode_102_441.java @@ -0,0 +1,118 @@ +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; + +/* + * @lc app=leetcode.cn id=102 lang=java + * + * [102] 二叉树的层次遍历 + */ + +// @lc code=start +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; } + * } + */ +class Solution { + // 自己写的迭代法 + // public List> levelOrder(TreeNode root) { + + // Queue queue1 = new LinkedList<>(); + // Queue queue2 = new LinkedList<>(); + + // List> results = new ArrayList<>(); + + // if (root != null){ + // queue1.offer(root); + // }else { + // return results; + // } + + // List level_list = new ArrayList<>(); + + // while (!queue1.isEmpty()){ + // TreeNode current_node = queue1.poll(); + + // level_list.add(current_node.val); + + // if (current_node.left != null) queue2.offer(current_node.left); + // if (current_node.right != null) queue2.offer(current_node.right); + + // if (queue1.isEmpty()){ + // while (!queue2.isEmpty()){ + // queue1.offer(queue2.poll()); + // } + // results.add(level_list); + // level_list = new ArrayList<>(); + // } + + // } + // return results; + // } + + // 官方题解的迭代法 bfs + // public List> levelOrder(TreeNode root) { + // List> levels = new ArrayList>(); + // if (root == null) return levels; + + // Queue queue = new LinkedList(); + // queue.add(root); + // int level = 0; + // while ( !queue.isEmpty() ) { + // // start the current level + // levels.add(new ArrayList()); + + // // number of elements in the current level + // int level_length = queue.size(); + // for(int i = 0; i < level_length; ++i) { + // TreeNode node = queue.remove(); + + // // fulfill the current level + // levels.get(level).add(node.val); + + // // add child nodes of the current level + // // in the queue for the next level + // if (node.left != null) queue.add(node.left); + // if (node.right != null) queue.add(node.right); + // } + // // go to next level + // level++; + // } + // return levels; + // } + + // 递归 dfs + public List> levelOrder(TreeNode root) { + + List> results = new ArrayList>(); + + if (root != null) helper(results, root, 0); + + return results; + } + + private void helper(List> results, TreeNode current_node, int level){ + + if (current_node == null){ + return; + } + if (results.size() > level){ + results.get(level).add(current_node.val); + }else { + results.add(new ArrayList()); + results.get(level).add(current_node.val); + } + + helper(results, current_node.left, level + 1); + helper(results, current_node.right, level + 1); + + } +} +// @lc code=end + diff --git a/Week_03/G20200343030441/LeetCode_169_441.java b/Week_03/G20200343030441/LeetCode_169_441.java new file mode 100644 index 00000000..70c0cfee --- /dev/null +++ b/Week_03/G20200343030441/LeetCode_169_441.java @@ -0,0 +1,59 @@ +/* + * @lc app=leetcode.cn id=169 lang=java + * + * [169] 多数元素 + */ + +// @lc code=start +class Solution { + public int majorityElement(int[] nums) { + // 遍历一遍法 + // int count = 1; + // int current_num = nums[0]; + + // for (int i = 1; i < nums.length; ++i){ + // if (nums[i] == current_num){ + // count++; + // }else { + // if (count == 0){ + // count = 1; + // current_num = nums[i]; + // }else { + // count--; + // } + // } + // } + // return current_num; + + // 分治法 + return _find(nums, 0, nums.length-1); + } + + private int _find(int[] nums, int index_left, int index_right){ + if (index_left == index_right) return nums[index_left]; + + + int left = _find(nums, index_left, (index_right-index_left)/2 + index_left); + int right = _find(nums, (index_right-index_left)/2 + index_left + 1, index_right); + + if (left == right) return left; + + // otherwise, count each element and return the "winner". + int leftCount = countInRange(nums, left, index_left, index_right); + int rightCount = countInRange(nums, right, index_left, index_right); + + return leftCount > rightCount ? left : right; + } + + private int countInRange(int[] nums, int num, int lo, int hi) { + int count = 0; + for (int i = lo; i <= hi; i++) { + if (nums[i] == num) { + count++; + } + } + return count; + } +} +// @lc code=end + diff --git a/Week_03/G20200343030441/LeetCode_200_441.java b/Week_03/G20200343030441/LeetCode_200_441.java new file mode 100644 index 00000000..92bd16b8 --- /dev/null +++ b/Week_03/G20200343030441/LeetCode_200_441.java @@ -0,0 +1,55 @@ +/* + * @lc app=leetcode.cn id=200 lang=java + * + * [200] 岛屿数量 + */ + +// @lc code=start +class Solution { + public int numIslands(char[][] grid) { + + // dfs + + int count_lands = 0; + + if (grid.length == 0) return 0; + + for (int i = 0; i < grid.length; ++i){ + for (int j = 0; j < grid[0].length; ++j){ + if (grid[i][j] == '1'){ + // 标记同岛屿的 1 为 0 + _mark(grid, i, j); + count_lands++; + } + } + } + + return count_lands; + } + + private void _mark(char[][] grid, int x, int y){ + grid[x][y] = '0'; + if (x < grid.length-1){ + if (grid[x+1][y] == '1'){ + _mark(grid, x+1, y); + } + } + if (y < grid[0].length-1){ + if (grid[x][y+1] == '1'){ + _mark(grid, x, y+1); + } + } + if (x > 0){ + if (grid[x-1][y] == '1'){ + _mark(grid, x-1, y); + } + } + if (y > 0){ + if (grid[x][y-1] == '1'){ + _mark(grid, x, y-1); + } + } + } +} +// @lc code=end + diff --git a/Week_03/G20200343030441/LeetCode_455_441.java b/Week_03/G20200343030441/LeetCode_455_441.java new file mode 100644 index 00000000..ba634b4e --- /dev/null +++ b/Week_03/G20200343030441/LeetCode_455_441.java @@ -0,0 +1,30 @@ + +/* + * @lc app=leetcode.cn id=455 lang=java + * + * [455] 分发饼干 + */ + +// @lc code=start +class Solution { + public int findContentChildren(int[] g, int[] s) { + Arrays.sort(g); + Arrays.sort(s); + + int g_step = 0, s_step = 0, count = 0; + + while (g_step < g.length && s_step < s.length){ + if (g[g_step] <= s[s_step]){ + g_step++; + s_step++; + count++; + }else{ + s_step++; + } + } + + return count; + } +} +// @lc code=end + diff --git a/Week_03/G20200343030441/LeetCode_50_441.java b/Week_03/G20200343030441/LeetCode_50_441.java new file mode 100644 index 00000000..5afa4e08 --- /dev/null +++ b/Week_03/G20200343030441/LeetCode_50_441.java @@ -0,0 +1,36 @@ +/* + * @lc app=leetcode.cn id=50 lang=java + * + * [50] Pow(x, n) + */ + +// @lc code=start +class Solution { + public double myPow(double x, long n) { + // 1.暴力法 + + // 2.分治 + if (n < 0){ + n = -n; + x = 1/x; + } + return _pow(x, n); + } + + private double _pow(double x, long n){ + if (n == 0){ + return 1.0; + } + + double half = _pow(x, n/2); + + if (n % 2 == 0){ + return half * half; + }else { + return half * half * x; + } + + } +} +// @lc code=end + diff --git a/Week_03/G20200343030441/LeetCode_78_441.java b/Week_03/G20200343030441/LeetCode_78_441.java new file mode 100644 index 00000000..a9117d4a --- /dev/null +++ b/Week_03/G20200343030441/LeetCode_78_441.java @@ -0,0 +1,38 @@ +import java.util.ArrayList; +import java.util.List; + +/* + * @lc app=leetcode.cn id=78 lang=java + * + * [78] 子集 + */ + +// @lc code=start +class Solution { + public List> subsets(int[] nums) { + List> result = new ArrayList<>(); + + if (nums == null) {return result;} + _dfs(result, nums, new ArrayList(), 0); + + return result; + } + + private void _dfs(List> result, int[] nums, List list, int index){ + + if (index == nums.length){ + result.add(new ArrayList(list)); + return; + } + + _dfs(result, nums, list, index+1); + + list.add(nums[index]); + + _dfs(result, nums, list, index+1); + + list.remove(list.size() - 1); + } +} +// @lc code=end + diff --git a/Week_03/G20200343030443/P45JumpGameIi.java b/Week_03/G20200343030443/P45JumpGameIi.java new file mode 100644 index 00000000..5bf22408 --- /dev/null +++ b/Week_03/G20200343030443/P45JumpGameIi.java @@ -0,0 +1,32 @@ +//Java:跳跃游戏 II +public class P45JumpGameIi { + + public static void main(String[] args) { + Solution solution = new P45JumpGameIi().new Solution(); + // TO TEST + } + + //leetcode submit region begin(Prohibit modification and deletion) + class Solution { + + public int jump(int[] nums) { + int minStep = 0, index = 0; + while (index < nums.length - 1) { + if (nums[index] + index >= nums.length - 1) { //最后一步正好到终点或超过终点 + return minStep + 1; + } + int maxStep = nums[index]; + for (int i = 1; i < nums[index]; i++) { //一步最优解 即 当前步长+下一步步长 最大 + if (maxStep + nums[index + maxStep] < i + nums[index + i]) { + maxStep = i; + } + } + index += maxStep; + minStep++; + } + return minStep; + } + } +//leetcode submit region end(Prohibit modification and deletion) + +} \ No newline at end of file diff --git a/Week_03/G20200343030443/P860LemonadeChange.java b/Week_03/G20200343030443/P860LemonadeChange.java new file mode 100644 index 00000000..d18218d9 --- /dev/null +++ b/Week_03/G20200343030443/P860LemonadeChange.java @@ -0,0 +1,40 @@ +//Java:柠檬水找零 +public class P860LemonadeChange { + + public static void main(String[] args) { + Solution solution = new P860LemonadeChange().new Solution(); + // TO TEST + } + + //leetcode submit region begin(Prohibit modification and deletion) + class Solution { + + public boolean lemonadeChange(int[] bills) { //傻瓜式写法 + int fiveSum = 0, tenSum = 0; + for (int i = 0; i < bills.length; i++) { + if (bills[i] == 5) { + fiveSum += 5; + } else if (bills[i] == 10) { + if (fiveSum == 0) { + return false; + } + fiveSum -= 5; + tenSum += 10; + } else if (bills[i] == 20) { + if (fiveSum + tenSum < 15 || fiveSum == 0) { + return false; + } + if (tenSum >= 10) { + tenSum -= 10; + fiveSum -= 5; + } else { + fiveSum -= 15; + } + } + } + return true; + } + } +//leetcode submit region end(Prohibit modification and deletion) + +} \ No newline at end of file diff --git a/Week_03/G20200343030445/LeetCode_127_445.py b/Week_03/G20200343030445/LeetCode_127_445.py new file mode 100644 index 00000000..4f61a3e3 --- /dev/null +++ b/Week_03/G20200343030445/LeetCode_127_445.py @@ -0,0 +1,30 @@ +# +# @lc app=leetcode.cn id=127 lang=python3 +# +# [127] 单词接龙 +# + +# @lc code=start +class Solution: + def ladderLength(self, beginWord: str, endWord: str, wordList: List[str]) -> int: + wordList = set(wordList) # speed up! + if endWord not in wordList: + return 0 + dictionary = list('abcdefghijklmnopqrstuvwxyz') + + q = [(beginWord, 0)] + while q: + word, step = q.pop(0) + if word == endWord: + return step + 1 + for i in range(len(word)): + for j in dictionary: + new = word[:i] + j + word[i+1:] + if new in wordList: + q.append((new, step+1)) + wordList.remove(new) + return 0 + + +# @lc code=end + diff --git a/Week_03/G20200343030445/LeetCode_200_445.py b/Week_03/G20200343030445/LeetCode_200_445.py new file mode 100644 index 00000000..1ffe9b44 --- /dev/null +++ b/Week_03/G20200343030445/LeetCode_200_445.py @@ -0,0 +1,44 @@ +# +# @lc app=leetcode.cn id=200 lang=python3 +# +# [200] 岛屿数量 +# + +# @lc code=start +class Solution: + def numIslands(self, grid: List[List[str]]) -> int: + if not grid: + return 0 + + x = len(grid) + y = len(grid[0]) + count = 0 + + def find(a, b): + q = [(a,b)] + while q: + i, j = q.pop(0) + if i-1 >= 0 and grid[i-1][j] == '1': + grid[i-1][j] = '0' + q.append((i-1, j)) + if j-1 >= 0 and grid[i][j-1] == '1': + grid[i][j-1] = '0' + q.append((i, j-1)) + if j+1 < y and grid[i][j+1] == '1': + grid[i][j+1] = '0' + q.append((i, j+1)) + if i+1 < x and grid[i+1][j] == '1': + grid[i+1][j] = '0' + q.append((i+1, j)) + + for i in range(x): + for j in range(y): + if grid[i][j] == '1': + grid[i][j] = '0' + count += 1 + find(i, j) + return count + + +# @lc code=end + diff --git a/Week_03/G20200343030445/LeetCode_33_445.py b/Week_03/G20200343030445/LeetCode_33_445.py new file mode 100644 index 00000000..997a26a5 --- /dev/null +++ b/Week_03/G20200343030445/LeetCode_33_445.py @@ -0,0 +1,31 @@ +# +# @lc app=leetcode.cn id=33 lang=python3 +# +# [33] 搜索旋转排序数组 +# + +# @lc code=start +class Solution: + def search(self, nums: List[int], target: int) -> int: + left = 0 + right = len(nums) - 1 + while left <= right: + mid = (left + right) // 2 + if nums[mid] == target: + return mid + if nums[left] <= nums[mid]: + if target >= nums[left] and target <= nums[mid]: + right = mid - 1 + else: + left = mid + 1 + + else: + if target >= nums[mid] and target <= nums[right]: + left = mid + 1 + else: + right = mid - 1 + + + return -1 +# @lc code=end + diff --git a/Week_03/G20200343030445/LeetCode_55_445.py b/Week_03/G20200343030445/LeetCode_55_445.py new file mode 100644 index 00000000..78ced4e3 --- /dev/null +++ b/Week_03/G20200343030445/LeetCode_55_445.py @@ -0,0 +1,18 @@ +# +# @lc app=leetcode.cn id=55 lang=python3 +# +# [55] 跳跃游戏 +# + +# @lc code=start +class Solution: + def canJump(self, nums: List[int]) -> bool: + + # greedy + pos = len(nums) - 1 + for i in range(len(nums)-1, -1, -1): + if i + nums[i] >= pos: + pos = i + return pos == 0 +# @lc code=end + diff --git a/Week_03/G20200343030449/LeetCode_122_449.cpp b/Week_03/G20200343030449/LeetCode_122_449.cpp new file mode 100644 index 00000000..89448f22 --- /dev/null +++ b/Week_03/G20200343030449/LeetCode_122_449.cpp @@ -0,0 +1,18 @@ +class Solution { +public: + int maxProfit(vector& prices) { + int max = 0; + + if (prices.size()==0||prices.size()==1) { + return 0; + } + + for (int i=1; i>& grid) { + auto numIslands = 0; + + for (int i = 0; i < grid.size(); i++) { + for (int j = 0; j < grid[i].size(); j++) { + if (grid[i][j]=='0') { + continue; + } + numIslands++; + sinkIsland(i,j,grid); + } + } + + return numIslands; + } + + void sinkIsland(int x, int y, vector>& grid) { + vector dx = {-1,0,0,1}; + vector dy = {0,-1,1,0}; + + grid[x][y] = '0'; + + for(int i = 0; i < dx.size(); i++) { + int xNeighbor = x + dx[i]; + int yNeighbor = y + dy[i]; + + if (xNeighbor>=0&&xNeighbor=0&&yNeighbor& g, vector& s) { + sort(g.begin(),g.end()); + sort(s.begin(),s.end()); + + int i = 0; + int j = 0; + int count = 0; + + for(;i < g.size();i++) { + while (j& nums) { + int k = 0; + + for (int i = 0; i < nums.size(); i++) { + if (i>k) return false; + k = max(k, i+nums[i]); + } + return true; + } +}; diff --git a/Week_03/G20200343030449/LeetCode_860_449.cpp b/Week_03/G20200343030449/LeetCode_860_449.cpp new file mode 100644 index 00000000..e69de29b diff --git a/Week_03/G20200343030451/122.c b/Week_03/G20200343030451/122.c new file mode 100644 index 00000000..f58fc2fa --- /dev/null +++ b/Week_03/G20200343030451/122.c @@ -0,0 +1,10 @@ +int maxProfit(int* prices, int pricesSize){ + int total = 0; + int i; + for ( i = 0; i < pricesSize - 1; i++ ) { + if ( prices[i] < prices[i+1]) { + total += prices[i+1] - prices[i]; + } + } + return total; +} diff --git a/Week_03/G20200343030451/860.c b/Week_03/G20200343030451/860.c new file mode 100644 index 00000000..cec16a72 --- /dev/null +++ b/Week_03/G20200343030451/860.c @@ -0,0 +1,30 @@ +//2020-2-27 complete + +bool lemonadeChange(int* bills, int billsSize){ + int five = 0, ten = 0; + int i; + int bill; + + for ( i = 0; i < billsSize; i++ ) { + bill = *( bills+i ); + + //process + if ( bill == 5 ) { + five++; + } else if ( bill == 10 && five > 0 ) { + five--; + ten++; + } else if ( bill == 20 && five > 0 && ten > 0 ) { + five--; + ten--; + } else if ( bill == 20 && five > 2 ) { + five-=3; + } else { + return false; + } + + } + return true; +} + + diff --git a/Week_03/G20200343030451/NOTE.md b/Week_03/G20200343030451/NOTE.md index 50de3041..3145e4a0 100644 --- a/Week_03/G20200343030451/NOTE.md +++ b/Week_03/G20200343030451/NOTE.md @@ -1 +1,38 @@ -学习笔记 \ No newline at end of file +学习笔记 + +# 【451-Week 03】学习总结 + +对于本周学习,内容让我最深刻的就是分治与回溯算法,以前分不清相关的区别,没有发现本质的区别,从这周的学习与查找。发现题目的固定的套路。 + +从老师给的解题方法: + +泛型递归的模板一般是下面这样 +1.递归终止条件 +2.处理当前层的逻辑 +3.进入下一层 +4.撤销当前层的操作 + +而对于回溯来说,可以具体为 对于每一项(每个格子)做选择 : 选择 or 不选择。 +1.递归终止条件 +2.for 选择 : 选择列表 +做当前层的选择 +递归函数进入下一层 +撤销当前层的选择 + + + +贪心算法 + +每一步中都选取最优解。 +贪心不能回退,动态规划能保存以前的运算结果,并且有回退功能。 +有整除关系才能用贪心法 + +二分查找 +前提: +1 目标函数单调 +2 存在上下界 +3 能够通过索引访问 + +对于以上的解题思想, 一定要多多练习。本周虽然学习了很多。 +但还是有许多的内容深度优先与广度优先,进行深度的练习。 +本周的解题方法,主要是要多多练习。 \ No newline at end of file diff --git a/Week_03/G20200343030453/LeetCode_455_453 b/Week_03/G20200343030453/LeetCode_455_453 new file mode 100755 index 00000000..3bade001 --- /dev/null +++ b/Week_03/G20200343030453/LeetCode_455_453 @@ -0,0 +1,18 @@ +// 455. 分发饼干 +class Solution { +public: + int findContentChildren(vector& g, vector& s) { + if(s.size() < 1) { + return 0; + } + sort(g.begin(), g.end(), greater()); + sort(s.begin(), s.end(), greater()); + int sum = 0; + for(int i = 0; i < g.size(); i++) { + if(sum < s.size() && s[sum] >= g[i]) { + sum++; + } + } + return sum; + } +}; \ No newline at end of file diff --git a/Week_03/G20200343030453/LeetCode_860_453 b/Week_03/G20200343030453/LeetCode_860_453 new file mode 100755 index 00000000..63b55403 --- /dev/null +++ b/Week_03/G20200343030453/LeetCode_860_453 @@ -0,0 +1,34 @@ +/* + 860. 柠檬水找零 + 2020.2.26 +*/ + +class Solution { +public: + bool lemonadeChange(vector& bills) { + int five = 0; + int ten = 0; + for(int bill: bills) { + if(bill == 5) { + five++; + } + else if(bill == 10 && five >= 1) { + five--; + ten++; + } + else { + if(ten >= 1 && five >= 1) { + ten--; + five--; + } + else if(five >= 3) { + five -= 3; + } + else { + return false; + } + } + } + return true; + } +}; \ No newline at end of file diff --git a/Week_03/G20200343030453/NOTE.md b/Week_03/G20200343030453/NOTE.md old mode 100644 new mode 100755 index 50de3041..19422f0b --- a/Week_03/G20200343030453/NOTE.md +++ b/Week_03/G20200343030453/NOTE.md @@ -1 +1,5 @@ -学习笔记 \ No newline at end of file +学习笔记 + +2020.2.26 + +860. 柠檬水找零 \ No newline at end of file diff --git a/Week_03/G20200343030457/lemonadeChange.php b/Week_03/G20200343030457/lemonadeChange.php new file mode 100644 index 00000000..e0ecff7c --- /dev/null +++ b/Week_03/G20200343030457/lemonadeChange.php @@ -0,0 +1,20 @@ + 0) { + $profit += $pro; + } + } + return $profit; + } +} diff --git a/Week_03/G20200343030457/maxProfit.php b/Week_03/G20200343030457/maxProfit.php new file mode 100644 index 00000000..182a5a80 --- /dev/null +++ b/Week_03/G20200343030457/maxProfit.php @@ -0,0 +1,18 @@ + 0) $profit += $pro; + } + return $profit; + } +} diff --git a/Week_03/G20200343030459/102.binary-tree-level-order-traversal.py b/Week_03/G20200343030459/102.binary-tree-level-order-traversal.py new file mode 100644 index 00000000..0737ffce --- /dev/null +++ b/Week_03/G20200343030459/102.binary-tree-level-order-traversal.py @@ -0,0 +1,72 @@ +# +# @lc app=leetcode id=102 lang=python3 +# +# [102] Binary Tree Level Order Traversal +# +# https://leetcode.com/problems/binary-tree-level-order-traversal/description/ +# +# algorithms +# Medium (52.09%) +# Likes: 2344 +# Dislikes: 62 +# Total Accepted: 524.5K +# Total Submissions: 1M +# Testcase Example: '[3,9,20,null,null,15,7]' +# +# Given a binary tree, return the level order traversal of its nodes' values. +# (ie, from left to right, level by level). +# +# +# For example: +# Given binary tree [3,9,20,null,null,15,7], +# +# ⁠ 3 +# ⁠ / \ +# ⁠ 9 20 +# ⁠ / \ +# ⁠ 15 7 +# +# +# +# return its level order traversal as: +# +# [ +# ⁠ [3], +# ⁠ [9,20], +# ⁠ [15,7] +# ] +# +# +# + +# @lc code=start +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +# bfs +from collections import deque +class Solution: + def levelOrder(self, root: TreeNode) -> List[List[int]]: + result = [] + if not root: + return result + queue = deque([root]) + while queue: + size = len(queue) + level = [] + for i in range(size): + node = queue.popleft() + level.append(node.val) + if node.left: + queue.append(node.left) + if node.right: + queue.append(node.right) + result.append(level) + return result + +# @lc code=end + diff --git a/Week_03/G20200343030459/127.word-ladder.py b/Week_03/G20200343030459/127.word-ladder.py new file mode 100644 index 00000000..a81a5d04 --- /dev/null +++ b/Week_03/G20200343030459/127.word-ladder.py @@ -0,0 +1,158 @@ +# +# @lc app=leetcode id=127 lang=python3 +# +# [127] Word Ladder +# +# https://leetcode.com/problems/word-ladder/description/ +# +# algorithms +# Medium (27.50%) +# Likes: 2483 +# Dislikes: 1014 +# Total Accepted: 367.1K +# Total Submissions: 1.3M +# Testcase Example: '"hit"\n"cog"\n["hot","dot","dog","lot","log","cog"]' +# +# Given two words (beginWord and endWord), and a dictionary's word list, find +# the length of shortest transformation sequence from beginWord to endWord, +# such that: +# +# +# Only one letter can be changed at a time. +# Each transformed word must exist in the word list. Note that beginWord is not +# a transformed word. +# +# +# Note: +# +# +# Return 0 if there is no such transformation sequence. +# All words have the same length. +# All words contain only lowercase alphabetic characters. +# You may assume no duplicates in the word list. +# You may assume beginWord and endWord are non-empty and are not the same. +# +# +# Example 1: +# +# +# Input: +# beginWord = "hit", +# endWord = "cog", +# wordList = ["hot","dot","dog","lot","log","cog"] +# +# Output: 5 +# +# Explanation: As one shortest transformation is "hit" -> "hot" -> "dot" -> +# "dog" -> "cog", +# return its length 5. +# +# +# Example 2: +# +# +# Input: +# beginWord = "hit" +# endWord = "cog" +# wordList = ["hot","dot","dog","lot","log"] +# +# Output: 0 +# +# Explanation: The endWord "cog" is not in wordList, therefore no possible +# transformation. +# +# +# +# +# +# + +# @lc code=start +# 自己写的 bfs +from collections import deque +class Solution: + def ladderLength(self, beginWord: str, endWord: str, wordList: List[str]) -> int: + steps = 0 + queue = deque([beginWord]) + visited = set([beginWord]) + word_set = set(wordList) + while queue: + size = len(queue) + steps += 1 + for i in range(size): + word = queue.popleft() + if word == endWord: + return steps + next_words = self.find_next(word) + for next_word in next_words: + if next_word not in visited and next_word in word_set: + queue.append(next_word) + visited.add(next_word) + return 0 + + + def find_next(self, word: str): + words = [] + for i in range(len(word)): + left, right = word[:i], word[i + 1:] + for c in 'abcdefghijklmnopqrstuvwxyz': + if word[i] == c: + continue + new_word = left + c + right + words.append(new_word) + + return words + + +# 很好的优化思路 +# https://leetcode-cn.com/problems/word-ladder/solution/suan-fa-shi-xian-he-you-hua-javashuang-xiang-bfs23/ +# 双端 bfs,每次从节点少的那边搜索 +from collections import deque +class Solution: + def ladderLength(self, beginWord: str, endWord: str, wordList: List[str]) -> int: + steps = 0 + if endWord not in wordList or not endWord or not beginWord or not wordList: + return steps + wordList.append(beginWord) + word_set = set(wordList) + begin_queue, begin_visited = deque([beginWord]), set([beginWord]) + end_queue, end_visited = deque([endWord]), set([endWord]) + + while begin_queue and end_queue: + steps += 1 + if len(begin_queue) <= len(end_queue): + is_finished = self.visit_word(begin_queue, begin_visited, end_visited, word_set) + if is_finished: return steps + else: + is_finished = self.visit_word(end_queue, end_visited, begin_visited, word_set) + if is_finished: return steps + return 0 + + def find_next(self, word: str): + words = [] + for i in range(len(word)): + left, right = word[:i], word[i + 1:] + for c in 'abcdefghijklmnopqrstuvwxyz': + if word[i] == c: + continue + new_word = left + c + right + words.append(new_word) + return words + + def visit_word(self, queue, visited, other_visited, word_set): + size = len(queue) + for i in range(size): + word = queue.popleft() + if word in other_visited: + return True + next_words = self.find_next(word) + for next_word in next_words: + if next_word not in visited and next_word in word_set: + visited.add(next_word) + queue.append(next_word) + + return False + + +# @lc code=end + diff --git a/Week_03/G20200343030459/131.palindrome-partitioning.py b/Week_03/G20200343030459/131.palindrome-partitioning.py new file mode 100644 index 00000000..bcd31a29 --- /dev/null +++ b/Week_03/G20200343030459/131.palindrome-partitioning.py @@ -0,0 +1,64 @@ +# +# @lc app=leetcode id=131 lang=python3 +# +# [131] Palindrome Partitioning +# +# https://leetcode.com/problems/palindrome-partitioning/description/ +# +# algorithms +# Medium (44.66%) +# Likes: 1442 +# Dislikes: 55 +# Total Accepted: 204.7K +# Total Submissions: 455.4K +# Testcase Example: '"aab"' +# +# Given a string s, partition s such that every substring of the partition is a +# palindrome. +# +# Return all possible palindrome partitioning of s. +# +# Example: +# +# +# Input: "aab" +# Output: +# [ +# ⁠ ["aa","b"], +# ⁠ ["a","a","b"] +# ] +# +# +# + +# @lc code=start +class Solution: + def partition(self, s: str) -> List[List[str]]: + result = [] + if not s: + return result + self.dfs(s, 0, [], result) + return result + + def dfs(self, s, startIndex, substrings, result): + if startIndex == len(s): + result.append(substrings[:]) + return + + for i in range(startIndex, len(s)): + if not self.is_palindrome(s[startIndex:i + 1]): + continue + substrings.append(s[startIndex:i + 1]) + self.dfs(s, i + 1, substrings, result) + substrings.pop() + + def is_palindrome(self, s: str): + left, right = 0, len(s) - 1 + while left < right: + if s[left] != s[right]: + return False + left, right = left + 1, right - 1 + return True + +# @lc code=end + diff --git a/Week_03/G20200343030459/133.clone-graph.py b/Week_03/G20200343030459/133.clone-graph.py new file mode 100644 index 00000000..b6fc4e72 --- /dev/null +++ b/Week_03/G20200343030459/133.clone-graph.py @@ -0,0 +1,134 @@ +# +# @lc app=leetcode id=133 lang=python3 +# +# [133] Clone Graph +# +# https://leetcode.com/problems/clone-graph/description/ +# +# algorithms +# Medium (31.37%) +# Likes: 1354 +# Dislikes: 1218 +# Total Accepted: 292.4K +# Total Submissions: 922.4K +# Testcase Example: '[[2,4],[1,3],[2,4],[1,3]]\r' +# +# Given a reference of a node in a connected undirected graph. +# +# Return a deep copy (clone) of the graph. +# +# Each node in the graph contains a val (int) and a list (List[Node]) of its +# neighbors. +# +# +# class Node { +# ⁠ public int val; +# ⁠ public List neighbors; +# } +# +# +# +# +# Test case format: +# +# For simplicity sake, each node's value is the same as the node's index +# (1-indexed). For example, the first node with val = 1, the second node with +# val = 2, and so on. The graph is represented in the test case using an +# adjacency list. +# +# Adjacency list is a collection of unordered lists used to represent a finite +# graph. Each list describes the set of neighbors of a node in the graph. +# +# The given node will always be the first node with val = 1. You must return +# the copy of the given node as a reference to the cloned graph. +# +# +# Example 1: +# +# +# Input: adjList = [[2,4],[1,3],[2,4],[1,3]] +# Output: [[2,4],[1,3],[2,4],[1,3]] +# Explanation: There are 4 nodes in the graph. +# 1st node (val = 1)'s neighbors are 2nd node (val = 2) and 4th node (val = 4). +# 2nd node (val = 2)'s neighbors are 1st node (val = 1) and 3rd node (val = 3). +# 3rd node (val = 3)'s neighbors are 2nd node (val = 2) and 4th node (val = 4). +# 4th node (val = 4)'s neighbors are 1st node (val = 1) and 3rd node (val = +# 3). +# +# +# Example 2: +# +# +# Input: adjList = [[]] +# Output: [[]] +# Explanation: Note that the input contains one empty list. The graph consists +# of only one node with val = 1 and it does not have any neighbors. +# +# +# Example 3: +# +# +# Input: adjList = [] +# Output: [] +# Explanation: This an empty graph, it does not have any nodes. +# +# +# Example 4: +# +# +# Input: adjList = [[2],[1]] +# Output: [[2],[1]] +# +# +# +# Constraints: +# +# +# 1 <= Node.val <= 100 +# Node.val is unique for each node. +# Number of Nodes will not exceed 100. +# There is no repeated edges and no self-loops in the graph. +# The Graph is connected and all nodes can be visited starting from the given +# node. +# +# +# + +# @lc code=start +""" +# Definition for a Node. +class Node: + def __init__(self, val = 0, neighbors = []): + self.val = val + self.neighbors = neighbors +""" +from collections import defaultdict, deque +class Solution: + def cloneGraph(self, node: 'Node') -> 'Node': + root = node + if not node: + return None + mapping = self.generate_map(node) + + for node, copied_node in mapping.items(): + for neighbor in node.neighbors: + copied_neighbor = mapping[neighbor] + copied_node.neighbors.append(copied_neighbor) + return mapping[root] + + def generate_map(self, node: 'Node'): + mapping = dict() + queue = deque([node]) + visited = set([node]) + while queue: + node = queue.popleft() + visited.add(node) + copied_node = Node(node.val) + mapping[node] = copied_node + for neighbor in node.neighbors: + if neighbor not in visited: + queue.append(neighbor) + return mapping + +# @lc code=end + diff --git a/Week_03/G20200343030459/162.find-peak-element.py b/Week_03/G20200343030459/162.find-peak-element.py new file mode 100644 index 00000000..baa89472 --- /dev/null +++ b/Week_03/G20200343030459/162.find-peak-element.py @@ -0,0 +1,71 @@ +# +# @lc app=leetcode id=162 lang=python3 +# +# [162] Find Peak Element +# +# https://leetcode.com/problems/find-peak-element/description/ +# +# algorithms +# Medium (42.54%) +# Likes: 1316 +# Dislikes: 1766 +# Total Accepted: 311.4K +# Total Submissions: 731K +# Testcase Example: '[1,2,3,1]' +# +# A peak element is an element that is greater than its neighbors. +# +# Given an input array nums, where nums[i] ≠ nums[i+1], find a peak element and +# return its index. +# +# The array may contain multiple peaks, in that case return the index to any +# one of the peaks is fine. +# +# You may imagine that nums[-1] = nums[n] = -∞. +# +# Example 1: +# +# +# Input: nums = [1,2,3,1] +# Output: 2 +# Explanation: 3 is a peak element and your function should return the index +# number 2. +# +# Example 2: +# +# +# Input: nums = [1,2,1,3,5,6,4] +# Output: 1 or 5 +# Explanation: Your function can return either index number 1 where the peak +# element is 2, +# or index number 5 where the peak element is 6. +# +# +# Note: +# +# Your solution should be in logarithmic complexity. +# +# + +# @lc code=start +# 思路:二分法多香啊 +class Solution: + def findPeakElement(self, nums: List[int]) -> int: + if not nums: + return -1 + if len(nums) == 1: + return 0 + start, end = 0, len(nums) - 1 + while start + 1 < end: + mid = start + (end - start) // 2 + if nums[mid] < nums[mid + 1]: + start = mid + else: + end = mid + if nums[start] < nums[end]: + return end + else: + return start + +# @lc code=end + diff --git a/Week_03/G20200343030459/200.number-of-islands.py b/Week_03/G20200343030459/200.number-of-islands.py new file mode 100644 index 00000000..77d6ad7a --- /dev/null +++ b/Week_03/G20200343030459/200.number-of-islands.py @@ -0,0 +1,114 @@ +# +# @lc app=leetcode id=200 lang=python3 +# +# [200] Number of Islands +# +# https://leetcode.com/problems/number-of-islands/description/ +# +# algorithms +# Medium (44.73%) +# Likes: 4197 +# Dislikes: 155 +# Total Accepted: 556.7K +# Total Submissions: 1.2M +# Testcase Example: '[["1","1","1","1","0"],["1","1","0","1","0"],["1","1","0","0","0"],["0","0","0","0","0"]]' +# +# Given a 2d grid map of '1's (land) and '0's (water), count the number of +# islands. An island is surrounded by water and is formed by connecting +# adjacent lands horizontally or vertically. You may assume all four edges of +# the grid are all surrounded by water. +# +# Example 1: +# +# +# Input: +# 11110 +# 11010 +# 11000 +# 00000 +# +# Output: 1 +# +# +# Example 2: +# +# +# Input: +# 11000 +# 11000 +# 00100 +# 00011 +# +# Output: 3 +# +# + +# @lc code=start + +# 第一种:BFS (AC) +# from collections import deque +# class Solution: +# def numIslands(self, grid: List[List[str]]) -> int: +# if not grid or not grid[0]: +# return 0 +# self.n, self.m = len(grid), len(grid[0]) +# islands = 0 +# for i in range(self.n): +# for j in range(self.m): +# if self.is_island(grid, i, j): +# self.bfs_marking(grid, i, j) +# islands += 1 + +# return islands + +# def is_island(self, grid: List[List[str]], x: int, y: int) -> bool: +# return 0 <= x < self.n and 0 <= y < self.m and grid[x][y] == '1' + +# def bfs_marking(self, grid: List[List[str]], x: int, y: int): +# dx = [1, 0, -1, 0] +# dy = [0, 1, 0, -1] +# queue = deque() +# queue.append((x, y)) +# grid[x][y] = '0' +# while queue: +# head_x, head_y = queue.popleft() +# for direction in range(4): +# adj_x = head_x + dx[direction] +# adj_y = head_y + dy[direction] +# if not self.is_island(grid, adj_x, adj_y): +# continue +# queue.append((adj_x, adj_y)) +# grid[adj_x][adj_y] = '0' + +# 第二种: DFS (这次选择使用一个 set) +class Solution: + def numIslands(self, grid: List[List[str]]) -> int: + if not grid or not grid[0]: + return 0 + self.n, self.m = len(grid), len(grid[0]) + islands = 0 + visited = set() + for i in range(self.n): + for j in range(self.m): + if self.is_island(grid, i, j, visited): + self.dfs_marking(grid, i, j, visited) + islands += 1 + + return islands + + def is_island(self, grid: List[List[str]], x: int, y: int, visited: set) -> bool: + return 0 <= x < self.n and 0 <= y < self.m and grid[x][y] == '1' and (x, y) not in visited + + def dfs_marking(self, grid: List[List[str]], x: int, y: int, visited: set): + dx = [1, 0, -1, 0] + dy = [0, 1, 0, -1] + if not self.is_island(grid, x, y, visited): + return + visited.add((x, y)) + for direction in range(4): + adj_x = x + dx[direction] + adj_y = y + dy[direction] + self.dfs_marking(grid, adj_x, adj_y, visited) + +# @lc code=end + diff --git a/Week_03/G20200343030459/207.course-schedule.py b/Week_03/G20200343030459/207.course-schedule.py new file mode 100644 index 00000000..7719def7 --- /dev/null +++ b/Week_03/G20200343030459/207.course-schedule.py @@ -0,0 +1,84 @@ +# +# @lc app=leetcode id=207 lang=python3 +# +# [207] Course Schedule +# +# https://leetcode.com/problems/course-schedule/description/ +# +# algorithms +# Medium (40.77%) +# Likes: 2932 +# Dislikes: 146 +# Total Accepted: 329.1K +# Total Submissions: 804.5K +# Testcase Example: '2\n[[1,0]]' +# +# There are a total of n courses you have to take, labeled from 0 to n-1. +# +# Some courses may have prerequisites, for example to take course 0 you have to +# first take course 1, which is expressed as a pair: [0,1] +# +# Given the total number of courses and a list of prerequisite pairs, is it +# possible for you to finish all courses? +# +# Example 1: +# +# +# Input: 2, [[1,0]] +# Output: true +# Explanation: There are a total of 2 courses to take. +# To take course 1 you should have finished course 0. So it is possible. +# +# Example 2: +# +# +# Input: 2, [[1,0],[0,1]] +# Output: false +# Explanation: There are a total of 2 courses to take. +# To take course 1 you should have finished course 0, and to take course 0 you +# should +# also have finished course 1. So it is impossible. +# +# +# Note: +# +# +# The input prerequisites is a graph represented by a list of edges, not +# adjacency matrices. Read more about how a graph is represented. +# You may assume that there are no duplicate edges in the input prerequisites. +# +# +# + +# @lc code=start +from collections import deque +class Solution: + def canFinish(self, numCourses: int, prerequisites: List[List[int]]) -> bool: + if not numCourses: + return False + graph, indegrees = self.get_graph_and_indegrees(numCourses, prerequisites) + start_courses = [c for c in range(numCourses) if indegrees[c] == 0] + + queue = deque(start_courses) + visited = set() + while queue: + course = queue.popleft() + visited.add(course) + avaliable_courses = graph[course] + for c in avaliable_courses: + indegrees[c] -= 1 + if indegrees[c] == 0: + queue.append(c) + + return len(visited) == numCourses + + def get_graph_and_indegrees(self, numCourses: int, prerequisites: List[List[int]]): + indegrees = {x: 0 for x in range(numCourses)} + graph = {x: [] for x in range(numCourses)} + for u, v in prerequisites: + graph[v].append(u) + indegrees[u] += 1 + return (graph, indegrees) + +# @lc code=end + diff --git a/Week_03/G20200343030459/210.course-schedule-ii.py b/Week_03/G20200343030459/210.course-schedule-ii.py new file mode 100644 index 00000000..da9736eb --- /dev/null +++ b/Week_03/G20200343030459/210.course-schedule-ii.py @@ -0,0 +1,91 @@ +# +# @lc app=leetcode id=210 lang=python3 +# +# [210] Course Schedule II +# +# https://leetcode.com/problems/course-schedule-ii/description/ +# +# algorithms +# Medium (37.98%) +# Likes: 1622 +# Dislikes: 107 +# Total Accepted: 215.8K +# Total Submissions: 565.8K +# Testcase Example: '2\n[[1,0]]' +# +# There are a total of n courses you have to take, labeled from 0 to n-1. +# +# Some courses may have prerequisites, for example to take course 0 you have to +# first take course 1, which is expressed as a pair: [0,1] +# +# Given the total number of courses and a list of prerequisite pairs, return +# the ordering of courses you should take to finish all courses. +# +# There may be multiple correct orders, you just need to return one of them. If +# it is impossible to finish all courses, return an empty array. +# +# Example 1: +# +# +# Input: 2, [[1,0]] +# Output: [0,1] +# Explanation: There are a total of 2 courses to take. To take course 1 you +# should have finished +# course 0. So the correct course order is [0,1] . +# +# Example 2: +# +# +# Input: 4, [[1,0],[2,0],[3,1],[3,2]] +# Output: [0,1,2,3] or [0,2,1,3] +# Explanation: There are a total of 4 courses to take. To take course 3 you +# should have finished both +# ⁠ courses 1 and 2. Both courses 1 and 2 should be taken after you +# finished course 0. +# So one correct course order is [0,1,2,3]. Another correct ordering is +# [0,2,1,3] . +# +# Note: +# +# +# The input prerequisites is a graph represented by a list of edges, not +# adjacency matrices. Read more about how a graph is represented. +# You may assume that there are no duplicate edges in the input prerequisites. +# +# +# + +# @lc code=start +from collections import deque +class Solution: + def findOrder(self, numCourses: int, prerequisites: List[List[int]]) -> List[int]: + result = [] + if not numCourses: + return result + graph, indegrees = self.get_graph_and_indegrees(numCourses, prerequisites) + start_courses = [c for c in range(numCourses) if indegrees[c] == 0] + queue = deque(start_courses) + visited = set() + while queue: + course = queue.popleft() + visited.add(course) + result.append(course) + next_courses = graph[course] + for c in next_courses: + indegrees[c] -= 1 + if indegrees[c] == 0: + queue.append(c) + if len(visited) == numCourses: + return result + return [] + + def get_graph_and_indegrees(self, numCourses: int, prerequisites: List[List[int]]): + graph = {x: [] for x in range(numCourses)} + indegrees = {x: 0 for x in range(numCourses)} + + for u, v in prerequisites: + graph[v].append(u) + indegrees[u] += 1 + return (graph, indegrees) +# @lc code=end + diff --git a/Week_03/G20200343030459/240.search-a-2-d-matrix-ii.py b/Week_03/G20200343030459/240.search-a-2-d-matrix-ii.py new file mode 100644 index 00000000..ca01b289 --- /dev/null +++ b/Week_03/G20200343030459/240.search-a-2-d-matrix-ii.py @@ -0,0 +1,69 @@ +# +# @lc app=leetcode id=240 lang=python3 +# +# [240] Search a 2D Matrix II +# +# https://leetcode.com/problems/search-a-2d-matrix-ii/description/ +# +# algorithms +# Medium (42.36%) +# Likes: 2447 +# Dislikes: 67 +# Total Accepted: 267K +# Total Submissions: 629.1K +# Testcase Example: '[[1,4,7,11,15],[2,5,8,12,19],[3,6,9,16,22],[10,13,14,17,24],[18,21,23,26,30]]\n5' +# +# Write an efficient algorithm that searches for a value in an m x n matrix. +# This matrix has the following properties: +# +# +# Integers in each row are sorted in ascending from left to right. +# Integers in each column are sorted in ascending from top to bottom. +# +# +# Example: +# +# Consider the following matrix: +# +# +# [ +# ⁠ [1, 4, 7, 11, 15], +# ⁠ [2, 5, 8, 12, 19], +# ⁠ [3, 6, 9, 16, 22], +# ⁠ [10, 13, 14, 17, 24], +# ⁠ [18, 21, 23, 26, 30] +# ] +# +# +# Given target = 5, return true. +# +# Given target = 20, return false. +# +# + +# @lc code=start +class Solution: + def searchMatrix(self, matrix, target): + """ + :type matrix: List[List[int]] + :type target: int + :rtype: bool + """ + if not matrix or not matrix[0]: + return False + + n, m = len(matrix), len(matrix[0]) + x, y = 0, m - 1 + + while x < n and y >= 0: + if matrix[x][y] == target: + return True + elif matrix[x][y] < target: + x += 1 + else: + y -= 1 + return False + + +# @lc code=end + diff --git a/Week_03/G20200343030459/278.first-bad-version.py b/Week_03/G20200343030459/278.first-bad-version.py new file mode 100644 index 00000000..dcf4f502 --- /dev/null +++ b/Week_03/G20200343030459/278.first-bad-version.py @@ -0,0 +1,70 @@ +# +# @lc app=leetcode id=278 lang=python3 +# +# [278] First Bad Version +# +# https://leetcode.com/problems/first-bad-version/description/ +# +# algorithms +# Easy (32.92%) +# Likes: 971 +# Dislikes: 553 +# Total Accepted: 298.8K +# Total Submissions: 904.9K +# Testcase Example: '5\n4' +# +# You are a product manager and currently leading a team to develop a new +# product. Unfortunately, the latest version of your product fails the quality +# check. Since each version is developed based on the previous version, all the +# versions after a bad version are also bad. +# +# Suppose you have n versions [1, 2, ..., n] and you want to find out the first +# bad one, which causes all the following ones to be bad. +# +# You are given an API bool isBadVersion(version) which will return whether +# version is bad. Implement a function to find the first bad version. You +# should minimize the number of calls to the API. +# +# Example: +# +# +# Given n = 5, and version = 4 is the first bad version. +# +# call isBadVersion(3) -> false +# call isBadVersion(5) -> true +# call isBadVersion(4) -> true +# +# Then 4 is the first bad version.  +# +# +# + +# @lc code=start +# The isBadVersion API is already defined for you. +# @param version, an integer +# @return a bool +# def isBadVersion(version): + +class Solution: + def firstBadVersion(self, n): + """ + :type n: int + :rtype: int + """ + if not n: + return -1 + start, end = 1, n + while start + 1 < end: + mid = start + (end - start) // 2 + if isBadVersion(mid): + end = mid + else: + start = mid + if isBadVersion(start): + return start + if isBadVersion(end): + return end + return -1 + +# @lc code=end + diff --git a/Week_03/G20200343030459/33.search-in-rotated-sorted-array.py b/Week_03/G20200343030459/33.search-in-rotated-sorted-array.py new file mode 100644 index 00000000..8e11325d --- /dev/null +++ b/Week_03/G20200343030459/33.search-in-rotated-sorted-array.py @@ -0,0 +1,91 @@ +# +# @lc app=leetcode id=33 lang=python3 +# +# [33] Search in Rotated Sorted Array +# +# https://leetcode.com/problems/search-in-rotated-sorted-array/description/ +# +# algorithms +# Medium (33.60%) +# Likes: 3801 +# Dislikes: 405 +# Total Accepted: 580.6K +# Total Submissions: 1.7M +# Testcase Example: '[4,5,6,7,0,1,2]\n0' +# +# Suppose an array sorted in ascending order is rotated at some pivot unknown +# to you beforehand. +# +# (i.e., [0,1,2,4,5,6,7] might become [4,5,6,7,0,1,2]). +# +# You are given a target value to search. If found in the array return its +# index, otherwise return -1. +# +# You may assume no duplicate exists in the array. +# +# Your algorithm's runtime complexity must be in the order of O(log n). +# +# Example 1: +# +# +# Input: nums = [4,5,6,7,0,1,2], target = 0 +# Output: 4 +# +# +# Example 2: +# +# +# Input: nums = [4,5,6,7,0,1,2], target = 3 +# Output: -1 +# +# + +# @lc code=start +# 这种方法是用一个二分法 把数组分成两个部分 +class Solution: + def search(self, nums: List[int], target: int) -> int: + if not nums: + return -1 + start, end = 0, len(nums) - 1 + while start + 1 < end: + mid = start + (end - start) // 2 + if nums[mid] > nums[end]: + if nums[start] <= target <= nums[mid]: + end = mid + else: + start = mid + else: + if nums[mid] <= target <= nums[end]: + start = mid + else: + end = mid + if nums[start] == target: + return start + if nums[end] == target: + return end + return -1 + +# 这种方法是受到光头哥的启发,讨论了 num[mid] 和 target 是否在数组的“同一边” +class Solution: + def search(self, nums: List[int], target: int) -> int: + if not nums: + return -1 + start, end = 0, len(nums) - 1 + while start + 1 < end: + mid = start + (end - start) // 2 + if (nums[mid] > nums[end]) == (target > nums[end]): + if nums[mid] <= target: + start = mid + elif nums[mid] > target: + end = mid + elif target > nums[end]: + end = mid + else: + start = mid + if nums[start] == target: + return start + if nums[end] == target: + return end + return -1 +# # @lc code=end + diff --git a/Week_03/G20200343030459/39.combination-sum.py b/Week_03/G20200343030459/39.combination-sum.py new file mode 100644 index 00000000..52080d40 --- /dev/null +++ b/Week_03/G20200343030459/39.combination-sum.py @@ -0,0 +1,80 @@ +# +# @lc app=leetcode id=39 lang=python3 +# +# [39] Combination Sum +# +# https://leetcode.com/problems/combination-sum/description/ +# +# algorithms +# Medium (53.15%) +# Likes: 3082 +# Dislikes: 97 +# Total Accepted: 472.7K +# Total Submissions: 883.7K +# Testcase Example: '[2,3,6,7]\n7' +# +# Given a set of candidate numbers (candidates) (without duplicates) and a +# target number (target), find all unique combinations in candidates where the +# candidate numbers sums to target. +# +# The same repeated number may be chosen from candidates unlimited number of +# times. +# +# Note: +# +# +# All numbers (including target) will be positive integers. +# The solution set must not contain duplicate combinations. +# +# +# Example 1: +# +# +# Input: candidates = [2,3,6,7], target = 7, +# A solution set is: +# [ +# ⁠ [7], +# ⁠ [2,2,3] +# ] +# +# +# Example 2: +# +# +# Input: candidates = [2,3,5], target = 8, +# A solution set is: +# [ +# [2,2,2,2], +# [2,3,3], +# [3,5] +# ] +# +# +# + +# @lc code=start +class Solution: + def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]: + result = [] + if not candidates: + return result + self.dfs(candidates, 0, target, [], result) + return result + + def dfs(self, candidates, startIndex, target, combination, result): + if target < 0: + return + if target == 0: + result.append(combination[:]) + return + + for i in range(startIndex, len(candidates)): + if i != 0 and candidates[i] == candidates[i - 1]: + continue + combination.append(candidates[i]) + self.dfs(candidates, i, target - candidates[i], combination, result) + combination.pop() + + +# @lc code=end + diff --git a/Week_03/G20200343030459/40.combination-sum-ii.py b/Week_03/G20200343030459/40.combination-sum-ii.py new file mode 100644 index 00000000..f7e6abbe --- /dev/null +++ b/Week_03/G20200343030459/40.combination-sum-ii.py @@ -0,0 +1,80 @@ +# +# @lc app=leetcode id=40 lang=python3 +# +# [40] Combination Sum II +# +# https://leetcode.com/problems/combination-sum-ii/description/ +# +# algorithms +# Medium (45.51%) +# Likes: 1374 +# Dislikes: 55 +# Total Accepted: 290.2K +# Total Submissions: 633.9K +# Testcase Example: '[10,1,2,7,6,1,5]\n8' +# +# Given a collection of candidate numbers (candidates) and a target number +# (target), find all unique combinations in candidates where the candidate +# numbers sums to target. +# +# Each number in candidates may only be used once in the combination. +# +# Note: +# +# +# All numbers (including target) will be positive integers. +# The solution set must not contain duplicate combinations. +# +# +# Example 1: +# +# +# Input: candidates = [10,1,2,7,6,1,5], target = 8, +# A solution set is: +# [ +# ⁠ [1, 7], +# ⁠ [1, 2, 5], +# ⁠ [2, 6], +# ⁠ [1, 1, 6] +# ] +# +# +# Example 2: +# +# +# Input: candidates = [2,5,2,1,2], target = 5, +# A solution set is: +# [ +# [1,2,2], +# [5] +# ] +# +# +# + +# @lc code=start +class Solution: + def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]: + result = [] + if not candidates: + return result + candidates = sorted(candidates) + self.dfs(candidates, 0, target, [], result) + return result + + def dfs(self, candidates, startIndex, target, combination, result): + if target < 0: + return + if target == 0: + result.append(combination[:]) + return + + for i in range(startIndex, len(candidates)): + if i != startIndex and candidates[i] == candidates[i - 1]: + continue + combination.append(candidates[i]) + self.dfs(candidates, i + 1, target - candidates[i], combination, result) + combination.pop() + +# @lc code=end + diff --git a/Week_03/G20200343030459/46.permutations.py b/Week_03/G20200343030459/46.permutations.py new file mode 100644 index 00000000..ab2e1eb9 --- /dev/null +++ b/Week_03/G20200343030459/46.permutations.py @@ -0,0 +1,61 @@ +# +# @lc app=leetcode id=46 lang=python3 +# +# [46] Permutations +# +# https://leetcode.com/problems/permutations/description/ +# +# algorithms +# Medium (60.16%) +# Likes: 3151 +# Dislikes: 94 +# Total Accepted: 525.4K +# Total Submissions: 867.8K +# Testcase Example: '[1,2,3]' +# +# Given a collection of distinct integers, return all possible permutations. +# +# Example: +# +# +# Input: [1,2,3] +# Output: +# [ +# ⁠ [1,2,3], +# ⁠ [1,3,2], +# ⁠ [2,1,3], +# ⁠ [2,3,1], +# ⁠ [3,1,2], +# ⁠ [3,2,1] +# ] +# +# +# + +# @lc code=start +class Solution: + def permute(self, nums: List[int]) -> List[List[int]]: + result = [] + visited = [False for i in range(len(nums))] + if not nums: + return nums + self.dfs(nums, visited, [], result) + return result + + def dfs(self, nums, visited, permutation, result): + size = len(nums) + if len(permutation) == size: + result.append(permutation[:]) + return + + for i in range(size): + if visited[i]: + continue + visited[i] = True + permutation.append(nums[i]) + self.dfs(nums, visited, permutation, result) + visited[i] = False + permutation.pop() + +# @lc code=end + diff --git a/Week_03/G20200343030459/47.permutations-ii.py b/Week_03/G20200343030459/47.permutations-ii.py new file mode 100644 index 00000000..09fc4bf2 --- /dev/null +++ b/Week_03/G20200343030459/47.permutations-ii.py @@ -0,0 +1,89 @@ +# +# @lc app=leetcode id=47 lang=python3 +# +# [47] Permutations II +# +# https://leetcode.com/problems/permutations-ii/description/ +# +# algorithms +# Medium (44.12%) +# Likes: 1600 +# Dislikes: 56 +# Total Accepted: 315.5K +# Total Submissions: 711K +# Testcase Example: '[1,1,2]' +# +# Given a collection of numbers that might contain duplicates, return all +# possible unique permutations. +# +# Example: +# +# +# Input: [1,1,2] +# Output: +# [ +# ⁠ [1,1,2], +# ⁠ [1,2,1], +# ⁠ [2,1,1] +# ] +# +# +# + +# @lc code=start +# dfs 中的两种条件 +# 1: if i != 0 and nums[i] == nums[i - 1]: +# continue +# 这种是不管什么时候只能选择第一个出现的值 +# 2: if i != startIndex and nums[i] == nums[i - 1] +# continue +# 这种是在同一层循环(dfs)的时候只能选第一个值(不能跳过上一个相同的值选择下一个) +class Solution: + def permuteUnique(self, nums: List[int]) -> List[List[int]]: + result = [] + visited = [False for i in range(len(nums))] + if not nums: + return result + nums = sorted(nums) + self.dfs(nums, visited, [], result) + return result + + def dfs(self, nums, visited, permutation, result): + size = len(nums) + if len(permutation) == size: + result.append(permutation[:]) + return + + for i in range(size): + if visited[i]: + continue + if i != 0 and nums[i] == nums[i - 1] and not visited[i - 1]: + continue + visited[i] = True + permutation.append(nums[i]) + self.dfs(nums, visited, permutation, result) + visited[i] = False + permutation.pop() + +# 方法 2: 每次向下传递的时候都把上次加入 permutaion 的值去掉,这样就不用多用一个 visited 数组 +class Solution: + def permuteUnique(self, nums: List[int]) -> List[List[int]]: + result = [] + if not nums: + return result + self.dfs(sorted(nums), [], result) + return result + def dfs(self, nums, permutation, result): + if not nums: + result.append(permutation) + return + + for i in range(len(nums)): + if i > 0 and nums[i] == nums[i - 1]: + continue + self.dfs(nums[:i] + nums[i + 1:], permutation + [nums[i]], result) + + + +# @lc code=end + diff --git a/Week_03/G20200343030459/51.n-queens.py b/Week_03/G20200343030459/51.n-queens.py new file mode 100644 index 00000000..5771b4d6 --- /dev/null +++ b/Week_03/G20200343030459/51.n-queens.py @@ -0,0 +1,136 @@ +# +# @lc app=leetcode id=51 lang=python3 +# +# [51] N-Queens +# +# https://leetcode.com/problems/n-queens/description/ +# +# algorithms +# Hard (43.64%) +# Likes: 1489 +# Dislikes: 65 +# Total Accepted: 181.5K +# Total Submissions: 412.8K +# Testcase Example: '4' +# +# The n-queens puzzle is the problem of placing n queens on an n×n chessboard +# such that no two queens attack each other. +# +# +# +# Given an integer n, return all distinct solutions to the n-queens puzzle. +# +# Each solution contains a distinct board configuration of the n-queens' +# placement, where 'Q' and '.' both indicate a queen and an empty space +# respectively. +# +# Example: +# +# +# Input: 4 +# Output: [ +# ⁠[".Q..", // Solution 1 +# ⁠ "...Q", +# ⁠ "Q...", +# ⁠ "..Q."], +# +# ⁠["..Q.", // Solution 2 +# ⁠ "Q...", +# ⁠ "...Q", +# ⁠ ".Q.."] +# ] +# Explanation: There exist two distinct solutions to the 4-queens puzzle as +# shown above. +# +# +# + +# @lc code=start +# 使用 permutation 的方法 +class Solution: + def solveNQueens(self, n: int) -> List[List[str]]: + positions = [] + visited = [False for i in range(n)] + self.dfs(n, visited, [], positions) + result = [] + for cols in positions: + result.append(self.draw_chessboard(cols)) + return result + + def dfs(self, n, visited, cols, positions): + if len(cols) == n: + positions.append(cols[:]) + return + + for i in range(n): + if not self.is_valid(cols, i): + continue + if visited[i]: + continue + visited[i] = True + self.dfs(n, visited, cols + [i], positions) + visited[i] = False + + def is_valid(self, cols, column): + row = len(cols) + for r, c in enumerate(cols): + if r + c == row + column: + return False + if r - c == row - column: + return False + return True + + def draw_chessboard(self, cols): + board = [] + for row, col in enumerate(cols): + board_row = ['Q' if i == col else '.' for i in range(len(cols))] + board.append(''.join(board_row)) + return board + +class Solution: + def solveNQueens(self, n: int) -> List[List[str]]: + result = [] + visited = { + 'col': set(), + 'sum': set(), + 'diff': set() + } + self.dfs(n, visited, [], result) + return result + + def dfs(self, n, visited, cols, result): + if len(cols) == n: + result.append(self.draw_chessboard(cols)) + + for col in range(n): + if not self.is_valid(visited, col, cols): + continue + visited['col'].add(col) + visited['sum'].add(col + len(cols)) + visited['diff'].add(col - len(cols)) + self.dfs(n, visited, cols + [col], result) + visited['col'].remove(col) + visited['sum'].remove(col + len(cols)) + visited['diff'].remove(col - len(cols)) + + + def is_valid(self, visited, col, cols): + row = len(cols) + if col in visited['col']: + return False + if col + row in visited['sum']: + return False + if col - row in visited['diff']: + return False + return True + + def draw_chessboard(self, cols): + board = [] + for col in cols: + board_row = ['Q' if i == col else '.' for i in range(len(cols))] + board.append(''.join(board_row)) + return board + + +# @lc code=end + diff --git "a/Week_03/G20200343030459/69.x-\347\232\204\345\271\263\346\226\271\346\240\271.py" "b/Week_03/G20200343030459/69.x-\347\232\204\345\271\263\346\226\271\346\240\271.py" new file mode 100644 index 00000000..a2902a78 --- /dev/null +++ "b/Week_03/G20200343030459/69.x-\347\232\204\345\271\263\346\226\271\346\240\271.py" @@ -0,0 +1,57 @@ +# +# @lc app=leetcode.cn id=69 lang=python3 +# +# [69] x 的平方根 +# +# https://leetcode-cn.com/problems/sqrtx/description/ +# +# algorithms +# Easy (37.61%) +# Likes: 333 +# Dislikes: 0 +# Total Accepted: 107.3K +# Total Submissions: 285.3K +# Testcase Example: '4' +# +# 实现 int sqrt(int x) 函数。 +# +# 计算并返回 x 的平方根,其中 x 是非负整数。 +# +# 由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去。 +# +# 示例 1: +# +# 输入: 4 +# 输出: 2 +# +# +# 示例 2: +# +# 输入: 8 +# 输出: 2 +# 说明: 8 的平方根是 2.82842..., +# 由于返回类型是整数,小数部分将被舍去。 +# +# +# + +# @lc code=start +class Solution: + def mySqrt(self, x: int) -> int: + if x <= 1: + return x + start, end = 1, x + while start + 1 < end: + mid = start + (end - start) // 2 + if mid == x // mid: + return mid + if mid < x // mid: + start = mid + else: + end = mid + if end * end> x // end: + return start + return end + +# @lc code=end + diff --git a/Week_03/G20200343030459/74.search-a-2-d-matrix.py b/Week_03/G20200343030459/74.search-a-2-d-matrix.py new file mode 100644 index 00000000..781caf35 --- /dev/null +++ b/Week_03/G20200343030459/74.search-a-2-d-matrix.py @@ -0,0 +1,120 @@ +# +# @lc app=leetcode id=74 lang=python3 +# +# [74] Search a 2D Matrix +# +# https://leetcode.com/problems/search-a-2d-matrix/description/ +# +# algorithms +# Medium (35.86%) +# Likes: 1341 +# Dislikes: 141 +# Total Accepted: 287.7K +# Total Submissions: 801.6K +# Testcase Example: '[[1,3,5,7],[10,11,16,20],[23,30,34,50]]\n3' +# +# Write an efficient algorithm that searches for a value in an m x n matrix. +# This matrix has the following properties: +# +# +# Integers in each row are sorted from left to right. +# The first integer of each row is greater than the last integer of the +# previous row. +# +# +# Example 1: +# +# +# Input: +# matrix = [ +# ⁠ [1, 3, 5, 7], +# ⁠ [10, 11, 16, 20], +# ⁠ [23, 30, 34, 50] +# ] +# target = 3 +# Output: true +# +# +# Example 2: +# +# +# Input: +# matrix = [ +# ⁠ [1, 3, 5, 7], +# ⁠ [10, 11, 16, 20], +# ⁠ [23, 30, 34, 50] +# ] +# target = 13 +# Output: false +# +# + +# @lc code=start +# 自己想的 两次二分法 感觉逻辑很冗余 +class Solution: + def searchMatrix(self, matrix: List[List[int]], target: int) -> bool: + if not matrix or not matrix[0]: + return False + start_x, end_x = 0, len(matrix) - 1 + start_y, end_y = 0, len(matrix[0]) - 1 + row = 0 + + while start_x + 1 < end_x: + mid = start_x + (end_x - start_x) // 2 + if matrix[mid][0] == target: + return True + elif matrix[mid][0] > target: + end_x = mid + else: + start_x = mid + if matrix[start_x][0] == target: + return True + if matrix[end_x][0] == target: + return True + + if matrix[end_x][0] < target: + row = end_x + else: + row = start_x + + while start_y + 1 < end_y: + mid = start_y + (end_y - start_y) // 2 + if matrix[row][mid] == target: + return True + elif matrix[row][mid] > target: + end_y = mid + else: + start_y = mid + if matrix[row][start_y] == target: + return True + if matrix[row][end_y] == target: + return True + return False + +class Solution: + def searchMatrix(self, matrix: List[List[int]], target: int) -> bool: + if not matrix or not matrix[0]: + return False + + row, col = len(matrix), len(matrix[0]) + start, end = 0, col * row - 1 + + while start + 1 < end: + mid = start + (end - start) // 2 + x, y = mid // col, mid % col + if matrix[x][y] < target: + start = mid + else: + end = mid + x, y = start // col, start % col + if matrix[x][y] == target: + return True + + x, y = end // col, end % col + if matrix[x][y] == target: + return True + + return False + +# @lc code=end + diff --git a/Week_03/G20200343030459/77.combinations.py b/Week_03/G20200343030459/77.combinations.py new file mode 100644 index 00000000..99f542f9 --- /dev/null +++ b/Week_03/G20200343030459/77.combinations.py @@ -0,0 +1,58 @@ +# +# @lc app=leetcode id=77 lang=python3 +# +# [77] Combinations +# +# https://leetcode.com/problems/combinations/description/ +# +# algorithms +# Medium (51.97%) +# Likes: 1192 +# Dislikes: 60 +# Total Accepted: 260.2K +# Total Submissions: 497.9K +# Testcase Example: '4\n2' +# +# Given two integers n and k, return all possible combinations of k numbers out +# of 1 ... n. +# +# Example: +# +# +# Input: n = 4, k = 2 +# Output: +# [ +# ⁠ [2,4], +# ⁠ [3,4], +# ⁠ [2,3], +# ⁠ [1,2], +# ⁠ [1,3], +# ⁠ [1,4], +# ] +# +# +# + +# @lc code=start +class Solution: + def combine(self, n: int, k: int) -> List[List[int]]: + result = [] + if not n or not k: + return result + self.dfs(n, 0, k, [], result) + return result + + def dfs(self, n, startIndex, k, combination, result): + if len(combination) == k: + result.append(combination[:]) + return + + for i in range(startIndex, n): + combination.append(i + 1) + self.dfs(n, i + 1, k, combination, result) + combination.pop() + + + +# @lc code=end + diff --git a/Week_03/G20200343030459/852.peak-index-in-a-mountain-array.py b/Week_03/G20200343030459/852.peak-index-in-a-mountain-array.py new file mode 100644 index 00000000..fc7a05bf --- /dev/null +++ b/Week_03/G20200343030459/852.peak-index-in-a-mountain-array.py @@ -0,0 +1,68 @@ +# +# @lc app=leetcode id=852 lang=python3 +# +# [852] Peak Index in a Mountain Array +# +# https://leetcode.com/problems/peak-index-in-a-mountain-array/description/ +# +# algorithms +# Easy (70.85%) +# Likes: 472 +# Dislikes: 974 +# Total Accepted: 128.9K +# Total Submissions: 181.9K +# Testcase Example: '[0,1,0]' +# +# Let's call an array A a mountain if the following properties hold: +# +# +# A.length >= 3 +# There exists some 0 < i < A.length - 1 such that A[0] < A[1] < ... A[i-1] < +# A[i] > A[i+1] > ... > A[A.length - 1] +# +# +# Given an array that is definitely a mountain, return any i such that A[0] < +# A[1] < ... A[i-1] < A[i] > A[i+1] > ... > A[A.length - 1]. +# +# Example 1: +# +# +# Input: [0,1,0] +# Output: 1 +# +# +# +# Example 2: +# +# +# Input: [0,2,1,0] +# Output: 1 +# +# +# Note: +# +# +# 3 <= A.length <= 10000 +# 0 <= A[i] <= 10^6 +# A is a mountain, as defined above. +# +# +# + +# @lc code=start +class Solution: + def peakIndexInMountainArray(self, A: List[int]) -> int: + start, end = 0, len(A) - 1 + while start + 1 < end: + mid = start + (end - start) // 2 + if A[mid - 1] < A[mid]: + start = mid + else: + end = mid + if A[start] > A[end]: + return start + else: + return end + +# @lc code=end + diff --git a/Week_03/G20200343030459/90.subsets-ii.py b/Week_03/G20200343030459/90.subsets-ii.py new file mode 100644 index 00000000..d6e0f3cf --- /dev/null +++ b/Week_03/G20200343030459/90.subsets-ii.py @@ -0,0 +1,56 @@ +# +# @lc app=leetcode id=90 lang=python3 +# +# [90] Subsets II +# +# https://leetcode.com/problems/subsets-ii/description/ +# +# algorithms +# Medium (45.20%) +# Likes: 1356 +# Dislikes: 58 +# Total Accepted: 251.5K +# Total Submissions: 554.7K +# Testcase Example: '[1,2,2]' +# +# Given a collection of integers that might contain duplicates, nums, return +# all possible subsets (the power set). +# +# Note: The solution set must not contain duplicate subsets. +# +# Example: +# +# +# Input: [1,2,2] +# Output: +# [ +# ⁠ [2], +# ⁠ [1], +# ⁠ [1,2,2], +# ⁠ [2,2], +# ⁠ [1,2], +# ⁠ [] +# ] +# +# +# + +# @lc code=start +class Solution: + def subsetsWithDup(self, nums: List[int]) -> List[List[int]]: + result = [] + nums = sorted(nums) + self.dfs(nums, 0, [], result) + return result + def dfs(self, nums: List[int], startIndex: int, subset: List[int], result: List[List[int]]): + result.append(subset[:]) + + for i in range(startIndex, len(nums)): + if i != startIndex and nums[i] == nums[i - 1]: + continue + subset.append(nums[i]) + self.dfs(nums, i + 1, subset, result) + subset.pop() + +# @lc code=end + diff --git a/Week_03/G20200343030463/463-Week 03/LeetCode_122_463.cpp b/Week_03/G20200343030463/463-Week 03/LeetCode_122_463.cpp new file mode 100644 index 00000000..95b84902 --- /dev/null +++ b/Week_03/G20200343030463/463-Week 03/LeetCode_122_463.cpp @@ -0,0 +1,27 @@ +题目:买卖股票的最佳时机 II +解法如下 贪心算法 + +解法一: +class Solution { +public: + int maxProfit(vector& prices) { + int profit = 0; + for (int i =1; i < prices.size();i++){ + if (prices[i] > prices[i-1]){ + profit += (prices[i]-prices[i-1]); + } + } + return profit; + } +}; + +解法二: 国际站投票最高的解法 +class Solution { +public: + int maxProfit(vector& prices) { + int ret = 0; + for (size_t p = 1; p < prices.size(); ++p) + ret += max(prices[p] - prices[p - 1], 0); + return ret; + } +}; diff --git a/Week_03/G20200343030463/463-Week 03/LeetCode_200_463.cpp b/Week_03/G20200343030463/463-Week 03/LeetCode_200_463.cpp new file mode 100644 index 00000000..9bc25840 --- /dev/null +++ b/Week_03/G20200343030463/463-Week 03/LeetCode_200_463.cpp @@ -0,0 +1,83 @@ +题目:岛屿数量 +dfs +解法: +class Solution { +private: + void dfs(vector>& grid,int r,int c){ + int nr = grid.size(); + int nc = grid[0].size(); + grid[r][c] = '0'; + + if(r -1 >= 0 && grid[r-1][c] == '1') dfs(grid,r-1,c); + if(r+1 < nr && grid[r+1][c] == '1') dfs(grid,r+1,c); + if(c-1 >= 0 && grid[r][c-1] == '1') dfs(grid,r,c-1); + if(c+1 < nc && grid[r][c+1] == '1') dfs(grid,r,c+1); + } + +public: + int numIslands(vector>& grid) { + int nr = grid.size(); + if (!nr) return 0; + int nc = grid[0].size(); + int num_islands = 0; + for(int r =0; r < nr; ++r){ + for(int c =0; c < nc;++c){ + if(grid[r][c]=='1'){ + ++num_islands; + dfs(grid,r,c); + } + } + } + return num_islands; + } +}; + +国际站提供的解法就是(洪水填充) + +https://leetcode.com/problems/number-of-islands/discuss/343513/C%2B%2B-Flood-Fill-faster-than-100 + +class Solution { +public: + + int dx[4] = {-1,0,1,0 }; + int dy[4] = {0,1,0,-1 }; + bool valid(int i,int j,int r,int c){ + return i>=0 && i=0 && j>& grid) + { + if(grid[i][j] == '.') + return; + else + grid[i][j] = '.'; + + for(int k=0;k<4;k++) + { + int r = i+dx[k]; + int c = j+dy[k]; + if(valid(r,c,grid.size(),grid[0].size()) && grid[r][c]=='1'){ + floodFill(r,c,grid); + } + } + } + int numIslands(vector>& grid) { + ios::sync_with_stdio(false); + cin.tie(NULL); + + int connected = 0; + for(int i=0;i& nums, int l, int r, int target){ + while(l<=r){ + int p = (l+r)/2; + if(nums[p] == target) + return p; + else if(nums[p] > target) + r = p -1; + else if (nums[p] < target) + l = p +1; + + } + return -1; + } + int search(vector& nums, int target) { + if (nums.empty()) + return -1; + + int l = 0; + int r = nums.size()-1; + int p; + while(l <=r){ + p = (l+r)/2; + if(p== nums.size()-1 || nums[p]>nums[p+1]) + break; + if(nums[l] > nums[p]) + r = p-1; + else + l = p+1; + } + + if(p==nums.size()-1) + return binarySearch(nums,0,nums.size()-1,target); + + int pos = binarySearch(nums,0,p,target); + if(pos !=-1) + return pos; + return binarySearch(nums,p+1,nums.size()-1,target); + } +}; diff --git a/Week_03/G20200343030463/463-Week 03/LeetCode_455_463.cpp b/Week_03/G20200343030463/463-Week 03/LeetCode_455_463.cpp new file mode 100644 index 00000000..9843ba33 --- /dev/null +++ b/Week_03/G20200343030463/463-Week 03/LeetCode_455_463.cpp @@ -0,0 +1,19 @@ +题目:分发饼干 +解法如下 贪心算法 + +解法一:每次都满足未被分配的孩子 +class Solution { +public: + int findContentChildren(vector& g, vector& s) { + + sort(g.begin(),g.end()); + sort(s.begin(),s.end()); + int gx = 0; + int sx = 0; + while(gx 0 && ten >0){ //有5元 和 10元纸币 各少一张 + five --; + ten --; + }else if ( five ==0 && ten >0){ //只有10块纸币 那就不满足 + return false; + }else if (five >=3){ //如果有超过三张5元 那么5元少三张 + five -= 3; + }else { + return false; //其余不满足 + } + } +} + +return true; + +解法二:国际站投票最高的 +https://leetcode.com/problems/lemonade-change/discuss/143719/C%2B%2BJavaPython-Straight-Forward +class Solution { +public: + bool lemonadeChange(vector& bills) { + int five = 0, ten = 0; + for (int i : bills) { + if (i == 5) five++; + else if (i == 10) five--, ten++; + else if (ten > 0) ten--, five--; //这里可以知道钱盒子里至少有一张5元 那就10元 5元各少一张 + else five -= 3; + if (five < 0) return false; //如果都不够找零那就不成功 + } + return true; + } +}; diff --git a/Week_03/G20200343030463/463-Week 03/LeetCode_874_463.cpp b/Week_03/G20200343030463/463-Week 03/LeetCode_874_463.cpp new file mode 100644 index 00000000..63f6e2b5 --- /dev/null +++ b/Week_03/G20200343030463/463-Week 03/LeetCode_874_463.cpp @@ -0,0 +1,61 @@ +题目:模拟行走机器人 +di以北为0,顺时针加1,所以是北0,东1,南2,西3 +-向左90°时,就是顺时针旋转,(drct + 3)% 4 +-向右90°时,就是逆时针旋转90°,相当于顺时针旋转270°,(drct + 1)% 4 + +int dx[4] = {0,1,0,-1}; +int dy[4] = {1,0,-1,0}; + +表示往x方向移动和往y方向移动时,移动的步数。 + +解法如下:https://leetcode-cn.com/problems/walking-robot-simulation/solution/874-mo-ni-xing-zou-ji-qi-ren-unordered_set-set-uno/ +#include +自定义一个set +struct pair_hash +{ + template + std::size_t operator() (const std::pair& p) const + { + auto h1 = std::hash{}(p.first); + auto h2 = std::hash{}(p.second); + return h1^h2; + } +}; + +class Solution { +public: + int robotSim(vector& commands, vector>& obstacles) { + int dx[4] = {0,1,0,-1}; + int dy[4] = {1,0,-1,0}; + int x = 0, y = 0, di = 0; + + unordered_set,pair_hash> obstacleSet; + for(vectorobstacle : obstacles){ + obstacleSet.insert(make_pair(obstacle[0],obstacle[1])); + } + + int ans =0; + for(int cmd : commands){ + if(cmd == -2) + di = (di +3)%4; + if(cmd ==-1) + di = (di +1)%4; + else{ + for(int k =0; k < cmd;++k){ + int nx = x + dx[di]; + int ny = y + dy[di]; + if(obstacleSet.find(make_pair(nx,ny)) == obstacleSet.end()){ + x = nx; + y = ny; + ans = max(ans,x*x+y*y); + } + + } + } + } + return ans; + } +}; + + + diff --git a/Week_03/G20200343030463/NOTE.md b/Week_03/G20200343030463/NOTE.md index 50de3041..88420b65 100644 --- a/Week_03/G20200343030463/NOTE.md +++ b/Week_03/G20200343030463/NOTE.md @@ -1 +1,61 @@ -学习笔记 \ No newline at end of file +学习总结: +使用二分查找,寻找一个半有序数组 [4, 5, 6, 7, 0, 1, 2] 中间无序的地方 + +1.clarification: 找到中间无序的地方 +二分查找的调节 +001 存在边界 +002 存在局部单调递增 +003 可以通过索引进行访问 + +二分法 找到数组中无序的边界点 得到一个单调递增的数组上下边界 +然后进行二分法寻找target + +解法如下: +class Solution { +public: +int binarySearch(vector& nums, int l, int r, int target) { +while (l <= r) { +int p = (l + r) / 2; +if (nums[p] == target) +return p; +if (nums[p] > target) +r = p - 1; +else +l = p + 1; +} + +return -1; +} + +int search(vector& nums, int target) { +if (nums.empty()) +return -1; + +int l = 0; +int r = nums.size() - 1; +int p; // Position of boundary + +while (l <= r) { +p = (l + r) / 2; +// 边界是最后一个 或者边界的值大于右边就break +if (p == nums.size() - 1 || nums[p] > nums[p + 1]) +break; +// +if (nums[l] > nums[p]) //左半部分存在无序就 +r = p - 1; +else +l = p + 1; //右边部分存在无序 +} + +if (p == nums.size() - 1) // +return binarySearch(nums, 0, nums.size() - 1, target); +int pos = binarySearch(nums, 0, p, target); //左半部分找 +if (pos != -1) +return pos; +return binarySearch(nums, p + 1, nums.size() - 1, target); //右半部分找 +} +}; + + + + diff --git a/Week_03/G20200343030465/LeetCode_127_465.java b/Week_03/G20200343030465/LeetCode_127_465.java new file mode 100644 index 00000000..899a6d14 --- /dev/null +++ b/Week_03/G20200343030465/LeetCode_127_465.java @@ -0,0 +1,44 @@ +class Solution { + public int ladderLength(String beginWord, String endWord, List wordList) { + if (wordList == null || wordList.size() == 0) return 0; + + HashSet start = new HashSet<>(); + + HashSet end = new HashSet<>(); + + HashSet dic = new HashSet<>(wordList); + start.add(beginWord); + end.add(endWord); + if (!dic.contains(endWord)) return 0; + + return bfs(start, end, dic, 2); + + } + + public int bfs(HashSet st, HashSet ed, HashSet dic, int l) { + if (st.size() == 0) return 0; + if (st.size() > ed.size()) { + return bfs(ed, st, dic, l); + } + dic.removeAll(st); + HashSet next = new HashSet<>(); + for (String s : st) { + char[] arr = s.toCharArray(); + for (int i = 0; i < arr.length; i++) { + char tmp = arr[i]; + for (char c = 'a'; c <= 'z'; c++) { + if (tmp == c) continue; + arr[i] = c; + String nstr = new String(arr); + if (dic.contains(nstr)) { + if (ed.contains(nstr)) return l; + else next.add(nstr); + } + } + + arr[i] = tmp; + } + } + return bfs(next, ed, dic, l + 1); + } +} \ No newline at end of file diff --git a/Week_03/G20200343030465/LeetCode_74_465.java b/Week_03/G20200343030465/LeetCode_74_465.java new file mode 100644 index 00000000..ba042d6f --- /dev/null +++ b/Week_03/G20200343030465/LeetCode_74_465.java @@ -0,0 +1,19 @@ +class Solution { + public boolean searchMatrix(int[][] matrix, int target) { + if (matrix == null || matrix.length == 0 || matrix[0].length == 0) { + return false; + } + int row = 0; + int col = matrix[0].length - 1; + while (row < matrix.length && col >= 0) { + if (matrix[row][col] == target) { + return true; + } else if (matrix[row][col] < target) { + row++; + } else { + col--; + } + } + return false; +} +} \ No newline at end of file diff --git a/Week_03/G20200343030485/LeetCode_122_485.cs b/Week_03/G20200343030485/LeetCode_122_485.cs new file mode 100644 index 00000000..c2e98e5e --- /dev/null +++ b/Week_03/G20200343030485/LeetCode_122_485.cs @@ -0,0 +1,19 @@ +public class Solution { + public int MaxProfit(int[] prices) { + if (prices.Length == 0) { + return 0; + } + + int totalProfit = 0; + int lastPrice = prices[0]; + for (int i = 1; i < prices.Length; i++) { + if (prices[i] > lastPrice) { + totalProfit += prices[i] - lastPrice; + } + + lastPrice = prices[i]; + } + + return totalProfit; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030485/LeetCode_200_485.cs b/Week_03/G20200343030485/LeetCode_200_485.cs new file mode 100644 index 00000000..b96de674 --- /dev/null +++ b/Week_03/G20200343030485/LeetCode_200_485.cs @@ -0,0 +1,43 @@ +public class Solution { + public int NumIslands(char[][] grid) { + int xsize = grid.Length; + if (xsize == 0) { + return 0; + } + + int ysize = grid[0].Length; + if (ysize == 0) { + return 0; + } + + int count = 0; + + for (int x = 0; x < xsize; x++) { + for (int y = 0; y < ysize; y++) { + if (grid[x][y] == '1') { + count++; + Dfs(grid, x, y); + } + } + } + + return count; + } + + public void Dfs(char[][] grid, int x, int y) { + if (x < 0 || x >= grid.Length || y < 0 || y >= grid[0].Length) { + return; + } + + if (grid[x][y] != '1') { + return; + } + + grid[x][y] = '2'; + + Dfs(grid, x - 1, y); + Dfs(grid, x + 1, y); + Dfs(grid, x, y - 1); + Dfs(grid, x, y + 1); + } +} \ No newline at end of file diff --git a/Week_03/G20200343030485/LeetCode_455_485.cs b/Week_03/G20200343030485/LeetCode_455_485.cs new file mode 100644 index 00000000..698d5825 --- /dev/null +++ b/Week_03/G20200343030485/LeetCode_455_485.cs @@ -0,0 +1,22 @@ +public class Solution { + public int FindContentChildren(int[] g, int[] s) { + Array.Sort(g); + Array.Sort(s); + + int result = 0; + int indexS = 0; + for (int i = 0; i < g.Length; i++) { + while (indexS < s.Length) { + int amount = s[indexS]; + indexS++; + + if (amount >= g[i]) { + result++; + break; + } + } + } + + return result; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030485/LeetCode_529_485.cs b/Week_03/G20200343030485/LeetCode_529_485.cs new file mode 100644 index 00000000..15e81698 --- /dev/null +++ b/Week_03/G20200343030485/LeetCode_529_485.cs @@ -0,0 +1,63 @@ +public class Solution { + public char[][] UpdateBoard(char[][] board, int[] click) { + Dfs(board, click[0], click[1]); + return board; + } + + public void Dfs(char[][] board, int x, int y) { + if (x < 0 || x >= board.Length || y < 0 || y >= board[0].Length) { + return; + } + + char result = board[x][y]; + if (result == 'B') { + return; + } + + if (result == 'M') { + board[x][y] = 'X'; + return; + } + + if (result == 'E') { + int count = SuroundMinesNum(board, x, y); + if (count > 0) { + board[x][y] = (char)(48 + count); + } + else { + board[x][y] = 'B'; + + for (int i = x - 1; i <= x + 1; i++) { + for (int j = y - 1; j <= y + 1; j++) { + if (i == x && j == y) { + continue; + } + + Dfs(board, i, j); + } + } + } + } + } + + public int SuroundMinesNum(char[][] board, int x, int y) { + int num = 0; + for (int i = x - 1; i <= x + 1; i++) { + for (int j = y - 1; j <= y + 1; j++) { + if (i == x && j == y) { + continue; + } + + if (i < 0 || i >= board.Length || j < 0 || j >= board[0].Length) { + continue; + } + + if (board[i][j] == 'M') { + num++; + } + } + } + + return num; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030485/LeetCode_55_485.cs b/Week_03/G20200343030485/LeetCode_55_485.cs new file mode 100644 index 00000000..c9c61097 --- /dev/null +++ b/Week_03/G20200343030485/LeetCode_55_485.cs @@ -0,0 +1,14 @@ +public class Solution { + public bool CanJump(int[] nums) { + int jumpTargetMax = 0; + for (int i = 0; i < nums.Length; i++) { + if (i > jumpTargetMax) { + return false; + } + + jumpTargetMax = Math.Max(jumpTargetMax, i + nums[i]); + } + + return true; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030485/LeetCode_74_485.cs b/Week_03/G20200343030485/LeetCode_74_485.cs new file mode 100644 index 00000000..aab5090a --- /dev/null +++ b/Week_03/G20200343030485/LeetCode_74_485.cs @@ -0,0 +1,84 @@ +public class Solution { + public bool SearchMatrix(int[][] matrix, int target) { + int row = matrix.Length; + if (row == 0) { + return false; + } + + int col = matrix[0].Length; + if (col == 0) { + return false; + } + + int left = 0; + int right = row - 1; + int targetRow = -1; + while (left <= right) { + int mid = (left + right) / 2; + if (matrix[mid][0] > target) { + right = mid - 1; + } + else if (matrix[mid][col-1] < target) { + left = mid + 1; + } + else { + targetRow = mid; + break; + } + } + + if (targetRow == -1) { + return false; + } + + left = 0; + right = col - 1; + while (left <= right) { + int mid = (left + right) / 2; + if (matrix[targetRow][mid] == target) { + return true; + } + else if (matrix[targetRow][mid] < target) { + left = mid + 1; + } + else { + right = mid - 1; + } + } + + return false; + } +} + +//官方解,更简洁,一次二分查找搞定 +public class Solution { + public bool SearchMatrix(int[][] matrix, int target) { + int row = matrix.Length; + if (row == 0) { + return false; + } + + int col = matrix[0].Length; + if (col == 0) { + return false; + } + + int left = 0; + int right = row * col - 1; + while (left <= right) { + int mid = (left + right) / 2; + int value = matrix[mid/col][mid%col]; + if (value == target) { + return true; + } + else if (value < target) { + left = mid + 1; + } + else { + right = mid - 1; + } + } + + return false; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030485/LeetCode_860_485.cs b/Week_03/G20200343030485/LeetCode_860_485.cs new file mode 100644 index 00000000..50c8091f --- /dev/null +++ b/Week_03/G20200343030485/LeetCode_860_485.cs @@ -0,0 +1,35 @@ + +public class Solution { + public bool LemonadeChange(int[] bills) { + int count5 = 0; + int count10 = 0; + for (int i = 0; i < bills.Length; i++) { + int num = bills[i]; + if (num == 5) { + count5++; + } + else if (num == 10) { + if (count5 == 0) { + return false; + } + + count5--; + count10++; + } + else if (num == 20) { + if (count10 > 0 && count5 > 0) { + count10--; + count5--; + } + else if (count5 >= 3) { + count5 = count5 - 3; + } + else { + return false; + } + } + } + + return true; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030487/leetcode_122_487.js b/Week_03/G20200343030487/leetcode_122_487.js new file mode 100644 index 00000000..a876c9dd --- /dev/null +++ b/Week_03/G20200343030487/leetcode_122_487.js @@ -0,0 +1,13 @@ +/** + * @param {number[]} prices + * @return {number} + */ +var maxProfit = function (prices) { + let max = 0 + for (let i = 0, len = prices.length; i < len - 1; i++) { + if (prices[i] < prices[i + 1]) { + max += prices[i + 1] - prices[i] + } + } + return max +} diff --git a/Week_03/G20200343030487/leetcode_153_487.js b/Week_03/G20200343030487/leetcode_153_487.js new file mode 100644 index 00000000..6ebb6ce1 --- /dev/null +++ b/Week_03/G20200343030487/leetcode_153_487.js @@ -0,0 +1,32 @@ +/** + * @param {number[]} nums + * @return {number} + */ +var findMin = function(nums) { + if (nums.length === 1) return nums[0] + for (let i = 0, len = nums.length; i < len - 1; i++) { + if (nums[i] < nums[i + 1]) { + return nums[i] + } + } + return nums[0] +} + +var findMin1 = function(nums) { + let left = 0, right = nums.length - 1 + while (right >= left) { + let mid = parseInt(left + (right - left) / 2) + if (nums[mid] > nums[mid + 1]) { + return nums[mid + 1] + } + if (nums[mid - 1] > nums[mid]) { + return nums[mid] + } + if (nums[mid] > nums[0]) { + left = mid + 1 + } else { + right = mid - 1 + } + } + return -1 +} diff --git a/Week_03/G20200343030487/leetcode_33_487.js b/Week_03/G20200343030487/leetcode_33_487.js new file mode 100644 index 00000000..9f71c4c6 --- /dev/null +++ b/Week_03/G20200343030487/leetcode_33_487.js @@ -0,0 +1,40 @@ +/** + * @param {number[]} nums + * @param {number} target + * @return {number} + */ +var search = function(nums, target) { + for (let i = 0, len = nums.length; i < len; i++) { + if (nums[i] === target) { + return i + } + } + return -1 +} + +var search1 = function(nums, target) { + if (nums.length === 0) return -1 + let left = 0, right = nums.length - 1, mid + while (right >= left) { + mid = parseInt(left + (right - left) / 2) + if (nums[mid] === target) { + return mid + } + if (nums[left] <= nums[mid]) { + if (target >= nums[left] && target < nums[mid]) { + right = mid - 1 + } else { + left = mid + 1 + } + } else { + if (nums[left] > nums[mid]) { + if (target < nums[right] && target >= nums[mid]) { + left = mid + 1 + } else { + right = mid - 1 + } + } + } + } + return -1 +} diff --git a/Week_03/G20200343030487/leetcode_455_487.js b/Week_03/G20200343030487/leetcode_455_487.js new file mode 100644 index 00000000..a312bb70 --- /dev/null +++ b/Week_03/G20200343030487/leetcode_455_487.js @@ -0,0 +1,20 @@ +/** + * @param {number[]} g + * @param {number[]} s + * @return {number} + */ +var findContentChildren = function (g, s) { + g.sort((a, b) => { return a - b }) + s.sort((a, b) => { return a - b }) + let count = 0, i = 0, j = 0 + while (i < g.length && j < s.length) { + if (g[i] <= s[j]) { + count++ + i++ + j++ + } else { + j++ + } + } + return count +} diff --git a/Week_03/G20200343030487/leetcode_55_487.js b/Week_03/G20200343030487/leetcode_55_487.js new file mode 100644 index 00000000..9274ad4a --- /dev/null +++ b/Week_03/G20200343030487/leetcode_55_487.js @@ -0,0 +1,12 @@ +/** + * @param {number[]} nums + * @return {boolean} + */ +var canJump = function (nums) { + let max = 0 + for (let i = 0, len = nums.length; i < len; i++) { + if (i > max) return false + max = Math.max(max, i + nums[i]) + } + return true +} diff --git a/Week_03/G20200343030487/leetcode_74_487.js b/Week_03/G20200343030487/leetcode_74_487.js new file mode 100644 index 00000000..5bc77d9e --- /dev/null +++ b/Week_03/G20200343030487/leetcode_74_487.js @@ -0,0 +1,19 @@ +/** + * @param {number[][]} matrix + * @param {number} target + * @return {boolean} + */ +var searchMatrix = function (matrix, target) { + if (!matrix.length) return false + let row = 0, col = matrix[0].length - 1 + while (row < matrix.length && col > -1) { + if (matrix[row][col] < target) { + row++ + } else if (matrix[row][col] > target) { + col-- + } else { + return true + } + } + return false +} diff --git a/Week_03/G20200343030487/leetcode_860_487.js b/Week_03/G20200343030487/leetcode_860_487.js new file mode 100644 index 00000000..9f709628 --- /dev/null +++ b/Week_03/G20200343030487/leetcode_860_487.js @@ -0,0 +1,29 @@ +/** + * @param {number[]} bills + * @return {boolean} + */ +var lemonadeChange = function (bills) { + let five = 0, ten = 0 + for (let i = 0, len = bills.length; i < len; i++) { + if (bills[i] === 5) { + five++ + } else if (bills[i] === 10) { + if (!five) { + return false + } else { + five-- + ten++ + } + } else { + if (ten > 0 && five > 0) { + five-- + ten-- + } else if (five >= 3) { + five -= 3 + } else { + return false + } + } + } + return true +} diff --git a/Week_03/G20200343030489/LeetCode_102_489.cpp b/Week_03/G20200343030489/LeetCode_102_489.cpp new file mode 100644 index 00000000..994b9cd5 --- /dev/null +++ b/Week_03/G20200343030489/LeetCode_102_489.cpp @@ -0,0 +1,53 @@ +/* + * @lc app=leetcode.cn id=102 lang=cpp + * + * [102] 二叉树的层次遍历 + */ + +// @lc code=start +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Solution +{ +public: + vector> levelOrder(TreeNode *root) + { + vector> res; + if (!root) + { + return res; + } + queue que; + TreeNode *tree; + que.push(root); + while (!que.empty()) + { + vector tmp; + int width = que.size(); + for (int i = 0; i < width; i++) + { + tree = que.front(); + tmp.push_back(tree->val); + que.pop(); + if (tree->left) + { + que.push(tree->left); + } + if (tree->right) + { + que.push(tree->right); + } + } + res.push_back(tmp); + } + return res; + } +}; +// @lc code=end diff --git a/Week_03/G20200343030489/LeetCode_122_489.cpp b/Week_03/G20200343030489/LeetCode_122_489.cpp new file mode 100644 index 00000000..f0ac65e3 --- /dev/null +++ b/Week_03/G20200343030489/LeetCode_122_489.cpp @@ -0,0 +1,47 @@ +/* + * @lc app=leetcode.cn id=122 lang=cpp + * + * [122] 买卖股票的最佳时机 II + */ + +// @lc code=start +class Solution +{ +public: + int maxProfit(vector &prices) + { + if(prices.size()==0) + return 0; + int count=0,max=0; + for (int i = 1; i < prices.size(); i++) + { + if(prices[i]>prices[i-1]&&i!=prices.size()-1) + count++; + else if(prices[i]<=prices[i-1]&&count>0){ + max=prices[i-1]-prices[i-1-count]+max; + count=0; + } + else if(prices[i]>prices[i-1]&&i==prices.size()-1){ + max=prices[i]-prices[i-count-1]+max; + } + } + return max; + + } +}; +// class Solution +// { +// public: +// int maxProfit(vector &prices) +// { +// if (prices.size() == 0) +// return 0; +// int max = 0; +// for (int i = 1; i < prices.size(); i++) +// if (prices[i] > prices[i - 1]) +// max = prices[i] - prices[i - 1] + max; +// return max; +// } +// }; + +// @lc code=end \ No newline at end of file diff --git a/Week_03/G20200343030489/LeetCode_126_489.cpp b/Week_03/G20200343030489/LeetCode_126_489.cpp new file mode 100644 index 00000000..4a04aebd --- /dev/null +++ b/Week_03/G20200343030489/LeetCode_126_489.cpp @@ -0,0 +1,136 @@ +/* + * @lc app=leetcode.cn id=126 lang=cpp + * + * [126] 单词接龙 II + */ + +// @lc code=start +class Solution +{ +public: + vector> findLadders(string beginWord, string endWord, vector &wordList) + { + unordered_map num; + vector> res; + for(auto w:wordList) + num.insert({w,INT_MAX}); + num[beginWord]=0; + queue>> que; + que.push({beginWord,{beginWord}}); + while (!que.empty()) + { + auto n=que.front(); + que.pop(); + string w=n.first; + auto v=n.second; + if (w==endWord) + { + res.push_back(v); + continue; + } + for (int i = 0; i < w.size(); i++) + { + string t=w; + for (char c='a'; c<='z'; c++) + { + t[i]=c; + if(t==w) + continue; + if(num.find(t)==num.end()) + continue; + if(num[t]<(int)v.size()) + continue; + num[t]=(int)v.size(); + v.push_back(t); + que.push({t,v}); + v.pop_back(); + } + + } + + } + return res; + } +}; +// class Solution +// { +// public: +// vector> findLadders(string beginWord, string endWord, vector &wordList) +// { +// vector> ans; +// unordered_set wordDict(wordList.begin(), wordList.end()); +// vector levDict; +// while (wordDict.count(endWord) == 0) +// return ans; +// queue> q; +// vector ladder; +// string curEnd; +// q.push(vector{beginWord}); +// bool goDeep = true; +// int minLadderLen = wordList.size(); +// int lev = 1; +// while (!q.empty()) +// { +// ladder = q.front(); +// q.pop(); + +// if (ladder.size() >= minLadderLen) +// break; + +// if (ladder.size() > lev) +// { +// lev++; +// for (auto word : levDict) +// wordDict.erase(word); +// levDict.clear(); +// } + +// curEnd = ladder.back(); + +// if (onediff(curEnd, endWord)) +// { +// ladder.push_back(endWord); +// ans.push_back(ladder); +// if (goDeep) +// { +// minLadderLen = ladder.size(); +// goDeep = false; +// } +// } + +// for (int i = 0; i < curEnd.length(); i++) +// { +// char ch = curEnd[i]; +// for (int j = 0; j < 26; j++) +// { +// curEnd[i] = 'a' + j; +// if (wordDict.count(curEnd) == 1) +// { +// ladder.push_back(curEnd); +// q.push(ladder); +// ladder.pop_back(); +// levDict.push_back(curEnd); +// } +// } +// curEnd[i] = ch; +// } +// } + +// return ans; +// } + +// private: +// bool onediff(string a, string b) +// { +// int diffs = 0; +// for (int i = 0; i < b.length(); i++) +// { +// if (a[i] != b[i]) +// diffs++; +// } +// if (diffs == 1) +// return true; +// return false; +// } +// }; +// @lc code=end diff --git a/Week_03/G20200343030489/LeetCode_127_489.cpp b/Week_03/G20200343030489/LeetCode_127_489.cpp new file mode 100644 index 00000000..6ba63703 --- /dev/null +++ b/Week_03/G20200343030489/LeetCode_127_489.cpp @@ -0,0 +1,61 @@ +/* + * @lc app=leetcode.cn id=127 lang=cpp + * + * [127] 单词接龙 + */ + +// @lc code=start +class Solution +{ +public: + int ladderLength(string beginWord, string endWord, vector &wordList) + { + unordered_set dict(wordList.begin(), wordList.end()), head, tail, *phead, *ptail; + if (dict.find(endWord) == dict.end()) + return 0; + head.insert(beginWord); + tail.insert(endWord); + int ladder = 2; + while (!head.empty() && !tail.empty()) + { + if (head.size() < tail.size()) + { + phead = &head; + ptail = &tail; + } + else + { + phead = &tail; + ptail = &head; + } + unordered_set tmp; + for (auto it = phead->begin(); it != phead->end(); it++) + { + string word = *it; + for (int i = 0; i < word.size(); i++) + { + char t = word[i]; + for (int j = 0; j < 26; j++) + { + word[i] = 'a' + j; + if (ptail->find(word) != ptail->end()) + { + return ladder; + } + if (dict.find(word) != dict.end()) + { + tmp.insert(word); + dict.erase(word); + } + } + word[i] = t; + } + } + ladder++; + phead->swap(tmp); + } + return 0; + } +}; + +// @lc code=end \ No newline at end of file diff --git a/Week_03/G20200343030489/LeetCode_153_489.cpp b/Week_03/G20200343030489/LeetCode_153_489.cpp new file mode 100644 index 00000000..bd201aaa --- /dev/null +++ b/Week_03/G20200343030489/LeetCode_153_489.cpp @@ -0,0 +1,27 @@ +/* + * @lc app=leetcode.cn id=153 lang=cpp + * + * [153] 寻找旋转排序数组中的最小值 + */ + +// @lc code=start +class Solution +{ +public: + int findMin(vector &nums) + { + if(nums.back()>nums[0]) + return nums[0]; + int start=0,end=nums.size()-1; + while(start>1; + if(nums[mid]> &grid) + { + int row = grid.size(), col = row ? grid[0].size() : 0, islands = 0; + for (int i = 0; i < row; i++) + { + for (int j = 0; j < col; j++) + { + if (grid[i][j] == '1') + { + islands++; + dfs_(grid, i, j); + } + } + } + return islands; + } + void dfs_(vector> &grid, int i, int j) + { + int row = grid.size(), col = grid[0].size(); + if (i < 0 || i == row || j < 0 || j == col || grid[i][j] == '0') + { + return; + } + grid[i][j] = '0'; + dfs_(grid, i - 1, j); + dfs_(grid, i + 1, j); + dfs_(grid, i, j - 1); + dfs_(grid, i, j + 1); + } +}; +// class Solution +// { +// public: +// int numIslands(vector> &grid) +// { +// int row = grid.size(), col = row ? grid[0].size() : 0, islands = 0, offsets[] = {0, 1, 0, -1, 0}; +// for (int i = 0; i < row; i++) +// { +// for (int j = 0; j < col; j++) +// { +// if (grid[i][j] == '1') +// { +// islands++; +// grid[i][j] = '0'; +// queue> que; +// que.push({i, j}); +// while (!que.empty()) +// { +// pair p = que.front(); +// que.pop(); +// for (int k = 0; k < 4; k++) +// { +// int r = p.first + offsets[k], c = p.second + offsets[k + 1]; +// if (r >= 0 && r < row && c >= 0 && c < col && grid[r][c] == '1') +// { +// grid[r][c] = '0'; +// que.push({r, c}); +// } +// } +// } +// } +// } + +// } +// return islands; +// } +// }; +// @lc code=end diff --git a/Week_03/G20200343030489/LeetCode_33_489.cpp b/Week_03/G20200343030489/LeetCode_33_489.cpp new file mode 100644 index 00000000..2582dcc6 --- /dev/null +++ b/Week_03/G20200343030489/LeetCode_33_489.cpp @@ -0,0 +1,25 @@ +/* + * @lc app=leetcode.cn id=33 lang=cpp + * + * [33] 搜索旋转排序数组 + */ + +// @lc code=start +class Solution +{ +public: + int search(vector &nums, int target) + { + int start=0,end=nums.size()-1; + while(starttarget)^(nums[0]>nums[mid])^(target>nums[mid])) + start=mid+1; + else + end=mid; + + } + return start==end&&nums[start]==target?start:-1; + } +}; +// @lc code=end diff --git a/Week_03/G20200343030489/LeetCode_367_489.cpp b/Week_03/G20200343030489/LeetCode_367_489.cpp new file mode 100644 index 00000000..85d178d4 --- /dev/null +++ b/Week_03/G20200343030489/LeetCode_367_489.cpp @@ -0,0 +1,29 @@ +/* + * @lc app=leetcode.cn id=367 lang=cpp + * + * [367] 有效的完全平方数 + */ + +// @lc code=start +class Solution +{ +public: + bool isPerfectSquare(int num) + { + long long i = 0; + long long j = num / 2 + 1; + while (i <= j) + { + long long mid = (i + j) / 2; + long long res = mid * mid; + if (res == num) + return true; + else if (res < num) + i = mid + 1; + else + j = mid - 1; + } + return false; + } +}; +// @lc code=end diff --git a/Week_03/G20200343030489/LeetCode_455_489.cpp b/Week_03/G20200343030489/LeetCode_455_489.cpp new file mode 100644 index 00000000..171f19ef --- /dev/null +++ b/Week_03/G20200343030489/LeetCode_455_489.cpp @@ -0,0 +1,50 @@ +/* + * @lc app=leetcode.cn id=455 lang=cpp + * + * [455] 分发饼干 + */ + +// @lc code=start +// class Solution { +// public: +// int findContentChildren(vector& g, vector& s) { +// if(g.size()==0) +// return 0; +// sort(s.begin(),s.end()); +// sort(g.begin(),g.end()); +// int num=0; +// for (int i = 0; i < g.size(); i++) +// { +// for (int j = 0; j < s.size(); j++) +// { +// if(s[j]>=g[i]){ +// num++; +// s.erase(s.begin()+j); +// break; +// } +// } +// g.erase(g.begin()+i); +// i--; +// } +// return num; +// } +// }; +class Solution { +public: + int findContentChildren(vector& g, vector& s) { + if(g.size()==0) + return 0; + sort(s.begin(),s.end()); + sort(g.begin(),g.end()); + int child=0; + int cookie=0; + while(child &nums) + { + int count = 0, end = 0, maxPos = 0; + for (int i = 0; i < nums.size() - 1; i++) + { + maxPos = max(nums[i] + i, maxPos); + if (i == end) + { + end = maxPos; + count++; + } + } + return count; + } +}; +// @lc code=end diff --git a/Week_03/G20200343030489/LeetCode_515_489.cpp b/Week_03/G20200343030489/LeetCode_515_489.cpp new file mode 100644 index 00000000..b9ae3197 --- /dev/null +++ b/Week_03/G20200343030489/LeetCode_515_489.cpp @@ -0,0 +1,36 @@ +/* + * @lc app=leetcode.cn id=515 lang=cpp + * + * [515] 在每个树行中找最大值 + */ + +// @lc code=start +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Solution { +public: + vector largestValues(TreeNode* root) { + vector res; + dfs_(root,0,res); + return res; + } + void dfs_(TreeNode* root,int level, vector& res){ + if(!root) + return; + if(level==res.size()) + res.push_back(root->val); + else + res[level]=max(res[level],root->val); + dfs_(root->left,level+1,res); + dfs_(root->right,level+1,res); + } +}; +// @lc code=end + diff --git a/Week_03/G20200343030489/LeetCode_529_489.cpp b/Week_03/G20200343030489/LeetCode_529_489.cpp new file mode 100644 index 00000000..276d3437 --- /dev/null +++ b/Week_03/G20200343030489/LeetCode_529_489.cpp @@ -0,0 +1,53 @@ +/* + * @lc app=leetcode.cn id=529 lang=cpp + * + * [529] 扫雷游戏 + */ + +// @lc code=start +class Solution +{ +public: + vector> updateBoard(vector> &board, vector &click) + { + if (board[click[0]][click[1]] == 'M') + { + board[click[0]][click[1]] = 'X'; + return board; + } + dfs_(board, click[0], click[1]); + return board; + } + + void dfs_(vector> &board, int x, int y) + { + if (!judge(x, y, board)) + return; + vector> v = {{1, -1}, {1, 0}, {1, 1}, {-1, -1}, {-1, 0}, {-1, 1}, {0, -1}, {0, 1}}; + int count = 0; + if (board[x][y] == 'E') + { + for (int i = 0; i < 8; i++) + { + if (judge(x + v[i][0], y + v[i][1], board) && board[x + v[i][0]][y + v[i][1]] == 'M') + count++; + } + if (count > 0) + board[x][y] = '0' + count; + else + { + board[x][y] = 'B'; + for (int i = 0; i < 8; i++) + { + dfs_(board, x + v[i][0], y + v[i][1]); + } + } + } + } + + bool judge(int x, int y, vector> board) + { + return x >= 0 && x < board.size() && y >= 0 && y < board[0].size(); + } +}; +// @lc code=end diff --git a/Week_03/G20200343030489/LeetCode_55_489.cpp b/Week_03/G20200343030489/LeetCode_55_489.cpp new file mode 100644 index 00000000..e8bf56f2 --- /dev/null +++ b/Week_03/G20200343030489/LeetCode_55_489.cpp @@ -0,0 +1,25 @@ +/* + * @lc app=leetcode.cn id=55 lang=cpp + * + * [55] 跳跃游戏 + */ + +// @lc code=start +class Solution +{ +public: + bool canJump(vector &nums) + { + int k = 0; + for (int i = 0; i < nums.size(); i++) + { + if (i > k) + return false; + k = max(k, i + nums[i]); + if (k >= nums.size() - 1) + break; + } + return true; + } +}; +// @lc code=end diff --git a/Week_03/G20200343030489/LeetCode_69_489.cpp b/Week_03/G20200343030489/LeetCode_69_489.cpp new file mode 100644 index 00000000..783810b6 --- /dev/null +++ b/Week_03/G20200343030489/LeetCode_69_489.cpp @@ -0,0 +1,43 @@ +/* + * @lc app=leetcode.cn id=69 lang=cpp + * + * [69] x 的平方根 + */ + +// @lc code=start +class Solution { +public: + int mySqrt(int x) { + long long i=0; + long long j=x/2+1; + while (i<=j) + { + long long mid=(i+j)/2; + long long res=mid*mid; + if(res==x) + return mid; + else if(res>& matrix, int target) { + if(matrix.empty()||matrix[0].empty()) + return 0; + int left=0,right=matrix.size()*matrix[0].size()-1; + int n=matrix[0].size(); + while(left<=right){ + int mid=left+((right-left)>>1); + if(matrix[mid/n][mid%n]>target) + right=mid-1; + else if(matrix[mid/n][mid%n] &bills) + { + int count5 = 0, count10 = 0; + for (int i = 0; i < bills.size(); i++) + { + if (bills[i] == 5) + count5++; + else if (bills[i] == 10 && count5 > 0) + { + count5--; + count10++; + } + else if (bills[i] == 20 && count10 > 0 && count5 > 0) + { + count10--; + count5--; + } + else if (bills[i] == 20 && count10 == 0 && count5 > 2) + count5 = count5 - 3; + else + return false; + } + return true; + } +}; +// @lc code=end diff --git a/Week_03/G20200343030489/LeetCode_874_489.cpp b/Week_03/G20200343030489/LeetCode_874_489.cpp new file mode 100644 index 00000000..168871f4 --- /dev/null +++ b/Week_03/G20200343030489/LeetCode_874_489.cpp @@ -0,0 +1,48 @@ +/* + * @lc app=leetcode.cn id=874 lang=cpp + * + * [874] 模拟行走机器人 + */ + +// @lc code=start +class Solution +{ +public: + int robotSim(vector &commands, vector> &obstacles) + { + int dx[4] = {0, 1, 0, -1}; + int dy[4] = {1, 0, -1, 0}; + int x = 0, y = 0; + int di = 0; + + set> obstacleSet; + for (vector obstacle : obstacles) + obstacleSet.insert(make_pair(obstacle[0], obstacle[1])); + + int ans = 0; + for (int cmd : commands) + { + if (cmd == -2) + di = (di + 3) % 4; + else if (cmd == -1) + di = (di + 1) % 4; + else + { + for (int k = 0; k < cmd; ++k) + { + int nx = x + dx[di]; + int ny = y + dy[di]; + if (obstacleSet.find(make_pair(nx, ny)) == obstacleSet.end()) + { + x = nx; + y = ny; + ans = max(ans, x * x + y * y); + } + } + } + } + return ans; + } +}; + +// @lc code=end diff --git a/Week_03/G20200343030491/LeetCode_122_491.py b/Week_03/G20200343030491/LeetCode_122_491.py new file mode 100644 index 00000000..e84660af --- /dev/null +++ b/Week_03/G20200343030491/LeetCode_122_491.py @@ -0,0 +1,8 @@ +class Solution: + def maxProfit(self, prices: List[int]) -> int: + res = 0 + for i in range(len(prices)-1): + if prices[i] <= prices[i+1]: + res += prices[i+1] - prices[i] + + return res \ No newline at end of file diff --git a/Week_03/G20200343030491/LeetCode_127_491.py b/Week_03/G20200343030491/LeetCode_127_491.py new file mode 100644 index 00000000..8a8b8649 --- /dev/null +++ b/Week_03/G20200343030491/LeetCode_127_491.py @@ -0,0 +1,27 @@ +from collections import defaultdict, deque +class Solution: + def ladderLength(self, beginWord: str, endWord: str, wordList: List[str]) -> int: + size = len(beginWord) + general_dic = defaultdict(list) + + for word in wordList: + for i in range(size): + general_dic[word[:i]+'*'+word[i+1:]].append(word) + + visited = set() + visited.add(beginWord) + q = deque() + q.append((beginWord,1)) + + while q: + cur,lev = q.popleft() + for i in range(size): + for distaneOne in general_dic[cur[:i]+'*'+cur[i+1:]]: + if endWord == distaneOne: + return lev + 1 + else: + if distaneOne not in visited: + visited.add(distaneOne) + q.append((distaneOne,lev + 1)) + + return 0 \ No newline at end of file diff --git a/Week_03/G20200343030491/LeetCode_153_491.py b/Week_03/G20200343030491/LeetCode_153_491.py new file mode 100644 index 00000000..61873552 --- /dev/null +++ b/Week_03/G20200343030491/LeetCode_153_491.py @@ -0,0 +1,12 @@ +class Solution: + def findMin(self, nums: List[int]) -> int: + l, r = 0, len(nums)-1 + if nums[0]>1 + if nums[mid] >= nums[0]: + l = mid + 1 + else: + r = mid + return nums[l] \ No newline at end of file diff --git a/Week_03/G20200343030491/LeetCode_200_491.py b/Week_03/G20200343030491/LeetCode_200_491.py new file mode 100644 index 00000000..ded94158 --- /dev/null +++ b/Week_03/G20200343030491/LeetCode_200_491.py @@ -0,0 +1,85 @@ +class Solution: + def numIslands(self, grid: List[List[str]]) -> int: + counter = 0 + + def dfs(row,col): + if row<0 or row>len(grid)-1 or col<0 or col>len(grid[0])-1: + return + if grid[row][col] == '0': + return + else: + grid[row][col] = '0' + dfs(row-1,col) + dfs(row+1,col) + dfs(row,col-1) + dfs(row,col+1) + + for row, line in enumerate(grid): + for col, value in enumerate(line): + if value=='1': + counter +=1 + dfs(row, col) + + return counter + + +class Solution: + def numIslands(self, grid: List[List[str]]) -> int: + counter = 0 + + def dfs(row,col): + r = len(grid) + c = len(grid[0]) + grid[row][col] = '0' + if row>0 and grid[row-1][col]=='1': + dfs(row-1,col) + if row0 and grid[row][col-1]=='1': + dfs(row,col-1) + if col int: + counter = 0 + + def bfs(row,col): + q = deque() + q.append((row,col)) + while q: + row,col = q.popleft() + + if row>0 and grid[row-1][col]=='1': + grid[row-1][col] = '0' + q.append((row-1,col)) + if row0 and grid[row][col-1]=='1': + grid[row][col-1] = '0' + q.append((row,col-1)) + if col int: + if not nums: + return -1 + left, right = 0, len(nums)-1 + + while left<=right: + mid = (left+right)>>1 + + if nums[mid]==target: + return mid + elif nums[mid] < nums[right]: + if nums[mid] < target and target <= nums[right]: + left = mid + 1 + else: + right = mid - 1 + else: + if nums[left] <= target and target < nums[mid]: + right = mid -1 + else: + left = mid + 1 + return -1 \ No newline at end of file diff --git a/Week_03/G20200343030491/LeetCode_455_491.py b/Week_03/G20200343030491/LeetCode_455_491.py new file mode 100644 index 00000000..1cb36225 --- /dev/null +++ b/Week_03/G20200343030491/LeetCode_455_491.py @@ -0,0 +1,16 @@ +class Solution: + def findContentChildren(self, g: List[int], s: List[int]) -> int: + + g.sort(reverse=True) + s.sort(reverse=True) + counter = 0 + + while g and s: + if s[-1]>=g[-1]: + counter += 1 + g.pop() + s.pop() + else: + s.pop() + + return counter \ No newline at end of file diff --git a/Week_03/G20200343030491/LeetCode_45_491.py b/Week_03/G20200343030491/LeetCode_45_491.py new file mode 100644 index 00000000..cef40726 --- /dev/null +++ b/Week_03/G20200343030491/LeetCode_45_491.py @@ -0,0 +1,25 @@ +class Solution: + def jump(self, nums: List[int]) -> int: + end, maxPos, step = 0, 0, 0 + + for i in range(len(nums)-1): + maxPos = max(maxPos, i+nums[i]) + if i == end: + end = maxPos + step += 1 + + return step + +class Solution: + def jump(self, nums: List[int]) -> int: + step = 0 + pos = len(nums)-1 + while pos>0: + for i in range(len(nums)): + if nums[i] + i >= pos: + pos = i + step += 1 + break + + return step + \ No newline at end of file diff --git a/Week_03/G20200343030491/LeetCode_529_491.py b/Week_03/G20200343030491/LeetCode_529_491.py new file mode 100644 index 00000000..8af4e612 --- /dev/null +++ b/Week_03/G20200343030491/LeetCode_529_491.py @@ -0,0 +1,42 @@ +class Solution: + + + def updateBoard(self, board: List[List[str]], click: List[int]) -> List[List[str]]: + + row, col = click[0], click[1] + + + + dx = [-1, -1, -1, 0, 1, 1, 1, 0] + dy = [-1, 0, 1, 1, 1, 0, -1, -1] + + + if board[row][col] == 'M': + board[row][col] = 'X' + return board + + visited = set() + + def adjacent(row, col): + mine = 0 + for k in range(len(dx)): + if row+dx[k]>=0 and row+dx[k]=0 and col+dy[k]=0 and row+dx[k]=0 and col+dy[k] bool: + k = 0 + for i in range(len(nums)): + if i > k: return False + k = max(k, i+nums[i]) + + return True + +class Solution: + def canJump(self, nums: List[int]) -> bool: + + lastPos = len(nums)-1 + for i in range(lastPos,-1,-1): + if (i+nums[i])>=lastPos: + lastPos = i + + return True if lastPos == 0 else False \ No newline at end of file diff --git a/Week_03/G20200343030491/LeetCode_74_491.py b/Week_03/G20200343030491/LeetCode_74_491.py new file mode 100644 index 00000000..1aea85b5 --- /dev/null +++ b/Week_03/G20200343030491/LeetCode_74_491.py @@ -0,0 +1,41 @@ +class Solution: + def searchMatrix(self, matrix: List[List[int]], target: int) -> bool: + if not matrix: + return False + tmp = [] + for i in matrix: + tmp.extend(i) + + left, right = 0, len(tmp)-1 + + while left <= right: + mid = (left + right)>>1 + if tmp[mid] == target: + return True + elif tmp[mid] > target: + right = mid - 1 + else: + left = mid + 1 + return False + + +class Solution: + def searchMatrix(self, matrix: List[List[int]], target: int) -> bool: + m = len(matrix) + if m == 0: + return False + n = len(matrix[0]) + + left, right = 0, m*n-1 + + while left<=right: + mid = (left+right)>>1 + val = matrix[mid//n][mid%n] + + if val == target: return True + elif val > target: + right = mid - 1 + else: + left = mid + 1 + + return False \ No newline at end of file diff --git a/Week_03/G20200343030491/LeetCode_860_491.py b/Week_03/G20200343030491/LeetCode_860_491.py new file mode 100644 index 00000000..fb17002a --- /dev/null +++ b/Week_03/G20200343030491/LeetCode_860_491.py @@ -0,0 +1,48 @@ +class Solution: + def lemonadeChange(self, bills: List[int]) -> bool: + + dic = { + '5' : 0, + '10' : 0, + } + + for i in bills: + if i==5: + dic['5'] += 1 + if i==10: + dic['10'] += 1 + dic['5'] -= 1 + if dic['5'] < 0: + return False + if i==20: + if dic['10'] >= 1: + dic['10'] -= 1 + dic['5'] -=1 + else: + dic['5'] -= 3 + if dic['5'] < 0: + return False + + return True + + +class Solution: + def lemonadeChange(self, bills: List[int]) -> bool: + + five, ten = 0, 0 + + for i in bills: + if i==5: five += 1 + elif i==10: + five -= 1 + ten += 1 + else: + if ten>0: + ten -= 1 + five -= 1 + else: + five -= 3 + + if five < 0: return False + + return True \ No newline at end of file diff --git a/Week_03/G20200343030491/LeetCode_874_491.py b/Week_03/G20200343030491/LeetCode_874_491.py new file mode 100644 index 00000000..2d076494 --- /dev/null +++ b/Week_03/G20200343030491/LeetCode_874_491.py @@ -0,0 +1,22 @@ +class Solution: + def robotSim(self, commands: List[int], obstacles: List[List[int]]) -> int: + dx = [0, 1, 0, -1] + dy = [1, 0, -1, 0] + + x, y, direction, ans = 0, 0, 0, 0 + obstacleSet = set(map(tuple, obstacles)) + + for cmd in commands: + + if cmd == -2: + direction = (direction - 1) % 4 + elif cmd == -1: + direction = (direction + 1) % 4 + else: + for _ in range(cmd): + if (x+dx[direction], y+dy[direction]) not in obstacleSet: + x += dx[direction] + y += dy[direction] + ans = max(ans, x*x + y*y) + + return ans \ No newline at end of file diff --git a/Week_03/G20200343030493/Nqueen_51.java b/Week_03/G20200343030493/Nqueen_51.java new file mode 100644 index 00000000..6bcb1b5a --- /dev/null +++ b/Week_03/G20200343030493/Nqueen_51.java @@ -0,0 +1,46 @@ +public class Solution { + public List> solveNQueens(int n) { + char[][] board = new char[n][n]; + for(int i = 0; i < n; i++) + for(int j = 0; j < n; j++) + board[i][j] = '.'; + List> res = new ArrayList>(); + dfs(board, 0, res); + return res; + } + + private void dfs(char[][] board, int colIndex, List> res) { + if(colIndex == board.length) { + res.add(construct(board)); + return; + } + + for(int i = 0; i < board.length; i++) { + if(validate(board, i, colIndex)) { + board[i][colIndex] = 'Q'; + dfs(board, colIndex + 1, res); + board[i][colIndex] = '.'; + } + } + } + + private boolean validate(char[][] board, int x, int y) { + for(int i = 0; i < board.length; i++) { + for(int j = 0; j < y; j++) { + if(board[i][j] == 'Q' && (x + j == y + i || x + y == i + j || x == i)) + return false; + } + } + + return true; + } + + private List construct(char[][] board) { + List res = new LinkedList(); + for(int i = 0; i < board.length; i++) { + String s = new String(board[i]); + res.add(s); + } + return res; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030493/Pow_50.java b/Week_03/G20200343030493/Pow_50.java new file mode 100644 index 00000000..fb7688c1 --- /dev/null +++ b/Week_03/G20200343030493/Pow_50.java @@ -0,0 +1,56 @@ +//实现 pow(x, n) ,即计算 x 的 n 次幂函数。 +// +// 示例 1: +// +// 输入: 2.00000, 10 +//输出: 1024.00000 +// +// +// 示例 2: +// +// 输入: 2.10000, 3 +//输出: 9.26100 +// +// +// 示例 3: +// +// 输入: 2.00000, -2 +//输出: 0.25000 +//解释: 2-2 = 1/22 = 1/4 = 0.25 +// +// 说明: +// +// +// -100.0 < x < 100.0 +// n 是 32 位有符号整数,其数值范围是 [−231, 231 − 1] 。 +// +// Related Topics 数学 二分查找 + + +//leetcode submit region begin(Prohibit modification and deletion) +class Solution { + private double fastPow(double x, long n) { + if (n == 0) { + return 1.0; + } + double half = fastPow(x, n/2); + if ( n % 2 == 0) { + return half * half; + }else { + return half * half * x; + } + } + + public double myPow(double x, int n) { + // 计算 x 的 n 次幂 + // 2 分治方法 + //template: terminator, process (split your big problem), drill down (subproblems),merge(subresult),reverse states + long N = n; + if ( N < 0 ) { + x = 1 / x; + N = -N; + } + return fastPow(x,N); + } +} +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week_03/G20200343030493/Solution.java b/Week_03/G20200343030493/Solution.java new file mode 100644 index 00000000..e69de29b diff --git a/Week_03/G20200343030493/cookie_455.java b/Week_03/G20200343030493/cookie_455.java new file mode 100644 index 00000000..0727cca7 --- /dev/null +++ b/Week_03/G20200343030493/cookie_455.java @@ -0,0 +1,55 @@ +//假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。对每个孩子 i ,都有一个胃口值 gi ,这是能让孩子们满足胃口的饼干 +//的最小尺寸;并且每块饼干 j ,都有一个尺寸 sj 。如果 sj >= gi ,我们可以将这个饼干 j 分配给孩子 i ,这个孩子会得到满足。你的目标是尽可能满 +//足越多数量的孩子,并输出这个最大数值。 +// +// 注意: +// +// 你可以假设胃口值为正。 +//一个小朋友最多只能拥有一块饼干。 +// +// 示例 1: +// +// +//输入: [1,2,3], [1,1] +// +//输出: 1 +// +//解释: +//你有三个孩子和两块小饼干,3个孩子的胃口值分别是:1,2,3。 +//虽然你有两块小饼干,由于他们的尺寸都是1,你只能让胃口值是1的孩子满足。 +//所以你应该输出1。 +// +// +// 示例 2: +// +// +//输入: [1,2], [1,2,3] +// +//输出: 2 +// +//解释: +//你有两个孩子和三块小饼干,2个孩子的胃口值分别是1,2。 +//你拥有的饼干数量和尺寸都足以让所有孩子满足。 +//所以你应该输出2. +// +// Related Topics 贪心算法 + + +//leetcode submit region begin(Prohibit modification and deletion) +class Solution { + public int findContentChildren(int[] g, int[] s) { + if (g == null || s == null) { + return 0; + } + Arrays.sort(g); + Arrays.sort(s); + int gi = 0; + for (int si = 0; gi < g.length && si < s.length; si++ ) { + if (g[gi] <= s[si]) { + gi ++; + } + } + return gi; + } +} +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week_03/G20200343030493/level_order_travesal_102.java b/Week_03/G20200343030493/level_order_travesal_102.java new file mode 100644 index 00000000..f09dc801 --- /dev/null +++ b/Week_03/G20200343030493/level_order_travesal_102.java @@ -0,0 +1,59 @@ +//给定一个二叉树,返回其按层次遍历的节点值。 (即逐层地,从左到右访问所有节点)。 +// +// 例如: +//给定二叉树: [3,9,20,null,null,15,7], +// +// 3 +// / \ +// 9 20 +// / \ +// 15 7 +// +// +// 返回其层次遍历结果: +// +// [ +// [3], +// [9,20], +// [15,7] +//] +// +// Related Topics 树 广度优先搜索 + + +//leetcode submit region begin(Prohibit modification and deletion) +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; } + * } + */ +class Solution { + public List> levelOrder(TreeNode root) { + List> res = new ArrayList<>(); + if (root == null) return res; + Queue queue = new LinkedList<>(); + queue.add(root); + while (!queue.isEmpty()) { + List level = new ArrayList<>(); + int cnt = queue.size(); + for (int i = 0; i < cnt; i++) { + TreeNode node = queue.poll(); + level.add(node.val); + if (node.left != null) { + queue.add(node.left); + } + if (node.right != null) { + queue.add(node.right); + } + } + res.add(level); + } + return res; + + } +} +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week_03/G20200343030493/number_of_island_20.java b/Week_03/G20200343030493/number_of_island_20.java new file mode 100644 index 00000000..b19b7750 --- /dev/null +++ b/Week_03/G20200343030493/number_of_island_20.java @@ -0,0 +1,94 @@ +//给定一个由 '1'(陆地)和 '0'(水)组成的的二维网格,计算岛屿的数量。一个岛被水包围,并且它是通过水平方向或垂直方向上相邻的陆地连接而成的。你可以假设 +//网格的四个边均被水包围。 +// +// 示例 1: +// +// 输入: +//11110 +//11010 +//11000 +//00000 +// +//输出: 1 +// +// +// 示例 2: +// +// 输入: +//11000 +//11000 +//00100 +//00011 +// +//输出: 3 +// +// Related Topics 深度优先搜索 广度优先搜索 并查集 + + +//leetcode submit region begin(Prohibit modification and deletion) +class Solution { + int y; // The height of the given grid + int x; // The width of the given grid + char[][] g; // The given grid, stored to reduce recursion memory usage + + /** + * Given a 2d grid map of '1's (land) and '0's (water), + * count the number of islands. + * + * This method approaches the problem as one of depth-first connected + * components search + * @param grid, the given grid. + * @return the number of islands. + */ + public int numIslands(char[][] grid) { + // Store the given grid + // This prevents having to make copies during recursion + g = grid; + + // Our count to return + int c = 0; + + // Dimensions of the given graph + y = g.length; + if (y == 0) return 0; + x = g[0].length; + + // Iterate over the entire given grid + for (int i = 0; i < y; i++) { + for (int j = 0; j < x; j++) { + if (g[i][j] == '1') { + dfs(i, j); + c++; + } + } + } + return c; + } + + /** + * Marks the given site as visited, then checks adjacent sites. + * + * Or, Marks the given site as water, if land, then checks adjacent sites. + * + * Or, Given one coordinate (i,j) of an island, obliterates the island + * from the given grid, so that it is not counted again. + * + * @param i, the row index of the given grid + * @param j, the column index of the given grid + */ + private void dfs(int i, int j) { + + // Check for invalid indices and for sites that aren't land + if (i < 0 || i >= y || j < 0 || j >= x || g[i][j] != '1') return; + + // Mark the site as visited + g[i][j] = '0'; + + // Check all adjacent sites + dfs(i + 1, j); + dfs(i - 1, j); + dfs(i, j + 1); + dfs(i, j - 1); + } +} +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week_03/G20200343030493/search_in_rotated_array_33.java b/Week_03/G20200343030493/search_in_rotated_array_33.java new file mode 100644 index 00000000..dff46851 --- /dev/null +++ b/Week_03/G20200343030493/search_in_rotated_array_33.java @@ -0,0 +1,58 @@ +//假设按照升序排序的数组在预先未知的某个点上进行了旋转。 +// +// ( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。 +// +// 搜索一个给定的目标值,如果数组中存在这个目标值,则返回它的索引,否则返回 -1 。 +// +// 你可以假设数组中不存在重复的元素。 +// +// 你的算法时间复杂度必须是 O(log n) 级别。 +// +// 示例 1: +// +// 输入: nums = [4,5,6,7,0,1,2], target = 0 +//输出: 4 +// +// +// 示例 2: +// +// 输入: nums = [4,5,6,7,0,1,2], target = 3 +//输出: -1 +// Related Topics 数组 二分查找 + + +//leetcode submit region begin(Prohibit modification and deletion) +class Solution { + public int search(int[] nums, int target) { + if (nums == null || nums.length == 0) { + return -1; + } + int start = 0; + int end = nums.length - 1; + int mid; + while (start <= end) { + mid = start + (end - start) / 2; + if (nums[mid] == target) { + return mid; + } + //前半部分有序,注意此处用小于等于 + if (nums[start] <= nums[mid]) { + //target在前半部分 + if (target >= nums[start] && target < nums[mid]) { + end = mid - 1; + } else { + start = mid + 1; + } + } else { + if (target <= nums[end] && target > nums[mid]) { + start = mid + 1; + } else { + end = mid - 1; + } + } + + } + return -1; + } +} +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week_03/G20200343030493/stock2_122.java b/Week_03/G20200343030493/stock2_122.java new file mode 100644 index 00000000..193d6e12 --- /dev/null +++ b/Week_03/G20200343030493/stock2_122.java @@ -0,0 +1,44 @@ +//给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。 +// +// 设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。 +// +// 注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。 +// +// 示例 1: +// +// 输入: [7,1,5,3,6,4] +//输出: 7 +//解释: 在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。 +//  随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6-3 = 3 。 +// +// +// 示例 2: +// +// 输入: [1,2,3,4,5] +//输出: 4 +//解释: 在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。 +//  注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。 +//  因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。 +// +// +// 示例 3: +// +// 输入: [7,6,4,3,1] +//输出: 0 +//解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。 +// Related Topics 贪心算法 数组 + + +//leetcode submit region begin(Prohibit modification and deletion) +class Solution { + public int maxProfit(int[] prices) { + int maxprofit = 0; + for (int i = 1;i < prices.length; i++) { + if (prices[i] > prices[i-1]) { + maxprofit += prices[i] - prices[i-1]; + } + } + return maxprofit; + } +} +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week_03/G20200343030493/xqrt_69.java b/Week_03/G20200343030493/xqrt_69.java new file mode 100644 index 00000000..d6fa139c --- /dev/null +++ b/Week_03/G20200343030493/xqrt_69.java @@ -0,0 +1,48 @@ +//实现 int sqrt(int x) 函数。 +// +// 计算并返回 x 的平方根,其中 x 是非负整数。 +// +// 由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去。 +// +// 示例 1: +// +// 输入: 4 +//输出: 2 +// +// +// 示例 2: +// +// 输入: 8 +//输出: 2 +//说明: 8 的平方根是 2.82842..., +//  由于返回类型是整数,小数部分将被舍去。 +// +// Related Topics 数学 二分查找 + + +//leetcode submit region begin(Prohibit modification and deletion) +class Solution { + public int mySqrt(int x) { + // 二分查找 单调递增 有上下界 + if (x == 0 || x == 1) { + return x; + } + // 写左界和右界 + long left = 1, right = x; + // 写中间的数 + long mid = 1; + // 套模板 + while (left <= right) { + // 防止越界 + mid = left + (right - left) /2; + if (mid * mid > x) { + right = mid - 1; + }else { + left = mid + 1; + } + } + return (int) right; + + } +} +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week_03/G20200343030497/LeetCode_55_497.cpp b/Week_03/G20200343030497/LeetCode_55_497.cpp new file mode 100644 index 00000000..865ad8c8 --- /dev/null +++ b/Week_03/G20200343030497/LeetCode_55_497.cpp @@ -0,0 +1,35 @@ +/** + * 55. 跳跃游戏 + * https://leetcode-cn.com/problems/jump-game/ + */ + + +class Solution { +public: + // 贪心算法,从左向右每次 + // 时间复杂度:O(n) + // 空间复杂度:O(1) + bool canJump(vector& nums) { + int maxIdx=0; // 记录可跳的最远下标 + for(int i=0; i maxIdx) return false; // 走不到该下标 + maxIdx = max(maxIdx, i + nums[i]); + } + + return true; + } + + // 贪心算法,从右向左遍历 + // 时间复杂度:O(n) + // 空间复杂度:O(1) + bool canJump1(vector& nums) { + int lastIndex = nums.size()-1; + for(int i=lastIndex; i>=0; i--){ + if(i + nums[i] >= lastIndex){ + lastIndex = i; + } + } + + return lastIndex == 0; + } +}; diff --git a/Week_03/G20200343030497/LeetCode_74_497.cpp b/Week_03/G20200343030497/LeetCode_74_497.cpp new file mode 100644 index 00000000..34a3cac2 --- /dev/null +++ b/Week_03/G20200343030497/LeetCode_74_497.cpp @@ -0,0 +1,35 @@ +/** + * 74. 搜索二维矩阵 + * https://leetcode-cn.com/problems/search-a-2d-matrix/ + * + */ + + +class Solution { +public: + // 二分查找 + // 时间复杂度:O(log(m*n)) + // 空间复杂度:O(1) + bool searchMatrix(vector>& matrix, int target) { + if(matrix.empty() || matrix[0].empty()){ + return false; + } + + int left = 0, right = matrix.size() * matrix[0].size() -1; + int n = matrix[0].size(); + int pivotIdx; + while(left <= right){ + pivotIdx = (left + right) / 2; + + if(target == matrix[pivotIdx / n][pivotIdx % n]){ + return true; + }else if(target < matrix[pivotIdx / n][pivotIdx % n]){ + right = pivotIdx - 1; + } else { + left = pivotIdx + 1; + } + } + + return false; + } +}; \ No newline at end of file diff --git a/Week_03/G20200343030499/LeetCode_122_499.java b/Week_03/G20200343030499/LeetCode_122_499.java new file mode 100644 index 00000000..e87b6cfd --- /dev/null +++ b/Week_03/G20200343030499/LeetCode_122_499.java @@ -0,0 +1,23 @@ +/* + * @lc app=leetcode id=122 lang=java + * + * [122] Best Time to Buy and Sell Stock II + */ + +// @lc code=start +class Solution { + public int maxProfit(int[] prices) { + if (prices == null || prices.length <= 1) { + return 0; + } + + int result = 0; + for (int i = 1; i < prices.length; i++) { + if (prices[i - 1] < prices[i]) { + result += prices[i] - prices[i - 1]; + } + } + return result; + } +} +// @lc code=end diff --git a/Week_03/G20200343030499/LeetCode_455_499.java b/Week_03/G20200343030499/LeetCode_455_499.java new file mode 100644 index 00000000..aac56508 --- /dev/null +++ b/Week_03/G20200343030499/LeetCode_455_499.java @@ -0,0 +1,27 @@ +/* + * @lc app=leetcode id=455 lang=java + * + * [455] Assign Cookies + */ + +// @lc code=start +class Solution { + public int findContentChildren(int[] g, int[] s) { + Arrays.sort(g); + Arrays.sort(s); + int result = 0; + int gp = 0; + int sp = 0; + while (gp < g.length && sp < s.length) { + if (s[sp] >= g[gp]) { + result++; + sp++; + gp++; + continue; + } + sp++; + } + return result; + } +} +// @lc code=end diff --git a/Week_03/G20200343030499/LeetCode_860_499.java b/Week_03/G20200343030499/LeetCode_860_499.java new file mode 100644 index 00000000..ec4a375d --- /dev/null +++ b/Week_03/G20200343030499/LeetCode_860_499.java @@ -0,0 +1,38 @@ +/* + * @lc app=leetcode id=860 lang=java + * + * [860] Lemonade Change + */ + +// @lc code=start +class Solution { + public boolean lemonadeChange(int[] bills) { + int fives = 0; + int tens = 0; + // int twenties = 0; 不用跟踪20的数量,因为退款时不会用到 + for (int bill : bills) { + switch (bill) { + case 5: + fives++; + break; + case 10: + tens++; + fives--; + break; + case 20: + if (tens > 0 && fives > 0) { + tens--; + fives--; + } else { + fives -= 3; + } + break; + } + if (fives < 0 || tens < 0) { + return false; + } + } + return true; + } +} +// @lc code=end diff --git a/Week_03/G20200343030499/LeetCode_874_499.java b/Week_03/G20200343030499/LeetCode_874_499.java new file mode 100644 index 00000000..69921091 --- /dev/null +++ b/Week_03/G20200343030499/LeetCode_874_499.java @@ -0,0 +1,39 @@ +/* + * @lc app=leetcode id=874 lang=java + * + * [874] Walking Robot Simulation + */ + +// @lc code=start +class Solution { + public int robotSim(int[] commands, int[][] obstacles) { + int[][] directions = new int[][] { { 0, 1 }, { -1, 0 }, { 0, -1 }, { 1, 0 } }; + int direction = 0; + int[] endPoint = new int[2]; + int result = 0; + Set obstacleSet = new HashSet<>(); + for (int[] obstacle : obstacles) { + obstacleSet.add(((long) obstacle[0] + 90000) * 60000 + (long) obstacle[1] + 90000); + } + + for (int command : commands) { + if (command == -1) { + direction = (direction + 3) % 4; + } else if (command == -2) { + direction = (direction + 1) % 4; + } else { + int steps = command; + while (steps-- > 0) { + int nextEndPointX = endPoint[0] + directions[direction][0]; + int nextEndPointY = endPoint[1] + directions[direction][1]; + if (!obstacleSet.contains(((long) nextEndPointX + 90000) * 60000 + (long) nextEndPointY + 90000)) { + endPoint = new int[] { nextEndPointX, nextEndPointY }; + } + result = Math.max(result, endPoint[0] * endPoint[0] + endPoint[1] * endPoint[1]); + } + } + } + return result; + } +} +// @lc code=end diff --git a/Week_03/G20200343030501/LeetCode_122_501.go b/Week_03/G20200343030501/LeetCode_122_501.go new file mode 100644 index 00000000..bcc10666 --- /dev/null +++ b/Week_03/G20200343030501/LeetCode_122_501.go @@ -0,0 +1,24 @@ +package G20200343030501 + +func maxProfit(prices []int) int { + sum := 0 + length := len(prices) + lowerIndex := 0 + upperIndex := 0 + counted := true + for index := 0; index < length; index++ { + if prices[index] >= prices[upperIndex] { + upperIndex = index + counted = false + } else { + sum += prices[upperIndex] - prices[lowerIndex] + lowerIndex = index + upperIndex = index + counted = true + } + } + if !counted { + sum += prices[upperIndex] - prices[lowerIndex] + } + return sum +} \ No newline at end of file diff --git a/Week_03/G20200343030501/LeetCode_200_501.go b/Week_03/G20200343030501/LeetCode_200_501.go new file mode 100644 index 00000000..8c3e366b --- /dev/null +++ b/Week_03/G20200343030501/LeetCode_200_501.go @@ -0,0 +1,35 @@ +package G20200343030501 + +func numIslands(grid [][]byte) int { + rowLength := len(grid) + if rowLength == 0 { + return 0 + } + colLength := len(grid[0]) + count := 0 + + for rowIndex := 0; rowIndex < rowLength; rowIndex++ { + for colIndex := 0; colIndex < colLength; colIndex++ { + if (int)(grid[rowIndex][colIndex]) == '1' { + clearToZero(grid, rowIndex, colIndex) + count += 1 + } + } + } + return count +} + +func clearToZero(grid [][]byte, rowIndex int, colIndex int) { + rowLength := len(grid) + colLength := len(grid[0]) + if rowIndex < 0 || colIndex < 0 || + rowIndex >= rowLength || colIndex >= colLength || + grid[rowIndex][colIndex] == '0' { + return + } + grid[rowIndex][colIndex] = '0' + clearToZero(grid, rowIndex - 1, colIndex) + clearToZero(grid, rowIndex + 1, colIndex) + clearToZero(grid, rowIndex, colIndex - 1) + clearToZero(grid, rowIndex, colIndex + 1) +} \ No newline at end of file diff --git a/Week_03/G20200343030503/LeetCode_122_503.java b/Week_03/G20200343030503/LeetCode_122_503.java new file mode 100644 index 00000000..9bbaa4cb --- /dev/null +++ b/Week_03/G20200343030503/LeetCode_122_503.java @@ -0,0 +1,13 @@ +class Solution { + public int maxProfit(int[] prices) { + int res = 0; //存放最大利润 + int len = prices.length; + for (int i = 0; i < len - 1; i++) { + int profit = prices[i+1] - prices[i]; + if (profit > 0) { + res += profit; + } + } + return res; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030503/LeetCode_17_503.java b/Week_03/G20200343030503/LeetCode_17_503.java new file mode 100644 index 00000000..5f07fd09 --- /dev/null +++ b/Week_03/G20200343030503/LeetCode_17_503.java @@ -0,0 +1,57 @@ +/** + * 思路 + * 1. 获取第 i 位数字。 + * 2. 获取第 i 位数字对应的各个字母 lettersletters。 + * 3. 选择 lettersletters 的第 j 位字母。 + * 4. 进入新的递归。 + * 5. 递归完成,将组合字符串添加进结果集。 + * 6. 撤销 lettersletters 的第 j 位字母。 + */ +class Solution { + public List letterCombinations(String digits) { + List result = new ArrayList<>(); + Map map = new HashMap(); + map.put("2","abc"); + map.put("3","def"); + map.put("4","ghi"); + map.put("5","jkl"); + map.put("6","mno"); + map.put("7","pqrs"); + map.put("8","tuv"); + map.put("9","wxyz"); + + StringBuilder sb = new StringBuilder(); + if (!"".equals(digits)) { + backtrack(0,result,map,digits,sb); + } + return result; + } + + public void backtrack(int index,List result,Map map,String digits,StringBuilder sb) { + //termination + if (sb.length() == digits.length()) { + result.add(sb.toString()); + return; + } + + //获取第 i 位数字。 + //获取第 i 位数字对应的各个字母 lettersletters。 + //选择 letters 的第 j 位字母。 + //进入新的递归。 + //递归完成,将组合字符串添加进结果集。 + //撤销 lettersletters 的第 j 位字母。 + //process + char digit = digits.charAt(index); + String value = map.get(String.valueOf(digit)); + for (int j = 0; j < value.length(); j++) { + sb.append(value.charAt(j)); //选择第j个字母 + //drill down + backtrack(index+1,result,map,digits,sb); + //reverse state + sb.deleteCharAt(sb.length()-1);// 撤销第j个字母 + } + + + + } +} \ No newline at end of file diff --git a/Week_03/G20200343030503/LeetCode_22_503.java b/Week_03/G20200343030503/LeetCode_22_503.java new file mode 100644 index 00000000..2515a2d0 --- /dev/null +++ b/Week_03/G20200343030503/LeetCode_22_503.java @@ -0,0 +1,31 @@ +/** + * + * 算法重点: 如果我们还剩一个位置,我们可以开始放一个左括号。 如果它不超过左括号的数量,我们可以放一个右括号。 + * + */ +class Solution { + public List generateParenthesis(int n) { + List result = new ArrayList<>(); + backtrack(result,"",0,0,n); + return result; + } + + public void backtrack(List result,String cur,int open,int close,int max) { + //termination + if (cur.length() == max*2) { + result.add(cur); + return; + } + //process + + //drill down + if (open < max) { + backtrack(result,cur+"(",open + 1,close,max); + } + if (close < open) { + backtrack(result,cur+")",open,close+1,max); + } + //reverse state + + } +} \ No newline at end of file diff --git a/Week_03/G20200343030503/LeetCode_455_503.java b/Week_03/G20200343030503/LeetCode_455_503.java new file mode 100644 index 00000000..d458149d --- /dev/null +++ b/Week_03/G20200343030503/LeetCode_455_503.java @@ -0,0 +1,19 @@ + +class Solution { + //g grid s size + public int findContentChildren(int[] g, int[] s) { + //将饼干和孩子降序排序 + Arrays.sort(g); + Arrays.sort(s); + int gi = 0; + int si = 0; + while (gi < g.length && si < s.length ) { + //最大的饼干满足胃口最大的孩子,饼干就给他,否则这孩子只能饿着,把最大的饼干分给下一个胃口第二大的孩子 + if (g[gi] <= s[si]) { + gi++; + } + si++; + } + return gi; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030503/LeetCode_46_503.java b/Week_03/G20200343030503/LeetCode_46_503.java new file mode 100644 index 00000000..879d64c5 --- /dev/null +++ b/Week_03/G20200343030503/LeetCode_46_503.java @@ -0,0 +1,69 @@ +/** + * + * 回溯算法: 回到过去,恢复现场 + * 全排列 + * 注意事项: 1. 借助栈(stack或者LinkedList)、 2.path的重置 3. res.add(new ArrayList<>(result)); + * + * 参考: https://leetcode-cn.com/problems/permutations/solution/hui-su-suan-fa-python-dai-ma-java-dai-ma-by-liweiw/?utm_source=LCUS&utm_medium=ip_redirect_q_uns&utm_campaign=transfer2china + * + * + * + * + */ +class Solution { + + + + //执行用时 :2 ms, 在所有 Java 提交中击败了60.71%的用户 + public List> permute(int[] nums) { //permute : 重新排列 + List> result = new ArrayList<>();//存放所有结果 + LinkedList path = new LinkedList(); //存放一次排列[1,2,3] + boolean[] visited = new boolean[nums.length]; + backtrack(nums,result,path,visited); + return result; + } + + public void backtrack(int[] nums,List> result,LinkedList path,boolean[] visited){ + //1. 选择结束的条件 + if (nums.length == path.size()) { + result.add(new ArrayList<>(path)); + return; + } + //2. 做选择 + for (int i = 0; i < nums.length; i++) { + if (visited[i] == true) continue; + path.add(nums[i]); + visited[i] = true; + backtrack(nums,result,path,visited); + //特别注意需要重置result + visited[i] = false; + path.removeLast(); + } + } + + //执行用时 :4 ms, 在所有 Java 提交中击败了16.13%的用户 + // public List> permute(int[] nums) { //permute : 重新排列 + // List> res = new ArrayList<>();//存放所有结果 + // LinkedList result = new LinkedList(); //存放一次排列[1,2,3] + // backtrack(nums,res,result); + // return res; + // } + + // public void backtrack(int[] nums,List> res,LinkedList result){ + // //1. 选择结束的条件 + // if (nums.length == result.size()) { + // res.add(new ArrayList<>(result)); + // return; + // } + // //2. 做选择 + // for (int i = 0; i < nums.length; i++) { + // if (result.contains(nums[i])) { + // continue; + // } + // result.add(nums[i]); + // backtrack(nums,res,result); + // //特别注意需要重置result + // result.removeLast(); + // } + // } +} \ No newline at end of file diff --git a/Week_03/G20200343030503/LeetCode_47_503.java b/Week_03/G20200343030503/LeetCode_47_503.java new file mode 100644 index 00000000..013a3a6a --- /dev/null +++ b/Week_03/G20200343030503/LeetCode_47_503.java @@ -0,0 +1,50 @@ +/** + * + * 回溯算法: 回到过去,恢复现场 + * 全排列|| + * + * 注意事项: 1. nums必须是有序数组 2. 使用java官方推荐的Deque代替Stack 3. 回溯+ 减枝(判断前一个点是否被使用过) + * + * + */ +class Solution { + public List> permuteUnique(int[] nums) { + //特别需要注意: nums一定要排序否则下变执行nums[i] == nums[i-1]做判断的时候会出错 + Arrays.sort(nums); + + //定义一个存放结果的集合 + List> result = new ArrayList>(); + //定义一个一趟结果的存放的集合,为方便状态重置,建议使用Deque或者LinkedList , + //不推荐使用Stack,java自己的人员都不再使用Stack + Deque stack = new ArrayDeque<>(); + //定义一个数组,确定nums中的数字是否被使用过 0 未使用过,1 使用过 + int[] used = new int[nums.length]; + dfs(nums,result,stack,used); + return result; + } + + public void dfs(int[] nums,List> result,Deque stack,int[] used){ + //termination + if (stack.size() == nums.length) { + result.add(new ArrayList<>(stack)); + return; + } + + //process + for (int i = 0; i < nums.length; i++) { + if (used[i] == 1) continue; + //减枝 + if (i > 0 && nums[i] == nums[i-1] && used[i-1] == 1) continue; + + stack.add(nums[i]); + used[i] = 1; + //drill down + dfs(nums,result,stack,used); + //reverse state + used[i] = 0; + stack.removeLast(); + } + + } + +} \ No newline at end of file diff --git a/Week_03/G20200343030503/LeetCode_860_503.java b/Week_03/G20200343030503/LeetCode_860_503.java new file mode 100644 index 00000000..aca7545c --- /dev/null +++ b/Week_03/G20200343030503/LeetCode_860_503.java @@ -0,0 +1,28 @@ +/** + * + */ +class Solution { + public boolean lemonadeChange(int[] bills) { + int five = 0; + int ten = 0; + for (int bill: bills) { + if (bill == 5) { //如果顾客给的正好是5元,直接five++ + five++; + } else if (bill == 10) { + if (five == 0) return false; //如果顾客给的是10元,看下手里有没有5元 + five--;//有的话需要给客户找5元 + ten++;//同时自己手里有一个10元 + } else if (bill == 20) { //如果客户给的是20元 + if (ten > 0 && five >0) { //情况1就是给顾客找一个10元+一个5元 + ten--; + five--; + } else if (five > 3) {//情况2就是给顾客找三个5元 + five -= 3; + } else {//找不开 + return false; + } + } + } + return true; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030503/NOTE.md b/Week_03/G20200343030503/NOTE.md index 50de3041..09fffa5d 100644 --- a/Week_03/G20200343030503/NOTE.md +++ b/Week_03/G20200343030503/NOTE.md @@ -1 +1,169 @@ -学习笔记 \ No newline at end of file +一、回溯算法 + +​ 定义: 回溯算法用于在一棵隐式的树上进行搜索.做题的时候需要现在纸上画出“递归树”,进而打开思路然后才是编码 + +1. 在隐式树上的深度优先遍历 + + a . 状态转换 + + b. 使用深度优先遍历,直接使用系统栈保存节点信息,编码简单 + + c. 深度优先遍历更符合人们做事情“一条道走到底”的态度 + + d. 如果使用广度优先遍历,得自己编写节点类和使用队列 + +2. 理解回溯 + + a. 从深层节点回到浅层节点必须“回到过去” + + b. 回溯可以理解“状态重置”,“回到过去”,“恢复现场” + c. 状态空间很大的时候,我们可能只需要其中的某些状态(一般都是叶子节点),因此全局使用一份状态即可 + + d. 在每一个节点都适用新的状态变量的时候不必回溯 + +3. 善用剪纸,提前结束搜索 + + a. 提前知道此路不通的时候,就“拐弯”,这一步操作称为“剪枝” + + b. 搜索算法状态庞大,剪枝是必须要的 + +二、贪心算法 + +三、分治算法 + +四、代码模板总结 + +1. 递归代码模版 + + ```java + public void recur(int level, int param) { + + // terminator + if (level > MAX_LEVEL) { + // process result + return; + } + + // process current logic + process(level, param); + + // drill down + recur( level: level + 1, newParam); + + // restore current status + + } + ``` + +2. 分治代码模板 + + ```python + def divide_conquer(problem, param1, param2, ...): + # recursion terminator + if problem is None: + print_result + return + + # prepare data + data = prepare_data(problem) + subproblems = split_problem(problem, data) + + # conquer subproblems + subresult1 = self.divide_conquer(subproblems[0], p1, ...) + subresult2 = self.divide_conquer(subproblems[1], p1, ...) + subresult3 = self.divide_conquer(subproblems[2], p1, ...) + … + + # process and generate the final result + result = process_result(subresult1, subresult2, subresult3, …) + + # revert the current level states + ``` + +3. 深度优先代码模板DFS + + a. 递归方式 + + ```python + def divide_conquer(problem, param1, param2, ...): + # recursion terminator + if problem is None: + print_result + return + + # prepare data + data = prepare_data(problem) + subproblems = split_problem(problem, data) + + # conquer subproblems + subresult1 = self.divide_conquer(subproblems[0], p1, ...) + subresult2 = self.divide_conquer(subproblems[1], p1, ...) + subresult3 = self.divide_conquer(subproblems[2], p1, ...) + … + + # process and generate the final result + result = process_result(subresult1, subresult2, subresult3, …) + + # revert the current level states + ``` + + b. 非递归方式 + + ```python + def DFS(self, tree): + + if tree.root is None: + return [] + + visited, stack = [], [tree.root] + + while stack: + node = stack.pop() + visited.add(node) + + process (node) + nodes = generate_related_nodes(node) + stack.push(nodes) + + # other processing work + ... + ``` + + + +4. 广度优先代码模板BFS + + ```python + def BFS(graph, start, end): + visited = set() + queue = [] + queue.append([start]) + + while queue: + node = queue.pop() + visited.add(node) + + process(node) + nodes = generate_related_nodes(node) + queue.push(nodes) + + # other processing work + ... + ``` + +5. 二分查找代码模板 + + ```java + left, right = 0, len(array) - 1 + while left <= right: + mid = (left + right) / 2 + if array[mid] == target: + # find the target!! + break or return result + elif array[mid] < target: + left = mid + 1 + else: + right = mid - 1 + ``` + + \ No newline at end of file diff --git a/Week_03/G20200343030505/LeetCode_122_505.java b/Week_03/G20200343030505/LeetCode_122_505.java new file mode 100644 index 00000000..bc9e48c3 --- /dev/null +++ b/Week_03/G20200343030505/LeetCode_122_505.java @@ -0,0 +1,17 @@ +class LeetCode_122_505 { + public int maxProfit(int[] prices) { + if (prices == null || prices.length < 2) { + return 0; + } + + int maxProfit = 0; + for (int i=1;i 0) { + maxProfit += tmp; + } + } + + return maxProfit; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030505/LeetCode_126_505.java b/Week_03/G20200343030505/LeetCode_126_505.java new file mode 100644 index 00000000..13d9301b --- /dev/null +++ b/Week_03/G20200343030505/LeetCode_126_505.java @@ -0,0 +1,86 @@ +class LeetCode_126_505 { + private Map> map; // 存储构建好的无向图 + private Map> nxtMap; // 记录每个搜索层次上的candidate节点 + private List> ans; // 存储答案 + private int minDist; // 转化序列的最短长度 + public List> findLadders(String beginWord, String endWord, List wordList) { + wordList.add(beginWord); + this.map = new HashMap<>(); + this.nxtMap = new HashMap<>(); + this.ans = new ArrayList<>(); + int n = wordList.size(); + + for (int i = 0; i < n; i++) { + for (int j = i+1; j < n; j++) { + String a = wordList.get(i), b = wordList.get(j); + if (check(a, b)) { + map.putIfAbsent(a, new HashSet<>()); + map.putIfAbsent(b, new HashSet<>()); + map.get(a).add(b); + map.get(b).add(a); + } + } + } + + minDist = BFS(beginWord, endWord); + // 如果minDist为-1,说明不存在这样的转化序列,直接返回空集 + if (minDist == -1) return ans; + DFS(beginWord, endWord, new HashSet(), new ArrayList()); + return ans; + + } + + private void DFS(String cur, String end, Set visit, List path) { + visit.add(cur); + path.add(cur); + if (path.size() == minDist) { + if (cur.compareTo(end)==0) { + ans.add(new ArrayList<>(path)); + } + } else { + for (String nxt : map.get(cur)) { + // 优化: 取当前未访问过,且在该层次候选集合中的节点 + if (visit.contains(nxt) || !nxtMap.get(path.size()).contains(nxt)) continue; + DFS(nxt, end, visit, path); + } + } + visit.remove(cur); + path.remove(path.size()-1); + + } + + private int BFS(String beginWord, String endWord) { + int level = 0; + Set visit = new HashSet<>(); + Queue queue = new LinkedList<>(); + queue.offer(beginWord); + visit.add(beginWord); + + while (!queue.isEmpty()) { + int size = queue.size(); + nxtMap.put(level+1, new HashSet<>()); + for (int i = 0; i < size; i++) { + String cur = queue.poll(); + if (cur.compareTo(endWord)==0) return level+1; + for (String nxt : map.getOrDefault(cur, new HashSet<>())) { + if (visit.contains(nxt)) continue; + visit.add(nxt); + queue.offer(nxt); + nxtMap.get(level+1).add(nxt); + } + } + level++; + } + return -1; + } + + // 判断字符串a能否通过只改变一个字母转化为b + private boolean check(String a, String b) { + int cnt = 0; + for (int i = 0; i < a.length(); i++) { + if (a.charAt(i) != b.charAt(i)) cnt++; + if (cnt > 1) return false; + } + return cnt == 1; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030505/LeetCode_127_505.java b/Week_03/G20200343030505/LeetCode_127_505.java new file mode 100644 index 00000000..c7d48792 --- /dev/null +++ b/Week_03/G20200343030505/LeetCode_127_505.java @@ -0,0 +1,54 @@ +class LeetCode_127_505 { + public int ladderLength(String beginWord, String endWord, List wordList) { + if (!wordList.contains(endWord)) { + return 0; + } + // visited修改为boolean数组 + boolean[] visited = new boolean[wordList.size()]; + int idx = wordList.indexOf(beginWord); + if (idx != -1) { + visited[idx] = true; + } + Queue queue = new LinkedList<>(); + queue.offer(beginWord); + int count = 0; + while (queue.size() > 0) { + int size = queue.size(); + ++count; + while (size-- > 0) { + String start = queue.poll(); + for (int i = 0; i < wordList.size(); ++i) { + // 通过index判断是否已经访问 + if (visited[i]) { + continue; + } + String s = wordList.get(i); + if (!canConvert(start, s)) { + continue; + } + if (s.equals(endWord)) { + return count + 1; + } + visited[i] = true; + queue.offer(s); + } + } + } + return 0; + } + + public boolean canConvert(String s1, String s2) { + // 因为题目说了单词长度相同,可以不考虑长度问题 + // if (s1.length() != s2.length()) return false; + int count = 0; + for (int i = 0; i < s1.length(); ++i) { + if (s1.charAt(i) != s2.charAt(i)) { + ++count; + if (count > 1) { + return false; + } + } + } + return count == 1; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030505/LeetCode_153_505.java b/Week_03/G20200343030505/LeetCode_153_505.java new file mode 100644 index 00000000..f5371edf --- /dev/null +++ b/Week_03/G20200343030505/LeetCode_153_505.java @@ -0,0 +1,26 @@ +class LeetCode_74_505 { + public boolean searchMatrix(int[][] matrix, int target) { + if (matrix == null) { + return false; + } + int m = matrix.length; + if (m == 0) { + return false; + } + int n = matrix[0].length; + int left = 0, right = m * n - 1; + while (left <= right) { + int mid = left + (right - left)/2; + int dx = mid/n, dy = mid%n; + if (matrix[dx][dy] == target) { + return true; + } else if (matrix[dx][dy] > target) { + right = mid -1; + } else { + left = mid + 1; + } + } + + return false; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030505/LeetCode_200_505.java b/Week_03/G20200343030505/LeetCode_200_505.java new file mode 100644 index 00000000..96e393d6 --- /dev/null +++ b/Week_03/G20200343030505/LeetCode_200_505.java @@ -0,0 +1,46 @@ +class LeetCode_200_505 { + private int count = 0; + private static final int[][] directs = new int[][]{{0,1}, {0,-1}, {1,0}, {-1,0}}; + private boolean[][] marked; + private int row; + private int column; + + public int numIslands(char[][] grid) { + if (grid == null || grid.length == 0) { + return 0; + } + + row = grid.length; + column = grid[0].length; + marked = new boolean[row][column]; + for (int i=0;i= 0 && j >= 0 && i <= row - 1 && j <= column - 1) ?true:false; + } + + + +} \ No newline at end of file diff --git a/Week_03/G20200343030505/LeetCode_33_505.java b/Week_03/G20200343030505/LeetCode_33_505.java new file mode 100644 index 00000000..c662c4ae --- /dev/null +++ b/Week_03/G20200343030505/LeetCode_33_505.java @@ -0,0 +1,40 @@ +/** + * 使用栈 + * @author huangwen05 + * + * @date: 2020年2月23日 下午7:53:59 + */ +class LeetCode_33_505 { + public int search(int[] nums, int target) { + if (nums == null) { + return -1; + } + + int left = 0, right = nums.length - 1; + int index = -1; + while (left <= right) { + int mid = left + (right - left)/2; + + if (nums[mid] == target) { + return mid; + } + + if (nums[left] <= nums[mid]) { + if (target >= nums[left] && target <= nums[mid]) { + right = mid - 1; + } else { + left = mid + 1; + } + } else { + if (target >= nums[mid] && target <= nums[right]) { + left = mid + 1; + } else { + right = mid - 1; + } + } + + } + + return index; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030505/LeetCode_455_505.java b/Week_03/G20200343030505/LeetCode_455_505.java new file mode 100644 index 00000000..a09b3118 --- /dev/null +++ b/Week_03/G20200343030505/LeetCode_455_505.java @@ -0,0 +1,22 @@ +class LeetCode_455_505 { + public int findContentChildren(int[] g, int[] s) { + if (g == null || s == null) { + return 0; + } + Arrays.sort(g); + Arrays.sort(s); + + int i = 0, j = 0, count = 0; + while (i < g.length && j < s.length) { + if (g[i] <= s[j]) { + ++i; + ++j; + ++count; + } else { + ++j; + } + } + + return count; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030505/LeetCode_45_505.java b/Week_03/G20200343030505/LeetCode_45_505.java new file mode 100644 index 00000000..79709e56 --- /dev/null +++ b/Week_03/G20200343030505/LeetCode_45_505.java @@ -0,0 +1,20 @@ +class LeetCode_45_505 { + public int jump(int[] nums) { + if (nums == null) { + return 0; + } + + int position = nums.length - 1; + int steps = 0; + while (position != 0) { + for (int i=0;i= position) { + ++steps; + position = i; + break; + } + } + } + return steps; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030505/LeetCode_529_505.java b/Week_03/G20200343030505/LeetCode_529_505.java new file mode 100644 index 00000000..aad7e37b --- /dev/null +++ b/Week_03/G20200343030505/LeetCode_529_505.java @@ -0,0 +1,58 @@ +class LeetCode_529_505 { + int[] dx = {-1, -1, 0, 1, 1, 1, 0, -1}; // 相邻位置 + int[] dy = {0, 1, 1, 1, 0, -1, -1, -1}; + + public char[][] updateBoard(char[][] board, int[] click) { + dfs(board, click[0], click[1]); + return board; + } + + public void dfs(char[][] board, int x, int y) { + int r = board.length; + int c = board[0].length; + if (x < 0 || x >= r || y < 0 || y >= c) { + return; + } + + if (board[x][y] == 'E') { // 如果当前为E,才进行判断是否要递归相邻结点 + board[x][y] = 'B'; + int count = judge(board, x, y); + if (count == 0) { // 如果为0,则进行递归 + for (int i = 0; i < 8; i++) { + dfs(board, x + dx[i], y + dy[i]); + } + } else { // 如果不为0,则更新当前结点的值为地雷数量 + board[x][y] = (char) (count + '0'); + } + } else if (board[x][y] == 'M'){ // 注意不要用else,否则会递归修改掉已经是数字的位置 + board[x][y] = 'X'; + } + } + + // 获取当前借点相邻的地雷数量 + public int judge(char[][] board, int x, int y) { + int r = board.length; + int c = board[0].length; + int count = 0; + for (int i = 0; i < 8; i++) { + int newX = x + dx[i]; + int newY = y + dy[i]; + if (newX < 0 || newX >= r || newY < 0 || newY >= c) { + continue; + } + if (board[newX][newY] == 'M') { + count++; + } + } + return count; + } + + static class Node { + int x; + int y; + Node(int x, int y) { + this.x = x; + this.y = y; + } + } +} \ No newline at end of file diff --git a/Week_03/G20200343030505/LeetCode_55_505.java b/Week_03/G20200343030505/LeetCode_55_505.java new file mode 100644 index 00000000..701b7ad2 --- /dev/null +++ b/Week_03/G20200343030505/LeetCode_55_505.java @@ -0,0 +1,20 @@ +class LeetCode_55_505 { + public boolean canJump(int[] nums) { + if (nums == null) { + return false; + } + + int k = 0;//k表示目前为止能走到的最大位置 + //每遍历一个i元素,计算以当前位置出发能走到的最远位置 + //如果i>k,表示之前能到的最远位置小于i 遍历结束 + for (int i=0;i k) { + return false; + } + if (k >= nums.length - 1) return true; + k = Math.max(k, i + nums[i]); + } + + return true; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030505/LeetCode_74_505.java b/Week_03/G20200343030505/LeetCode_74_505.java new file mode 100644 index 00000000..f5371edf --- /dev/null +++ b/Week_03/G20200343030505/LeetCode_74_505.java @@ -0,0 +1,26 @@ +class LeetCode_74_505 { + public boolean searchMatrix(int[][] matrix, int target) { + if (matrix == null) { + return false; + } + int m = matrix.length; + if (m == 0) { + return false; + } + int n = matrix[0].length; + int left = 0, right = m * n - 1; + while (left <= right) { + int mid = left + (right - left)/2; + int dx = mid/n, dy = mid%n; + if (matrix[dx][dy] == target) { + return true; + } else if (matrix[dx][dy] > target) { + right = mid -1; + } else { + left = mid + 1; + } + } + + return false; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030505/LeetCode_860_505.java b/Week_03/G20200343030505/LeetCode_860_505.java new file mode 100644 index 00000000..b749d6b8 --- /dev/null +++ b/Week_03/G20200343030505/LeetCode_860_505.java @@ -0,0 +1,31 @@ +class LeetCode_860_505 { + public boolean lemonadeChange(int[] bills) { + if (bills == null) { + return false; + } + + int five = 0, ten = 0; + for (int i=0;i 0 && ten > 0) { + five--; + ten--; + } else if (five >= 3) { + five -= 3; + } else { + return false; + } + } + } + + return true; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030505/LeetCode_874_505.java b/Week_03/G20200343030505/LeetCode_874_505.java new file mode 100644 index 00000000..c6ab205d --- /dev/null +++ b/Week_03/G20200343030505/LeetCode_874_505.java @@ -0,0 +1,40 @@ + +class LeetCode_874_505 { + public int robotSim(int[] commands, int[][] obstacles) { + if (commands == null || obstacles == null) { + return 0; + } + + int[] dx = new int[]{0,1,0,-1}; + int[] dy = new int[]{1,0,-1,0}; + int x = 0, y = 0, di = 0; + Set obStatus = new HashSet(); + for (int[] arr:obstacles) { + long nx = (long)arr[0] + 30000; + long ny = (long)arr[1] + 30000; + obStatus.add((nx << 16) + ny); + } + + int ans = 0; + for (int co:commands) { + if (co == -1) { + di = (di + 1)%4; + } else if (co == -2) { + di = (di + 3)%4; + } else { + for (int i=0;i int: + profit = 0 + for i in range(1, len(prices)): + tmp = prices[i] - prices[i - 1] + if tmp > 0: profit += tmp + return profit diff --git a/Week_03/G20200343030507/507-Week 03/LeetCode_455_507.py b/Week_03/G20200343030507/507-Week 03/LeetCode_455_507.py new file mode 100644 index 00000000..35a63296 --- /dev/null +++ b/Week_03/G20200343030507/507-Week 03/LeetCode_455_507.py @@ -0,0 +1,17 @@ +from typing import List + +class Solution: + def findContentChildren(self, g: List[int], s: List[int]) -> int: + # 对g和s升序排序,s是饼干,g是胃口 + g.sort() + s.sort() + res = 0 + i = 0 + for e in s: + if i == len(g): + break + # 可以满足胃口,把小饼干喂给小朋友,否则看下一块饼干 + if e >= g[i]: + res += 1 + i += 1 + return res \ No newline at end of file diff --git a/Week_03/G20200343030507/507-Week 03/LeetCode_860_507.py b/Week_03/G20200343030507/507-Week 03/LeetCode_860_507.py new file mode 100644 index 00000000..8a553379 --- /dev/null +++ b/Week_03/G20200343030507/507-Week 03/LeetCode_860_507.py @@ -0,0 +1,23 @@ +from typing import List + +class Solution: + def lemonadeChange(self, bills: List[int]) -> bool: + five = ten = 0 + for bill in bills: + if bill == 5: + five += 1 + elif bill == 10: + if not five: + return False + five -= 1 + ten += 1 + else: + if ten and five: + ten -= 1 + five -= 1 + elif five >= 3: + five -= 3 + else: + return False + return True + diff --git a/Week_03/G20200343030507/507-Week 03/LeetCode_874_507.py b/Week_03/G20200343030507/507-Week 03/LeetCode_874_507.py new file mode 100644 index 00000000..f4abb531 --- /dev/null +++ b/Week_03/G20200343030507/507-Week 03/LeetCode_874_507.py @@ -0,0 +1,23 @@ +from typing import List + +class Solution: + def robotSim(self, commands: List[int], obstacles: List[List[int]]) -> int: + dx = [0, 1, 0, -1] + dy = [1, 0, -1, 0] + x = y = di = 0 + obstacleSet = set(map(tuple, obstacles)) + ans = 0 + + for cmd in commands: + if cmd == -2: #left + di = (di - 1) % 4 + elif cmd == -1: #right + di = (di + 1) % 4 + else: + for k in xrange(cmd): + if (x+dx[di], y+dy[di]) not in obstacleSet: + x += dx[di] + y += dy[di] + ans = max(ans, x*x + y*y) + + return ans diff --git a/Week_03/G20200343030509/017_509.java b/Week_03/G20200343030509/017_509.java new file mode 100644 index 00000000..f96ca78d --- /dev/null +++ b/Week_03/G20200343030509/017_509.java @@ -0,0 +1,37 @@ +/* + * @lc app=leetcode.cn id=17 lang=java + * + * [17] 电话号码的字母组合 + */ + +class Solution { + public List letterCombinations(String digits) { + List result = new ArrayList<>(); + HashMap map = new HashMap(); + map.put("2", "abc"); + map.put("3", "def"); + map.put("4", "ghi"); + map.put("5", "jkl"); + map.put("6", "mno"); + map.put("7", "pqrs"); + map.put("8", "tuv"); + map.put("9", "wxyz"); + + letters(digits, 0, "", result, map); + + return result; + } + + private void letters(String digits, int index, String str, List result, HashMap map) { + if (index == digits.length()) { + result.add(str); + return; + } + + String digit = digits.substring(index, index + 1); + String temp = map.get(digit); + for (int i = 0; i < temp.length(); i++) { + letters(digits, index + 1, str + temp.charAt(i), result, map); + } + } +} \ No newline at end of file diff --git a/Week_03/G20200343030509/050_509.java b/Week_03/G20200343030509/050_509.java new file mode 100644 index 00000000..a24d221d --- /dev/null +++ b/Week_03/G20200343030509/050_509.java @@ -0,0 +1,53 @@ +/* + * @lc app=leetcode.cn id=50 lang=java + * + * [50] Pow(x, n) + */ + +class Solution { + // 暴力 + public double myPow(double x, int n) { + long N = n; + if (N < 0) { + x = 1 / x; + N = -N; + } + + double result = 1; + for (long i = 0; i < N; i++) { + result *= x; + } + return result; + } + + // 分治 + public double myPow1(double x, int n) { + long N = n; + if (N < 0) { + x = 1 / x; + N = -N; + } + + return splitePow(x, N); +} + +private double splitePow(double x, long n) { + // terminator + if (n == 0) { + return 1; + } + + // drill down + double result = splitePow(x, n/2); + + // merge + if (n%2 == 1) { + result = result * result * x; + } + else { + result *= result; + } + + return result; +} +} \ No newline at end of file diff --git a/Week_03/G20200343030509/051_509.java b/Week_03/G20200343030509/051_509.java new file mode 100644 index 00000000..507e0e27 --- /dev/null +++ b/Week_03/G20200343030509/051_509.java @@ -0,0 +1,45 @@ +/* + * @lc app=leetcode.cn id=51 lang=java + * + * [51] N皇后 + */ + +class Solution { + private Set col = new HashSet<>(); + private Set left = new HashSet<>(); + private Set right = new HashSet<>(); + + public List> solveNQueens(int n) { + List> result = new ArrayList<>(); + dfs(result, new ArrayList(), 0, n); + return result; + } + + private void dfs(List> result, ArrayList list, int row, int n) { + if (row == n) { + result.add(new ArrayList(list)); + return; + } + + for (int i = 0; i < n; i++) { + if (col.contains(i) || left.contains(row - i) || right.contains(row + i) ) continue; + + char[] charArray = new char[n]; + Arrays.fill(charArray, '.'); + charArray[i] = 'Q'; + String rowStr = new String(charArray); + + list.add(rowStr); + col.add(i); + left.add(row - i); + right.add(row + i); + + dfs(result, list, row + 1, n); + + list.remove(list.size() - 1); + col.remove(i); + left.remove(row -i); + right.remove(row + i); + } + } +} \ No newline at end of file diff --git a/Week_03/G20200343030509/074_509.java b/Week_03/G20200343030509/074_509.java new file mode 100644 index 00000000..af6cbce0 --- /dev/null +++ b/Week_03/G20200343030509/074_509.java @@ -0,0 +1,31 @@ +/* + * @lc app=leetcode.cn id=74 lang=java + * + * [74] 搜索二维矩阵 + */ + +class Solution { + public boolean searchMatrix(int[][] matrix, int target) { + if (matrix.length == 0 || matrix[0].length == 0) return false; + + int start = 0; + int end = (matrix.length * matrix[0].length) - 1; + int colNum = matrix[0].length; + + while (start <= end) { + int mid = (start + end) / 2; + + int tempRow = (mid / colNum); + int tempCol = (mid % colNum); + + if (matrix[tempRow][tempCol] == target) return true; + if (matrix[tempRow][tempCol] < target) { + start = mid +1; + } + else { + end = mid - 1; + } + } + return false; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030509/078_509.java b/Week_03/G20200343030509/078_509.java new file mode 100644 index 00000000..f60f8dfd --- /dev/null +++ b/Week_03/G20200343030509/078_509.java @@ -0,0 +1,27 @@ +/* + * @lc app=leetcode.cn id=78 lang=java + * + * [78] 子集 + */ + +class Solution { + public List> subsets(int[] nums) { + List> result = new ArrayList<>(); + if (nums == null) return result; + dfs(nums, new ArrayList(), 0, result); + return result; + } + + private void dfs(int[] nums, List list, int index, List> result) { + if (index == nums.length) { + result.add(new ArrayList(list)); + return; + } + + dfs(nums, list, index + 1, result); + list.add(nums[index]); + dfs(nums, list, index + 1, result); + + list.remove(list.size() -1); + } +} \ No newline at end of file diff --git a/Week_03/G20200343030509/122_509.java b/Week_03/G20200343030509/122_509.java new file mode 100644 index 00000000..64d1e338 --- /dev/null +++ b/Week_03/G20200343030509/122_509.java @@ -0,0 +1,17 @@ +/* + * @lc app=leetcode.cn id=122 lang=java + * + * [122] 买卖股票的最佳时机 II + */ + +class Solution { + public int maxProfit(int[] prices) { + int total = 0; + for (int i = 0; i < prices.length - 1; i++) { + if (prices[i] < prices[i+1]) { + total += prices[i+1] - prices[i]; + } + } + return total; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030509/127_509.java b/Week_03/G20200343030509/127_509.java new file mode 100644 index 00000000..afafe6ad --- /dev/null +++ b/Week_03/G20200343030509/127_509.java @@ -0,0 +1,57 @@ +/* + * @lc app=leetcode.cn id=127 lang=java + * + * [127] 单词接龙 + */ + +class Solution { + public int ladderLength(String beginWord, String endWord, List wordList) { + if (!wordList.contains(endWord)) { + return 0; + } + + Set wordSet = new HashSet<>(wordList); + Set beginSet = new HashSet<>(); + Set endSet = new HashSet<>(); + beginSet.add(beginWord); + endSet.add(endWord); + + int step = 1; + Set visited = new HashSet<>(); + while (!beginSet.isEmpty() && !endSet.isEmpty()) { + // 谁短先走谁 + if (beginSet.size() > endSet.size()) { + Set set = beginSet; + beginSet = endSet; + endSet = set; + } + Set temp = new HashSet(); + for (String word : beginSet) { + char[] chars = word.toCharArray(); + + // 每个字母替换 + for (int i = 0; i < chars.length; i++) { + for (char c = 'a'; c < 'z'; c++) { + char old = chars[i]; + chars[i] = c; + String target = String.valueOf(chars); + + // 已经在end里面有了,接上了 + if (endSet.contains(target)) { + return step + 1; + } + // 是不是在单词池里,并且没访问过 + if (!visited.contains(target) && wordSet.contains(target)) { + temp.add(target); + visited.add(target); + } + chars[i] = old; + } + } + } + beginSet = temp; + step++; + } + return 0; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030509/169_509.java b/Week_03/G20200343030509/169_509.java new file mode 100644 index 00000000..2073ab6e --- /dev/null +++ b/Week_03/G20200343030509/169_509.java @@ -0,0 +1,43 @@ +/* + * @lc app=leetcode.cn id=169 lang=java + * + * [169] 求众数 + */ + +class Solution { + // 排序 + public int majorityElement(int[] nums) { + Arrays.sort(nums); + return nums[nums.length/2]; + } + + //分治 + public int majorityElement2(int[] nums) { + int length = nums.length; + int res = seprateCount(nums, 0, length -1); + return res; +} + +private int seprateCount(int[] nums, int low, int high) { + if (low == high) return nums[low]; + + int mid = (high - low) / 2 + low; + int left = seprateCount(nums, low, mid); + int right = seprateCount(nums, mid + 1, high); + + if (left == right) return left; + int leftCount = countMaj(nums, low, mid, left); + int rightCount = countMaj(nums, mid + 1, high, right); + + return leftCount > rightCount ? left : right; +} + +private int countMaj(int[] nums, int start, int end, int right) { + int count = 0; + for (int i=start; i <= end; i++){ + if(nums[i] == right) count++; + } + + return count; +} +} \ No newline at end of file diff --git a/Week_03/G20200343030509/200_509.java b/Week_03/G20200343030509/200_509.java new file mode 100644 index 00000000..ccb268a1 --- /dev/null +++ b/Week_03/G20200343030509/200_509.java @@ -0,0 +1,29 @@ +/* + * @lc app=leetcode.cn id=200 lang=java + * + * [200] 岛屿数量 + */ + +class Solution { + public int numIslands(char[][] grid) { + int count = 0; + for (int i = 0; i < grid.length; i++) { + for (int j = 0; j < grid[0].length; j++) { + if (grid[i][j] == '1') { + count++; + dfs(grid, i, j); + } + } + } + return count; + } + + private void dfs(char[][] grid, int row, int col) { + if (row < 0 || col < 0 || row == grid.length || col == grid[0].length || grid[row][col] != '1') return; + grid[row][col] = '0'; + dfs(grid, row, col + 1); + dfs(grid, row - 1, col); + dfs(grid, row + 1, col); + dfs(grid, row, col - 1); + } +} \ No newline at end of file diff --git a/Week_03/G20200343030511/LeetCode_126_511.java b/Week_03/G20200343030511/LeetCode_126_511.java new file mode 100644 index 00000000..6f75abc0 --- /dev/null +++ b/Week_03/G20200343030511/LeetCode_126_511.java @@ -0,0 +1,126 @@ +class Solution { + public List> findLadders(String beginWord, String endWord, List wordList) { + // + List> result = new ArrayList<>(); + // ֵвĿ굥,ҪתHashSetΪwordList̫ʱ + Set wordSet = new HashSet<>(wordList); + if (!distSet.contains(endWord)) + return result; + // õÿһĽڵ + LinkedList> queue = new LinkedList<>(); + // ײڵ + queue.offer(Arrays.asList(beginWord)); + Set visited = new HashSet<>(); + visited.add(beginWord); + // 趨Ƿ񵽿ԽIJˡ + boolean flag = false; + while (!queue.isEmpty() && !flag) { + int size = queue.size(); + Set perVisited = new HashSet<>(); + for (int i = 0; i < size; i++) { + List tempList = queue.poll(); + // ȡlistеһԪأж + String word = tempList.get(tempList.size() - 1); + char[] chars = word.toCharArray(); + for (int j = 0; j < chars.length; j++) { + char temp = chars[j];// ԭʼֵ + for (char j2 = 'a'; j2 <= 'z'; j2++) { + if (j2 == temp) + continue; + chars[j] = j2; + // õ滻ַ + String newString = new String(chars); + if (!visited.contains(newString) && wordSet.contains(newString)) { + List newList = new ArrayList<>(tempList); + newList.add(newString); + if (newString.equals(endWord)) { + flag = true; + result.add(newList); + } + perVisited.add(newString); + queue.offer(newList); + } + } + chars[j] = temp;// ָԭʼֵ + } + } + visited.addAll(perVisited); + } + return result; + } + + public List> findLadders1(String beginWord, String endWord, List wordList) { + List> result = new ArrayList<>(); + if (wordList == null || wordList.size() == 0) + return result; + // תhashٶȿ졣 + Set words = new HashSet(wordList); + if(!words.contains(endWord)) return result; + Set begin = new HashSet<>(), end = new HashSet<>(); + begin.add(beginWord); + end.add(endWord); + Map> treeMap = new HashMap<>(); + boolean front = true; + boolean flag = buildTreeMap(words, begin, end, treeMap, front); + if (flag) + dfs(result, treeMap, beginWord, endWord, new LinkedList<>()); + return result; + } + + private void dfs(List> result, Map> treeMap, String beginWord, String endWord, + LinkedList list) { + list.add(beginWord); + if (beginWord.equals(endWord)) { + result.add(new ArrayList<>(list)); + list.removeLast(); + return; + } + if (treeMap.containsKey(beginWord)) { + for (String word : treeMap.get(beginWord)) { + dfs(result, treeMap, word, endWord, list); + } + } + list.removeLast(); + } + private boolean buildTreeMap(Set words, Set begin, Set end, + Map> treeMap, boolean front) { + if (begin.size() == 0) + return true; + + if (begin.size() > end.size()) + return buildTreeMap(words, end, begin, treeMap, !front); + + words.removeAll(begin); + Set nextLevel = new HashSet<>(); + boolean isMeet = false; + for (String word : begin) { + char[] chars = word.toCharArray(); + for (int i = 0; i < chars.length; i++) { + char tmp = chars[i]; + for (char j = 'a'; j <= 'z'; j++) { + chars[i] = j; + if (chars[i] == tmp) + continue; + String newString = String.valueOf(chars); + if (words.contains(newString)) { + nextLevel.add(newString); + if (end.contains(newString)) { + isMeet = true; + } + String key = front ? word : newString; + String nextWord = front ? newString : word; + if (!treeMap.containsKey(key)) { + treeMap.put(key, new ArrayList<>()); + } + treeMap.get(key).add(nextWord); + } + } + chars[i] = tmp; + } + } + if (isMeet) + return true; + return buildTreeMap(words, nextLevel, end, treeMap, front); + } + +} \ No newline at end of file diff --git a/Week_03/G20200343030511/LeetCode_127_511.java b/Week_03/G20200343030511/LeetCode_127_511.java new file mode 100644 index 00000000..b2db6baf --- /dev/null +++ b/Week_03/G20200343030511/LeetCode_127_511.java @@ -0,0 +1,46 @@ +class Solution { + public int ladderLength(String beginWord, String endWord, List wordList) { + if (!wordList.contains(endWord)) { + return 0; + } + // visited޸Ϊboolean + boolean[] visited = new boolean[wordList.size()]; + int idx = wordList.indexOf(beginWord); + if (idx != -1) { + visited[idx] = true; + } + Queue queue = new LinkedList<>(); + queue.offer(beginWord); + int count = 0; + while (queue.size() > 0) { + count++; + int len=queue.size(); + for (int j = 0; j < len; j++) { + String word = queue.poll(); + for (int i = 0; i < wordList.size(); i++) { + if (word.equals(endWord)) + return count; + if (!visited[i]&&isValid(word, wordList.get(i))) { + queue.offer(wordList.get(i)); + visited[i] = true; + } + } + } + } + return 0; + } + + boolean isValid(String word1, String word2) { + char[] word1char = word1.toCharArray(); + char[] word2char = word2.toCharArray(); + int count = 0; + for (int i = 0; i < word2char.length; i++) { + if (word1char[i] != word2char[i]) { + count++; + } + } + if (count == 1) + return true; + return false; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030511/LeetCode_153_511.java b/Week_03/G20200343030511/LeetCode_153_511.java new file mode 100644 index 00000000..5468cb07 --- /dev/null +++ b/Week_03/G20200343030511/LeetCode_153_511.java @@ -0,0 +1,19 @@ +class Solution { + public int findMin(int[] nums) { + if (nums == null || nums.length == 0) + return -1; + int l = 0; + int r = nums.length - 1; + int mid; + while (l < r) { + mid = l + (r - l) / 2; + if (nums[mid] >= nums[l] && nums[l] > nums[r]) + l = mid + 1; + else { + r = mid; + } + + } + return nums[l]; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030511/LeetCode_200_511.java b/Week_03/G20200343030511/LeetCode_200_511.java new file mode 100644 index 00000000..8a768534 --- /dev/null +++ b/Week_03/G20200343030511/LeetCode_200_511.java @@ -0,0 +1,31 @@ +class Solution { + public int numIslands(char[][] grid) { + if (grid == null) + return 0; + int count = 0; + // ¼ + for (int i = 0; i < grid.length; i++) { + for (int j = 0; j < grid[i].length; j++) { + count += sink(i, j, grid); + } + } + return count; + } + + private int sink(int i, int j, char[][] grid) { + int nr = grid.length; + int nc = grid[0].length; + + // ݹֹ + if ( i >= nr || i < 0 || j >= nc || j < 0||grid[i][j] == '0' ) + return 0; + // ǰ + // ݹ + grid[i][j] = '0'; + sink(i + 1, j, grid); + sink(i - 1, j, grid); + sink(i, j + 1, grid); + sink(i, j - 1, grid); + return 1; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030511/LeetCode_33_511.java b/Week_03/G20200343030511/LeetCode_33_511.java new file mode 100644 index 00000000..4728477a --- /dev/null +++ b/Week_03/G20200343030511/LeetCode_33_511.java @@ -0,0 +1,23 @@ +class Solution { + public int search(int[] nums, int target) { + if (nums == null || nums.length == 0) + return -1; + int l = 0; + int r = nums.length - 1; + int mid; + while (l < r) { + mid = l + (r - l) / 2; + //ҪжϵȺ + if (target > nums[mid] && nums[mid] >= nums[l]) { + l = mid + 1; + } else if (target > nums[mid] && target < nums[l]) { + l = mid + 1; + } else if (target < nums[l] && nums[l] <= nums[mid]) { + l = mid + 1; + } else { + r = mid; + } + } + return l == r && nums[l] == target ? l : -1; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030511/LeetCode_45_511.java b/Week_03/G20200343030511/LeetCode_45_511.java new file mode 100644 index 00000000..e69de29b diff --git a/Week_03/G20200343030511/LeetCode_55_511.java b/Week_03/G20200343030511/LeetCode_55_511.java new file mode 100644 index 00000000..5ce11eb3 --- /dev/null +++ b/Week_03/G20200343030511/LeetCode_55_511.java @@ -0,0 +1,31 @@ +class Solution { + enum Index { + GOOD, BAD, UNKNOWN + } + public boolean canJump(int[] nums) { + if (nums == null || nums.length == 0) + return false; + Index[] mem = new Index[nums.length]; + for (int i = 0; i < nums.length; i++) { + mem[i]=Index.UNKNOWN; + } + mem[nums.length-1]=Index.GOOD; + boolean flag = dfs1(nums,0,mem); + return flag; + } + + private boolean dfs1(int[] nums, int i,Index[] mem) { + if (mem[i] != Index.UNKNOWN) { + return mem[i] == Index.GOOD ? true : false; + } + int foot = Math.min(nums[i]+i,nums.length-1); + for (int j = i+1; j <=foot; j++) { + if(dfs1(nums,j,mem)){ + mem[i]=Index.GOOD; + return true; + } + } + mem[i]=Index.BAD; + return false; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030511/LeetCode_74_511.java b/Week_03/G20200343030511/LeetCode_74_511.java new file mode 100644 index 00000000..95a25497 --- /dev/null +++ b/Week_03/G20200343030511/LeetCode_74_511.java @@ -0,0 +1,41 @@ +class Solution { + public boolean searchMatrix(int[][] matrix, int target) { + + if (matrix == null||matrix.length==0||matrix[0].length==0) + return false; + // жûе + if (matrix[0][0] > target) + return false; + if (matrix[matrix.length - 1][matrix[0].length - 1] < target) + return false; + int l = 0; + int r = matrix.length - 1; + int length = matrix[0].length - 1; + int mid; + while (l < r) { + mid = l + (r - l) / 2; + if (target >= matrix[mid][0] && target <= matrix[mid][length]) { + l = mid; + break; + } else if (target > matrix[mid][length]) { + l = mid + 1; + } else { + r = mid; + } + } + // еl + int l_l = 0; + int l_r = length; + int l_mid; + while (l_l < l_r) { + l_mid = l_l + (l_r - l_l) / 2; + if (target > matrix[l][l_mid]) { + l_l = l_mid + 1; + } else { + l_r = l_mid; + } + } + + return l_l == l_r && matrix[l][l_l] == target ? true : false; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030513/LeetCode_122_513.java b/Week_03/G20200343030513/LeetCode_122_513.java new file mode 100644 index 00000000..e89fcb56 --- /dev/null +++ b/Week_03/G20200343030513/LeetCode_122_513.java @@ -0,0 +1,43 @@ +//给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。 +// +// 设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。 +// +// 注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。 +// +// 示例 1: +// +// 输入: [7,1,5,3,6,4] +//输出: 7 +//解释: 在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。 +//  随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6-3 = 3 。 +// +// +// 示例 2: +// +// 输入: [1,2,3,4,5] +//输出: 4 +//解释: 在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。 +//  注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。 +//  因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。 +// +// +// 示例 3: +// +// 输入: [7,6,4,3,1] +//输出: 0 +//解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。 +// Related Topics 贪心算法 数组 + + +//leetcode submit region begin(Prohibit modification and deletion) +class Solution { + public int maxProfit(int[] prices) { + int profit = 0; + for (int i = 1; i < prices.length; i++) { + int tmp = prices[i] - prices[i - 1]; + if (tmp > 0) profit += tmp; + } + return profit; + } +} +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week_03/G20200343030513/LeetCode_127_513.java b/Week_03/G20200343030513/LeetCode_127_513.java new file mode 100644 index 00000000..4bfed972 --- /dev/null +++ b/Week_03/G20200343030513/LeetCode_127_513.java @@ -0,0 +1,100 @@ +//给定两个单词(beginWord 和 endWord)和一个字典,找到从 beginWord 到 endWord 的最短转换序列的长度。转换需遵循如下规则: +// +// +// +// 每次转换只能改变一个字母。 +// 转换过程中的中间单词必须是字典中的单词。 +// +// +// 说明: +// +// +// 如果不存在这样的转换序列,返回 0。 +// 所有单词具有相同的长度。 +// 所有单词只由小写字母组成。 +// 字典中不存在重复的单词。 +// 你可以假设 beginWord 和 endWord 是非空的,且二者不相同。 +// +// +// 示例 1: +// +// 输入: +//beginWord = "hit", +//endWord = "cog", +//wordList = ["hot","dot","dog","lot","log","cog"] +// +//输出: 5 +// +//解释: 一个最短转换序列是 "hit" -> "hot" -> "dot" -> "dog" -> "cog", +// 返回它的长度 5。 +// +// +// 示例 2: +// +// 输入: +//beginWord = "hit" +//endWord = "cog" +//wordList = ["hot","dot","dog","lot","log"] +// +//输出: 0 +// +//解释: endWord "cog" 不在字典中,所以无法进行转换。 +// Related Topics 广度优先搜索 + + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Set; + +//leetcode submit region begin(Prohibit modification and deletion) +class Solution { + public int ladderLength(String beginWord, String endWord, List wordList) { + if(!wordList.contains(endWord)) + return 0; + int n = beginWord.length(); + HashMap>all_commons = new HashMap<>(); + wordList.forEach( + word->{ + for(int i=0; i()); + all_commons.get(common).add(word); + } + } + ); + HashSet begin = new HashSet<>(); + HashSet end = new HashSet<>(); + begin.add(beginWord); + end.add(endWord); + HashSet visited = new HashSet<>(); + int len = 1; + while(!begin.isEmpty() && !end.isEmpty()){ + if(begin.size()>end.size()){ + HashSet tmp = begin; + begin = end; + end = tmp; + } + HashSet neighbor = new HashSet<>(); + for(String cur : begin){ + for(int i=0; i= gi ,我们可以将这个饼干 j 分配给孩子 i ,这个孩子会得到满足。你的目标是尽可能满 +//足越多数量的孩子,并输出这个最大数值。 +// +// 注意: +// +// 你可以假设胃口值为正。 +//一个小朋友最多只能拥有一块饼干。 +// +// 示例 1: +// +// +//输入: [1,2,3], [1,1] +// +//输出: 1 +// +//解释: +//你有三个孩子和两块小饼干,3个孩子的胃口值分别是:1,2,3。 +//虽然你有两块小饼干,由于他们的尺寸都是1,你只能让胃口值是1的孩子满足。 +//所以你应该输出1。 +// +// +// 示例 2: +// +// +//输入: [1,2], [1,2,3] +// +//输出: 2 +// +//解释: +//你有两个孩子和三块小饼干,2个孩子的胃口值分别是1,2。 +//你拥有的饼干数量和尺寸都足以让所有孩子满足。 +//所以你应该输出2. +// +// Related Topics 贪心算法 + + +import java.util.Arrays; + +//leetcode submit region begin(Prohibit modification and deletion) +class Solution { + public int findContentChildren(int[] g, int[] s) { + if (g == null || s == null) return 0; + Arrays.sort(g); + Arrays.sort(s); + int i = 0, j = 0; + while (i < g.length && j < s.length) { + if(g[i] <= s[j]) i++; + j++; + } + return i; + } +} +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week_03/G20200343030513/LeetCode_860_513.java b/Week_03/G20200343030513/LeetCode_860_513.java new file mode 100644 index 00000000..59151f46 --- /dev/null +++ b/Week_03/G20200343030513/LeetCode_860_513.java @@ -0,0 +1,88 @@ +//在柠檬水摊上,每一杯柠檬水的售价为 5 美元。 +// +// 顾客排队购买你的产品,(按账单 bills 支付的顺序)一次购买一杯。 +// +// 每位顾客只买一杯柠檬水,然后向你付 5 美元、10 美元或 20 美元。你必须给每个顾客正确找零,也就是说净交易是每位顾客向你支付 5 美元。 +// +// 注意,一开始你手头没有任何零钱。 +// +// 如果你能给每位顾客正确找零,返回 true ,否则返回 false 。 +// +// 示例 1: +// +// 输入:[5,5,5,10,20] +//输出:true +//解释: +//前 3 位顾客那里,我们按顺序收取 3 张 5 美元的钞票。 +//第 4 位顾客那里,我们收取一张 10 美元的钞票,并返还 5 美元。 +//第 5 位顾客那里,我们找还一张 10 美元的钞票和一张 5 美元的钞票。 +//由于所有客户都得到了正确的找零,所以我们输出 true。 +// +// +// 示例 2: +// +// 输入:[5,5,10] +//输出:true +// +// +// 示例 3: +// +// 输入:[10,10] +//输出:false +// +// +// 示例 4: +// +// 输入:[5,5,10,10,20] +//输出:false +//解释: +//前 2 位顾客那里,我们按顺序收取 2 张 5 美元的钞票。 +//对于接下来的 2 位顾客,我们收取一张 10 美元的钞票,然后返还 5 美元。 +//对于最后一位顾客,我们无法退回 15 美元,因为我们现在只有两张 10 美元的钞票。 +//由于不是每位顾客都得到了正确的找零,所以答案是 false。 +// +// +// +// +// 提示: +// +// +// 0 <= bills.length <= 10000 +// bills[i] 不是 5 就是 10 或是 20 +// +// Related Topics 贪心算法 + + +//leetcode submit region begin(Prohibit modification and deletion) +class Solution { + public boolean lemonadeChange(int[] bills) { + int five = 0, ten = 0; + for (int bill : bills) { + switch (bill) { + case 5: { + five++; break; + } + case 10: { + if (five == 0) return false; + five--; + ten++; + break; + } + case 20:{ + if (five > 0 && ten > 0) { + ten--; + five--; + }else if (five >= 3){ + five -= 3; + }else { + return false; + } + break; + } + default:break; + } + } + return true; + } +} +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week_03/G20200343030519/Week 03/LeetCode_122_519.js b/Week_03/G20200343030519/Week 03/LeetCode_122_519.js new file mode 100644 index 00000000..eee99f52 --- /dev/null +++ b/Week_03/G20200343030519/Week 03/LeetCode_122_519.js @@ -0,0 +1,21 @@ +// https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/description/ + +var maxProfit = function(prices) { + var valley = prices[0]; // 谷值 + var peak = prices[0]; // 峰值 + var maxProfit = 0; // 最大利润值 + var lenNeed = prices.length - 1; + var i = 0; + while (i < lenNeed) { + while (i < lenNeed && prices[i] > prices[i + 1]) { + i++; + } + valley = prices[i]; + while (i < lenNeed && prices[i] <= prices[i + 1]) { + i++; + } + peak = prices[i]; + maxProfit += peak - valley; + } + return maxProfit; +}; \ No newline at end of file diff --git a/Week_03/G20200343030519/Week 03/LeetCode_127_519.js b/Week_03/G20200343030519/Week 03/LeetCode_127_519.js new file mode 100644 index 00000000..c37547d1 --- /dev/null +++ b/Week_03/G20200343030519/Week 03/LeetCode_127_519.js @@ -0,0 +1,26 @@ +// https://leetcode-cn.com/problems/word-ladder/description/ + +const ladderLength = (beginWord, endWord, wordList) => { + let wordSet = new Set(wordList); + if (!wordSet.has(endWord)) return 0; + let queue = [[beginWord, 1]]; + while (queue.length) { + let [word, transNumber] = queue.pop(); + if (word === endWord) return transNumber; + for (let str of wordSet) { + if (charDiff(word, str) === 1) { + queue.unshift([str, transNumber + 1]) ; + wordSet.delete(str); + } + } + } + return 0; + }; + + const charDiff = (str1, str2) => { + let changes = 0 + for (let i = 0; i < str1.length; i++) { + if (str1[i] != str2[i]) changes += 1; + } + return changes; + }; \ No newline at end of file diff --git a/Week_03/G20200343030519/Week 03/LeetCode_153_519.js b/Week_03/G20200343030519/Week 03/LeetCode_153_519.js new file mode 100644 index 00000000..b8bff9c1 --- /dev/null +++ b/Week_03/G20200343030519/Week 03/LeetCode_153_519.js @@ -0,0 +1,16 @@ +// https://leetcode-cn.com/problems/find-minimum-in-rotated-sorted-array/ + + +var findMin = function(nums) { + var low = 0; + var high = nums.length - 1; + while(low < high){ + var mid = (low + high) >> 1; + if (nums[mid] > nums[high]) { + low = mid + 1; + } else { + high = mid + } + } + return nums[low]; +}; diff --git a/Week_03/G20200343030519/Week 03/LeetCode_169_519.js b/Week_03/G20200343030519/Week 03/LeetCode_169_519.js new file mode 100644 index 00000000..9d61a5f7 --- /dev/null +++ b/Week_03/G20200343030519/Week 03/LeetCode_169_519.js @@ -0,0 +1,17 @@ +// https://leetcode-cn.com/problems/majority-element/description/ + +var majorityElement = function(nums) { + let count = 1; + let majority = nums[0]; + for(let i = 1; i < nums.length; i++) { + if (count === 0) { + majority = nums[i]; + } + if (nums[i] === majority) { + count ++; + } else { + count --; + } + } + return majority; +}; \ No newline at end of file diff --git a/Week_03/G20200343030519/Week 03/LeetCode_17_519.js b/Week_03/G20200343030519/Week 03/LeetCode_17_519.js new file mode 100644 index 00000000..f62aa7a2 --- /dev/null +++ b/Week_03/G20200343030519/Week 03/LeetCode_17_519.js @@ -0,0 +1,33 @@ +// https://leetcode-cn.com/problems/letter-combinations-of-a-phone-number/ + +var letterCombinations = function(digits) { + if (!digits) { + return []; + } + var len = digits.length; + var map = new Map(); + map.set('2', 'abc'); + map.set('3', 'def'); + map.set('4', 'ghi'); + map.set('5', 'jkl'); + map.set('6', 'mno'); + map.set('7', 'pqrs'); + map.set('8', 'tuv'); + map.set('9', 'wxyz'); + var result = []; + function _generate(i, str) { + // terminator + if (i == len) { + result.push(str); + return; + } + // process + // drill down + var tmp = map.get(digits[i]); + for (var r = 0; r < tmp.length; r++) { + _generate(i + 1, str + tmp[r]); + } + } + _generate(0, ''); + return result; +}; \ No newline at end of file diff --git a/Week_03/G20200343030519/Week 03/LeetCode_200_519.js b/Week_03/G20200343030519/Week 03/LeetCode_200_519.js new file mode 100644 index 00000000..06d2a071 --- /dev/null +++ b/Week_03/G20200343030519/Week 03/LeetCode_200_519.js @@ -0,0 +1,26 @@ +// https://leetcode-cn.com/problems/number-of-islands/ + +var numIslands = function(grid) { + var count = 0 + if(grid.length === 0) return count; + for(var i = 0; i < grid.length; i++){ + for(var j = 0; j < grid[0].length; j++){ + if(grid[i][j] === '1'){ + dfsSearch(grid,i,j) + count++ + } + } + } + return count; +}; + +function dfsSearch(grid,i,j){ + if(i < 0 || j < 0 || i >=grid.length || j >= grid[0].length) return; + if(grid[i][j] === '1'){ + grid[i][j] = '0'; + dfsSearch(grid,i + 1,j); + dfsSearch(grid,i - 1,j); + dfsSearch(grid,i,j + 1); + dfsSearch(grid,i,j - 1); + } +}; \ No newline at end of file diff --git a/Week_03/G20200343030519/Week 03/LeetCode_33_519.js b/Week_03/G20200343030519/Week 03/LeetCode_33_519.js new file mode 100644 index 00000000..3eac0650 --- /dev/null +++ b/Week_03/G20200343030519/Week 03/LeetCode_33_519.js @@ -0,0 +1,31 @@ +// https://leetcode-cn.com/problems/search-in-rotated-sorted-array/ + +var search = function (nums, target) { + let start = 0; + let end = nums.length - 1; + + while (start <= end) { + + let mid = (start + end) >> 1; + + if (nums[mid] === target) { + return mid; + } + + if (nums[mid] < nums[end]) { + if (nums[mid] < target && target <= nums[end]) { + start = mid + 1; + } else { + end = mid - 1; + } + } else { + if (nums[start] <= target && target < nums[mid]) { + end = mid - 1; + } else { + start = mid + 1; + } + } + } + + return -1; +}; \ No newline at end of file diff --git a/Week_03/G20200343030519/Week 03/LeetCode_455_519.js b/Week_03/G20200343030519/Week 03/LeetCode_455_519.js new file mode 100644 index 00000000..08df4737 --- /dev/null +++ b/Week_03/G20200343030519/Week 03/LeetCode_455_519.js @@ -0,0 +1,20 @@ +// https://leetcode-cn.com/problems/assign-cookies/description/ + +var findContentChildren = function(g, s) { + g.sort((a, b) => b - a); + s.sort((a, b) => b - a); + let gi = 0; // 胃口值 + let sj = 0; // 饼干尺寸 + let res = 0; + while (gi < g.length && sj < s.length) { + // 如果sj大于gi 我们可以将这个饼干j分配给孩子i 孩子会满足 + if (s[sj] >= g[gi]) { + gi++; + sj++; + res++; + } else { + gi++; + } + } + return res; +}; \ No newline at end of file diff --git a/Week_03/G20200343030519/Week 03/LeetCode_45_519.js b/Week_03/G20200343030519/Week 03/LeetCode_45_519.js new file mode 100644 index 00000000..7f14dc73 --- /dev/null +++ b/Week_03/G20200343030519/Week 03/LeetCode_45_519.js @@ -0,0 +1,19 @@ +// https://leetcode-cn.com/problems/jump-game-ii/ + +var jump = function(nums) { + var steps = 0; + var len = nums.length; + var canJumpMax = 0; + var last_canJumpMax = 0; + for(var i = 0;i= len-1){ + break; + } + } + return steps; +}; \ No newline at end of file diff --git a/Week_03/G20200343030519/Week 03/LeetCode_50_519.js b/Week_03/G20200343030519/Week 03/LeetCode_50_519.js new file mode 100644 index 00000000..fbf35713 --- /dev/null +++ b/Week_03/G20200343030519/Week 03/LeetCode_50_519.js @@ -0,0 +1,21 @@ +// https://leetcode-cn.com/problems/powx-n/ + +var myPow = function(x, n) { + if (n == 0) { + return 1; + } + x = parseFloat(x); + if (n < 0) { + x = parseFloat(1/x); + n = -n; + } + var subresult = x; + var result = 1; + for (var i = n; i > 0; i = parseInt(i/2)) { + if (i&1 == 1) { + result = result * subresult; + } + subresult = subresult * subresult; + } + return result; +}; \ No newline at end of file diff --git a/Week_03/G20200343030519/Week 03/LeetCode_51_519.js b/Week_03/G20200343030519/Week 03/LeetCode_51_519.js new file mode 100644 index 00000000..8bf3f72a --- /dev/null +++ b/Week_03/G20200343030519/Week 03/LeetCode_51_519.js @@ -0,0 +1,23 @@ +// https://leetcode-cn.com/problems/n-queens/ + +var solveNQueens = function(n) { + let res = [], qChar = 'Q', emptyChar = '.'; + function doTry(row, tmp = []) { + if (row === n) { + res.push(tmp.map(colIndex => `${emptyChar.repeat(colIndex)}${qChar}${emptyChar.repeat(n-colIndex-1)}`)); + return; + } + for (let col = 0; col < n; col++) { + if (tmp.some((colIndex, rowIndex) => { + return colIndex === col || + rowIndex === row - col + colIndex || + rowIndex === row + col - colIndex + })) { + continue; + } + doTry(row + 1, [...tmp,col]); + } + } + doTry(0, []); + return res; +}; \ No newline at end of file diff --git a/Week_03/G20200343030519/Week 03/LeetCode_529_519.js b/Week_03/G20200343030519/Week 03/LeetCode_529_519.js new file mode 100644 index 00000000..692c8b92 --- /dev/null +++ b/Week_03/G20200343030519/Week 03/LeetCode_529_519.js @@ -0,0 +1,48 @@ +// https://leetcode-cn.com/problems/minesweeper/description/ + +var updateBoard = function(board, click) { + let x = click[0]; + let y = click[1]; + // 踩中地雷 + if(board[x][y] == 'M'){ + board[x][y] = 'X'; + return board; + } + let dx = [-1, -1, -1, 1, 1, 1, 0, 0]; + let dy = [-1, 1, 0, -1, 1, 0, -1, 1]; + // 获取当前节点相邻的地雷数量 + let getNumsBombs = (board,x,y) => { + let num = 0; + for(let i = 0;i < 8;i++){ + let newX = x + dx[i]; + let newY = y + dy[i]; + if(newX < 0 || newX >= board.length || newY < 0 || newY >= board[0].length){ + continue; + } + // 八大方向中的其中一点如果是M或者X 说明有地雷 + if(board[newX][newY] == 'M' || board[newX][newY] == 'X'){ + num++; + } + } + return num; + } + let dfs = (board,x,y) => { + // 边界 当前点的横、纵坐标不能小于0,不能大于一维、二维长度 + if(x < 0 || x >= board.length || y < 0 || y >= board[0].length || board[x][y] != 'E'){ + return; + } + let num = getNumsBombs(board,x,y); + if(num == 0){ // 如果为0则进行递归 无地雷继续递归 + board[x][y] = 'B'; + for(let i = 0;i < 8;i++){ + let newX = x + dx[i]; + let newY = y + dy[i]; + dfs(board,newX,newY); + } + }else{ // 不为0则更新当前节点的值为地雷数量 有地雷 + board[x][y] = num + ''; + } + } + dfs(board,x,y); + return board; + }; \ No newline at end of file diff --git a/Week_03/G20200343030519/Week 03/LeetCode_55_519.js b/Week_03/G20200343030519/Week 03/LeetCode_55_519.js new file mode 100644 index 00000000..7b280d55 --- /dev/null +++ b/Week_03/G20200343030519/Week 03/LeetCode_55_519.js @@ -0,0 +1,12 @@ +// https://leetcode-cn.com/problems/jump-game/ + +var camJump = function(nums) { + var lenPoint = nums.length - 1; + var leftPos = lenPoint; + for (var left = lenPoint; left >= 0; left--) { + if (nums[left] + left >= leftPos) { + leftPos = left; + } + } + return leftPos == 0; +}; \ No newline at end of file diff --git a/Week_03/G20200343030519/Week 03/LeetCode_74_519.js b/Week_03/G20200343030519/Week 03/LeetCode_74_519.js new file mode 100644 index 00000000..b658f4ad --- /dev/null +++ b/Week_03/G20200343030519/Week 03/LeetCode_74_519.js @@ -0,0 +1,23 @@ +// https://leetcode-cn.com/problems/search-a-2d-matrix/ + +var searchMatrix = function(matrix, target) { + var m = matrix.length; + if (m == 0) return false; + var n = matrix[0].length; + var low = 0; + var high = m * n - 1; + while (low <= high) { + var mid = (low + high) >> 1; + var row = parseInt(mid / n); + var col = mid % n; + var matrixMid = matrix[row][col]; + if (matrixMid < target) { + low = mid + 1; + } else if (matrixMid > target) { + high = mid -1; + } else if (matrixMid == target) { + return true; + } + } + return false; +}; \ No newline at end of file diff --git a/Week_03/G20200343030519/Week 03/LeetCode_78_519.js b/Week_03/G20200343030519/Week 03/LeetCode_78_519.js new file mode 100644 index 00000000..83ca7aa7 --- /dev/null +++ b/Week_03/G20200343030519/Week 03/LeetCode_78_519.js @@ -0,0 +1,14 @@ +// https://leetcode-cn.com/problems/subsets/ + +var subsets = function(nums) { + let res = [[]]; + for (let i = 0; i < nums.length; i++) { + let len = res.length; + for (let j = 0; j < len; j++) { + let sub = res[j].slice(); + sub.push(nums[i]); + res.push(sub); + } + } + return res; +}; \ No newline at end of file diff --git a/Week_03/G20200343030519/Week 03/LeetCode_860_519.js b/Week_03/G20200343030519/Week 03/LeetCode_860_519.js new file mode 100644 index 00000000..65b54816 --- /dev/null +++ b/Week_03/G20200343030519/Week 03/LeetCode_860_519.js @@ -0,0 +1,28 @@ +// https://leetcode-cn.com/problems/lemonade-change/description/ + +var lemonadeChange = function(bills) { + var five = 0; + var ten = 0; + var len = bills.length; + for (var i = 0; i < len; i++) { + if (bills[i] == 5) { + five++; + } else if (bills[i] == 10) { + if (five == 0) { + return false; + } + five--; + ten++; + } else if (bills[i] == 20) { + if (ten > 0 && five > 0) { + ten--; + five--; + } else if (five >= 3) { + five -= 3; + } else { + return false; + } + } + } + return true; +}; \ No newline at end of file diff --git a/Week_03/G20200343030519/Week 03/LeetCode_874_519.js b/Week_03/G20200343030519/Week 03/LeetCode_874_519.js new file mode 100644 index 00000000..e6ad1382 --- /dev/null +++ b/Week_03/G20200343030519/Week 03/LeetCode_874_519.js @@ -0,0 +1,35 @@ +// https://leetcode-cn.com/problems/walking-robot-simulation/ + +var robotSim = function(commands, obstacles) { + var dx = [0, 1, 0, -1]; + var dy = [1, 0, -1, 0]; + var di = 0; + var endX = 0; + var endY = 0; + var result = 0; + var hashObstacle = {}; + for (var r = 0; r < obstacles.length; r++) { + hashObstacle[obstacles[r][0] + '-' + obstacles[r][1]] = true; + } + for (var s = 0; s < commands.length; s++) { + if (commands[s] == -2) { + di = (di + 3) % 4; + } else if (commands[s] == -1){ + di = (di + 1) % 4; + } else { + // 每次走一步 + for (var z = 1; z <= commands[s]; z++) { + var nextX = endX + dx[di]; + var nextY = endY + dy[di]; + // 判断下一步是否为障碍物 + if (hashObstacle[nextX + '-' + nextY]) { + break; + } + endX = nextX; + endY = nextY; + result = Math.max(result, endX * endX + endY * endY); + } + } + } + return result; +}; \ No newline at end of file diff --git a/Week_03/G20200343030523/id_523/LeetCode_122_523.java b/Week_03/G20200343030523/id_523/LeetCode_122_523.java new file mode 100644 index 00000000..e3800c47 --- /dev/null +++ b/Week_03/G20200343030523/id_523/LeetCode_122_523.java @@ -0,0 +1,25 @@ +package greedy; + +/** + * https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/ + */ +public class BestTimeToBuySellStock { + + public int maxProfit(int[] prices) { + int profit = 0; + for (int i = 0; i < prices.length - 1; i++) { + if (prices[i] < prices[i + 1]) { + profit += prices[i + 1] - prices[i]; + } + } + return profit; + } + + public static void main(String[] args) { + BestTimeToBuySellStock sellStock = new BestTimeToBuySellStock(); + + int[] prices = new int[]{7,6,4,3,1}; + System.out.println(sellStock.maxProfit(prices)); + + } +} diff --git a/Week_03/G20200343030523/id_523/LeetCode_455_523.java b/Week_03/G20200343030523/id_523/LeetCode_455_523.java new file mode 100644 index 00000000..ad9b33f8 --- /dev/null +++ b/Week_03/G20200343030523/id_523/LeetCode_455_523.java @@ -0,0 +1,39 @@ +package greedy; + +import java.util.Arrays; + +/** + * https://leetcode-cn.com/problems/assign-cookies + */ +public class AssignCookies01 { + + public int findContentChildren(int[] g, int[] s) { + + if (g == null || s == null) { + return 0; + } + + Arrays.sort(g); + Arrays.sort(s); + + int gi = 0; + int si = 0; + while (gi < g.length && si < s.length) { + if (s[si] >= g[gi]) { + gi++; + } + si++; + } + + return gi; + } + + public static void main(String[] args) { + int[] g = new int[]{1, 2, 3}; + int[] s = new int[]{2, 1}; + + AssignCookies01 assignCookies = new AssignCookies01(); + System.out.println(assignCookies.findContentChildren(g, s)); + } + +} diff --git a/Week_03/G20200343030523/id_523/LeetCode_860_523.java b/Week_03/G20200343030523/id_523/LeetCode_860_523.java new file mode 100644 index 00000000..e81929ce --- /dev/null +++ b/Week_03/G20200343030523/id_523/LeetCode_860_523.java @@ -0,0 +1,39 @@ +package greedy; + +/** + * https://leetcode-cn.com/problems/lemonade-change + */ +public class LemonadeChange { + + public boolean lemonadeChange(int[] bills) { + int five = 0, ten = 0; + for (int i = 0; i < bills.length; i++) { + if (bills[i] == 5) { + five++; + } else if (bills[i] == 10) { + if (five == 0) { + return false; + } + five--; + ten++; + } else if (bills[i] == 20) { + if (ten > 0 && five > 0) { + ten--; + five--; + } else if (five >= 3) { + five -= 3; + } else { + return false; + } + } + } + return true; + } + + public static void main(String[] args) { + int[] bills = new int[]{5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20, 5, 10, 5, 20}; + LemonadeChange change = new LemonadeChange(); + System.out.println(change.lemonadeChange(bills)); + } + +} diff --git a/Week_03/G20200343030523/id_523/LeetCode_874_523.java b/Week_03/G20200343030523/id_523/LeetCode_874_523.java new file mode 100644 index 00000000..3d66a7ba --- /dev/null +++ b/Week_03/G20200343030523/id_523/LeetCode_874_523.java @@ -0,0 +1,48 @@ +package greedy; + +import java.util.HashSet; +import java.util.Set; + +/** + * https://leetcode-cn.com/problems/walking-robot-simulation + */ +public class WalkingRobotSimulation { + + public int robotSim(int[] commands, int[][] obstacles) { + + Set set = new HashSet<>(); + for (int i = 0; i < obstacles.length; i++) { + set.add(obstacles[i][0] + " " + obstacles[i][1]); + } + + int[][] directions = new int[][]{{0, 1}, {1, 0}, {0, -1}, {-1, 0}}; + + int d = 0, x = 0, y = 0; + int result = 0; + for (int command : commands) { + if (command == -1) { + d = (d + 1) % 4; + } else if (command == -2) { + d = (d - 1 + 4) % 4; + } else { + for (int i = 0; i < command; i++) { + if (!set.contains((x + directions[d][0]) + " " + (y + directions[d][1]))) { + x += directions[d][0]; + y += directions[d][1]; + } + } + } + result = Math.max(result, x * x + y * y); + } + return result; + } + + public static void main(String[] args) { + int[] commands = new int[]{4, -1, 4, -2, 4}; + int[][] obstacles = new int[][]{{2, 4}}; + + WalkingRobotSimulation simulation = new WalkingRobotSimulation(); + System.out.println(simulation.robotSim(commands, obstacles)); + } + +} diff --git a/Week_03/G20200343030527/LeetCode_122_527.java b/Week_03/G20200343030527/LeetCode_122_527.java new file mode 100644 index 00000000..9ccedee8 --- /dev/null +++ b/Week_03/G20200343030527/LeetCode_122_527.java @@ -0,0 +1,9 @@ +class BestTimeToBuyAndSellStockII { + public int maxProfit(int[] prices) { + int maxP = 0; + for(int i = 0; i < prices.length - 1; i++) { + maxP += Math.max(0, prices[i + 1] - prices[i]); + } + return maxP; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030527/LeetCode_169_527.java b/Week_03/G20200343030527/LeetCode_169_527.java new file mode 100644 index 00000000..3d777d48 --- /dev/null +++ b/Week_03/G20200343030527/LeetCode_169_527.java @@ -0,0 +1,17 @@ +class MajorityElement { + public int majorityElement(int[] nums) { + int key = nums[0]; + int count = 0; + for (int i = 0; i < nums.length; i++){ + if(nums[i] == key) + count++; + else + count--; + if(count <= 0) + { + key = nums[i + 1]; + } + } + return key; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030527/LeetCode_860_527.java b/Week_03/G20200343030527/LeetCode_860_527.java new file mode 100644 index 00000000..6e218f9e --- /dev/null +++ b/Week_03/G20200343030527/LeetCode_860_527.java @@ -0,0 +1,24 @@ +class Solution { + public boolean lemonadeChange(int[] bills) { + int five = 0; + int ten = 0; + for (int key : bills) { + if (key == 5) { + five++; + } + else if (key == 10) { + five--; + ten++; + } + else if (ten > 0){ + ten--; + five--; + } + else five -= 3; + if (five < 0) { + return false; + } + } + return true; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030529/LeetCode_127_529.java b/Week_03/G20200343030529/LeetCode_127_529.java new file mode 100644 index 00000000..54c4532d --- /dev/null +++ b/Week_03/G20200343030529/LeetCode_127_529.java @@ -0,0 +1,39 @@ +class Solution { + public int ladderLength(String beginWord, String endWord, List wordList) { + int wordLength = beginWord.length(); + Map> allComboDict = new HashMap<>(); + wordList.forEach(word -> { + for (int i = 0; i < wordLength; i++) { + String express = word.substring(0, i) + "*" + word.substring(i + 1, wordLength); + List combos = allComboDict.getOrDefault(express, new ArrayList<>()); + combos.add(word); + allComboDict.put(express, combos); + } + }); + Queue> queue = new LinkedList<>(); + queue.add(new Pair<>(beginWord, 0)); + + HashMap visited = new HashMap(); + visited.put(beginWord, true); + + while (!queue.isEmpty()) { + Pair pair = queue.poll(); + String word = pair.getKey(); + int level = pair.getValue(); + if (word.equalsIgnoreCase(endWord)) { + return level + 1; + } + for (int i = 0; i < wordLength; i++) { + String express = word.substring(0, i) + "*" + word.substring(i + 1, wordLength); + for(String potential : allComboDict.getOrDefault(express, new ArrayList<>())) { + if (!visited.containsKey(potential)) { + queue.add(new Pair<>(potential, level + 1)); + visited.put(potential, true); + } + + } + } + } + return 0; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030529/LeetCode_200_529.java b/Week_03/G20200343030529/LeetCode_200_529.java new file mode 100644 index 00000000..11686f11 --- /dev/null +++ b/Week_03/G20200343030529/LeetCode_200_529.java @@ -0,0 +1,30 @@ +class Solution { + func numIslands(_ grid: [[Character]]) -> Int { + var count = 0 + var _grid = grid + for i in 0.. 0)留给小额(5块) +// 最后判定的时候back > 0,就是找不开,失败了 + +// 结束判定条件,可以通过five < 0来判断是否符合条件 +/* +func lemonadeChange(bills []int) bool { + // 中间变量,five存五块钱,ten存十块钱,back放找零的钱 + five, ten, back := 0, 0, 0 + + for i := 0; i < len(bills); i++ { + if bills[i] == 5 { + five++ + }else if bills[i] == 10 { + ten++ + } + // 柠檬水五块一杯,返回找零 + back = bills[i] - 5 + // 优先找零十块钱 + // 条件是back >= 10,ten > 0 + for back >= 10 && ten > 0 { + back -= 10 + ten-- + } + // 再次找零5元 + // 条件是back >= 5, five > 0 + for back >= 5 && five > 0 { + back -= 5 + five-- + } + // 余额back大于0,无法完成找零 + if back >0 { + return false + } + } + return true +} +*/ + +// 另一种解法,贪心算法,局部最优 +func lemonadeChange(bills []int) bool { + five, ten := 0, 0 + for i := 0; i < len(bills); i++ { + switch bills[i] { + case 5: + five++ + break + case 10: + { + ten++ + five-- + } + break + case 20: + { + if ten > 0 { + ten-- + five-- + } else { + five = five - 3 + } + break + } + default: + break + } + if five < 0 { + return false + } + } + return true +} diff --git a/Week_03/G20200343030533/LeetCode-153-533.cpp b/Week_03/G20200343030533/LeetCode-153-533.cpp new file mode 100644 index 00000000..addf92f5 --- /dev/null +++ b/Week_03/G20200343030533/LeetCode-153-533.cpp @@ -0,0 +1,17 @@ +// https://leetcode-cn.com/problems/find-minimum-in-rotated-sorted-array/ + +//暴力 +class Solution { +public: + int findMin(vector& nums) { + + int min = INT_MAX; + int n = nums.size(); + + for (int i = 0; i < n; i++){ + if (nums[i] < min) min = nums[i]; + } + return min; + + } +}; \ No newline at end of file diff --git a/Week_03/G20200343030533/LeetCode_017_533.cpp b/Week_03/G20200343030533/LeetCode_017_533.cpp new file mode 100644 index 00000000..3901e7a1 --- /dev/null +++ b/Week_03/G20200343030533/LeetCode_017_533.cpp @@ -0,0 +1,44 @@ +//17. 电话号码的字母组合 +//https://leetcode-cn.com/problems/letter-combinations-of-a-phone-number/ +#include +#include +using namespace std; + +//回溯算法,每次选择一个字母,之后回溯。 +//本质上排列题目 + +class Solution { +public: + vector letterCombinations(string digits) { + + vector m = { + "", + "", "abc","def", + "ghi","jkl","mno", + "pqrs","tuv","wxyz" + }; + + vector res; + if (digits.size() == 0) return res; + string s; + + + DFS(digits, 0, s, res, m); + return res; + } + + void DFS(string digits, int depth, string & s, vector &res, vector& m){ + if (depth == digits.size()){ + res.push_back(s); + return ; + } + //获取对应键盘的字母 + string tmp = m[digits[depth] - '0']; + for (int i = 0; i < tmp.size(); i++){ + s.push_back(tmp[i]); + DFS(digits, depth+1, s, res, m); + s.pop_back(); + } + return ; + } +}; \ No newline at end of file diff --git a/Week_03/G20200343030533/LeetCode_022_533.cpp b/Week_03/G20200343030533/LeetCode_022_533.cpp new file mode 100644 index 00000000..604c8977 --- /dev/null +++ b/Week_03/G20200343030533/LeetCode_022_533.cpp @@ -0,0 +1,33 @@ +//https://leetcode-cn.com/problems/generate-parentheses/ +// 因为每次参数s都要往后传的时候都在已有的基础上发生了变化,因此回来的时候,要重置状态。 +class Solution { +public: + vector generateParenthesis(int n) { + vector res; + string s; + DFS(0,0,n, s, res); + return res; + + } + void DFS(int left, int right, int n, string& s, vector &res){ + if (left == n && right == n){ + res.push_back(s); + return ; + } + + if (left < n){ + s.push_back('('); + DFS(left+1, right, n, s, res); + //reverse state + s.pop_back(); + } + if (right < left){ + s.push_back(')'); + DFS(left, right+1, n, s, res); + //reverse state + s.pop_back(); + } + + + } +}; \ No newline at end of file diff --git a/Week_03/G20200343030533/LeetCode_033_533.cpp b/Week_03/G20200343030533/LeetCode_033_533.cpp new file mode 100644 index 00000000..832be4d6 --- /dev/null +++ b/Week_03/G20200343030533/LeetCode_033_533.cpp @@ -0,0 +1,57 @@ +// https://leetcode-cn.com/problems/search-in-rotated-sorted-array/ + + +//代码比较长度版本 +//先确定自己是在那个部分 + +class Solution{ +public: + int search(vector& nums, int target){ + int low = 0, high = nums.size() - 1; + + while ( low <= high){ + int mid = low + (high - low ) / 2; + if (target == nums[mid]) return mid; //找到了 + //low-mid递增 + if ( nums[low] <= nums[mid]){ + // targe在当前区间里 + if ( target >= nums[low] && target < nums[mid]){ + high = mid - 1; + } else { + low = mid + 1; //不在, 说明在mid-high里 + } + } else{ //分析mid-high + if ( target > nums[mid] && target <= nums[high]){ + low = mid + 1; + } else{ + high = mid - 1; + } + } + } + return -1; + } +}; + +// 代码2 +class Solution { +public: + int search(vector& nums, int target) { + + int low = 0; + int high = nums.size() - 1; + + while (low < high) { + int mid = ( low + high) >> 1; + if (nums[mid] == target ) return mid; + if (nums[0] <= nums[mid] && ( target > nums[mid] || target < nums[0] )){ + low = mid + 1; + } else if ( target > nums[mid] && target < nums[0]){ + low = mid + 1; + } else{ + high = mid; + } + } + return low == high && nums[low] == target ? low : - 1; + } + +}; \ No newline at end of file diff --git a/Week_03/G20200343030533/LeetCode_045_533.cpp b/Week_03/G20200343030533/LeetCode_045_533.cpp new file mode 100644 index 00000000..7406bc0b --- /dev/null +++ b/Week_03/G20200343030533/LeetCode_045_533.cpp @@ -0,0 +1,22 @@ +//https://leetcode-cn.com/problems/jump-game-ii/ + +//局部贪心法, +//每次跳之前,分析后续可抵达位置,选择后面位置最大的哪一个 + +class Solution { +public: + int jump(vector& nums) { + int step = 0; + int end = 0; + int maxPos = 0; //最远抵达的位置 + for (int i = 0; i < nums.size() - 1; i++){ + maxPos = max(nums[i] + i, maxPos); + if ( i == end ){ + end = maxPos; //更新最远的位置 + step++; + } + } + return step; + + } +}; \ No newline at end of file diff --git a/Week_03/G20200343030533/LeetCode_050_533.cpp b/Week_03/G20200343030533/LeetCode_050_533.cpp new file mode 100644 index 00000000..5b804943 --- /dev/null +++ b/Week_03/G20200343030533/LeetCode_050_533.cpp @@ -0,0 +1,31 @@ +// 50. Pow(x, n) +// https://leetcode-cn.com/problems/powx-n/ +// 由于整型的正数比负数少了一位,因此最小值不能直接取负 +// 必须要转换一下类型 +class Solution { +public: + double myPow(double x, int n) { + int flag = 0; + + long long N = (long long)n; + + if (N < 0){ + N = - N; + flag = 1; + } + + return flag == 0 ? fastPow(x, N) : 1.0 / fastPow(x, N); + + + + } + double fastPow(double x, long long n){ + if (n == 0 ) return 1; + if (n == 1 ) return x; + + double result = fastPow(x, n / 2); + + return n % 2 == 0 ? result * result : result * result * x; + + } +}; \ No newline at end of file diff --git a/Week_03/G20200343030533/LeetCode_051_533.cpp b/Week_03/G20200343030533/LeetCode_051_533.cpp new file mode 100644 index 00000000..922ae031 --- /dev/null +++ b/Week_03/G20200343030533/LeetCode_051_533.cpp @@ -0,0 +1,118 @@ +//51. N皇后 +// https://leetcode-cn.com/problems/n-queens/ + +//51. N皇后 +// https://leetcode-cn.com/problems/n-queens/ + +class Solution { +public: + vector> solveNQueens(int n) { + + vector> res; + if (n < 1) return res; + + set cols; + set pie; + set na; + + vector curr; + + DFS(n, 0, cols, pie , na, curr, res); + + return res; + + } + void DFS(int n, int row, set& cols, set& pie, set& na, vector& curr, vector>& res){ + if (row >= n){ + res.push_back(generate_result(curr, n)); + return ; + } + + for (int col = 0; col < n; col++){ + if ( cols.count(col) > 0 || pie.count(row+col) >0 || na.count(row-col) >0 ) { + continue; + } + cols.insert(col); + pie.insert(row+col); + na.insert(row-col); + + curr.push_back(col); + DFS(n, row+1, cols, pie, na, curr, res); + // reverse + curr.pop_back(); + cols.erase(col); + pie.erase(row+col); + na.erase(row-col); + + + } + + } + //产生结果 + vector generate_result(vector& curr, int n){ + vector res; + for (int i = 0; i < curr.size(); i++){ + string tmp ; + for (int j = 0; j < curr[i]; j++){ + tmp += "."; + } + tmp += "Q"; + for (int j = curr[i]+1; j < n; j++){ + tmp += "."; + } + res.push_back(tmp); + } + return res; + + } +}; +class Solution { +//更加简洁的方法 +private: + vector board; + vector> ans; + /* + *@param board: 棋盘 + *@param pos: 当前位置 + *@param depth: 深度,也就是所在行 + *@param n: 皇后数 + */ + void solve(vector& board, vector& pos, int depth, int n){ + if (depth == n){ + ans.push_back(board); + return ; + } + for (int i = 0; i < n ; i++){ + pos[depth] = i; + if (valid(pos, depth)){ + board[depth][i] = 'Q'; + solve(board, pos, depth + 1, n); + board[depth][i] = '.'; + } + } + } + //列相同最容易判断 + //主要是对角线判断 + //对角线 y = |x|, y-y0 = | x-x0 | + bool valid(vector pos, int curLen){ + //检查之前的皇后影响 + for (int i = 0; i < curLen; i++){ + if ( pos[i] == pos[curLen] || abs(pos[i] - pos[curLen]) == curLen - i){ + return false; + } + } + return true; + } +public: + vector> solveNQueens(int n){ + //初始化棋盘 + string row(n, '.'); + for (int i = 0; i pos = vector(n); + solve(board, pos, 0, n); + return ans; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030533/LeetCode_055_533.cpp b/Week_03/G20200343030533/LeetCode_055_533.cpp new file mode 100644 index 00000000..1782814c --- /dev/null +++ b/Week_03/G20200343030533/LeetCode_055_533.cpp @@ -0,0 +1,111 @@ + +// 55. 跳跃游戏 +// https://leetcode-cn.com/problems/jump-game/ + +//贪心法 +//算法思想: 从后往前循环,记住能抵达终点的位置 +class Solution { +public: + bool canJump(vector& nums) { + if ( nums.size() == 0 ) return false; + + int canReach = nums.size() - 1; + + for (int i =nums.size() - 1; i >= 0 ; i--){ + //当前位置所走的步数是否大于最后一个可抵达的位置。 + if ( nums[i] + i >= canReach ){ + canReach = i; + } + } + return canReach == 0; + + } +}; + + +//回溯代码 + +/*这是原来的代码, 存在bug +class Solution { +public: + bool canJump(vector& nums) { + + if (nums.size() == 0 ) return false; + + return DFS(nums, 0); + + } + + bool DFS(vector& nums, int d){ + //递归终止条件 + // 当前位置是0,或者到达矩阵最后一个位置 + if (nums[d] == 0 || d>=nums.size()-1){ + return d>=nums.size() -1 ? true : false; + } + int maxStep = nums[d]; + bool status = true; + for ( int i = maxStep; i >= 1; i--){ + if (d + i >= nums.size() - 1){ + return true; + } + status = DFS(nums, d + i); + } + return status; + } +}; + +//通过学习官方题解,修改如下 +class Solution { +public: + bool canJump(vector& nums) { + + if (nums.size() == 0 ) return false; + + return DFS(nums, 0); + + } + + bool DFS(vector& nums, int d){ + //递归终止条件 + if (d>=nums.size()-1){ + return true ; + } + int maxStep = nums[d]; + for ( int i = maxStep; i >= 1; i--){ + if (DFS( nums, d +i)){ + return true; + } + } + return false; + } +}; + +//代码的问题,是存在大量重复运算,需要进行记忆化,(这就是动态规划了),但是依旧超出时间 +class Solution { +public: + vector visited; + bool canJump(vector& nums) { + + if (nums.size() == 0 ) return false; + visited = vector(nums.size(), false); + + return DFS(nums, 0); + + } + + bool DFS(vector& nums, int d){ + //递归终止条件 + if (d>=nums.size()-1){ + return true ; + } + visited[d] = true; + int maxStep = nums[d]; + for ( int i = maxStep; i >= 1; i--){ + if ( ! visited[d+i] && DFS( nums, d +i)){ + return true; + } + } + return false; + } +}; +*/ \ No newline at end of file diff --git a/Week_03/G20200343030533/LeetCode_069_533.cpp b/Week_03/G20200343030533/LeetCode_069_533.cpp new file mode 100644 index 00000000..4d3a93d3 --- /dev/null +++ b/Week_03/G20200343030533/LeetCode_069_533.cpp @@ -0,0 +1,47 @@ +//69. x 的平方根 +//https://leetcode-cn.com/problems/sqrtx/ + +//注意点: +// 溢出 mid * mid 可能会溢出, 因此用除法 +// 因为用除法,要小心0和1 +// 最后返回left-1, 因为最终是left== right, 而right是大于结果的。 +// left 肯定大于1 +class Solution { +public: + int mySqrt(int x) { + + if (x == 0 || x == 1) return x; + + int left = 1, right = x; + int mid; + + while (left <= right){ + mid = left + ((right-left) >> 1); + if (mid == x / mid){ + return mid; + } else if ( mid < x / mid){ + left = mid + 1; + } else{ + right = mid -1; + } + } + return left-1; + + } +}; + +//牛顿迭代法 +//https://www.beyond3d.com/content/articles/8/ +//注意,long long r, 否则溢出 +class Solution { +public: + int mySqrt(int x) { + if ( x== 0 || x == 1) return x; + long long r = x; + while(r *r > x){ + r = ( r + x /r ) >> 1; + } + return r; + + } +}; \ No newline at end of file diff --git a/Week_03/G20200343030533/LeetCode_074_533.cpp b/Week_03/G20200343030533/LeetCode_074_533.cpp new file mode 100644 index 00000000..35f57462 --- /dev/null +++ b/Week_03/G20200343030533/LeetCode_074_533.cpp @@ -0,0 +1,28 @@ +// https://leetcode-cn.com/problems/search-a-2d-matrix/ + +//二维数组整体升序,因此当作一维数组 +class Solution { +public: + bool searchMatrix(vector>& matrix, int target) { + + if ( matrix.size() == 0 ) return false; + int row = matrix.size(); + int col = matrix[0].size(); + + int left = 0, right = row * col - 1; + + while (left <= right){ + int mid = left + (right-left) / 2; + int ele = matrix[mid/col][mid%col]; + if ( target == ele) return true; + if ( target > ele){ + left = mid + 1; + } else{ + right = mid - 1; + } + } + + return false; + + } +}; \ No newline at end of file diff --git a/Week_03/G20200343030533/LeetCode_078_533.cpp b/Week_03/G20200343030533/LeetCode_078_533.cpp new file mode 100644 index 00000000..1866d655 --- /dev/null +++ b/Week_03/G20200343030533/LeetCode_078_533.cpp @@ -0,0 +1,32 @@ +// 78.子集 +// https://leetcode-cn.com/problems/subsets/ + +// 题目求解思路是回溯, 每一次就试试不同可能性 + +class Solution { +public: + vector> subsets(vector& nums) { + vector> res; + vector subset; + + _DFS(nums, 0, subset, res); + return res; + + } + void _DFS(vector& nums, int pos, vector& subset, vector>& res){ + if (pos >= nums.size()) { + res.push_back(subset); + return; + } + //不增加元素 + _DFS(nums, pos+1, subset, res); + //增加元素 + subset.push_back(nums[pos]); + _DFS(nums, pos+1, subset, res); + //重置状态 + subset.pop_back(); + return; + + + } +}; \ No newline at end of file diff --git a/Week_03/G20200343030533/LeetCode_102_533.cpp b/Week_03/G20200343030533/LeetCode_102_533.cpp new file mode 100644 index 00000000..f2842528 --- /dev/null +++ b/Week_03/G20200343030533/LeetCode_102_533.cpp @@ -0,0 +1,31 @@ +// 102. 二叉树的层次遍历 +// https://leetcode-cn.com/problems/binary-tree-level-order-traversal/ + +//和BFS模版不同处在于,在while循环内嵌套了一层for循环 +//原来对每个循环处理一个node,现在每个循环处理一层node + +class Solution { +public: + vector> levelOrder(TreeNode* root) { + vector> ret; + if ( root == NULL ) return ret; + + queue myque; + myque.push(root); + + while ( ! myque.empty() ){ + vector curr; + int level_size = myque.size(); + for (int i = 0; i < level_size; ++i){ + TreeNode *node = myque.front(); + myque.pop(); + curr.push_back(node->val); + if (node->left != NULL ) myque.push(node->left); + if (node->right != NULL ) myque.push(node->right); + } + ret.push_back(curr); + } + return ret; + + } +}; \ No newline at end of file diff --git a/Week_03/G20200343030533/LeetCode_122_533.cpp b/Week_03/G20200343030533/LeetCode_122_533.cpp new file mode 100644 index 00000000..1ec83074 --- /dev/null +++ b/Week_03/G20200343030533/LeetCode_122_533.cpp @@ -0,0 +1,19 @@ +// https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/ + +//贪心算法,每次移动一天,如果第二天比今天高,就买,否则就不买 +class Solution { +public: + int maxProfit(vector& prices) { + if ( prices.size() == 0 ) return 0; + int profit = 0; + int i = 0; + while (i < prices.size() - 1){ + if (prices[i] < prices[i+1]){ + profit += prices[i+1] - prices[i]; + } + i++; + } + return profit; + + } +}; \ No newline at end of file diff --git a/Week_03/G20200343030533/LeetCode_126_533.cpp b/Week_03/G20200343030533/LeetCode_126_533.cpp new file mode 100644 index 00000000..2925ad09 --- /dev/null +++ b/Week_03/G20200343030533/LeetCode_126_533.cpp @@ -0,0 +1,54 @@ +// 126. 单词接龙 II +// https://leetcode-cn.com/problems/word-ladder-ii/ + +//和127相似,只不过这次要把可能路径都输出 +// 和层次遍历类似,不是单个单个出队,而不是一起出队。 +class Solution { +public: + vector> findLadders(string beginWord, string endWord, vector& wordList) { + + vector> res;// 输出结果 + unordered_set dict(wordList.begin(), wordList.end()); //记录节点 + if ( dict.find(endWord) == dict.end()) return res;//没有结果 + + queue> q; + q.push({beginWord}); //加入初始值 + + while ( ! q.empty() ){ + vector path; //路径 + int s = q.size(); //处理当前队列的所有节点 + vector newWords; //添加当前队列所有节点的访问节点 + while ( s--) { + path = q.front(); + q.pop(); + //如果路径的最后一个word就是终点,增加记录 + if (path.back() == endWord) { + res.push_back(path); + } + string word = path.back(); + for ( int i = 0 ; i < word.size(); i++ ){ + char tmp = word[i]; + for ( char ch = 'a'; ch <= 'z'; ch++){ + if ( word[i] == ch) continue; + word[i] = ch; + //关键部分,如果能找到下一个词 + if ( dict.find(word) != dict.end() ){ + vector newPath (path.begin(), path.end()); + newPath.push_back(word); + q.push(newPath); + newWords.push_back(word); //记录访问的节点 + } + } + word[i] = tmp; + } + } + //在队列结束之后 + for (string w : newWords){ + dict.erase(w); + } + } + + return res; + + } +}; \ No newline at end of file diff --git a/Week_03/G20200343030533/LeetCode_127_533.cpp b/Week_03/G20200343030533/LeetCode_127_533.cpp new file mode 100644 index 00000000..0cb9c785 --- /dev/null +++ b/Week_03/G20200343030533/LeetCode_127_533.cpp @@ -0,0 +1,112 @@ +// 127.单词接龙 +// https://leetcode-cn.com/problems/word-ladder/ + +class Solution{ +private: + //计算两个单词之间的距离 + int wordDist(const string& w1, const string &w2){ + int cnt = 0; + for (int i = 0; i < w1.size(); i++){ + if (w1[i] != w2[i]) cnt++; + } + return cnt; + } + //寻找当前单词的所有邻接单词 + vector findAdj(string& target, vector& wordList){ + vector res; + for (const auto& word : wordList){ + if(wordDist(target, word) == 1){ + res.push_back(word); + } + } + return res; + } +public: + int ladderLength(string beginWord, string endWord, vector& wordList){ + + deque de; + deque nde; //临近单词队列 + //记录访问过的节点 + unordered_set visited; + + //加入第一个节点 + de.push_back(beginWord); + visited.insert(beginWord); + + int cnt = 0; + while(!de.empty () || !nde.empty() ){ + if (de.empty()){ + swap(de, nde); + cnt++; + } + //出队,获取当前word + auto str = de.front(); + de.pop_front(); + //找到当前单词的所有临近词 + for (auto e : findAdj(str, wordList)){ + if ( e == endWord) return cnt + 2; //临近词就是结束 + if (visited.find(e) == visited.end() ){ //没有访问 + visited.insert(e); + nde.push_back(e); + } + } + } + return 0; + + } +}; + +/* 提前算好算好距离, 速度可能会慢,因为有些词,访问不到,存在无效计算。 + + unordered_map> m; + m[beginWord] = findAdj(beginWord, wordList); + for (auto word : wordList){ + m[word] = findAdj(word, wordList); + } +*/ + +//双端BFS +//不再按个计算和其他单词的距离,直接替换单词,看能不能换,能换就继续下去。 +class Solution{ +public: + int ladderLength(string beginWord, string endWord, vector& wordList){ + //加入所有节点,访问过一次,删除一个。 + unordered_set s; + for (auto &i : wordList) s.insert(i); + + queue> q; + //加入beginword + q.push({beginWord, 1}); + + string tmp; //每个节点的字符 + int step; //抵达该节点的step + + while ( !q.empty() ){ + if ( q.front().first == endWord){ + return (q.front().second); + } + tmp = q.front().first; + step = q.front().second; + q.pop(); + + //寻找下一个单词了 + char ch; + for (int i = 0; i < tmp.length(); i++){ + ch = tmp[i]; + for (char c = 'a'; c <= 'z'; c++){ + //从'a'-'z'尝试一次 + if ( ch == c) continue; + tmp[i] = c ; + //如果找到的到 + if ( s.find(tmp) != s.end() ){ + q.push({tmp, step+1}); + s.erase(tmp) ; //删除该节点 + } + tmp[i] = ch; //复原 + } + + } + } + return 0; + } +}; diff --git a/Week_03/G20200343030533/LeetCode_153_533.cpp b/Week_03/G20200343030533/LeetCode_153_533.cpp new file mode 100644 index 00000000..addf92f5 --- /dev/null +++ b/Week_03/G20200343030533/LeetCode_153_533.cpp @@ -0,0 +1,17 @@ +// https://leetcode-cn.com/problems/find-minimum-in-rotated-sorted-array/ + +//暴力 +class Solution { +public: + int findMin(vector& nums) { + + int min = INT_MAX; + int n = nums.size(); + + for (int i = 0; i < n; i++){ + if (nums[i] < min) min = nums[i]; + } + return min; + + } +}; \ No newline at end of file diff --git a/Week_03/G20200343030533/LeetCode_169_533.cpp b/Week_03/G20200343030533/LeetCode_169_533.cpp new file mode 100644 index 00000000..3fc94933 --- /dev/null +++ b/Week_03/G20200343030533/LeetCode_169_533.cpp @@ -0,0 +1,95 @@ +//169. 多数元素 +// https://leetcode-cn.com/problems/majority-element/description/ + +//方法1, 用map统计, 40ms +class Solution { +public: + int majorityElement(vector& nums) { + + unordered_map dict; + for (int i = 0 ;i < nums.size(); i++){ + if (dict.count(nums[i]) == 0 ){ + dict[nums[i]] = 1; + } else{ + dict[nums[i]]++; + } + } + int max_freq = 0; + int max_num = 0; + for (auto it = dict.begin(); it != dict.end(); it++){ + if (it->second > max_freq){ + max_freq = it->second; + max_num = it->first; + } + } + return max_num; + + } +}; + +//方法2: 分治方法 +//注意输入的high=nums.size()-1 +//难点在于merge +class Solution { +public: + int majorityElement(vector& nums) { + int high = nums.size(); + int res = DC(nums, 0, high-1); + return res; + + } + int DC(vector&nums, int low, int high){ + //只有一个元素 + if ( low == high) return nums[low]; + + //分割元素, 递归 + int mid = low + ((high-low) >> 1); + int left = DC(nums, low, mid); + int right= DC(nums, mid+1, high); + + //如果左右一致,则合并 + if (left == right) return left; + //如果不一致, 统计次数 + int leftCount = countNums(left, nums, low, mid); + int rightCount = countNums(right, nums, mid+1, high); + + return leftCount > rightCount ? left : right; + + } + int countNums(int num, vector& nums, int low, int high){ + int count = 0; + for (int i = low; i <= high; i++){ + if (nums[i] == num) count+=1; + } + return count; + } +}; + +//方法3:排序, +// 占据了n/2的空间,因此排序后的n/2元素一定是众数 +class Solution { +public: + int majorityElement(vector& nums) { + sort(nums.begin(), nums.end()); + return nums[nums.size() / 2]; + + } +}; + +//方法4: 投票法. 不直观,但是很巧妙 +class Solution { +public: + int majorityElement(vector& nums) { + int candidate; + int count = 0; + for (auto num : nums){ + if (count == 0){ + candidate = num; + } + count += (num == candidate) ? 1 : -1; + } + return candidate; + + } +}; + diff --git a/Week_03/G20200343030533/LeetCode_200_533.cpp b/Week_03/G20200343030533/LeetCode_200_533.cpp new file mode 100644 index 00000000..a449109d --- /dev/null +++ b/Week_03/G20200343030533/LeetCode_200_533.cpp @@ -0,0 +1,38 @@ +// 200. 岛屿数量 +// https://leetcode-cn.com/problems/number-of-islands/ + +class Solution { +public: + int dx[4] = {-1, 1, 0, 0}; + int dy[4] = { 0, 0,-1, 1}; + int numIslands(vector>& grid) { + int nums = 0; + for (int i = 0; i < grid.size(); i++){ + for (int j = 0; j < grid[i].size(); j++){ + if ( grid[i][j] == '1') { + DFS(grid, i, j); + nums++; + } + } + } + return nums; + + } + void DFS(vector>& grid, int row, int col){ + if (grid[row][col] == '0'){ + return ; + } + grid[row][col] = '0'; + + for (int k = 0; k < 4; k++){ + int x = row + dx[k]; + int y = col + dy[k]; + if ( x >= 0 && x < grid.size() && y >=0 && y < grid[0].size() ){ + if (grid[x][y] == '0') continue; + DFS(grid, x, y); + } + } + return ; + + } +}; \ No newline at end of file diff --git a/Week_03/G20200343030533/LeetCode_367_533.cpp b/Week_03/G20200343030533/LeetCode_367_533.cpp new file mode 100644 index 00000000..dbd89b1c --- /dev/null +++ b/Week_03/G20200343030533/LeetCode_367_533.cpp @@ -0,0 +1,39 @@ +// +class Solution { +public: + bool isPerfectSquare(int num) { + if ( num == 0 ) return false; + if ( num == 1) return true; + + int left = 1, right = num; + long long mid; + while (left <= right){ + mid = left + ( (right-left) >> 1); + if ( mid * mid == num){ + return true; + } else if ( mid * mid > num){ + right = mid -1; + } else{ + left = mid + 1; + } + } + return false; + + } +}; + + + +//完全平方数的性质,从1开始的n个奇数的和是完全平方数。 +class Solution { +public: + bool isPerfectSquare(int num) { + int num1 = 1; + while (num > 0){ + num -= num1; + num1 += 2; + } + return num == 0; + + } +}; diff --git a/Week_03/G20200343030533/LeetCode_433_533.cpp b/Week_03/G20200343030533/LeetCode_433_533.cpp new file mode 100644 index 00000000..61563578 --- /dev/null +++ b/Week_03/G20200343030533/LeetCode_433_533.cpp @@ -0,0 +1,48 @@ +//433. 最小基因变化 +//https://leetcode-cn.com/problems/minimum-genetic-mutation/#/description + +//思路是127一样, 127题目的简化版 + +class Solution { +public: + int minMutation(string start, string end, vector& bank) { + + //记录所有需要访问的节点 + unordered_set candidate(bank.begin(), bank.end()); + //记录基因和step + queue> q; + + q.push({start, 0}); + + string gene; + int step; + + while( ! q.empty()) { + //终止条件 + if (q.front().first == end){ + return q.front().second; + } + + gene = q.front().first; + step = q.front().second; + q.pop(); +// 遍历基因的每个碱基,然后将其进行替换,如果在基因库中有候选,那就完成一次突变,并且从基因库中将对应的基因删除。 + + for (int i = 0; i < gene.length(); i++){ + char tmp = gene[i]; //记录原状态 + for (char base : "ATCG"){ + if (gene[i] == base) continue; //相同就不变化 + gene[i] = base; //修改碱基 + if( candidate.find(gene) != candidate.end()){ + q.push({gene, step+1}); + candidate.erase(gene); + } + } + gene[i] = tmp; + + } + } + return -1; + + } +}; \ No newline at end of file diff --git a/Week_03/G20200343030533/LeetCode_455_533.cpp b/Week_03/G20200343030533/LeetCode_455_533.cpp new file mode 100644 index 00000000..8cfd1856 --- /dev/null +++ b/Week_03/G20200343030533/LeetCode_455_533.cpp @@ -0,0 +1,17 @@ +// 455. 分发饼干 +// https://leetcode-cn.com/problems/assign-cookies/ +class Solution { +public: + int findContentChildren(vector& g, vector& s) { + sort(g.begin(), g.end()); + sort(s.begin(), s.end()); + + register int gi = 0, si = 0; + while (gi < g.size() && si < s.size()){ + if ( g[gi] <= s[si]) gi++; //用最小的满足胃口最小 + si++; //无论是否满足,都换到下一个饼干 + } + return gi; + + } +}; \ No newline at end of file diff --git a/Week_03/G20200343030533/LeetCode_515_533.cpp b/Week_03/G20200343030533/LeetCode_515_533.cpp new file mode 100644 index 00000000..b645a486 --- /dev/null +++ b/Week_03/G20200343030533/LeetCode_515_533.cpp @@ -0,0 +1,59 @@ +// 515. 在每个树行中找最大值 +//https://leetcode-cn.com/problems/find-largest-value-in-each-tree-row/#/description + +//这题思路和102题一样。因此会了102题之后就觉得很简单。 +// 主要是队列中嵌套循环,每一次处理一层而不是一个。 +class Solution { +public: + vector largestValues(TreeNode* root) { + vector res; + if (root == NULL) return res; + + queue myque; + myque.push(root); + + while ( ! myque.empty() ){ + int level_size = myque.size(); + int max = INT_MIN; + for (int i = 0; i < level_size; i++){ + TreeNode *node = myque.front(); + myque.pop(); + max = node->val > max ? node->val : max; + + if (node->left != NULL) myque.push(node->left); + if (node->right != NULL) myque.push(node->right); + } + res.push_back(max); + } + return res; + + } +}; + +//深度优先代码,利用有序map存放结果(可以用数组) +class Solution { +public: + + vector largestValues(TreeNode* root) { + map m; + DFS(root, 0, m); + //输出结果 + vector res; + for (auto &p : m){ + res.push_back(p.second); + } + return res; + + } + + void DFS(TreeNode* root, int d, map & m){ + if (root == NULL) return; + //利用字典记录深度 + m[d] = (m.count(d) == 0) ? root->val : max(m[d], root->val); + + DFS(root->left, d+1, m); + DFS(root->right, d+1, m); + return ; + } + +}; \ No newline at end of file diff --git a/Week_03/G20200343030533/LeetCode_529.533.cpp b/Week_03/G20200343030533/LeetCode_529.533.cpp new file mode 100644 index 00000000..a01cccfd --- /dev/null +++ b/Week_03/G20200343030533/LeetCode_529.533.cpp @@ -0,0 +1,91 @@ +//529. 扫雷游戏 +//https://leetcode-cn.com/problems/minesweeper/description/ + +/* 字母的含义 + * M: 未挖的地雷 + * E: 未挖的空块 + * B: 四个对角线都没有地雷, 挖出方块 + * 1-8: 表示附近有多少地雷 + */ + +//需要一个坐标记录是否访问, 避免无效搜索 +//四面八方的搜索,而不是上下左右 +class Solution { +public: + int dx[8] = {-1,-1,-1, 0, 0, 1, 1, 1}; + int dy[8] = { 1, 0,-1, 1,-1, 1, 0, -1}; + vector> updateBoard(vector>& board, vector& click) { + int row = click[0]; + int col = click[1]; + //访问记录 + vector> visited( board.size(), + vector(board[0].size(), false) ); + if(board[row][col] == 'M'){ + board[row][col] = 'X'; + } else{ + DFS(row, col, board, visited); + } + return board; + } + void DFS(int row, int col, vector>& board, vector>& visited){ + visited[row][col] = true; + + //统计附近是否有雷, 有雷就返回 + int mn = findMine(row, col, board); + if ( mn > 0 ) { + board[row][col] = '0' + mn; + return ; + } + //没有雷就移动 + board[row][col] = 'B'; + for (int k = 0; k < 8; k++){ + int x = row + dx[k], y = col + dy[k]; + if ( x >= 0 && x < board.size() && y >= 0 && y < board[0].size() && \ + board[x][y]=='E' && !visited[x][y]){ + DFS(x, y, board, visited); + } + } + } + int findMine(int row, int col, vector>& board){ + //左上、左、左下、上、下、右上、右、右下 + int count = 0; + for (int i = 0; i < 8; i++){ + int x = row + dx[i], y = col + dy[i]; + if ( x >= 0 && x < board.size() && y >= 0 && y < board[0].size()){ + if ( board[x][y] == 'M') count+=1; //有雷+1 + } + } + return count; + } +}; + +/* +[["E","E","E","E","E","E","E","E"], + ["E","E","E","E","E","E","E","M"], + ["E","E","M","E","E","E","E","E"], + ["M","E","E","E","E","E","E","E"], + ["E","E","E","E","E","E","E","E"], + ["E","E","E","E","E","E","E","E"], + ["E","E","E","E","E","E","E","E"], + ["E","E","M","M","E","E","E","E"]] +[0,0] + + +[["B","B","B","B","B","B","1","E"], + ["B","1","1","1","B","B","1","M"], + ["1","E","M","1","B","B","1","1"], + ["M","E","1","1","B","B","B","B"], + ["1","1","B","B","B","B","B","B"], + ["B","B","B","B","B","B","B","B"], + ["B","1","2","2","1","B","B","B"], + ["B","1","M","M","1","B","B","B"]] + +[["B","B","B","B","B","B","1","E"], + ["B","1","1","1","B","B","1","M"], + ["1","2","M","1","B","B","1","1"], + ["M","2","1","1","B","B","B","B"], + ["1","1","B","B","B","B","B","B"], + ["B","B","B","B","B","B","B","B"], + ["B","1","2","2","1","B","B","B"], + ["B","1","M","M","1","B","B","B"]] +*/ \ No newline at end of file diff --git a/Week_03/G20200343030533/LeetCode_860_533.cpp b/Week_03/G20200343030533/LeetCode_860_533.cpp new file mode 100644 index 00000000..74e46b92 --- /dev/null +++ b/Week_03/G20200343030533/LeetCode_860_533.cpp @@ -0,0 +1,41 @@ +// 860. 柠檬水找零 +// https://leetcode-cn.com/problems/lemonade-change/ +// 因为是倍数关系,因此能用贪心 + +/*考虑的情况 + * 5, 可用5+1 + * 10,可用5-1,可用10+1 + * 20: 分为两种情况 + * - 5 和 10 都有,可用5-1,可用10-1 + * - 只有5,且大于2张, 可用5-3 + */ + +class Solution { +public: + bool lemonadeChange(vector& bills) { + if (bills.size() == 0 ) return true; + int used_five = 0; //可用5元 + int used_ten = 0; //可用的10元 + for ( int i = 0 ; i < bills.size(); i++ ){ + if (bills[i] == 5) { + used_five += 1; + } else if ( bills[i] == 10){ + if ( used_five == 0 ) return false; + used_five -= 1; + used_ten += 1; + } else { + if (used_five > 0 && used_ten > 0){ + used_five -= 1; + used_ten -= 1; + } else if ( used_five > 2){ + used_five -= 3; + } else{ + return false; + } + + } + } + return true; + + } +}; \ No newline at end of file diff --git a/Week_03/G20200343030533/LeetCode_874_533.cpp b/Week_03/G20200343030533/LeetCode_874_533.cpp new file mode 100644 index 00000000..e7332242 --- /dev/null +++ b/Week_03/G20200343030533/LeetCode_874_533.cpp @@ -0,0 +1,211 @@ + +//https://leetcode-cn.com/problems/walking-robot-simulation/description/ + +/*做题过程: +审题: +1. 一共有2类指令,一种是改变方向,一种是移动。第一个问题如何记住当前移动方向 +2. 空间中存在障碍物,移动的时候会碰壁。如何分析自己会碰壁? + +第一个问题的解决思路,让我想到了之前的dx, dy,建立一个方向变量,每次变更位置后,传递方向变量对应位置 +于是我写下了下面这部分代码,先保证在没有障碍之前,我的程序能够运行 +*/ + +class Solution { +private: + //up, right, down, left + int dx[4] = { 0, 1, 0, -1}; + int dy[4] = { 1, 0, -1, 0}; + int end[2] = {0, 0} ;//初始位置 +public: + int robotSim(vector& commands, vector>& obstacles) { + int towards = 0;//默认是上 + for (auto c : commands){ + if ( c == -2){ + towards = (towards+4-1) % 4; + } else if ( c == -1 ){ + towards = (towards+1) % 4; + } else{ + end[0] += c * dx[towards]; + end[1] += c * dy[towards]; + } + } + return end[0] * end[0] + end[1] * end[1]; + + + } +}; + +// 但是发现代码有问题,结果不正确,我以为是行走部分的代码错了,仔细检查,发现是审题不当, +// 要求返回的是返回从原点到机器人的最大欧式距离的平方。而不是最后一个位置, +// 修改后 +class Solution { +private: + //up, right, down, left + int dx[4] = { 0, 1, 0, -1}; + int dy[4] = { 1, 0, -1, 0}; + int end[2] = {0, 0} ;//初始位置 +public: + int robotSim(vector& commands, vector>& obstacles) { + int towards = 0;//默认是上 + int maxpos = 0; + for (auto c : commands){ + if ( c == -2){ + towards = (towards+4-1) % 4; + } else if ( c == -1 ){ + towards = (towards+1) % 4; + } else{ + end[0] += c * dx[towards]; + end[1] += c * dy[towards]; + maxpos = max(end[0] * end[0] + end[1] * end[1], maxpos); + } + } + return maxpos + + + } +}; + +/* 下一个问题,是如何处理障碍物。 +或者是说,什么时候要考虑障碍物? +假如有[2,4],[0,8]两个障碍物, +当我在[1,1]的时候,无论往哪里走都不会被限制住。 +当我在[0,4]的时候,往上会遇到[0,8] 往右会遇到[2,4]. +一开始我的想法是,根据要走的方向来筛选可能会遇到的障碍物,但是仔细思考,觉得这样子会很复杂,代码量很大。 +不如直接把路走了(也就是规划好可能的位置),然后分析和预期终点的x或者y相同的可能障碍。 +进一步,我又想到,我们可以记录前一个位置的x和y, +- 如果x没变化,那我们就寻找x相同的障碍 +- 如果y没变化,那我们就寻找y相同的障碍 +*/ + +class Solution { +private: + //up, right, down, left + int dx[4] = { 0, 1, 0, -1}; + int dy[4] = { 1, 0, -1, 0}; + int end[2] = {0, 0} ;//初始位置 + int prev[2] = {0,0} ;//前一个位置 +public: + int robotSim(vector& commands, vector>& obstacles) { + int towards = 0;//默认是上 + int maxpos = 0; + for (auto c : commands){ + if ( c == -2){ + towards = (towards+4-1) % 4; + } else if ( c == -1 ){ + towards = (towards+1) % 4; + } else{ + end[0] += c * dx[towards]; + end[1] += c * dy[towards]; + if (end[0] == prev[0]){ + //上下移动,寻找x相同的障碍 + for ( auto it : obstacles){ + if (it[0] == end[0]){ + end[1] = min(end[1], it[1]); + } + } + } else { + //寻找y相同的障碍 + for ( auto it : obstacles){ + if (it[1] == end[1]){ + end[0] = min(end[0], it[0]); + } + } + } + prev[0] = end[0], prev[1] = end[1]; + maxpos = max(end[0] * end[0] + end[1] * end[1], maxpos); + } + } + return maxpos ; + + + } +}; +// 然后上面代码,在运行的时候又出现了问题, +// 向上/下移动,并不需要考虑左/右边的障碍,同理,向左/右移动。也不需要考虑上/下障碍 +// 想到就很头大,于是我将这部分调整为指导代码进行了抽象,单独领出来思考 +class Solution { +private: + //up, right, down, left + int dx[4] = { 0, 1, 0, -1}; + int dy[4] = { 1, 0, -1, 0}; + int end[2] = {0, 0} ;//初始位置 + int prev[2] = {0,0} ;//前一个位置 +public: + int robotSim(vector& commands, vector>& obstacles) { + int towards = 0;//默认是上 + int maxpos = 0; + for (auto c : commands){ + if ( c == -2){ + towards = (towards+4-1) % 4; + } else if ( c == -1 ){ + towards = (towards+1) % 4; + } else{ + end[0] += c * dx[towards]; + end[1] += c * dy[towards]; + meetObstacle(end, prev, obstacles); + prev[0] = end[0], prev[1] = end[1]; + maxpos = max(end[0] * end[0] + end[1] * end[1], maxpos); + } + } + return maxpos ; + + + } + void meetObstacle(int *end, int*prev, vector>& obstacles){ + + } +}; + +/*问题就在于meetObstacle函数的定义, +然而实在想不通, + +我就看题解了,有2点收获 +1. 不用循环进行查找,而是用set +2. 先把所有的路都走遍一遍,看我们抵达位置是不是障碍点,如果不是障碍点,就更新。 + +if (obstacleSet.find(make_pair(nx, ny)) == obstacleSet.end()) { + x = nx; + y = ny; + ans = max(ans, x*x + y*y); +} +*/ + +//最终代码如下 +class Solution { + +public: + int robotSim(vector& commands, vector>& obstacles) { + //up, right, down, left + int dx[4] = { 0, 1, 0, -1}; + int dy[4] = { 1, 0, -1, 0}; + int x = 0, y = 0 ;//初始位置 + int towards = 0;//默认是上 + int maxpos = 0; + + set> pos; + for (auto it : obstacles){ + pos.insert( {it[0], it[1]} ); + } + for (auto c : commands){ + if ( c == -2){ + towards = (towards+4-1) % 4; + } else if ( c == -1 ){ + towards = (towards+1) % 4; + } else{ + for (int k = 0; k < c; ++k){ + int nx = x + dx[towards]; + int ny = y + dy[towards]; + if (pos.find({nx,ny}) == pos.end()){ + x = nx; + y = ny; + maxpos = max(maxpos, x*x + y*y); + } + } + } + } + return maxpos ; + + + } + +}; \ No newline at end of file diff --git a/Week_03/G20200343030533/NOTE.md b/Week_03/G20200343030533/NOTE.md index 50de3041..9eb1992e 100644 --- a/Week_03/G20200343030533/NOTE.md +++ b/Week_03/G20200343030533/NOTE.md @@ -1 +1,330 @@ -学习笔记 \ No newline at end of file +# 学习笔记 + +## 分治、回溯 + +两者的本质就是递归。 + +碰到题目,就去找重复性。重复性分为最近重复性和最优重复性。最优重复性也可以认为是最优子结构,用动态规划来完成。 + +基本思路: 找重复性,分解问题,最后合并。 + +本质上是机器只能做循环和逻辑判断,因此就需要把大问题拆分成重复的问题 + +### 分治 + +为什么可以分解子问题?大问题或者复杂问题之所以复杂和庞大,就是因为它是由许多小问题构成。在一般人眼里复杂问题就是一个问题,但是在专业人士里面,这个复杂问题就能分成小问题,庖丁解牛就是这个道理。 + +代码模版 + +```python +def divide_conquer(problem, param1, param2, ...): + # recursion terminator + if problem in None: + print_result + return + # prepare data + data = prepare_data(problem) + subproblems = split_problem(problem, data) + # conquer subproblems + subresult1 = self.divide_conquer(subproblems[0], p1, ...) + subresult2 = self.divide_conquer(subproblems[0], p1, ...) + subresult3 = self.divide_conquer(subproblems[0], p1, ...) + ... + # process and generate the final result + result = process_result(subresult1, subresult2, subresult3) + +``` + +代码和泛形递归的差异区别: 多了一步合并子结果 + +- 问题解决标志: 不存在子问题 +- 处理当前逻辑: 将大问题分成子问题 +- 下探一层: 处理子问题 +- 结果组装 + +分治的关键,**如何分解问题**, **如果合并结果**,**如何保证子结果** + +不要下探太多层,不要人肉递归(你会很累) + +### 回溯 + +回溯: 归去来兮 + +不断得在每一层就去试,如果错了就返回,如果没有出错就继续下探。 + +### 题目部分 + +题目1: pow(x,n) + +审题, x和n的取值问题 + +解题方法 + +1. 暴力法, for循环, O(n) +1. 分治方法,O(log n) +1. 牛顿迭代法 + +子问题拆解:考虑奇偶性 + +题目2: subset + +状态重置, 参数变量发生了变化,因此需要重置。如果不希望重置,就需要在每一层拷贝一个新的列表。 + +题目3: 众数, 简单但高频 + +题目4: 电话号码的组合. 括号生成的套壳升级而已 + +题目5: N皇后. 回溯问题,主要考验验证当前的位置能否使用的方法 + +## 深度搜索,广度搜索 + +搜索基本就是暴力,本身没有任何智识存在。 + +搜索-遍历 + +- 每个节点都要访问一次 +- 每个节点仅仅要访问一次 +- 对于节点的访问顺序不限,(DFS, BFS). 优先性搜索(启发性搜索) + +深度优先搜索递归模版 + +```python +def dfs(node): + # already visted + if node in visited: + return + visited.add(node) + # process current node + # ... logic here + dfs(node.left) + dfs(node.right) +``` + +非递归模版(手动模拟栈) + +```python +def DFS(self, tree): + if tree.root is None: + return [] + + visited, stack = [], [tree.root] + while stack: + node = stack.pop() + visited.add(node) + + process(node) + nodes = generate_related_nodes(node) + stack.push(nodes) + # other processing work +``` + +如果有大于两个子节点 + +```python +visited = set() +def DFS(node, visited): + if node in visited: # terminator + #alredy visited + return + visited.add(node) + #process current node here + ... + for next_node in node.children(): + if next_node not in visited: + DFS(next_node, visited) +``` + +广度优先搜索模版(队列) + +```python +def BFS(graph, start, end): + queue = [] + queue.append([start]) + visted.add(start) + + while queue: + node = queue.pop() + visted.add(node) + + process(node) + nodes = generate_related_nodes(node) + queue.push(nodes) + #other processing work + ... +``` + +算法步骤是: + +- 先加入root +- 取出顶部节点 +- 处理节点 +- 获取子节点 +- 在队列中加入子节点 + +**学习感受**: 看到stack,递归,就可以想到DFS,看到queue就想到BFS。tree可以不需要记录访问节点,graph必须得要记录访问节点。 + +### 题目 + +**二叉树层次遍历**:硅谷面试前三个考题 + +方法 + +1. BFS +1. DFS, 记住每次所在层,然后在对应层来加入内容 + +**括号生成**: 明明只是一个字符串,又不是树,也不是图,为啥我们认为他是深度优先搜索呢?原因是我们每个节点都会分岔,也就是递归的状态树。我们在递归的状态树进行深度优先。能否用广度优先进行处理? + +**word-ladder-ii** 高频题目, 问题可以抽象成一个无向无权图, 单词作为一个节点,节点之间只差一个字母。 + +**岛屿数目**: 遇见岛就把岛屿给炸了, sink函数,从当前位置出发,把附近的1都变成0. + +一个技巧,上下左右的移动方法 + +```cpp +int dx[4] = {-1, 1, 0, 0}; +int dy[4] = { 0, 0, -1, 1}; +``` + +四面八方的移动写法 + +```cpp +int dx[8] = {-1,-1,-1, 0, 0, 1, 1, 1}; +int dy[8] = { 1, 0,-1, 1,-1, 1, 0, -1}; +``` + +思路: floofill, 冲水算法,看到一个1,就把附近都变成0,于是就成了DFS(深度优先了) + +后面的扫雷也是DFS,看到一个E,就把四海八荒的区域都看遍。终止条件是,附近有雷。 + +## 贪心算法 + +每次是局部最优,**希望**达到全局最优。 + +贪心和动态规划,贪心每次选最优不回退,动态规划会**保存**结果,根据之前结果选择,从而得到全剧最优。 + +一旦一个问题可以用贪心法解决,那么贪心法就会是最优算法。例如最小生成树,Dijkstra + +意义:高效,并且接近最佳结果,因此是一种辅助算法。 + +coin change: 前面硬币依次是后续硬币的倍数,[20,10,5,1], 也就是有整除关系 + +**使用场景**:大问题能够变成小问题,小问题的最优解能递推最终问题的最优解。子问题的最优解称之为最优子结构。 + +贪心的难点在于,你需要用数学的方法去证明,这个过程最重要。 + +另外贪心的角度也不不好找,可能是从**后往前**,也可能是**局部切入** + +## 二分查找 + +前提 + +1. 单调性(不需要是严格的单调) +1. 上下界 +1. 随机访问 + +代码模版 + +```python +left, right = 0, len(array)-1 +while left <= right: + mid = left + ((right - left) >> 1) + if array[mid] == target: + #find the target !! + break or return result + elif array[mid] < target: + left = mid + 1 + else: + right = mid -1 +``` + +- 先判断是否相同,相同的直接返回 +- 如果left和right不是整型,就不需要`+/-1` + +经验,先把代码模版放上,然后修改。 + +1. 暴力: 还原O(log N) -> 升序 -> 二分 +2. 正解 + +求根公式:牛顿迭代法, r= num, 不断迭代 r = (r + num / r) // 2, + +## 思考题 + +查找半有序数组[4, 5, 6, 7, 0, 1, 2] 中间无序的地方 + +如何确定自己的位置就是无序的位置, + +- 左一位小-右一位小 +- 左一位大-右一位大 + +如果不符合,如何确定下一步的搜索范围 + +- a[mid]比a[0], a[high]都高,说明要往右边移动, low = mid +- a[mid]比a[0], a[high]都低,说明要往左边移动, high =mid + + + +## 其他 + +cpp动态数组 + +```cpp +int *foo = new int [5]; +delete foo; //释放单一内存 +delete[] foo; //释放一组内存 +//或者用array +array arr; //大小为3 +arr.fill(0);//填充0 +``` + +小技巧,数组声明为静态或者全局默认都是0 + +```cpp +static int *foo = new int[5]; +``` + +array其实就是数组的封装而已,固定大小,不能向vector一样动态扩容。 + +set的常用操作 + +```cpp +set s; //empty set +s.insert(20); //插入元素 +s.count(20); //统计元素是否在 + +``` + +写`C++`代码的时候,类似于`function(vec.push_back(num))` 好像是不允许的,也就是不能在参数里面调用成员函数 + +queue的常用操作 + +```cpp +std::queue myqueue; +queue.push(); //入队 +queue.pop(); //出队 +queue.front(); //查看顶部元素 +queue.empty(); //是否为空 +``` + +stack的常用操作 + +```cpp +std::stack mystack; +mystack.push(); //入队 +mystack.pop(); //出队 +mystack.front(); //查看顶部元素 +mystack.empty(); //是否为空 +``` + +双端队列, deque + +```cpp +std::deque mydeque(4,100);// 初始化4个元素,分别为100 +mydeque.push_back(); +mydeque.pop_back(); +mydeque.push_front(); +mydeque.pop_front(); +mydeque.back(); +mydeque.fron(); +``` + +抑或的用法`^`: 参加运算的二进制位置相同为0,否则为1. diff --git a/Week_03/G20200343030535/LeetCode_860_535.java b/Week_03/G20200343030535/LeetCode_860_535.java new file mode 100644 index 00000000..f88f01db --- /dev/null +++ b/Week_03/G20200343030535/LeetCode_860_535.java @@ -0,0 +1,28 @@ +package G20200343030535; + +public class LeetCode_860_535 { + + public boolean lemonadeChange(int[] bills) { + int five = 0, ten = 0; + for (int bill: bills) { + if (bill == 5) + five++; + else if (bill == 10) { + if (five == 0) return false; + five--; + ten++; + } else { + if (five > 0 && ten > 0) { + five--; + ten--; + } else if (five >= 3) { + five -= 3; + } else { + return false; + } + } + } + + return true; + } +} diff --git a/Week_03/G20200343030535/LeetCode_874_535.java b/Week_03/G20200343030535/LeetCode_874_535.java new file mode 100644 index 00000000..f476b8f1 --- /dev/null +++ b/Week_03/G20200343030535/LeetCode_874_535.java @@ -0,0 +1,43 @@ +package G20200343030535; + +import java.util.HashSet; +import java.util.Set; + +public class LeetCode_874_535 { + + public int robotSim(int[] commands, int[][] obstacles) { + int[] dx = new int[]{0, 1, 0, -1}; + int[] dy = new int[]{1, 0, -1, 0}; + int x = 0, y = 0, di = 0; + + Set obstacleSet = new HashSet(); + for (int[] obstacle: obstacles) { + long ox = (long) obstacle[0] + 30000; + long oy = (long) obstacle[1] + 30000; + obstacleSet.add((ox << 16) + oy); + } + + int ans = 0; + for (int cmd: commands) { + if (cmd == -2) { //左边 + di = (di + 3) % 4; + } else if (cmd == -1) { //右边 + di = (di + 1) % 4; + } else { + for (int k = 0; k < cmd; ++k) { + int nx = x + dx[di]; + int ny = y + dy[di]; + long code = (((long) nx + 30000) << 16) + ((long) ny + 30000); + if (!obstacleSet.contains(code)) { + x = nx; + y = ny; + ans = Math.max(ans, x*x + y*y); + } + } + } + } + + return ans; + } + +} diff --git a/Week_03/G20200343030537/LeetCode_200_537.py b/Week_03/G20200343030537/LeetCode_200_537.py new file mode 100644 index 00000000..72843268 --- /dev/null +++ b/Week_03/G20200343030537/LeetCode_200_537.py @@ -0,0 +1,49 @@ +# 给定一个由 '1'(陆地)和 '0'(水)组成的的二维网格,计算岛屿的数量。一个岛被水包围,并且它是通过水平方向或垂直方向上相邻的陆地连接而成的。你可以假设 +# 网格的四个边均被水包围。 +# +# 示例 1: +# +# 输入: +# 11110 +# 11010 +# 11000 +# 00000 +# +# 输出: 1 +# +# +# 示例 2: +# +# 输入: +# 11000 +# 11000 +# 00100 +# 00011 +# +# 输出: 3 +# +# Related Topics 深度优先搜索 广度优先搜索 并查集 + + +# leetcode submit region begin(Prohibit modification and deletion) +class Solution: + def numIslands(self, grid: List[List[str]]) -> int: + def dfs(grid, i, j): + if not 0 <= i < len(grid) or not 0 <= j < len(grid[0]) or grid[i][j] == '0': return + grid[i][j] = '0' + dfs(grid, i + 1, j) + dfs(grid, i, j + 1) + dfs(grid, i - 1, j) + dfs(grid, i, j - 1) + + count = 0 + for i in range(len(grid)): + for j in range(len(grid[0])): + if grid[i][j] == '1': + dfs(grid, i, j) + count += 1 + return count + + + +# leetcode submit region end(Prohibit modification and deletion) diff --git a/Week_03/G20200343030537/LeetCode_63_537.py b/Week_03/G20200343030537/LeetCode_63_537.py new file mode 100644 index 00000000..c80cab94 --- /dev/null +++ b/Week_03/G20200343030537/LeetCode_63_537.py @@ -0,0 +1,42 @@ +# 假设把某股票的价格按照时间先后顺序存储在数组中,请问买卖该股票一次可能获得的最大利润是多少? +# +# +# +# 示例 1: +# +# 输入: [7,1,5,3,6,4] +# 输出: 5 +# 解释: 在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。 +# 注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格。 +# +# +# 示例 2: +# +# 输入: [7,6,4,3,1] +# 输出: 0 +# 解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。 +# +# +# +# 限制: +# +# 0 <= 数组长度 <= 10^5 +# +# +# +# 注意:本题与主站 121 题相同:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-s +# tock/ +# Related Topics 动态规划 + + +# leetcode submit region begin(Prohibit modification and deletion) +class Solution: + def maxProfit(self, prices: List[int]) -> int: + profit = 0 + for i in range(1, len(prices)): + tmp = prices[i] - prices[i - 1] + if tmp > 0: profit += tmp + return profit + + +# leetcode submit region end(Prohibit modification and deletion) diff --git a/Week_03/G20200343030537/LeetCode_860_537.py b/Week_03/G20200343030537/LeetCode_860_537.py new file mode 100644 index 00000000..d788d34a --- /dev/null +++ b/Week_03/G20200343030537/LeetCode_860_537.py @@ -0,0 +1,78 @@ +# 在柠檬水摊上,每一杯柠檬水的售价为 5 美元。 +# +# 顾客排队购买你的产品,(按账单 bills 支付的顺序)一次购买一杯。 +# +# 每位顾客只买一杯柠檬水,然后向你付 5 美元、10 美元或 20 美元。你必须给每个顾客正确找零,也就是说净交易是每位顾客向你支付 5 美元。 +# +# 注意,一开始你手头没有任何零钱。 +# +# 如果你能给每位顾客正确找零,返回 true ,否则返回 false 。 +# +# 示例 1: +# +# 输入:[5,5,5,10,20] +# 输出:true +# 解释: +# 前 3 位顾客那里,我们按顺序收取 3 张 5 美元的钞票。 +# 第 4 位顾客那里,我们收取一张 10 美元的钞票,并返还 5 美元。 +# 第 5 位顾客那里,我们找还一张 10 美元的钞票和一张 5 美元的钞票。 +# 由于所有客户都得到了正确的找零,所以我们输出 true。 +# +# +# 示例 2: +# +# 输入:[5,5,10] +# 输出:true +# +# +# 示例 3: +# +# 输入:[10,10] +# 输出:false +# +# +# 示例 4: +# +# 输入:[5,5,10,10,20] +# 输出:false +# 解释: +# 前 2 位顾客那里,我们按顺序收取 2 张 5 美元的钞票。 +# 对于接下来的 2 位顾客,我们收取一张 10 美元的钞票,然后返还 5 美元。 +# 对于最后一位顾客,我们无法退回 15 美元,因为我们现在只有两张 10 美元的钞票。 +# 由于不是每位顾客都得到了正确的找零,所以答案是 false。 +# +# +# +# +# 提示: +# +# +# 0 <= bills.length <= 10000 +# bills[i] 不是 5 就是 10 或是 20 +# +# Related Topics 贪心算法 + + +# leetcode submit region begin(Prohibit modification and deletion) +class Solution: + def lemonadeChange(self, bills: List[int]) -> bool: + five = ten = 0 + for bill in bills: + if bill == 5: + five += 1 + elif bill == 10: + if not five: return False + five -= 1 + ten += 1 + else: + if ten and five: + ten -= 1 + five -= 1 + elif five >= 3: + five -= 3 + else: + return False + return True + + +# leetcode submit region end(Prohibit modification and deletion) diff --git a/Week_03/G20200343030541/LeetCode_33_541.java b/Week_03/G20200343030541/LeetCode_33_541.java new file mode 100644 index 00000000..714b6c2e --- /dev/null +++ b/Week_03/G20200343030541/LeetCode_33_541.java @@ -0,0 +1,36 @@ +public class LeetCode_33_541 { + public int search(int[] nums, int target) { + if (nums == null || nums.length == 0) { + return -1; + } + + int start = 0; + int end = nums.length - 1; + int mid; + while ( start <= end ) { + mid = start + ( end - start) / 2; + if ( nums[mid] == target ) { + return mid; + } + + // 前半部分升序,注意此处用小于等于 + if ( nums[start] <= nums[mid] ) { + // target 在前半部分 + if( target >= nums[start] && target < nums[mid] ){ + end = mid - 1; + } else { + start = mid + 1; + } + // 后半部分升序 + } else { + if( target >= nums[start] && target < nums[mid] ){ + end = mid - 1; + } else { + start = mid + 1; + } + } + + } + return -1; + } +} diff --git a/Week_03/G20200343030541/LeetCode_74_541.java b/Week_03/G20200343030541/LeetCode_74_541.java new file mode 100644 index 00000000..b401ca8e --- /dev/null +++ b/Week_03/G20200343030541/LeetCode_74_541.java @@ -0,0 +1,88 @@ +public class LeetCode_74_541 { + + // 暴力穷举 + public boolean searchMatrix_Solution1(int[][] matrix, int target) { + if (matrix == null || matrix.length == 0) { + return false; + } + if (matrix[0] == null || matrix[0].length == 0) { + return false; + } + + int row = matrix.length; + int column = matrix[0].length; + + // find the row index, the last number <= target + int start = 0, end = row - 1; + while (start + 1 < end) { + int mid = start + (end - start) / 2; + if (matrix[mid][0] == target) { + return true; + } else if (matrix[mid][0] < target) { + start = mid; + } else { + end = mid; + } + } + if (matrix[end][0] <= target) { + row = end; + } else if (matrix[start][0] <= target) { + row = start; + } else { + return false; + } + + // find the column index, the number equal to target + start = 0; + end = column - 1; + while (start + 1 < end) { + int mid = start + (end - start) / 2; + if (matrix[row][mid] == target) { + return true; + } else if (matrix[row][mid] < target) { + start = mid; + } else { + end = mid; + } + } + if (matrix[row][start] == target) { + return true; + } else if (matrix[row][end] == target) { + return true; + } + return false; + } + + // 当做是一维有序数组被分割成n段,用二分法分别查找行和列 + public boolean searchMatrix_Solution2( int[][] matrix, int target ) { + if (matrix == null || matrix.length == 0) { + return false; + } + + if (matrix[0] == null || matrix[0].length == 0) { + return false; + } + + int row = matrix.length; + int column = matrix[0].length; + + int start = 0, end = row * column -1; + while ( start <= end ) { + int mid = start + (end - start) / 2; + int number = matrix[mid / column][mid % column]; + if (number == target) { + return true; + } else if (number > target) { + end = mid - 1; + } else { + start = mid + 1; + } + } + return false; + } + + // TODO: 使用排除法 + public boolean searchMatrix_Solution3(int[][] matrix, int target) { + return false; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030543/LeetCode_127_543.java b/Week_03/G20200343030543/LeetCode_127_543.java new file mode 100644 index 00000000..e24629df --- /dev/null +++ b/Week_03/G20200343030543/LeetCode_127_543.java @@ -0,0 +1,47 @@ +import javafx.util.Pair; + +class Solution { + public int ladderLength(String beginWord, String endWord, List wordList) { + + int L = beginWord.length(); + + HashMap> allComboDict = new HashMap>(); + + wordList.forEach( + word -> { + for (int i = 0; i < L; i++) { + String newWord = word.substring(0, i) + '*' + word.substring(i + 1, L); + ArrayList transformations = + allComboDict.getOrDefault(newWord, new ArrayList()); + transformations.add(word); + allComboDict.put(newWord, transformations); + } + }); + + Queue> Q = new LinkedList>(); + Q.add(new Pair(beginWord, 1)); + + HashMap visited = new HashMap(); + visited.put(beginWord, true); + + while (!Q.isEmpty()) { + Pair node = Q.remove(); + String word = node.getKey(); + int level = node.getValue(); + for (int i = 0; i < L; i++) { + String newWord = word.substring(0, i) + '*' + word.substring(i + 1, L); + for (String adjacentWord : allComboDict.getOrDefault(newWord, new ArrayList())) { + if (adjacentWord.equals(endWord)) { + return level + 1; + } + if (!visited.containsKey(adjacentWord)) { + visited.put(adjacentWord, true); + Q.add(new Pair(adjacentWord, level + 1)); + } + } + } + } + + return 0; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030543/LeetCode_200_543.java b/Week_03/G20200343030543/LeetCode_200_543.java new file mode 100644 index 00000000..d60fde30 --- /dev/null +++ b/Week_03/G20200343030543/LeetCode_200_543.java @@ -0,0 +1,36 @@ +class Solution { + void dfs(char[][] grid, int r, int c) { + int nr = grid.length; + int nc = grid[0].length; + + if (r < 0 || c < 0 || r >= nr || c >= nc || grid[r][c] == '0') { + return; + } + + grid[r][c] = '0'; + dfs(grid, r - 1, c); + dfs(grid, r + 1, c); + dfs(grid, r, c - 1); + dfs(grid, r, c + 1); + } + + public int numIslands(char[][] grid) { + if (grid == null || grid.length == 0) { + return 0; + } + + int nr = grid.length; + int nc = grid[0].length; + int num_islands = 0; + for (int r = 0; r < nr; ++r) { + for (int c = 0; c < nc; ++c) { + if (grid[r][c] == '1') { + ++num_islands; + dfs(grid, r, c); + } + } + } + + return num_islands; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030543/LeetCode_74_543.java b/Week_03/G20200343030543/LeetCode_74_543.java new file mode 100644 index 00000000..8a81ac22 --- /dev/null +++ b/Week_03/G20200343030543/LeetCode_74_543.java @@ -0,0 +1,21 @@ +class Solution { + public boolean searchMatrix(int[][] matrix, int target) { + int m = matrix.length; + if (m == 0) return false; + int n = matrix[0].length; + + // 二分查找 + int left = 0, right = m * n - 1; + int pivotIdx, pivotElement; + while (left <= right) { + pivotIdx = (left + right) / 2; + pivotElement = matrix[pivotIdx / n][pivotIdx % n]; + if (target == pivotElement) return true; + else { + if (target < pivotElement) right = pivotIdx - 1; + else left = pivotIdx + 1; + } + } + return false; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030543/LeetCode_874_543.java b/Week_03/G20200343030543/LeetCode_874_543.java new file mode 100644 index 00000000..8cd9bc98 --- /dev/null +++ b/Week_03/G20200343030543/LeetCode_874_543.java @@ -0,0 +1,36 @@ +class Solution { + public int robotSim(int[] commands, int[][] obstacles) { + int[] dx = new int[]{0, 1, 0, -1}; + int[] dy = new int[]{1, 0, -1, 0}; + int x = 0, y = 0, di = 0; + + Set obstacleSet = new HashSet(); + for (int[] obstacle: obstacles) { + long ox = (long) obstacle[0] + 30000; + long oy = (long) obstacle[1] + 30000; + obstacleSet.add((ox << 16) + oy); + } + + int ans = 0; + for (int cmd: commands) { + if (cmd == -2) + di = (di + 3) % 4; + else if (cmd == -1) + di = (di + 1) % 4; + else { + for (int k = 0; k < cmd; ++k) { + int nx = x + dx[di]; + int ny = y + dy[di]; + long code = (((long) nx + 30000) << 16) + ((long) ny + 30000); + if (!obstacleSet.contains(code)) { + x = nx; + y = ny; + ans = Math.max(ans, x*x + y*y); + } + } + } + } + + return ans; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030545/LeetCode_102_545.py b/Week_03/G20200343030545/LeetCode_102_545.py new file mode 100644 index 00000000..b53149d8 --- /dev/null +++ b/Week_03/G20200343030545/LeetCode_102_545.py @@ -0,0 +1,62 @@ +""" + 给定一个二叉树,返回其按层次遍历的节点值。 (即逐层地,从左到右访问所有节点)。 + + 例如: + 给定二叉树: [3,9,20,null,null,15,7], +""" + +from typing import List + + +class TreeNode: + def __init__(self, x): + self.val = x + self.left = None + self.right = None + + +class Solution: + def levelOrder(self, root: TreeNode) -> List[List[int]]: + res = [] + if root: + self.DFS(root, 0, res) + + return res + + @classmethod + def DFS(cls, node: TreeNode, level: int, res: List[List[int]]): + """ + 深度优先 一条线走到低,然后从底开始回溯 递归的解法 + """ + # terminator + if level == len(res): + res.append([]) + res[level].append(node.val) + + if node.left: + cls.DFS(node.left, level + 1, res) + if node.right: + cls.DFS(node.right, level + 1, res) + + @classmethod + def BFS(cls, root: TreeNode) -> List[List[int]]: + """ + 广度优先 一层一层访问 + """ + res = [] + + if res: + queue = [root] + while queue: + new_queue = [] + tmp_res = [] + for node in queue: + if node.left: + new_queue.append(node.left) + if node.right: + new_queue.append(node.right) + tmp_res.append(node.val) + + new_queue.append(tmp_res) + queue = new_queue + return res diff --git a/Week_03/G20200343030545/LeetCode_122_545.py b/Week_03/G20200343030545/LeetCode_122_545.py new file mode 100644 index 00000000..93c1198e --- /dev/null +++ b/Week_03/G20200343030545/LeetCode_122_545.py @@ -0,0 +1,85 @@ +""" + 给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。 + 设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。 + + 注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。 + + 示例 1: + 输入: + [7,1,5,3,6,4] + 输出: + 7 + 解释: + 在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。 +  随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6-3 = 3 。 + + 示例 2: + 输入: + [1,2,3,4,5] + 输出: + 4 + 解释: + 在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。 +  注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。 +  因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。 + + 示例 3: + 输入: [7,6,4,3,1] + 输出: 0 + 解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。 +""" +from typing import List + + +class Solution: + def maxProfit(self, prices: List[int]) -> int: + return self.greedy(prices) + + @classmethod + def greedy(cls, prices: List[int]) -> int: + """ + 时间复杂度:O(n) + 空间复杂度:O(1) + """ + profit = 0 + + for index in range(1, len(prices)): + if prices[index] > prices[index - 1]: + profit += prices[index] - prices[index - 1] + return profit + + @classmethod + def recursive(cls, prices: List[int], index: int = 0) -> int: + """ + 时间复杂度:O(n^n) + 空间复杂度:O(n) + """ + if index >= len(prices): + return 0 + + max_profit = 0 + for i in range(index, len(prices)): + for j in range(i + 1, len(prices)): + if prices[j] > prices[i]: + profit = cls.recursive(prices, j + 1) + prices[j] - prices[i] + max_profit = max(profit, profit) + + return max_profit + + # if index >= len(prices): + # return 0 + # + # max_profit = 0 + # + # for i in range(index, len(prices)): + # tmp_max_profit = 0 + # for j in range(i + 1, len(prices)): + # if prices[j] > prices[i]: + # profit = cls.recursive(prices, j + 1) + prices[j] - prices[i] + # tmp_max_profit = max(tmp_max_profit, profit) + # max_profit = max(max_profit, tmp_max_profit) + # return max_profit + + +if __name__ == '__main__': + print(Solution.recursive([7, 1, 5, 6, 3, 4])) diff --git a/Week_03/G20200343030545/LeetCode_126_545.py b/Week_03/G20200343030545/LeetCode_126_545.py new file mode 100644 index 00000000..aab32ddb --- /dev/null +++ b/Week_03/G20200343030545/LeetCode_126_545.py @@ -0,0 +1,157 @@ +""" + 给定两个单词(beginWord 和 endWord)和一个字典 wordList, + 找出所有从 beginWord 到 endWord 的最短转换序列。 + 转换需遵循如下规则: + + 每次转换只能改变一个字母。 + 转换过程中的中间单词必须是字典中的单词。 + 说明: + 如果不存在这样的转换序列,返回一个空列表。 + 所有单词具有相同的长度。 + 所有单词只由小写字母组成。 + 字典中不存在重复的单词。 + 你可以假设 beginWord 和 endWord 是非空的,且二者不相同。 + + 示例 1: + 输入: + beginWord = "hit", + endWord = "cog", + wordList = ["hot","dot","dog","lot","log","cog"] + + 输出: + [ + ["hit","hot","dot","dog","cog"], +   ["hit","hot","lot","log","cog"] + ] + + 示例 2: + 输入: + beginWord = "hit" + endWord = "cog" + wordList = ["hot","dot","dog","lot","log"] + 输出: [] + 解释: endWord "cog" 不在字典中,所以不存在符合要求的转换序列。 +""" +from typing import List, Dict + + +class Solution: + def __init__(self): + self.min_info = float("inf") + + def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]: + # res = [] + # if beginWord and endWord and wordList: + # self.DFS(beginWord, endWord, wordList, [beginWord], res) + # return res + res = [] + if beginWord and endWord and wordList: + hash_map = {} + distance_map = {} + self.BFS(beginWord, endWord, wordList, hash_map, distance_map) + self.DFS_FIND(beginWord, endWord, hash_map, distance_map, [], res) + return res + + def BFS( + self, + begin_word: str, + end_word: str, + word_list: List[str], + hash_map: Dict[str, List[str]], + distance_map: Dict[str, int] + ): + queue = [begin_word] + distance_map[begin_word] = 0 + is_found = False + depth = 0 + word_set = set(word_list) + + while queue: + queue_size = len(queue) + depth += 1 + print(queue) + for i in range(queue_size): + tmp_word = queue.pop() + # 得到这个tmp_word下的所有节点 + all_neighbors = self.get_neighbors(tmp_word, word_set) + hash_map[tmp_word] = all_neighbors + for neighbor in all_neighbors: + if neighbor not in distance_map: + distance_map[neighbor] = depth + if neighbor == end_word: + is_found = True + + queue.append(neighbor) + if is_found: + break + + def DFS(self, begin_word: str, end_word: str, word_list: List[str], tmp_list: List[str], res: List[List[str]]): + # terminator + if begin_word == end_word: + if self.min_info > len(tmp_list): + res.clear() + self.min_info = len(tmp_list) + res.append(tmp_list[:]) + elif self.min_info == len(tmp_list): + res.append(tmp_list[:]) + return + if len(tmp_list) > self.min_info: + return + # process + for word in word_list: + # TODO 如果这个word已经出现过了 并且 + if word in tmp_list: + continue + if self.word_changed(begin_word, word): + tmp_list.append(word) + # drill down + self.DFS(word, end_word, word_list, tmp_list, res) + # reverse state + tmp_list.pop() + + @classmethod + def get_neighbors(cls, word: str, word_set: set) -> List[str]: + res = [] + for tmp_word in word_set: + if cls.word_changed(word, tmp_word): + res.append(tmp_word) + return res + + @classmethod + def word_changed(cls, word1: str, word2: str) -> bool: + count = 0 + for index, row in enumerate(word1): + if row != word2[index]: + count += 1 + if count == 2: + break + return count == 1 + + @classmethod + def DFS_FIND( + cls, + begin_word: str, + end_word: str, + hash_map: Dict[str, List[str]], + distance_map: Dict[str, int], + tmp_list: List[str], + res: List[List[str]] + ): + # terminator + if begin_word == end_word: + res.append(tmp_list[:]) + return + + neighbors = hash_map.get(begin_word, []) + for neighbor in neighbors: + if distance_map[begin_word] + 1 == distance_map[neighbor]: + tmp_list.append(neighbor) + cls.DFS_FIND(neighbor, end_word, hash_map, distance_map, tmp_list, res) + tmp_list.pop() + + +if __name__ == "__main__": + b_w = "hit" + e_w = "cog" + w_l = ["hot", "dot", "dog", "lot", "log", "cog"] + print(Solution().findLadders(b_w, e_w, w_l)) diff --git a/Week_03/G20200343030545/LeetCode_127_545.py b/Week_03/G20200343030545/LeetCode_127_545.py new file mode 100644 index 00000000..f9d563c1 --- /dev/null +++ b/Week_03/G20200343030545/LeetCode_127_545.py @@ -0,0 +1,74 @@ +""" + 给定两个单词(beginWord 和 endWord)和一个字典,找到从 beginWord 到 endWord 的最短转换序列的长度。 + 转换需遵循如下规则: + 每次转换只能改变一个字母。 + 转换过程中的中间单词必须是字典中的单词。 + + 说明: + 如果不存在这样的转换序列,返回 0。 + 所有单词具有相同的长度。 + 所有单词只由小写字母组成。 + 字典中不存在重复的单词。 + 你可以假设 beginWord 和 endWord 是非空的,且二者不相同。 + + 示例 1: + + 输入: + beginWord = "hit", + endWord = "cog", + wordList = ["hot","dot","dog","lot","log","cog"] + 输出: 5 + 解释: 一个最短转换序列是 "hit" -> "hot" -> "dot" -> "dog" -> "cog", 返回它的长度 5。 + + 示例 2: + 输入: + beginWord = "hit" + endWord = "cog" + wordList = ["hot","dot","dog","lot","log"] + 输出: 0 + 解释: endWord "cog" 不在字典中,所以无法进行转换。 +""" +from collections import defaultdict +from typing import List + + +class Solution: + def ladderLength(self, beginWord: str, endWord: str, wordList: List[str]) -> int: + return self.BFS(beginWord, endWord, wordList) + + @classmethod + def BFS(cls, begin_word: str, end_word: str, word_list: List[str]) -> int: + """ + 时间复杂度:O(m*n) m是单词的长度 n是单词表中的个数 + 空间复杂度:O(m*n) blur_word_dict所占 + """ + # 1. 转换格式 + blur_word_dict = defaultdict(list) + begin_word_len = len(begin_word) + for word in word_list: + for index in range(begin_word_len): + blur_word_dict[word[:index] + "*" + word[index + 1:]].append(word) + + # 2. BFS + queue = [(begin_word, 1)] + visited = {begin_word: True} + + while queue: + current_word, current_level = queue.pop(0) + + for index in range(begin_word_len): + for word in blur_word_dict[current_word[:index] + "*" + current_word[index + 1:]]: + if word == end_word: + return current_level + 1 + if word not in visited: + visited[word] = True + queue.append((word, current_level + 1)) + return -1 + + +if __name__ == '__main__': + begin_word = "hit" + end_word = "hit" + word_list = ["hit", "dot", "dog", "lot", "log", "cog"] + + print(Solution().ladderLength(begin_word, end_word, word_list)) diff --git a/Week_03/G20200343030545/LeetCode_153_545.py b/Week_03/G20200343030545/LeetCode_153_545.py new file mode 100644 index 00000000..b34762b8 --- /dev/null +++ b/Week_03/G20200343030545/LeetCode_153_545.py @@ -0,0 +1,61 @@ +""" + 假设按照升序排序的数组在预先未知的某个点上进行了旋转。 + ( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。 + 请找出其中最小的元素。 + 你可以假设数组中不存在重复元素。 + + 示例 1: + 输入: [3,4,5,1,2] + 输出: 1 + + 示例 2: + 输入: [4,5,6,7,0,1,2] + 输出: 0 + + https://leetcode-cn.com/problems/find-minimum-in-rotated-sorted-array +""" +from typing import List + + +class Solution: + def findMin(self, nums: List[int]) -> int: + return self.use_mid(nums) + + @classmethod + def use_mid(cls, nums: List[int]) -> int: + """ + 二分查找 + """ + if nums: + left = 0 + right = len(nums) - 1 + # 特殊情况判断 + if nums[left] <= nums[right]: + return nums[left] + + while right >= left: + mid = (left + right) // 2 + mid_val = nums[mid] + + if mid_val > nums[mid + 1]: + return nums[mid + 1] + + if mid_val < nums[mid - 1]: + return mid_val + + if mid_val > nums[0]: + left = mid + 1 + else: + right = mid - 1 + + @classmethod + def directly(cls, nums: List[int]) -> int: + """ + 遍历一边原始数组 + 时间复杂度:O(n) + 空间复杂度:O(1) + """ + res = float("inf") + for num in nums: + res = min(res, num) + return res diff --git a/Week_03/G20200343030545/LeetCode_169_545.py b/Week_03/G20200343030545/LeetCode_169_545.py new file mode 100644 index 00000000..32ea258e --- /dev/null +++ b/Week_03/G20200343030545/LeetCode_169_545.py @@ -0,0 +1,106 @@ +""" + 给定一个大小为 n 的数组,找到其中的多数元素。多数元素是指在数组中出现次数大于 ⌊ n/2 ⌋ 的元素。 + 你可以假设数组是非空的,并且给定的数组总是存在多数元素。 + + 示例 1: + 输入: [3,2,3] + 输出: 3 + + 示例 2: + 输入: [2,2,1,1,1,2,2] + 输出: 2 +""" +from typing import List + + +class Solution: + def majorityElement(self, nums: List[int]) -> int: + pass + + @classmethod + def directly(cls, nums: List[int]) -> int: + """ + 暴力破解法 + 时间复杂度:O(n^2),空间复杂度:O(1) + """ + check_cnt = len(nums) // 2 + + for num in nums: + cnt = 0 + for tmp_num in nums: + if num == tmp_num: + cnt += 1 + if cnt > check_cnt: + return num + + @classmethod + def use_hash(cls, nums: List[int]) -> int: + """ + 使用字典存储 + 时间复杂度:O(n) 空间复杂度:O(n) + """ + mapping = {} + check_cnt = len(nums) // 2 + for num in nums: + if num in mapping: + mapping[num] += 1 + else: + mapping[num] = 1 + + for key, val in mapping.items(): + if val > check_cnt: + return val + return -1 + + @classmethod + def use_sort(cls, nums: List[int]) -> int: + """ + 排序 + 时间复杂度:O(nlogn) 空间复杂度:O(1) + """ + nums.sort() + return nums[len(nums) // 2] + + @classmethod + def use_divide(cls, nums: List[int]) -> int: + """ + 时间复杂度:O(nlogn) + 空间负责度:O(logn) + """ + + def recursive(left_index: int, right_index: int) -> int: + if left_index == right_index: + return nums[left_index] + + mid_index = (left_index + right_index) // 2 + left_val = recursive(left_index, mid_index) + right_val = recursive(mid_index + 1, right_index) + + if left_val == right_val: + return left_val + + left_count = sum(1 for i in range(left_index, right_index + 1) if nums[i] == left_val) + right_count = sum(1 for i in range(left_index, right_index + 1) if nums[i] == right_val) + + return left_val if left_count > right_count else right_val + + return recursive(0, len(nums) - 1) + + @classmethod + def use_boyer_moore(cls, nums: List[int]) -> int: + """ + 时间复杂度:O(n) + 空间复杂度:O(1) + + """ + res = count = 0 + for num in nums: + if count == 0: + res = num + count += (1 if res == num else -1) + + return res + + +if __name__ == '__main__': + print(Solution.use_divide([3, 2, 3])) diff --git a/Week_03/G20200343030545/LeetCode_17_545.py b/Week_03/G20200343030545/LeetCode_17_545.py new file mode 100644 index 00000000..9899c1c5 --- /dev/null +++ b/Week_03/G20200343030545/LeetCode_17_545.py @@ -0,0 +1,47 @@ +""" + 给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。 + 给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。 + + 示例: + 输入:"23" + 输出:["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"]. + +""" +from typing import List + + +class Solution: + mobile = { + "2": "abc", + "3": "def", + "4": "ghi", + "5": "jkl", + "6": "mno", + "7": "pqrs", + "8": "tuv", + "9": "wxyz", + } + + def letterCombinations(self, digits: str) -> List[str]: + """ + 时间复杂度:O(3**n * 4 ** m) + 空间复杂度:O(3**n * 4 ** m) + """ + + res = [] + if digits: + self.recursive(0, "", res, digits) + return res + + @classmethod + def recursive(cls, index: int, s: str, res: List[str], digits: str): + if index == len(digits): + res.append(s) + return + + for letter in cls.mobile[digits[index]]: + cls.recursive(index + 1, s + letter, res, digits) + + +if __name__ == "__main__": + print(Solution().letterCombinations("23")) diff --git a/Week_03/G20200343030545/LeetCode_220_545.py b/Week_03/G20200343030545/LeetCode_220_545.py new file mode 100644 index 00000000..9278f4ac --- /dev/null +++ b/Week_03/G20200343030545/LeetCode_220_545.py @@ -0,0 +1,63 @@ +""" + 给定一个由 '1'(陆地)和 '0'(水)组成的的二维网格,计算岛屿的数量。 + 一个岛被水包围,并且它是通过水平方向或垂直方向上相邻的陆地连接而成的。 + 你可以假设网格的四个边均被水包围。 + + 示例 1: + 输入: + 11110 + 11010 + 11000 + 00000 + 输出: 1 + + 示例 2: + 输入: + 11000 + 11000 + 00100 + 00011 + 输出: 3 +""" + +from typing import List + + +class Solution: + def numIslands(self, grid: List[List[str]]) -> int: + return self.DFS_HAND(grid) + + def DFS_HAND(self, grid: List[List[str]]) -> int: + """ + 解题思路:如果碰到岛屿则用递归的 方式将岛屿附近所有的岛全部变成0 + 时间复杂度:O(m*n) + 空间复杂度:O(m*n) + + """ + + count = 0 + if len(grid): + for row_index, row in enumerate(grid): + for col_index, col in enumerate(row): + if grid[row_index][col_index] == "1": + self.DFS(grid, row_index, col_index) + count += 1 + return count + + @classmethod + def DFS(cls, grid: List[List[str]], row_index: int, col_index: int): + # terminator + if row_index < 0 or col_index < 0 or row_index >= len(grid) or col_index >= len(grid[0]) or grid[row_index][ + col_index] != "1": + return + + # process + grid[row_index][col_index] = 0 + + # drill down + cls.DFS(grid, row_index - 1, col_index) + cls.DFS(grid, row_index + 1, col_index) + cls.DFS(grid, row_index, col_index - 1) + cls.DFS(grid, row_index, col_index + 1) + + # reverse state diff --git a/Week_03/G20200343030545/LeetCode_22_545.py b/Week_03/G20200343030545/LeetCode_22_545.py new file mode 100644 index 00000000..0dc96e5d --- /dev/null +++ b/Week_03/G20200343030545/LeetCode_22_545.py @@ -0,0 +1,42 @@ +""" + 给出 n 代表生成括号的对数,请你写出一个函数,使其能够生成所有可能的并且有效的括号组合。 + 例如,给出 n = 3,生成结果为: + [ + "((()))", + "(()())", + "(())()", + "()(())", + "()()()" + ] + +""" + +from typing import List + + +class Solution: + def generateParenthesis(self, n: int) -> List[str]: + res = [] + if n > 0: + self.recursive(0, 0, n, "", res) + return res + + @classmethod + def recursive(cls, left: int, right: int, n: int, s: str, res: List[str]) -> None: + # terminator + if left == right == n: + res.append(s) + return + + # code logic + if left < n: + # drill down + cls.recursive(left + 1, right, n, s + "(", res) + + if right < left: + # drill down + cls.recursive(left, right + 1, n, s + ")", res) + + +if __name__ == "__main__": + print(Solution().generateParenthesis(3)) diff --git a/Week_03/G20200343030545/LeetCode_322_545.py b/Week_03/G20200343030545/LeetCode_322_545.py new file mode 100644 index 00000000..05daadf4 --- /dev/null +++ b/Week_03/G20200343030545/LeetCode_322_545.py @@ -0,0 +1,73 @@ +""" + 给定不同面额的硬币 coins 和一个总金额 amount。 + 编写一个函数来计算可以凑成总金额所需的最少的硬币个数。 + 如果没有任何一种硬币组合能组成总金额,返回 -1。 + + 示例 1: + 输入: coins = [1, 2, 5], amount = 11 + 输出: 3 + 解释: 11 = 5 + 5 + 1 + + 示例 2: + 输入: coins = [2], amount = 3 + 输出: -1 + 说明: + 你可以认为每种硬币的数量是无限的。 + + https://leetcode-cn.com/problems/coin-change +""" +from typing import List, Dict + + +class Solution: + def coinChange(self, coins: List[int], amount: int) -> int: + return self.recursive_use_memo(coins, amount, {}) + + @classmethod + def recursive(cls, coins: List[int], amount: int) -> int: + """ + 时间复杂度: O(k*n^k) + """ + if amount == 0: + return 0 + if amount < 0: + return -1 + + res = float("inf") + + for coin in coins: + sub_problem = cls.recursive(coins, amount - coin) + if sub_problem == -1: + continue + res = min(res, sub_problem + 1) + return res if res != float("inf") else -1 + + @classmethod + def recursive_use_memo(cls, coins: List[int], amount: int, memo: Dict): + """ + 时间复杂度:O(kn) + """ + if amount in memo: + return memo[amount] + + if amount == 0: + return 0 + + if amount < 0: + return -1 + + res = float("inf") + + for coin in coins: + sub_problem = cls.recursive_use_memo(coins, amount - coin, memo) + if sub_problem == -1: + continue + + res = min(res, sub_problem + 1) + + memo[amount] = res if res != float("inf") else -1 + return memo[amount] + + +if __name__ == '__main__': + print(Solution.recursive([1, 2, 2], 11)) diff --git a/Week_03/G20200343030545/LeetCode_33_545.py b/Week_03/G20200343030545/LeetCode_33_545.py new file mode 100644 index 00000000..3f8a9e35 --- /dev/null +++ b/Week_03/G20200343030545/LeetCode_33_545.py @@ -0,0 +1,117 @@ +""" + 假设按照升序排序的数组在预先未知的某个点上进行了旋转。 + ( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。 + 搜索一个给定的目标值,如果数组中存在这个目标值,则返回它的索引,否则返回 -1 。 + 你可以假设数组中不存在重复的元素。 + 你的算法时间复杂度必须是 O(log n) 级别。 + + 示例 1: + 输入: nums = [4,5,6,7,0,1,2], target = 0 + 输出: 4 + + 示例 2: + 输入: nums = [4,5,6,7,0,1,2], target = 3 + 输出: -1 +""" + +from typing import List + + +class Solution: + def search(self, nums: List[int], target: int) -> int: + return self.mid_query(nums, target) + + @classmethod + def directly(cls, nums: List[int], target: int) -> int: + """ + 时间复杂度 O(n) 不符合要求 + 空间复杂度 O(1) + """ + for index, num in enumerate(nums): + if num == target: + return index + return -1 + + @classmethod + def mid_query(cls, nums: List[int], target: int) -> int: + """ + 硬套 二分查找模版 + 时间复杂度:O(logn) + 空间复杂度:O(1) + """ + start = 0 + end = len(nums) - 1 + + while end >= start: + mid = (start + end) // 2 + + start_val = nums[start] + mid_val = nums[mid] + end_val = nums[end] + + if mid_val == target: + return mid + + if mid_val < end_val: + # 说明后半部分是单调递增 + if mid_val < target <= end_val: + start = mid + 1 + else: + end = mid - 1 + else: + if start_val <= target < mid_val: + end = mid - 1 + else: + start = mid + 1 + return -1 + + +class SolutionExt: + """ + 寻找一个旋转序数组中的 中间无效的地方, 假设坏点只出现了一次 + 比如 [4,5,6,7,0,1,2] + """ + +def find_bat_pointer(self, nums: List[int]): + left = 0 + right = len(nums) - 1 + + if nums[left] < nums[right]: + return 0 + + while left <= right: + mid = (left + right) // 2 + if nums[mid] > nums[mid + 1]: + return mid + 1 + else: + if nums[mid] < nums[left]: + right = mid - 1 + else: + left = mid + 1 + return 0 + + +if __name__ == '__main__': + from typing import List + + + def find_bat_pointer(nums: List[int]): + if not nums: + raise ValueError("Nums Empty") + + left = 0 + right = len(nums) - 1 + + if nums[left] < nums[right]: + # 说明这个数组是单调递增的 + return 0 + while left <= right: + mid = (left + right) // 2 + if nums[mid] > nums[mid + 1]: + return mid + 1 + else: + if nums[mid] < nums[left]: + right = mid - 1 + else: + left = mid + 1 + return 0 \ No newline at end of file diff --git a/Week_03/G20200343030545/LeetCode_367_545.py b/Week_03/G20200343030545/LeetCode_367_545.py new file mode 100644 index 00000000..f5f9e504 --- /dev/null +++ b/Week_03/G20200343030545/LeetCode_367_545.py @@ -0,0 +1,37 @@ +""" + 给定一个正整数 num,编写一个函数,如果 num 是一个完全平方数,则返回 True,否则返回 False。 + 说明:不要使用任何内置的库函数,如  sqrt。 + 示例 1: + 输入:16 + 输出:True + + 示例 2: + 输入:14 + 输出:False +""" + + +class Solution: + def isPerfectSquare(self, num: int) -> bool: + return self.use_mid_query(num) + + @classmethod + def use_mid_query(cls, num: int) -> bool: + if num < 2: + return True + + left, right = 2, num // 2 + + while left <= right: + mid = (left + right) // 2 + + check_num = mid * mid + + if check_num == num: + return True + + if check_num > num: + right = mid - 1 + else: + left = mid + 1 + return False diff --git a/Week_03/G20200343030545/LeetCode_433_545.py b/Week_03/G20200343030545/LeetCode_433_545.py new file mode 100644 index 00000000..e4168add --- /dev/null +++ b/Week_03/G20200343030545/LeetCode_433_545.py @@ -0,0 +1,74 @@ +""" + 一条基因序列由一个带有8个字符的字符串表示,其中每个字符都属于 "A", "C", "G", "T"中的任意一个。 + 假设我们要调查一个基因序列的变化。一次基因变化意味着这个基因序列中的一个字符发生了变化。 + + 例如,基因序列由"AACCGGTT" 变化至 "AACCGGTA" 即发生了一次基因变化。 + 与此同时,每一次基因变化的结果,都需要是一个合法的基因串,即该结果属于一个基因库。 + + 现在给定3个参数 — start, end, bank,分别代表起始基因序列,目标基因序列及基因库, + 请找出能够使起始基因序列变化为目标基因序列所需的最少变化次数。 + 如果无法实现目标变化,请返回 -1。 + + 注意: + 起始基因序列默认是合法的,但是它并不一定会出现在基因库中。 + 所有的目标基因序列必须是合法的。 + 假定起始基因序列与目标基因序列是不一样的。 + + 示例 1: + start: "AACCGGTT" + end: "AACCGGTA" + bank: ["AACCGGTA"] + 返回值: 1 + + 示例 2: + start: "AACCGGTT" + end: "AAACGGTA" + bank: ["AACCGGTA", "AACCGCTA", "AAACGGTA"] + 返回值: 2 + + 示例 3: + start: "AAAAACCC" + end: "AACCCCCC" + bank: ["AAAACCCC", "AAACCCCC", "AACCCCCC"] + 返回值: 3 + + https://leetcode-cn.com/problems/minimum-genetic-mutation +""" +from typing import List + + +class Solution: + change_detail = { + 'A': 'GCT', + 'G': 'ACT', + 'C': 'AGT', + 'T': 'AGC' + } + + def minMutation(self, start: str, end: str, bank: List[str]) -> int: + counts = [] + if start and end and bank: + self.recursive(start, end, bank, 0, counts) + return min(counts) if counts else -1 + + @classmethod + def recursive(cls, start: str, end: str, bank: List[str], count: int, counts: List[int]) -> None: + # terminator + if start == end: + counts.append(count) + if not bank: + return + + # code logic + for index, s_row in enumerate(start): + for change_info in cls.change_detail[s_row]: + new_s_row = start[:index] + change_info + start[index + 1:] + + if new_s_row in bank: + bank.remove(new_s_row) + + # drill down + cls.recursive(new_s_row, end, bank, count + 1, counts) + + # reverse state + bank.append(new_s_row) diff --git a/Week_03/G20200343030545/LeetCode_455_545.py b/Week_03/G20200343030545/LeetCode_455_545.py new file mode 100644 index 00000000..6a12668e --- /dev/null +++ b/Week_03/G20200343030545/LeetCode_455_545.py @@ -0,0 +1,48 @@ +""" + 假设你是一位很棒的家长,想要给你的孩子们一些小饼干。 + 但是,每个孩子最多只能给一块饼干。对每个孩子 i ,都有一个胃口值 gi , + 这是能让孩子们满足胃口的饼干的最小尺寸;并且每块饼干 j , + 都有一个尺寸 sj 。如果 sj >= gi ,我们可以将这个饼干 j 分配给孩子 i , + 这个孩子会得到满足。你的目标是尽可能满足越多数量的孩子,并输出这个最大数值。 + + 注意: + 你可以假设胃口值为正。 + 一个小朋友最多只能拥有一块饼干。 + + 示例 1: + 输入: [1,2,3], [1,1] + 输出: 1 + 解释: + 你有三个孩子和两块小饼干,3个孩子的胃口值分别是:1,2,3。 + 虽然你有两块小饼干,由于他们的尺寸都是1,你只能让胃口值是1的孩子满足。 + 所以你应该输出1。 + + 示例 2: + 输入: [1,2], [1,2,3] + 输出: 2 + 解释: + 你有两个孩子和三块小饼干,2个孩子的胃口值分别是1,2。 + 你拥有的饼干数量和尺寸都足以让所有孩子满足。 + 所以你应该输出2。 +""" +from typing import List + + +class Solution: + def findContentChildren(self, g: List[int], s: List[int]) -> int: + g.sort() + s.sort() + s_len = len(s) + g_len = len(g) + s_index = g_index = 0 + while s_index < s_len and g_index < g_len: + if s[s_index] >= g[g_index]: + g_index += 1 + + s_index += 1 + + return g_index + + +if __name__ == '__main__': + print(Solution().findContentChildren([10, 9, 8, 7], [5, 6, 7, 8])) diff --git a/Week_03/G20200343030545/LeetCode_45_545.py b/Week_03/G20200343030545/LeetCode_45_545.py new file mode 100644 index 00000000..aaeb1a63 --- /dev/null +++ b/Week_03/G20200343030545/LeetCode_45_545.py @@ -0,0 +1,39 @@ +""" + 给定一个非负整数数组,你最初位于数组的第一个位置。 + 数组中的每个元素代表你在该位置可以跳跃的最大长度。 + 你的目标是使用最少的跳跃次数到达数组的最后一个位置。 + + 示例: + 输入: [2,3,1,1,4] + 输出: 2 + 解释: 跳到最后一个位置的最小跳跃数是 2。 +   从下标为 0 跳到下标为 1 的位置,跳 1 步,然后跳 3 步到达数组的最后一个位置。 + + 说明: + 假设你总是可以到达数组的最后一个位置。 +""" +from typing import List + + +class Solution: + def jump(self, nums: List[int]) -> int: + """ + 时间复杂度:O(n) + 空间复杂度:O(1) + 每次找到能跳到最远的位置 + 如果循环下标到达这个位置,则更新步数和边界值 + + """ + steps = end = max_area = 0 + + for index, num in enumerate(nums[:-1]): # 因为这个里index是从0开始的,上来肯定先加1,如果num不是到最后一个停止,就会导致结果多加1 + max_area = max(max_area, nums[index] + index) + + if end == index: + steps += 1 + end = max_area + return steps + + +if __name__ == '__main__': + print(Solution().jump([2, 3, 1, 1, 4])) diff --git a/Week_03/G20200343030545/LeetCode_50_545.py b/Week_03/G20200343030545/LeetCode_50_545.py new file mode 100644 index 00000000..fd61ae25 --- /dev/null +++ b/Week_03/G20200343030545/LeetCode_50_545.py @@ -0,0 +1,41 @@ +""" + 实现 pow(x, n) ,即计算 x 的 n 次幂函数。 + + 示例 1: + 输入: 2.00000, 10 + 输出: 1024.00000 + + 示例 2: + 输入: 2.10000, 3 + 输出: 9.26100 + + 示例 3: + 输入: 2.00000, -2 + 输出: 0.25000 + 解释: 2-2 = 1/22 = 1/4 = 0.25 + + 说明: + -100.0 < x < 100.0 + n 是 32 位有符号整数,其数值范围是 [−2**31, 2**31 − 1] 。 +""" + + +class Solution: + def myPow(self, x: float, n: int) -> float: + if n < 0: + x = 1 / x + n = -n + return self.recursive(x, n) + + @classmethod + def recursive(cls, x: float, n: int) -> float: + if n == 0: + return 1.0 + + half = cls.recursive(x, n // 2) + + return half * half if n % 2 == 0 else half * half * x + + +if __name__ == '__main__': + print(Solution().myPow(0.00001, 2147483647)) diff --git a/Week_03/G20200343030545/LeetCode_515_545.py b/Week_03/G20200343030545/LeetCode_515_545.py new file mode 100644 index 00000000..b47bf73f --- /dev/null +++ b/Week_03/G20200343030545/LeetCode_515_545.py @@ -0,0 +1,65 @@ +""" + 您需要在二叉树的每一行中找到最大的值。 + + 示例: + + 输入: + + 1 + / \ + 3 2 + / \ \ + 5 3 9 + + 输出: [1, 3, 9] +""" +from typing import List + + +class TreeNode: + def __init__(self, x): + self.val = x + self.left = None + self.right = None + + +class Solution: + def largestValues(self, root: TreeNode) -> List[int]: + if root: + # return self.BFS(root) + res = [] + self.DFS(root, 0, res) + return [max(i) for i in res] + # res = [] + # self.DFS(root, 0, res) + + @classmethod + def DFS(cls, root: TreeNode, index: int, res: List[List[int]]): + if index == len(res): + res.append([]) + res[index].append(root.val) + + if root.left: + cls.DFS(root.left, index + 1, res) + + if root.right: + cls.DFS(root.right, index + 1, res) + + @classmethod + def BFS(cls, root: TreeNode) -> List[int]: + + res = [] + queue = [root] + while queue: + new_queue = [] + max_res = float("-inf") + for node in queue: + if node.left: + new_queue.append(node.left) + if node.right: + new_queue.append(node.right) + max_res = max(max_res, node.val) + res.append(max_res) + + queue = new_queue + return res diff --git a/Week_03/G20200343030545/LeetCode_51_545.py b/Week_03/G20200343030545/LeetCode_51_545.py new file mode 100644 index 00000000..bbfa6d1e --- /dev/null +++ b/Week_03/G20200343030545/LeetCode_51_545.py @@ -0,0 +1,52 @@ +""" + n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。 + 给定一个整数 n,返回所有不同的 n 皇后问题的解决方案。 + 每一种解法包含一个明确的 n 皇后问题的棋子放置方案,该方案中 'Q' 和 '.' 分别代表了皇后和空位。 + + 示例: + 输入: 4 + 输出: [ + [".Q..", // 解法 1 + "...Q", + "Q...", + "..Q."], + + ["..Q.", // 解法 2 + "Q...", + "...Q", + ".Q.."] + ] + 解释: 4 皇后问题存在两个不同的解法。 + + https://leetcode-cn.com/problems/n-queens +""" +from typing import List + + +class Solution: + def solveNQueens(self, n: int) -> List[List[str]]: + res = [] + self.recursive([], [], [], n, res) + return [["." * col + "Q" + (n - col - 1) * "." for col in row] for row in res] + + @classmethod + def recursive(cls, queues: List[int], xy_diff: List[int], xy_sum: List[int], n: int, res: List[List[int]]): + # terminator + row = len(queues) + if row == n: + res.append(queues[:]) + return + + for col in range(n): + if col not in queues and row - col not in xy_diff and row + col not in xy_sum: + queues.append(col) + xy_diff.append(row - col) + xy_sum.append(row + col) + cls.recursive(queues, xy_diff, xy_sum, n, res) + queues.pop() + xy_diff.pop() + xy_sum.pop() + + +if __name__ == "__main__": + print(Solution().solveNQueens(8)) diff --git a/Week_03/G20200343030545/LeetCode_55_545.py b/Week_03/G20200343030545/LeetCode_55_545.py new file mode 100644 index 00000000..527a9054 --- /dev/null +++ b/Week_03/G20200343030545/LeetCode_55_545.py @@ -0,0 +1,39 @@ +""" + 给定一个非负整数数组,你最初位于数组的第一个位置。 + 数组中的每个元素代表你在该位置可以跳跃的最大长度。 + 判断你是否能够到达最后一个位置。 + + 示例 1: + 输入: [2,3,1,1,4] + 输出: true + 解释: 我们可以先跳 1 步,从位置 0 到达 位置 1, 然后再从位置 1 跳 3 步到达最后一个位置。 + + 示例 2: + 输入: [3,2,1,0,4] + 输出: false + 解释: 无论怎样,你总会到达索引为 3 的位置。但该位置的最大跳跃长度是 0 , 所以你永远不可能到达最后一个位置。 +""" + +from typing import List + + +class Solution: + def canJump(self, nums: List[int]) -> bool: + """ + 每次都往最远的地方跳转 + 时间复杂度:O(n),空间复杂度:O(1) + """ + max_index = 0 + for index, num in enumerate(nums): + + if index > max_index: + return False + else: + max_index = max(max_index, index + nums[index]) + return True + + +if __name__ == '__main__': + nums = [3, 2, 1, 0, 4] + + print(Solution().canJump(nums)) diff --git a/Week_03/G20200343030545/LeetCode_69_545.py b/Week_03/G20200343030545/LeetCode_69_545.py new file mode 100644 index 00000000..311504b1 --- /dev/null +++ b/Week_03/G20200343030545/LeetCode_69_545.py @@ -0,0 +1,43 @@ +""" + 实现 int sqrt(int x) 函数。 + 计算并返回 x 的平方根,其中 x 是非负整数。 + 由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去。 + + 示例 1: + 输入: 4 + 输出: 2 + + 示例 2: + 输入: 8 + 输出: 2 + 说明: 8 的平方根是 2.82842..., +   由于返回类型是整数,小数部分将被舍去。 + https://leetcode-cn.com/problems/sqrtx +""" + + +class Solution: + def mySqrt(self, x: int) -> int: + return self.use_mid_query(x) + + @classmethod + def use_mid_query(cls, x: int) -> int: + if x in (0, 1): + return x + left = 1 + right = x // 2 + + while right > left: + mid = left + (right - left) // 2 + check_sum = mid * mid + if check_sum > x: + right = mid - 1 + elif check_sum < x: + left = mid + 1 + else: + return mid + return right + + +if __name__ == '__main__': + print(Solution.use_mid_query(4)) diff --git a/Week_03/G20200343030545/LeetCode_74_545.py b/Week_03/G20200343030545/LeetCode_74_545.py new file mode 100644 index 00000000..d49afa23 --- /dev/null +++ b/Week_03/G20200343030545/LeetCode_74_545.py @@ -0,0 +1,88 @@ +""" + 编写一个高效的算法来判断 m x n 矩阵中,是否存在一个目标值。该矩阵具有如下特性: + 每行中的整数从左到右按升序排列。 + 每行的第一个整数大于前一行的最后一个整数。 + + 示例 1: + 输入: + matrix = [ + [1, 3, 5, 7], + [10, 11, 16, 20], + [23, 30, 34, 50] + ] + + target = 3 + 输出: true + + 示例 2: + + 输入: + matrix = [ + [1, 3, 5, 7], + [10, 11, 16, 20], + [23, 30, 34, 50] + ] + target = 13 + 输出: + false +""" + +from typing import List + + +class Solution: + def searchMatrix(self, matrix: List[List[int]], target: int) -> bool: + return self.mid_query(matrix, target) + + @classmethod + def convert(cls, matrix: List[List[int]], target: int) -> bool: + """ + 时间复杂度 O(m+logm*n) k为二位数组中 的行数 + 空间复杂度 O(m*n) n为二维数组中总个数 + """ + new_nums = [] + for nums in matrix: + new_nums.extend(nums) + + start = 0 + end = len(new_nums) - 1 + + while start <= end: + mid = (start + end) // 2 + if new_nums[mid] == target: + return True + if new_nums[mid] > target: + end = mid - 1 + else: + start = start + 1 + return False + + @classmethod + def mid_query(cls, matrix: List[List[int]], target: int) -> bool: + """ + 将二维数组视为一维数组 套用二分查找的模版 + 时间复杂度: O(log mn) + 空间复杂度: O(1) + """ + if matrix and matrix[0]: + row = len(matrix) + col = len(matrix[0]) + + start = 0 + end = row * col - 1 + + while end >= start: + mid = (start + end) // 2 + mid_val = matrix[mid // col][mid % col] + if mid_val == target: + return True + elif mid_val > target: + end = mid - 1 + else: + start = mid + 1 + return False + + +if __name__ == '__main__': + Solution.mid_query( + [[1, 3, 5, 7], [10, 11, 16, 20], [23, 30, 34, 50]], 3) diff --git a/Week_03/G20200343030545/LeetCode_78_545.py b/Week_03/G20200343030545/LeetCode_78_545.py new file mode 100644 index 00000000..b48445b9 --- /dev/null +++ b/Week_03/G20200343030545/LeetCode_78_545.py @@ -0,0 +1,62 @@ +""" + 给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。 + 说明:解集不能包含重复的子集。 + + 示例: + 输入: nums = [1,2,3] + 输出: + [ + [3], +   [1], +   [2], +   [1,2,3], +   [1,3], +   [2,3], +   [1,2], +   [] + ] +""" +from typing import List + + +class Solution: + def subsets(self, nums: List[int]) -> List[List[int]]: + res = [] + if nums: + res = [] + self.recursive(res, nums, [], 0) + + return res + + @classmethod + def use_iteration(cls, nums: List[int]) -> List[List[int]]: + result = [[]] + for num in nums: + new_sets = [] + for sub_set in result: + tmp_set = sub_set + [num] + new_sets.append(tmp_set) + + result.extend(new_sets) + return result + + @classmethod + def recursive(cls, res: List[List[int]], nums: List[int], tmp_nums: List[int], index: int): + # 1.terminator + if index == len(nums): + res.append(tmp_nums[:]) + return + + # 不选这个index + cls.recursive(res, nums, tmp_nums[:], index + 1) + + # 选这个index + tmp_nums.append(nums[index]) + cls.recursive(res, nums, tmp_nums[:], index + 1) + + # tmp_nums.pop() + + +if __name__ == '__main__': + nums = [1, 2, 3] + print(Solution.use_iteration(nums)) diff --git a/Week_03/G20200343030545/LeetCode_860_545.py b/Week_03/G20200343030545/LeetCode_860_545.py new file mode 100644 index 00000000..46c0dfcc --- /dev/null +++ b/Week_03/G20200343030545/LeetCode_860_545.py @@ -0,0 +1,77 @@ +""" + 在柠檬水摊上,每一杯柠檬水的售价为 5 美元。 + 顾客排队购买你的产品,(按账单 bills 支付的顺序)一次购买一杯。 + 每位顾客只买一杯柠檬水,然后向你付 5 美元、10 美元或 20 美元。 + 你必须给每个顾客正确找零,也就是说净交易是每位顾客向你支付 5 美元。 + + 注意,一开始你手头没有任何零钱。如果你能给每位顾客正确找零,返回 true ,否则返回 false 。 + + 示例 1: + 输入:[5,5,5,10,20] + 输出:true + 解释: + 前 3 位顾客那里,我们按顺序收取 3 张 5 美元的钞票。 + 第 4 位顾客那里,我们收取一张 10 美元的钞票,并返还 5 美元。 + 第 5 位顾客那里,我们找还一张 10 美元的钞票和一张 5 美元的钞票。 + 由于所有客户都得到了正确的找零,所以我们输出 true。 + + 示例 2: + 输入:[5,5,10] + 输出:true + + 示例 3: + 输入:[10,10] + 输出:false + + 示例 4: + 输入:[5,5,10,10,20] + 输出:false + 解释: + 前 2 位顾客那里,我们按顺序收取 2 张 5 美元的钞票。 + 对于接下来的 2 位顾客,我们收取一张 10 美元的钞票,然后返还 5 美元。 + 对于最后一位顾客,我们无法退回 15 美元,因为我们现在只有两张 10 美元的钞票。 + 由于不是每位顾客都得到了正确的找零,所以答案是 false。 + + 提示: + 0 <= bills.length <= 10000 + bills[i] 不是 5 就是 10 或是 20  + + https://leetcode-cn.com/problems/lemonade-change +""" + +from typing import List + + +class Solution: + def lemonadeChange(self, bills: List[int]) -> bool: + """ + 当收5块时,5块张数+1 + 当收10块时,如果没有5块,直接返回False,如果有5块则说明可以找钱,则5块张数-1 + 当收20块时,如果手里有5块并且有10块,则5块张数-1,10块张数-1。如果有3张五块,则五块张数-3。否则返回False + + 时间复杂度 O(n) + """ + ten = five = 0 + + for bill in bills: + if bill == 5: + five += 1 + elif bill == 10: + if five: + five -= 1 + ten += 1 + else: + return False + elif bill == 20: + if ten and five: + five -= 1 + ten -= 1 + elif five >= 3: + five -= 3 + else: + return False + return True + + +if __name__ == '__main__': + print(Solution().lemonadeChange([5, 5, 5, 10, 20])) diff --git a/Week_03/G20200343030545/LeetCode_874_545.py b/Week_03/G20200343030545/LeetCode_874_545.py new file mode 100644 index 00000000..2650167f --- /dev/null +++ b/Week_03/G20200343030545/LeetCode_874_545.py @@ -0,0 +1,63 @@ +""" + 机器人在一个无限大小的网格上行走,从点 (0, 0) 处开始出发,面向北方。 + 该机器人可以接收以下三种类型的命令: + -2:向左转 90 度 + -1:向右转 90 度 + 1 <= x <= 9:向前移动 x 个单位长度 + + 在网格上有一些格子被视为障碍物。 + 第 i 个障碍物位于网格点  (obstacles[i][0], obstacles[i][1]) + 如果机器人试图走到障碍物上方,那么它将停留在障碍物的前一个网格方块上,但仍然可以继续该路线的其余部分。 + 返回从原点到机器人的最大欧式距离的平方。 + +  示例 1: + 输入: commands = [4,-1,3], obstacles = [] + 输出: 25 + 解释: 机器人将会到达 (3, 4) + + 示例 2: + 输入: commands = [4,-1,4,-2,4], obstacles = [[2,4]] + 输出: 65 + 解释: 机器人在左转走到 (1, 8) 之前将被困在 (1, 4) 处 +  + 提示: + 0 <= commands.length <= 10000 + 0 <= obstacles.length <= 10000 + -30000 <= obstacle[i][0] <= 30000 + -30000 <= obstacle[i][1] <= 30000 + 答案保证小于 2 ^ 31 +""" +from typing import List + + +class Solution: + def robotSim(self, commands: List[int], obstacles: List[List[int]]) -> int: + distance = dx = x = y = 0 + dy = 1 + obs_dict = dict() + + for obs in obstacles: + obs_dict[tuple(obs)] = 0 + + for com in commands: + if com == -2: + # 左转 + dx, dy = -dy, dx + elif com == -1: + # 右转 + dx, dy = dy, -dx + else: + # 走 或者 原地踏步 + for j in range(com): + next_x = x + dx + next_y = y + dy + + if (next_x, next_y) in obs_dict: + break + x, y = next_x, next_y + distance = max(distance, x * x + y * y) + return distance + + +if __name__ == '__main__': + print(Solution().robotSim([-1, -2, 3], [])) diff --git a/Week_03/G20200343030545/NOTE.md b/Week_03/G20200343030545/NOTE.md index 50de3041..86ba5b3e 100644 --- a/Week_03/G20200343030545/NOTE.md +++ b/Week_03/G20200343030545/NOTE.md @@ -1 +1,3 @@ -学习笔记 \ No newline at end of file +#学习笔记 + +### \ No newline at end of file diff --git a/Week_03/G20200343030553/LeetCode_200_553.java b/Week_03/G20200343030553/LeetCode_200_553.java new file mode 100644 index 00000000..9b0832e1 --- /dev/null +++ b/Week_03/G20200343030553/LeetCode_200_553.java @@ -0,0 +1,27 @@ +class Solution { + public int numIslands(char[][] grid) { + int count = 0; + for(int i=0; i< grid.length;i++){ + for(int j=0;j(n-1) || j>(m-1) || grid[i][j]=='0') + return; + grid[i][j] = '0'; + xiaochu(i-1,j,grid); + xiaochu(i+1,j,grid); + xiaochu(i,j-1,grid); + xiaochu(i,j+1,grid); + } +} \ No newline at end of file diff --git a/Week_03/G20200343030553/LeetCode_455_553.java b/Week_03/G20200343030553/LeetCode_455_553.java new file mode 100644 index 00000000..5a030ec4 --- /dev/null +++ b/Week_03/G20200343030553/LeetCode_455_553.java @@ -0,0 +1,20 @@ +class Solution { + public int findContentChildren(int[] g, int[] s) { + Arrays.sort(g); + Arrays.sort(s); + + int count = 0; + int gp = 0; + int sp = 0; + while(gp= g[gp]){ + sp++; + gp++; + count++; + }else{ + sp ++; + } + } + return count; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030553/NOTE.md b/Week_03/G20200343030553/NOTE.md index 50de3041..7dd9b01d 100644 --- a/Week_03/G20200343030553/NOTE.md +++ b/Week_03/G20200343030553/NOTE.md @@ -1 +1,123 @@ -学习笔记 \ No newline at end of file +学习笔记 + +## 第八课 分治、回溯 + +本质上都是递归 + +分治:对一个问题划分为多个子问题split,最后合并子问题结果merge。(和普通递归区别,最后需要合并子问题结果) + +n的x幂问题([50. Pow(x, n)](https://leetcode-cn.com/problems/powx-n/))、求众数([169. 多数元素](https://leetcode-cn.com/problems/majority-element/)) + +```python +def divide_conquer(problem, param1, param2, ...): + # recursion terminator + if problem is None: + print_result + return + # prepare data + data = prepare_data(problem) + subproblems = split_problem(problem, data) + # conquer subproblems + subresult1 = self.divide_conquer(subproblems[0], p1, ...) + subresult2 = self.divide_conquer(subproblems[1], p1, ...) + subresult3 = self.divide_conquer(subproblems[2], p1, ...) + … + # process and generate the final result + result = process_result(subresult1, subresult2, subresult3, …) + # revert the current level states +``` + +回溯:采用试错的思想,分步的解决一个问题,当解决过程中发现当前分步答案错误则取消该分支。 + +八皇后问题、数组组合问题([78. 子集](https://leetcode-cn.com/problems/subsets/)、[17. 电话号码的字母组合](https://leetcode-cn.com/problems/letter-combinations-of-a-phone-number/))。 + +## 第九课 深度优先、广度优先搜索: + +DFS(深度优先):分为前序、中序、后序搜索;可通过递归或栈实现; 其中对于图结构,遍历是增加visited集合,用于存放已访问节点,防止重复访问。 + +```python +递归写法 +visited = set() +def dfs(node, visited): + if node in visited: # terminator + # already visited + return + visited.add(node) + # process current node here. + ... + for next_node in node.children(): + if next_node not in visited: + dfs(next_node, visited) +``` + +```python +非递归写法 +def DFS(self, tree): + if tree.root is None: + return [] + visited, stack = [], [tree.root] + + while stack: + node = stack.pop() + visited.add(node) + process (node) + nodes = generate_related_nodes(node) + stack.push(nodes) + # other processing work + ... +``` + +BFS(广度优先):层级遍历;可通过queue实现;其中对于图结构,遍历是增加visited集合,用于存放已访问节点,防止重复访问。 + +```python + +def BFS(graph, start, end): + visited = set() + queue = [] + queue.append([start]) + while queue: + node = queue.pop() + visited.add(node) + process(node) + nodes = generate_related_nodes(node) + queue.push(nodes) + # other processing work + ... +``` + +BFS([102. 二叉树的层次遍历](https://leetcode-cn.com/problems/binary-tree-level-order-traversal/)、[127. 单词接龙](https://leetcode-cn.com/problems/word-ladder/))、DFS([22. 括号生成](https://leetcode-cn.com/problems/generate-parentheses/)) + +## 第十课 贪心算法 + +贪心算法:每一步选择中都采取当前状态下最好或最优的选择,从而导致全局最优,比较高效;问题是全局并不一定最优;从开始贪心、从最后贪心 + +贪心 & 回溯 & 动态规划 + +贪心:当下局部最优 + +回溯:能够回退 + +动态规划:最优判断+回退 + +最小生成树、找零问题([322. 零钱兑换](https://leetcode-cn.com/problems/coin-change/)、[860. 柠檬水找零](https://leetcode-cn.com/problems/lemonade-change/)、[455. 分发饼干](https://leetcode-cn.com/problems/assign-cookies/)) + + + +## 二分查找 + +二分查找:三个条件 1、目标函数单调性 2、存在上下界 3、能够通过索引访问 + +```python +left, right = 0, len(array) - 1 +while left <= right: + mid = (left + right) / 2 + if array[mid] == target: + # find the target!! + break or return result + elif array[mid] < target: + left = mid + 1 + else: + right = mid - 1 +``` + +求平方根([69. x 的平方根](https://leetcode-cn.com/problems/sqrtx/))、半有序数组 \ No newline at end of file diff --git a/Week_03/G20200343030559/LeetCode_860_559.java b/Week_03/G20200343030559/LeetCode_860_559.java new file mode 100644 index 00000000..288b4d81 --- /dev/null +++ b/Week_03/G20200343030559/LeetCode_860_559.java @@ -0,0 +1,75 @@ +package jc.demo.LeetCode; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +public class LeetCode_860_559 { + public static void main(String[] args) { + LeetCode_860_559 l = new LeetCode_860_559(); + int[] bills = {5,5,10}; + boolean t = l.lemonadeChange(bills); + System.out.println(t); + } + public boolean lemonadeChange(int[] bills) { + int five=0,ten=0; + if(bills.length>10000){ + return false; + } + //Map cash = new HashMap(); + //cash.put(5,0); + //cash.put(10,0); + boolean changeOver =false; + if(bills[0]!=5){ + return false; + } + if(bills.length==1&&bills[0]==5){ + return true; + } + //经过特殊情况的处理,现在第一个人肯定给的是5元,且来买的人肯定多于1个人 + for(int i =0;i0){ + //找5元,5元-1 + //cash.put(5,cash.get(5)-1); + five-=1; + changeOver=true; + }else { + changeOver=false; + break; + } + } + else if(bills[i]==20){ + //1找1张10元1张5元 + if (five>0&&ten>0){ + //cash.put(10,cash.get(10)-1); + ten-=1; + //cash.put(5,cash.get(5)-1); + five-=1; + changeOver=true; + continue; + //找3张5元 + }else if(ten==0&&five>=3){ + //cash.put(5,cash.get(5)-3); + five-=3; + changeOver=true; + continue; + }else { + changeOver=false; + break; + } + } + + } + return changeOver; + } + +//leetcode submit region end(Prohibit modification and deletion) +} diff --git a/Week_03/G20200343030559/LeetCode_874_559.java b/Week_03/G20200343030559/LeetCode_874_559.java new file mode 100644 index 00000000..b994a6b5 --- /dev/null +++ b/Week_03/G20200343030559/LeetCode_874_559.java @@ -0,0 +1,77 @@ +package jc.demo.LeetCode; + +import java.util.HashSet; +import java.util.Set; + +public class LeetCode_874_559 { + public int robotSim(int[] commands, int[][] obstacles) { + int x=0,y=0; + //0=north 1=east 2=south 3=west + int di=0; + int maxRoute=0; + //将障碍的坐标位置组成字符串存到set中 + Set set = new HashSet(); + for(int[] i :obstacles){ + set.add(i[0]+","+i[1]); + } + for(int i =0;i0){ + switch (di){ + case 0: + for(int j=0;j= nums[lo] && target < nums[mid]) + hi = mid - 1; + else + lo = mid + 1; // 1 + } else { + if (target <= nums[hi] && target > nums[mid]) + lo = mid + 1; + else + hi = mid - 1; + } + } + return -1; + } +} */ + +// @lc code=end + diff --git a/Week_03/G20200343030561/Leetcode_045_561.java b/Week_03/G20200343030561/Leetcode_045_561.java new file mode 100644 index 00000000..bc758de7 --- /dev/null +++ b/Week_03/G20200343030561/Leetcode_045_561.java @@ -0,0 +1,41 @@ +/* + * @lc app=leetcode.cn id=45 lang=java + * + * [45] 跳跃游戏 II + */ + +// @lc code=start +/* +class Solution { + public int jump(int[] nums) { + int pos = nums.length - 1; + int steps = 0; + while (pos != 0) { + for(int i = 0; i < pos; i ++) { + if(nums[i] + i >= pos) { + pos = i; + steps ++; + break; + } + } + } + return steps; + } +} +*/ +// bfs liked greedy +class Solution { + public int jump(int[] nums) { + int steps = 0, pos = 0, farthest = 0; + for (int i = 0; i < nums.length - 1; i++) { // 不需要i走到最后一个元素 + farthest = Math.max(farthest, i + nums[i]); // current level max size + if (i == pos) { // already visited all element in current level + steps++; // level ++; + pos = farthest; // queue.size(); + } + } + return steps; + } +} +// @lc code=end + diff --git a/Week_03/G20200343030561/Leetcode_055_561.java b/Week_03/G20200343030561/Leetcode_055_561.java new file mode 100644 index 00000000..50a340f1 --- /dev/null +++ b/Week_03/G20200343030561/Leetcode_055_561.java @@ -0,0 +1,19 @@ +/* + * @lc app=leetcode.cn id=55 lang=java + * + * [55] 跳跃游戏 + */ + +// @lc code=start +// 因为它如果能从i跳到j,就能跳到i到j之间任意一个,因此从后贪心是最优的 +class Solution { + public boolean canJump(int[] nums) { + int end = nums.length - 1; + for (int i = nums.length - 1; i >= 0 ;i --) { + if (nums[i] + i >= end) end = i; + } + return end == 0; + } +} +// @lc code=end + diff --git a/Week_03/G20200343030561/Leetcode_074_561.java b/Week_03/G20200343030561/Leetcode_074_561.java new file mode 100644 index 00000000..b9a1d972 --- /dev/null +++ b/Week_03/G20200343030561/Leetcode_074_561.java @@ -0,0 +1,39 @@ +/* + * @lc app=leetcode.cn id=74 lang=java + * + * [74] 搜索二维矩阵 + */ + +// @lc code=start +class Solution { + public boolean searchMatrix(int[][] matrix, int target) { + if (matrix.length == 0 || matrix[0].length == 0) return false; + int lo = 0, hi = matrix.length - 1, mid, dim = 0; + while (lo <= hi) { + mid = lo + (hi - lo) / 2; + if ((matrix[mid][0] <= target && mid == matrix.length - 1) || + (matrix[mid][0] <= target && matrix[mid + 1][0] > target)) { + dim = mid; + break; + } else if (matrix[mid][0] < target) { + lo = mid + 1; + } else if (matrix[mid][0] > target) { + hi = mid - 1; + } + } + int left = 0, right = matrix[dim].length - 1; + while (left <= right) { + mid = left + (right - left) / 2; + if (matrix[dim][mid] == target) { + return true; + } else if (matrix[dim][mid] < target) { + left = mid + 1; + } else if (matrix[dim][mid] > target) { + right = mid - 1; + } + } + return false; + } +} +// @lc code=end + diff --git a/Week_03/G20200343030561/Leetcode_122_561.java b/Week_03/G20200343030561/Leetcode_122_561.java new file mode 100644 index 00000000..99ad0c8f --- /dev/null +++ b/Week_03/G20200343030561/Leetcode_122_561.java @@ -0,0 +1,19 @@ +/* + * @lc app=leetcode.cn id=122 lang=java + * + * [122] 买卖股票的最佳时机 II + */ + +// @lc code=start +class Solution { + public int maxProfit(int[] prices) { + int max = 0; + for (int i = 1; i < prices.length; i ++) { + if (prices[i - 1] < prices[i]) + max += prices[i] - prices[i - 1] ; + } + return max; + } +} +// @lc code=end + diff --git a/Week_03/G20200343030561/Leetcode_126_561.java b/Week_03/G20200343030561/Leetcode_126_561.java new file mode 100644 index 00000000..08264ab4 --- /dev/null +++ b/Week_03/G20200343030561/Leetcode_126_561.java @@ -0,0 +1,311 @@ +import java.util.*; +/* + * @lc app=leetcode.cn id=126 lang=java + * + * [126] 单词接龙 II + */ + +// @lc code=start +/* bfs +class Solution { + public List> findLadders(String beginWord, String endWord, List wordList) { + List> res = new ArrayList<>(); + Set dict = new HashSet<>(wordList); + if (!dict.contains(endWord)) return res; + Set visited = new HashSet<>(); + Queue> queue = new LinkedList<>(); + List list = new ArrayList<>(Arrays.asList(beginWord)); + queue.offer(list); + visited.add(beginWord); + //wordSet.remove(beginWord); + int wordLength = beginWord.length(); + boolean reachEnd = false; + + while (!queue.isEmpty() && !reachEnd) { + Set visitedInLevel = new HashSet<>(); + for (int i = queue.size(); i > 0; i --) { + List path = queue.poll(); + // visitedInLevel = new HashSet<>(path); + // System.out.println(path); + for (int j = 0; j < wordLength; j ++) { + char[] alphabet = path.get(path.size() - 1).toCharArray(); + for (char letter = 'a'; letter <= 'z'; letter++) { + if (alphabet[j] == letter) continue; + alphabet[j] = letter; + String word = new String(alphabet); + if (!visited.contains(word) && dict.contains(word)){ + // System.out.println(word); + visitedInLevel.add(word); + List newPath = new ArrayList<>(path); + newPath.add(word); + queue.offer(newPath); + if (endWord.equals(word)) { + reachEnd = true; + res.add(newPath); + } + } + } + } + // for (Iterator it = wordSet.iterator(); it.hasNext();) { + // String element = it.next(); + // if (visited.contains(element)) continue; + // int diff = 0; + // for (int j = 0; j < wordLength; j ++) { + // if (word.charAt(j) != element.charAt(j)) + // if (++diff > 1) break; + // } + // if (diff == 1) { + // List newPath = new ArrayList<>(path); + // newPath.add(element); + // if (endWord.equals(element)){ + // reachEnd = true; + // res.add(newPath); + // } + // queue.add(newPath); + // // it.remove(); + // } + // } + } + visited.addAll(visitedInLevel); + } + return res; + } +} // public List> findLadders(String beginWord, String endWord, List wordList) { + // // 结果集 + // List> res = new ArrayList<>(); + // Set words = new HashSet<>(wordList); + // // 字典中不包含目标单词 + // if (!words.contains(endWord)) { + // return res; + // } + // // 存放关系:每个单词可达的下层单词 + // Map> mapTree = new HashMap<>(); + // Set begin = new HashSet<>(), end = new HashSet<>(); + // begin.add(beginWord); + // end.add(endWord); + // if (buildTree(words, begin, end, mapTree, true)) { + // System.out.println(mapTree.size()); + // dfs(res, mapTree, beginWord, endWord, new LinkedList<>()); + // } + // return res; + // } + + // // 双向BFS,构建每个单词的层级对应关系 + // private boolean buildTree(Set words, Set begin, Set end, Map> mapTree, boolean isFront){ + // if (begin.size() == 0) { + // return false; + // } + // // 始终以少的进行探索 + // if (begin.size() > end.size()) { + // return buildTree(words, end, begin, mapTree, !isFront); + // } + // // 在已访问的单词集合中去除 + // words.removeAll(begin); + // // 标记本层是否已到达目标单词 + // boolean isMeet = false; + // // 记录本层所访问的单词 + // Set nextLevel = new HashSet<>(); + // for (String word : begin) { + // char[] chars = word.toCharArray(); + // for (int i = 0; i < chars.length; i++) { + // char temp = chars[i]; + // for (char ch = 'a'; ch <= 'z'; ch++) { + // chars[i] = ch; + // String str = String.valueOf(chars); + // if (words.contains(str)) { + // nextLevel.add(str); + // // 根据访问顺序,添加层级对应关系:始终保持从上层到下层的存储存储关系 + // // true: 从上往下探索:word -> str + // // false: 从下往上探索:str -> word(查找到的 str 是 word 上层的单词) + // String key = isFront ? word : str; + // String nextWord = isFront ? str : word; + // // 判断是否遇见目标单词 + // if (end.contains(str)) { + // isMeet = true; + // } + // if (!mapTree.containsKey(key)) { + // mapTree.put(key, new ArrayList<>()); + // } + // mapTree.get(key).add(nextWord); + // } + // } + // chars[i] = temp; + // } + // } + // if (isMeet) { + // return true; + // } + // return // public List> findLadders(String beginWord, String endWord, List wordList) { + // // 结果集 + // List> res = new ArrayList<>(); + // Set words = new HashSet<>(wordList); + // // 字典中不包含目标单词 + // if (!words.contains(endWord)) { + // return res; + // } + // // 存放关系:每个单词可达的下层单词 + // Map> mapTree = new HashMap<>(); + // Set begin = new HashSet<>(), end = new HashSet<>(); + // begin.add(beginWord); + // end.add(endWord); + // if (buildTree(words, begin, end, mapTree, true)) { + // System.out.println(mapTree.size()); + // dfs(res, mapTree, beginWord, endWord, new LinkedList<>()); + // } + // return res; + // } + + // // 双向BFS,构建每个单词的层级对应关系 + // private boolean buildTree(Set words, Set begin, Set end, Map> mapTree, boolean isFront){ + // if (begin.size() == 0) { + // return false; + // } + // // 始终以少的进行探索 + // if (begin.size() > end.size()) { + // return buildTree(words, end, begin, mapTree, !isFront); + // } + // // 在已访问的单词集合中去除 + // words.removeAll(begin); + // // 标记本层是否已到达目标单词 + // boolean isMeet = false; + // // 记录本层所访问的单词 + // Set nextLevel = new HashSet<>(); + // for (String word : begin) { + // char[] chars = word.toCharArray(); + // for (int i = 0; i < chars.length; i++) { + // char temp = chars[i]; + // for (char ch = 'a'; ch <= 'z'; ch++) { + // chars[i] = ch; + // String str = String.valueOf(chars); + // if (words.contains(str)) { + // nextLevel.add(str); + // // 根据访问顺序,添加层级对应关系:始终保持从上层到下层的存储存储关系 + // // true: 从上往下探索:word -> str + // // false: 从下往上探索:str -> word(查找到的 str 是 word 上层的单词) + // String key = isFront ? word : str; + // String nextWord = isFront ? str : word; + // // 判断是否遇见目标单词 + // if (end.contains(str)) { + // isMeet = true; + // } + // if (!mapTree.containsKey(key)) { + // mapTree.put(key, new ArrayList<>()); + // } + // mapTree.get(key).add(nextWord); + // } + // } + // chars[i] = temp; + // } + // } + // if (isMeet) { + // return true; + // } + // return buildTree(words, nextLevel, end, mapTree, isFront); + // } + + // // DFS: 组合路径 + // private void dfs (List> res, Map> mapTree, String beginWord, String endWord, LinkedList list) { + // list.add(beginWord); + // if (beginWord.equals(endWord)) { + // res.add(new ArrayList<>(list)); + // list.removeLast(); + // return; + // } + // if (mapTree.containsKey(beginWord)) { + // for (String word : mapTree.get(beginWord)) { + // dfs(res, mapTree, word, endWord, list); + // } + // } + // list.removeLast(); + // } + buildTree(words, nextLevel, end, mapTree, isFront); + // } + + // // DFS: 组合路径 + // private void dfs (List> res, Map> mapTree, String beginWord, String endWord, LinkedList list) { + // list.add(beginWord); + // if (beginWord.equals(endWord)) { + // res.add(new ArrayList<>(list)); + // list.removeLast(); + // return; + // } + // if (mapTree.containsKey(beginWord)) { + // for (String word : mapTree.get(beginWord)) { + // dfs(res, mapTree, word, endWord, list); + // } + // } + // list.removeLast(); + // } + +*/ +// bfs and dfs +class Solution { + public List> findLadders(String beginWord, String endWord, List wordList) { + List> res = new ArrayList<>(); + Set dic = new HashSet<>(wordList); + if (!dic.contains(endWord)) return res; + + Map> map = new HashMap<>(); + Set set = new HashSet<>(), reverseSet = new HashSet<>(); + set.add(beginWord); + reverseSet.add(endWord); + if (bfs(dic, set, reverseSet, map, true)){ + System.out.println(map.size()); + LinkedList list = new LinkedList<>(); + list.add(beginWord); + dfs(res, map, beginWord, endWord, list); + } + return res; + } + + private boolean bfs(Set dic, Set set, Set reverseSet, + Map> map, boolean isFront) { + if(set.isEmpty()) return false; + if (set.size() > reverseSet.size()) { + return bfs(dic, reverseSet, set, map, !isFront); + } + dic.removeAll(set); + boolean flag = false; + Set nextSet = new HashSet<>(); + for (String word: set) { + for (int i = 0; i < word.length(); i ++) { + char[] alphabet = word.toCharArray(); + for (char letter = 'a'; letter <= 'z'; letter ++) { + if (alphabet[i] == letter) continue; + alphabet[i] = letter; + String newWord = new String(alphabet); + if (dic.contains(newWord)) { + nextSet.add(newWord); + if (reverseSet.contains(newWord)) + flag = true; + String k = isFront ? word : newWord; + String v = isFront ? newWord : word; + if (!map.containsKey(k)) + map.put(k, new ArrayList<>()); + map.get(k).add(v); + } + } + } + } + if (flag) return true; + return bfs(dic, nextSet, reverseSet, map, isFront); + } + + private void dfs(List> res, Map> map, + String beginWord, String endWord, LinkedList list) { + if (beginWord.equals(endWord)) { + res.add(new ArrayList<>(list)); + return; + } + if (map.containsKey(beginWord)) { + for (String word: map.get(beginWord)) { + list.add(word); + dfs(res, map, word, endWord, list); + list.removeLast(); + } + } + } +} + +// @lc code=end + diff --git a/Week_03/G20200343030561/Leetcode_127_561.java b/Week_03/G20200343030561/Leetcode_127_561.java new file mode 100644 index 00000000..d4c0ab79 --- /dev/null +++ b/Week_03/G20200343030561/Leetcode_127_561.java @@ -0,0 +1,41 @@ +import java.util.*; +/* + * @lc app=leetcode.cn id=127 lang=java + * + * [127] 单词接龙 + */ + +// @lc code=start +class Solution { + public int ladderLength(String beginWord, String endWord, List wordList) { + Set wordSet = new HashSet<>(wordList); + if (!wordSet.contains(endWord)) return 0; + Queue queue = new LinkedList<>(); + queue.offer(beginWord); + wordSet.remove(beginWord); + int step = 0, wordLength = beginWord.length(); + while (!queue.isEmpty()) { + step ++; + for (int i = queue.size(); i > 0; i --) { + String word = queue.poll(); + for (Iterator it = wordSet.iterator(); it.hasNext();) { + String element = it.next(); + int diff = 0; + for (int j = 0; j < wordLength; j ++) { + if (word.charAt(j) != element.charAt(j)) + if (++diff > 1) break; + } + if (diff == 1) { + if (endWord.equals(element)) + return step + 1; + queue.add(element); + it.remove(); + } + } + } + } + return 0; + } +} +// @lc code=end + diff --git a/Week_03/G20200343030561/Leetcode_153_561.java b/Week_03/G20200343030561/Leetcode_153_561.java new file mode 100644 index 00000000..36de7061 --- /dev/null +++ b/Week_03/G20200343030561/Leetcode_153_561.java @@ -0,0 +1,56 @@ +/* + * @lc app=leetcode.cn id=153 lang=java + * + * [153] 寻找旋转排序数组中的最小值 + */ + +// @lc code=start +// best +class Solution { + public int findMin(int[] nums) { + int lo = 0, hi = nums.length - 1, mid; + while (lo < hi) { + if (nums[lo] < nums[hi]) return nums[lo]; + mid = lo + (hi - lo) / 2; + if (nums[lo] <= nums[mid]) + lo = mid + 1; + else + hi = mid; + } + return nums[lo]; + } +} +/* class Solution { + public int findMin(int[] nums) { + int lo = 0, hi = nums.length - 1, mid; + + if (nums[hi] >= nums[lo]) return nums[lo]; + while(lo <= hi) { + mid = lo + (hi - lo) / 2; + if (nums[mid] > nums[mid + 1]) return nums[mid + 1]; + if (nums[mid - 1] > nums[mid]) return nums[mid]; + if (nums[mid] > nums[0]) // important + lo = mid + 1; + else + hi = mid - 1; + } + return -1; + } +} */ + +/* class Solution { + public int findMin(int[] nums) { + int lo = 0, hi = nums.length - 1, mid; + while (lo <= hi) { + if (nums[lo] <= nums[hi]) return nums[lo]; + if ((mid = lo + (hi - lo) / 2) == lo) return Math.min(nums[lo], nums[hi]); + if (nums[lo] < nums[mid]) + lo = mid; + else + hi = mid; + } + return -1; + } +} */ +// @lc code=end + diff --git a/Week_03/G20200343030561/Leetcode_200_561.java b/Week_03/G20200343030561/Leetcode_200_561.java new file mode 100644 index 00000000..c9f6bc97 --- /dev/null +++ b/Week_03/G20200343030561/Leetcode_200_561.java @@ -0,0 +1,39 @@ +/* + * @lc app=leetcode.cn id=200 lang=java + * + * [200] 岛屿数量 + */ + +// @lc code=start +class Solution { + public int numIslands(char[][] grid) { + if (grid == null || grid.length == 0) return 0; + int nr = grid.length; + int nc = grid[0].length; + int ni = 0; + for (int r = 0; r < nr; r++) { + for(int c = 0; c < nc; c++) { + if(grid[r][c] == '1') { + ni ++; + dfs(grid, r, c); + } + } + } + return ni; + } + + private void dfs(char[][] grid, int r, int c) { + int nr = grid.length; + int nc = grid[0].length; + if (r < 0 || c < 0 || r >= nr || c >= nc || grid[r][c] == '0') + return; + + grid[r][c] = '0'; + dfs(grid, r - 1, c); + dfs(grid, r + 1, c); + dfs(grid, r, c - 1); + dfs(grid, r, c + 1); + } +} +// @lc code=end + diff --git a/Week_03/G20200343030561/Leetcode_455_561.java b/Week_03/G20200343030561/Leetcode_455_561.java new file mode 100644 index 00000000..0be6a8b1 --- /dev/null +++ b/Week_03/G20200343030561/Leetcode_455_561.java @@ -0,0 +1,22 @@ +import java.util.*; +/* + * @lc app=leetcode.cn id=455 lang=java + * + * [455] 分发饼干 + */ + +// @lc code=start +class Solution { + public int findContentChildren(int[] g, int[] s) { + Arrays.sort(g); + Arrays.sort(s); + int kid = 0; + int biscuit = 0; + while (kid < g.length && biscuit < s.length) + if (g[kid] <= s[biscuit ++]) kid ++; + + return kid; + } +} +// @lc code=end + diff --git a/Week_03/G20200343030561/Leetcode_529_561.java b/Week_03/G20200343030561/Leetcode_529_561.java new file mode 100644 index 00000000..d4975b02 --- /dev/null +++ b/Week_03/G20200343030561/Leetcode_529_561.java @@ -0,0 +1,47 @@ +/* + * @lc app=leetcode.cn id=529 lang=java + * + * [529] 扫雷游戏 + */ + +// @lc code=start +class Solution { + public char[][] updateBoard(char[][] board, int[] click) { + int nr = board.length, nc = board[0].length; + int row = click[0], col = click[1]; + + if(board[row][col] == 'M') + board[row][col] = 'X'; + else { + int count = 0; + for (int i = -1; i < 2; i ++) { + for (int j = -1; j < 2; j ++){ + if (i == 0 && j == 0) continue; + int r = row + i, c = col + j; + if (r<0||c<0||r>=nr||c>=nc) continue; + if (board[r][c] == 'M') + count ++; + } + } + + if (count > 0) + board[row][col] = (char)(count + 48); // '0' ascii code + else { + board[row][col] = 'B'; + for (int i = -1; i < 2; i ++) { + for (int j = -1; j < 2; j ++){ + if (i == 0 && j == 0) continue; + int r = row + i, c = col + j; + if (r<0||c<0||r>=nr||c>=nc) continue; + if (board[r][c] == 'E') + updateBoard(board, new int[]{r, c}); + } + } + } + + } + return board; + } +} +// @lc code=end + diff --git a/Week_03/G20200343030561/Leetcode_860_561.java b/Week_03/G20200343030561/Leetcode_860_561.java new file mode 100644 index 00000000..e549755d --- /dev/null +++ b/Week_03/G20200343030561/Leetcode_860_561.java @@ -0,0 +1,52 @@ +/* + * @lc app=leetcode.cn id=860 lang=java + * + * [860] 柠檬水找零 + */ + +// @lc code=start +class Solution { + public boolean lemonadeChange(int[] bills) { + int five = 0, ten = 0; + for (int b: bills) { + if (b == 5) five ++; + else if (b == 10) {five --; ten ++;} + else if (ten > 0) {five --; ten --;} // b==20&&ten>0 + else five -= 3; // b==20&&ten<=0 + if(five<0) return false; + } + return true; + } +} +/* +class Solution { + public boolean lemonadeChange(int[] bills) { + int five = 0, ten = 0; + for (int b : bills) { + switch(b){ + case 5: + five ++; + break; + case 10: + if (five == 0) return false; + five --; + ten ++; + break; + case 20: + if (five > 0 && ten > 0) { + five --; + ten --; + } else if ( five > 2) { + five -= 3; + } else { + return false; + } + break; + } + } + return true; + } +} +*/ +// @lc code=end + diff --git a/Week_03/G20200343030561/Leetcode_874_561.java b/Week_03/G20200343030561/Leetcode_874_561.java new file mode 100644 index 00000000..8b695e5e --- /dev/null +++ b/Week_03/G20200343030561/Leetcode_874_561.java @@ -0,0 +1,45 @@ +import java.util.*; +/* + * @lc app=leetcode.cn id=874 lang=java + * + * [874] 模拟行走机器人 + */ + +// @lc code=start +class Solution { + public int robotSim(int[] commands, int[][] obstacles) { + int[][] dir = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}}; // 北东南西 + int dirIdx = 0, x = 0, y = 0, nextX, nextY, res = 0; + + + Set obstaclesSet = new HashSet<>(); + for (int k = 0; k < obstacles.length; k ++) { + obstaclesSet.add(obstacles[k][0] + "," + obstacles[k][1]); + } + + for (int i = 0; i < commands.length; i ++) { + int com = commands[i]; + switch (com) { + case -1: + dirIdx = (dirIdx + 1) % 4; // 右转 + break; + case -2: + dirIdx = (dirIdx + 3) % 4; // 左转 + break; + default: + for (int j = 1; j <= com; j++) { + nextX = x + dir[dirIdx][0]; + nextY = y + dir[dirIdx][1]; + if (!obstaclesSet.contains(nextX + "," + nextY)){ + x = nextX; + y = nextY; + res = Math.max(res, x*x + y*y); + } + } + } + } + return res; + } +} +// @lc code=end + diff --git a/Week_03/G20200343030561/NOTE.md b/Week_03/G20200343030561/NOTE.md deleted file mode 100644 index 50de3041..00000000 --- a/Week_03/G20200343030561/NOTE.md +++ /dev/null @@ -1 +0,0 @@ -学习笔记 \ No newline at end of file diff --git a/Week_03/G20200343030561/NOTE.org b/Week_03/G20200343030561/NOTE.org new file mode 100644 index 00000000..8c0b61a3 --- /dev/null +++ b/Week_03/G20200343030561/NOTE.org @@ -0,0 +1,129 @@ +* convert ArrayList to int[] in one line :Java: +#+begin_src java +arraylist.stream().mapToInt(i -> i).toArray(); +#+end_src +[[https://stackoverflow.com/questions/718554/how-to-convert-an-arraylist-containing-integers-to-primitive-int-array][source]] +* push a element to an array like array.push() :Java: +#+begin_src java +array = push(array, item); +private String[] push(String[] array, String push) { + String[] longer = new String[array.length + 1]; + for (int i = 0; i < array.length; i++) + longer[i] = array[i]; + longer[array.length] = push; + return longer; +} +#+end_src +[[https://stackoverflow.com/questions/4537980/equivalent-to-push-or-pop-for-arrays][source]] +a better solution use intStream of Java8 +#+begin_src java +private static int[] push(int[] array, int value) { + return IntStream.concat(Arrays.stream(array), IntStream.of(value)).toArray(); +} +#+end_src +[[https://codereview.stackexchange.com/questions/149801/push-an-item-onto-the-end-of-array-in-java][source]] +uglier... +* debug Java in Visual Studio Code :Java: +https://code.visualstudio.com/docs/java/java-debugging + +* TODO Iterator vs. ListIterator :Java: +https://www.baeldung.com/java-iterate-list + +* TODO Collections.copy(dest, src) vs. new ArrayList[src] :Java: +https://stackoverflow.com/questions/10427109/how-to-copy-values-not-references-of-listinteger-into-another-list +comments are very important + +* TODO String concatenate :Java: +https://javarevisited.blogspot.com/2015/01/3-examples-to-concatenate-string-in-java.html + +* BFS template :Java: +#+begin_src java + private viod bfs (TreeNode root){ + Set visited = new HashSet<>(); + Queue queue = new LinkedList<>(); + queue.offer(root); + } + while (!queue.isEmpty()) { + int node = queue.poll(); + visited.add(node); + + process(node); + + nodes = node.children(); + for (TreeNode n : nodes) { + if (!visited.contains(n)) + queue.offer(nodes); + } + + } + // other process work + ... +#+end_src + +* DFS recursion template :Java: +#+begin_src java + Set visited = new HashSet<>(); + private void dfs(TreeNode node) { + if (visited.contains(node)) + return + visited.add(node); + // process + ... + for(TreeNode n : node.children()) { + if (!visited.contains(n)) + dfs(n); + } + } + +#+end_src +* DFS stack template :Java: +#+begin_src java + private void dfs (TreeNode root) { + Set visited = new HashSet<>(); + List stack = new LinkedList<>(); + while (stack.size() != 0)) { + node = stack.pop(); + visited.add(node); + + // process + ... + nodes = node.childrens(); + for (TreeNode n : nodes) { + if (!visited.contains(node)) + stack.push(nodes); + } + } + } +#+end_src +* BSA template +#+begin_src java + int left = 0; + int right = arr.length - 1; + while (left <= right) { + mid = left + right / 2; + if (arr[mid] = target) { + break; + else if (array[mid] < target) + left = mid + 1; + else + right = mid - 1; + } +#+end_src +* BSA +想明白只有两个元素时怎么处理,以及偶数元素时mid在前在后是否+1,就基本不会错 +* 贪心 +先情景模拟,再找重复性 +* java.util.ConcurrentModificationException :Java: +#+begin_src java + for (String w: wordSet) { + if (shit_happens) wordSet.remove(w); + } +#+end_src +this will throw java.util.ConcurrentModificationException +should be done like this +#+begin_src java +for (Iterator it = wordSet.iterator(); it.hasNext();) { + StringInteger element = it.next(); + if (shit_happens) it.remove(); +} +#+end_src diff --git a/Week_03/G20200343030567/LeetCode_11_567.java b/Week_03/G20200343030567/LeetCode_11_567.java new file mode 100644 index 00000000..cb195098 --- /dev/null +++ b/Week_03/G20200343030567/LeetCode_11_567.java @@ -0,0 +1,143 @@ +package com.aizain.jhome.computer.data.list; + +/** + * MaxArea + * 11. 盛最多水的容器 + *

+ * 给定 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 Zain + * @date 2020/2/28 + */ +public class MaxArea { + + /** + * 审题: + * 1 非负整数 + * 2 n>=2 + *

+ * 思路: + * 1 暴力:两层循环,找出最大的 + * 2 左右夹逼,移动矮的指针 + *

+ * 反馈: + * 1 中文站题解 + * 2 国际站题解 + * + * @param height + * @return + */ + public int maxArea(int[] height) { + // return directlySolution(height); + // return squeezeSolution(height); + // return squeezeFastSolution(height); + return squeezeZoomSolution(height); + } + + /** + * 左右夹逼计算急速版,国际站大佬提供 + * + * @param height + * @return + */ + private int squeezeZoomSolution(int[] height) { + int water = 0; + int i = 0, j = height.length - 1; + while (i < j) { + int h = Math.min(height[i], height[j]); + water = Math.max(water, h * (j - i)); + // 提速关键,找到下一个更长的 + while (height[i] <= h && i < j) i++; + while (height[j] <= h && i < j) j--; + } + return water; + } + + /** + * 左右夹逼计算快速版 + * + * @param height + * @return + */ + private int squeezeFastSolution(int[] height) { + int maxArea = 0; + int head = 0; + int tail = height.length - 1; + while (head < tail) { + int hh = height[head]; + int th = height[tail]; + int thisArea; + // 提速关键1,减少逻辑判断次数 + if (hh < th) { + thisArea = (tail - head) * hh; + head++; + } else { + thisArea = (tail - head) * th; + tail--; + } + // 提速关键2,减少赋值次数 + if (thisArea > maxArea) { + maxArea = thisArea; + } + } + return maxArea; + } + + /** + * 左右夹逼计算,移动矮的指针 + *

+ * 执行用时 : 4 ms, 在所有 Java 提交中击败了 75.11% 的用户(第一次貌似会慢一些) + * 内存消耗 : 41.2 MB, 在所有 Java 提交中击败了 5.05% 的用户 + * + * @param height + * @return + */ + private int squeezeSolution(int[] height) { + int max = 0; + int head = 0; + int tail = height.length - 1; + while (head < tail) { + max = Math.max(max, (tail - head) * Math.min(height[head], height[tail])); + if (height[head] < height[tail]) { + head++; + } else { + tail--; + } + } + return max; + } + + /** + * 暴力法求解 + * i,j两层循环要写熟练 + *

+ * 执行用时 : 481 ms, 在所有 Java 提交中击败了 7.41% 的用户 + * 内存消耗 : 41.5 MB, 在所有 Java 提交中击败了 5.05% 的用户 + * + * @param height + * @return + */ + private int directlySolution(int[] height) { + int max = 0; + for (int i = 0; i < height.length; i++) { + for (int j = i + 1; j < height.length; j++) { + max = Math.max(max, (j - i) * Math.min(height[i], height[j])); + } + } + return max; + } + +} diff --git a/Week_03/G20200343030567/LeetCode_122_567.java b/Week_03/G20200343030567/LeetCode_122_567.java new file mode 100644 index 00000000..417082f2 --- /dev/null +++ b/Week_03/G20200343030567/LeetCode_122_567.java @@ -0,0 +1,96 @@ +package com.aizain.jhome.computer.data.recursive; + +/** + * MaxProfit + * 122. 买卖股票的最佳时机 II + *

+ * 给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。 + * 设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。 + * 注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。 + *

+ * 示例 1: + * 输入: [7,1,5,3,6,4] + * 输出: 7 + * 解释: 在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。 + *   随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6-3 = 3 。 + *

+ * 示例 2: + * 输入: [1,2,3,4,5] + * 输出: 4 + * 解释: 在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。 + *   注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。 + *   因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。 + *

+ * 示例 3: + * 输入: [7,6,4,3,1] + * 输出: 0 + * 解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。 + *

+ * 来源:力扣(LeetCode) + * 链接:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii + * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + * + * @author Zain + * @date 2020/3/1 + */ +public class MaxProfit2 { + + /** + * 审题: + * 1 买卖次数不限制 + * 2 买前必须全部卖出 + *

+ * 思路: + * 1 无思路,直接看题解 + * 2 贪心算法:买进,高就卖出,重复以上 + *

+ * 反馈: + * 1 贪心算法简洁版 + * + * @param prices + * @return + */ + public int maxProfit(int[] prices) { + // return greedySolution(prices); + return greedyCleanSolution(prices); + } + + /** + * 贪心算法简洁版 + * 1 ms 42.9 MB + * + * @param prices + * @return + */ + private int greedyCleanSolution(int[] prices) { + int profit = 0; + for (int i = 1; i < prices.length; i++) { + if (prices[i] > prices[i - 1]) { + profit += prices[i] - prices[i - 1]; + } + } + return profit; + } + + /** + * 贪心算法:买进,高就卖出,重复以上 + * 1 ms 42.4 MB + * + * @param prices + * @return + */ + private int greedySolution(int[] prices) { + int profit = 0; + for (int i = 1, buy = 0; i < prices.length; i++) { + if (prices[buy] > prices[i]) { + buy = i; + } + if (prices[i] > prices[buy]) { + profit += prices[i] - prices[buy]; + buy = i; + } + } + return profit; + } + +} diff --git a/Week_03/G20200343030567/LeetCode_15_567.java b/Week_03/G20200343030567/LeetCode_15_567.java new file mode 100644 index 00000000..4f372576 --- /dev/null +++ b/Week_03/G20200343030567/LeetCode_15_567.java @@ -0,0 +1,241 @@ +package com.aizain.jhome.computer.data.list; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.LinkedHashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * ThreeSum + * 15. 三数之和 + *

+ * 给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组。 + * 注意:答案中不可以包含重复的三元组。 + *

+ * 示例: + * 给定数组 nums = [-1, 0, 1, 2, -1, -4], + *

+ * 满足要求的三元组集合为: + * [ + * [-1, 0, 1], + * [-1, -1, 2] + * ] + *

+ * 来源:力扣(LeetCode) + * 链接:https://leetcode-cn.com/problems/3sum + * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + * + * @author Zain + * @date 2020/2/29 + */ +public class ThreeSum { + + /** + * 审题: + * 1 返回不重复的三元组 + * 2 会有复数,无序 + * 3 可能不存在(实际要求返回空数组) + * 4 a+b=-c + * 5 数组内有重复数字,结果有可能有重复 + *

+ * 思路: + * 1 暴力:三重循环 + * 2 hash:两重暴力+hash + * 3 夹逼:因为不需要下标,可以排序后夹逼 + * + * @param nums + * @return + */ + public List> threeSum(int[] nums) { + // return directlySolution(nums); + // return hashSolution(nums); + // return squeezeSolution(nums); + // return hashFastSolution(nums); + return squeezeFastSolution(nums); + } + + /** + * 失败 + * + * @param nums + * @return + */ + private List> hashFastSolution(int[] nums) { + if (nums == null || nums.length <= 2) { + return Collections.emptyList(); + } + List> result = new LinkedList<>(); + Arrays.sort(nums); + for (int i = 0; i < nums.length - 2; i++) { + if (nums[i] > 0) { + return result; + } + if (i > 0 && nums[i] == nums[i - 1]) { + continue; + } + int target = -nums[i]; + Map hashMap = new HashMap<>(nums.length - i); + for (int j = i + 1; j < nums.length; j++) { + int v = target - nums[j]; + Integer exist = hashMap.get(v); + if (exist != null) { + result.add(Arrays.asList(nums[i], exist, nums[j])); + } else { + hashMap.put(nums[j], nums[j]); + } + while (j < nums.length && nums[j] == nums[j + 1]) j++; + } + } + + return result; + } + + /** + * 夹逼快速版 + *

+ * 18 ms 45.6 MB + * + * @param nums + * @return + */ + private List> squeezeFastSolution(int[] nums) { + if (nums == null || nums.length <= 2) { + return Collections.emptyList(); + } + List> result = new LinkedList<>(); + + Arrays.sort(nums); + for (int i = 0; i < nums.length - 2; i++) { + // 加速1:c为非负数,就不能满足a+b+c=0了 + if (nums[i] > 0) { + return result; + } + // 加速2:跳过计算过的数据,同时防止结果重复 + if (i != 0 && nums[i] == nums[i - 1]) { + continue; + } + int head = i + 1; + int tail = nums.length - 1; + while (head < tail) { + int sum = -(nums[head] + nums[tail]); + if (sum == nums[i]) { + result.add(Arrays.asList(nums[i], nums[head], nums[tail])); + // 加速3:跳过计算过的数据,同时防止结果重复 + while (head < tail && nums[head] == nums[head + 1]) { + head++; + } + while (head < tail && nums[tail] == nums[tail - 1]) { + tail--; + } + } + if (sum <= nums[i]) { + tail--; + } else { + head++; + } + } + } + + return result; + } + + /** + * 夹逼法 + * 899 ms 45.9 MB + * + * @param nums + * @return + */ + private List> squeezeSolution(int[] nums) { + if (nums == null || nums.length <= 2) { + return Collections.emptyList(); + } + Set> result = new LinkedHashSet<>(); + + Arrays.sort(nums); + for (int i = 0; i < nums.length - 2; i++) { + int head = i + 1; + int tail = nums.length - 1; + while (head < tail) { + int sum = -(nums[head] + nums[tail]); + if (sum == nums[i]) { + List value = Arrays.asList(nums[i], nums[head], nums[tail]); + result.add(value); + } + if (sum <= nums[i]) { + tail--; + } else { + head++; + } + } + } + + return new ArrayList<>(result); + } + + /** + * hash slow + * 1406 ms 46 MB + * + * @param nums + * @return + */ + private List> hashSolution(int[] nums) { + if (nums == null || nums.length <= 2) { + return Collections.emptyList(); + } + Set> result = new LinkedHashSet<>(); + + for (int i = 0; i < nums.length - 2; i++) { + int target = -nums[i]; + Map hashMap = new HashMap<>(nums.length - i); + for (int j = i + 1; j < nums.length; j++) { + int v = target - nums[j]; + Integer exist = hashMap.get(v); + if (exist != null) { + List list = Arrays.asList(nums[i], exist, nums[j]); + list.sort(Comparator.naturalOrder()); + result.add(list); + } else { + hashMap.put(nums[j], nums[j]); + } + } + } + + return new ArrayList<>(result); + } + + /** + * 暴力:超出时间限制 + * + * @param nums + * @return + */ + private List> directlySolution(int[] nums) { + if (nums == null || nums.length <= 2) { + return Collections.emptyList(); + } + Arrays.sort(nums); + Set> result = new LinkedHashSet<>(); + for (int i = 0; i < nums.length; i++) { + for (int j = i + 1; j < nums.length; j++) { + for (int k = j + 1; k < nums.length; k++) { + if (nums[i] + nums[j] + nums[k] == 0) { + List value = Arrays.asList(nums[i], nums[j], nums[k]); + result.add(value); + } + } + } + } + + return new ArrayList<>(result); + } + + +} diff --git a/Week_03/G20200343030567/LeetCode_1_567.java b/Week_03/G20200343030567/LeetCode_1_567.java new file mode 100644 index 00000000..358eaaa6 --- /dev/null +++ b/Week_03/G20200343030567/LeetCode_1_567.java @@ -0,0 +1,129 @@ +package com.aizain.jhome.computer.data.list; + +import java.util.HashMap; +import java.util.Map; + +/** + * TwoSum + * 1. 两数之和 + *

+ * 给定一个整数数组 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 + * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + * + * @author Zain + * @date 2020/2/29 + */ +public class TwoSum { + + /** + * 审题: + * 1 都是整数,有可能有复数 + * 2 返回数组下标,下标不相同 + * 3 列表无序 + *

+ * 思路: + * 1 暴力:两层循环求解 + * 2 hash表:key为目标数与当前数之差 + * 3 双指针:夹逼找到是否有目标数 + *

+ * 反馈: + * 1 国际站有(log n)方法,一个数据排序双指针找,单独复制出来的数组用于找回下标 + * + * @param nums + * @param target + * @return + */ + public int[] twoSum(int[] nums, int target) { + // return directlySolution(nums, target); + // return hashSolution(nums, target); + return squeezeSolution(nums, target); + } + + + /** + * 双指针,除非列表有序 + * + * @param nums + * @param target + * @return + */ + private int[] squeezeSolution(int[] nums, int target) { + if (nums == null || nums.length <= 1) { + return null; + } + + for (int i = 0, j = nums.length - 1; i < j; ) { + int sum = nums[i] + nums[j]; + if (sum == target) { + return new int[]{i, j}; + } + if (sum > target) { + j--; + } else { + i++; + } + } + return null; + } + + /** + * hash方式 + *

+ * 执行用时 : 2 ms, 在所有 Java 提交中击败了 99.50% 的用户 + * 内存消耗 : 41.5 MB, 在所有 Java 提交中击败了 5.10% 的用户 + * + * @param nums + * @param target + * @return + */ + private int[] hashSolution(int[] nums, int target) { + if (nums == null || nums.length <= 1) { + return null; + } + Map map = new HashMap<>(nums.length); + for (int i = 0; i < nums.length; i++) { + int v = target - nums[i]; + Integer exist = map.get(v); + if (exist != null) { + return new int[]{exist, i}; + } + map.put(nums[i], i); + } + + return null; + } + + /** + * 暴力法 + *

+ * 执行用时 : 105 ms, 在所有 Java 提交中击败了 5.10% 的用户 + * 内存消耗 : 39.3 MB, 在所有 Java 提交中击败了 5.10% 的用户 + * + * @param nums + * @param target + * @return + */ + private int[] directlySolution(int[] nums, int target) { + if (nums == null || nums.length <= 1) { + return null; + } + 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 null; + } + +} diff --git a/Week_03/G20200343030567/LeetCode_22_567.java b/Week_03/G20200343030567/LeetCode_22_567.java new file mode 100644 index 00000000..a4b63351 --- /dev/null +++ b/Week_03/G20200343030567/LeetCode_22_567.java @@ -0,0 +1,177 @@ +package com.aizain.jhome.computer.data.recursive; + +import java.util.Collections; +import java.util.Deque; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +/** + * GenerateParenthesis + * 22. 括号生成 + *

+ * 给出 n 代表生成括号的对数,请你写出一个函数,使其能够生成所有可能的并且有效的括号组合。 + * 例如,给出 n = 3,生成结果为: + *

+ * [ + * "((()))", + * "(()())", + * "(())()", + * "()(())", + * "()()()" + * ] + *

+ * 来源:力扣(LeetCode) + * 链接:https://leetcode-cn.com/problems/generate-parentheses + * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + * + * @author Zain + * @date 2020/3/1 + */ +public class GenerateParenthesis { + + private static Map doubleMap = new HashMap<>(3); + + static { + doubleMap.put("(", ")"); + doubleMap.put("?", "?"); + } + + private List result = new LinkedList<>(); + + /** + * 审题: + * 1 有效的小括号组合 + * 2 需要判断n边界 + * 3 n是括号对的数量 + *

+ * 思路: + * 1 无思路,看题解 + * 2 分治、回溯:左括号、右括号 + *

+ * 反馈: + * 1 回溯(深度优先) + * 2 广度优先 + * 3 动态规划 + * + * @param n + * @return + */ + public List generateParenthesis(int n) { + // return recursiveSolution(n); + // return backtrackSolution(n); + return backtrackCleanSolution(n); + } + + /** + * 回溯法简洁版 + * 1 ms 39.4 MB + * + * @param n + * @return + */ + private List backtrackCleanSolution(int n) { + return backtrackCleanGenerate("(", n - 1, n); + } + + private List backtrackCleanGenerate(String line, int left, int right) { + if (left > 0) { + backtrackCleanGenerate(line + "(", left - 1, right); + } + if (right > left) { + backtrackCleanGenerate(line + ")", left, right - 1); + } + if (right <= 0) { + result.add(line); + } + return result; + } + + /** + * 递归分治回溯法:左括号数小于n,右括号数小于左括号数 + *

+ * 1 ms 39.4 MB + * + * @param n + * @return + */ + private List backtrackSolution(int n) { + if (n < 1) { + return Collections.emptyList(); + } + List result = new LinkedList<>(); + backtrackGenerate(result, "(", 1, 0, n); + return result; + } + + private void backtrackGenerate(List result, String line, int left, int right, int max) { + // 1 终止条件 + if (line.length() == max * 2) { + result.add(line); + return; + } + // 2 当前层 + // 3 子问题 + if (left < max) { + backtrackGenerate(result, line + "(", left + 1, right, max); + } + if (right < left) { + backtrackGenerate(result, line + ")", left, right + 1, max); + } + // 4 合并 + // 5 清理 + } + + /** + * 暴力递归:找出所有可能性,过滤掉不合适的 + * 102 ms 42.1 MB + * + * @param n + * @return + */ + private List recursiveSolution(int n) { + if (n < 1) { + return Collections.emptyList(); + } + + List result = new LinkedList<>(); + recursiveGenerate("(", n * 2, result); + + return result; + } + + private void recursiveGenerate(String line, int max, List result) { + // 1 递归终结条件 + if (line.length() == max) { + if (valid(line)) { + result.add(line); + } + return; + } + // 2 准备数据,处理当前层 + String l1 = line + "("; + String l2 = line + ")"; + // 3 下探处理子问题 + recursiveGenerate(l1, max, result); + recursiveGenerate(l2, max, result); + // 4 合并子问题结果 + // 5 清理 + } + + private boolean valid(String line) { + Deque stack = new LinkedList<>(); + stack.push("?"); + line += "?"; + for (String one : line.split("")) { + String pop = stack.peek(); + if (one.equals(pop)) { + stack.pop(); + } else { + stack.push(doubleMap.get(one)); + } + } + return stack.isEmpty(); + } + +} diff --git a/Week_03/G20200343030567/LeetCode_283_567.java b/Week_03/G20200343030567/LeetCode_283_567.java new file mode 100644 index 00000000..dfadd651 --- /dev/null +++ b/Week_03/G20200343030567/LeetCode_283_567.java @@ -0,0 +1,171 @@ +package com.aizain.jhome.computer.data.list; + +/** + * MoveZeroes + * 283. 移动零 + *

+ * 给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。 + * 示例: + * 输入: [0,1,0,3,12] + * 输出: [1,3,12,0,0] + * 说明: + * 必须在原数组上操作,不能拷贝额外的数组。 + * 尽量减少操作次数。 + *

+ * 来源:力扣(LeetCode) + * 链接:https://leetcode-cn.com/problems/move-zeroes + * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + * + * @author Zain + * @date 2020/2/29 + */ +public class MoveZeroes { + + /** + * 审题: + * 1 结果是原数组 + * 2 数组末尾都是0就行 + * 3 其他元素是相对顺序 + * 4 可能有复数 + *

+ * 思路: + * 1 暴力:遇到0就删除后放到数组最后一位 + * 2 双指针:指针1记录最近非0的位置,指针2往后找非0元素前移 + * 3 额外空间:在申请一个空间存非零,最后再导回来 中文站提供 + * 4 滚雪球:记录0步长为雪球,遇非0交换雪球的第一个 国际站提供 + *

+ * 反馈: + * 1 中文站解题 + * 2 国际站解题 + * + * @param nums + */ + public void moveZeroes(int[] nums) { + // directlySolution(nums); + // fixedSolution(nums); + // fixedLazySolution(nums); + fixedCleanSolution(nums); + // snowBallSolution(nums); + // extraSolution(nums); + } + + private void snowBallSolution(int[] nums) { + int ballSize = 0; + for (int i = 0; i < nums.length; i++) { + if (nums[i] == 0) { + ballSize++; + } else if (ballSize > 0) { + nums[i - ballSize] = nums[i]; + nums[i] = 0; + } + } + } + + private void fixedCleanSolution(int[] nums) { + for (int i = 0, j = 0; j < nums.length; j++) { + if (nums[j] != 0) { + int tmp = nums[j]; + nums[j] = nums[i]; + nums[i++] = tmp; + } + } + } + + + private void extraSolution(int[] nums) { + // 1 check bound + if (nums == null || nums.length <= 1) { + return; + } + // 2 move + int[] extra = new int[nums.length]; + for (int i = 0, j = 0; i < nums.length; i++) { + if (nums[i] != 0) { + extra[j] = nums[i]; + j++; + } + } + System.arraycopy(extra, 0, nums, 0, nums.length); + } + + private void fixedLazySolution(int[] nums) { + // 1 check bound + if (nums == null || nums.length <= 1) { + return; + } + // 2 move + int fixed = 0; + for (int j = 0; j < nums.length; j++) { + if (nums[j] != 0) { + nums[fixed] = nums[j]; + fixed++; + } + } + for (; fixed < nums.length; fixed++) { + nums[fixed] = 0; + } + } + + /** + * 双指针:固定非0元素 + *

+ * 执行用时 : 0 ms, 在所有 Java 提交中击败了 100.00% 的用户 + * 内存消耗 : 42.2 MB, 在所有 Java 提交中击败了 5.01% 的用户 + * + * @param nums + */ + private void fixedSolution(int[] nums) { + // 1 check bound + if (nums == null || nums.length <= 1) { + return; + } + // 2 move + for (int i = 0, j = 0; j < nums.length; j++) { + if (nums[j] != 0) { + if (i != j) { + nums[i] = nums[j]; + nums[j] = 0; + } + i++; + } + } + } + + /** + * 暴力:遇到0就删除后放到数组最后一位,直到后面都是0 + *

+ * 执行用时 : 14 ms, 在所有 Java 提交中击败了 12.73% 的用户 + * 内存消耗 : 42.1 MB, 在所有 Java 提交中击败了 5.01% 的用户 + * + * @param nums + */ + private void directlySolution(int[] nums) { + // 1 check bound + if (nums == null || nums.length <= 1) { + return; + } + + // 2 move + for (int i = 0; i < nums.length; ) { + if (nums[i] != 0) { + i++; + continue; + } + + boolean isZeroEnd = true; + int del = nums[i]; + for (int j = i + 1; j < nums.length; j++) { + nums[j - 1] = nums[j]; + if (nums[j] != 0) { + isZeroEnd = false; + } + } + nums[nums.length - 1] = del; + if (isZeroEnd) { + break; + } + } + } + + +} diff --git a/Week_03/G20200343030567/LeetCode_50_567.java b/Week_03/G20200343030567/LeetCode_50_567.java new file mode 100644 index 00000000..72b6b6f2 --- /dev/null +++ b/Week_03/G20200343030567/LeetCode_50_567.java @@ -0,0 +1,143 @@ +package com.aizain.jhome.computer.data.recursive; + +/** + * MyPow + * 50. Pow(x, n) + *

+ * 实现 pow(x, n) ,即计算 x 的 n 次幂函数。 + *

+ * 示例 1: + * 输入: 2.00000, 10 + * 输出: 1024.00000 + *

+ * 示例 2: + * 输入: 2.10000, 3 + * 输出: 9.26100 + *

+ * 示例 3: + * 输入: 2.00000, -2 + * 输出: 0.25000 + * 解释: 2-2 = 1/22 = 1/4 = 0.25 + *

+ * 说明: + * -100.0 < x < 100.0 + * n 是 32 位有符号整数,其数值范围是 [−231, 231 − 1] 。 + *

+ * 来源:力扣(LeetCode) + * 链接:https://leetcode-cn.com/problems/powx-n + * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + * + * @author Zain + * @date 2020/3/1 + */ +public class MyPow { + + /** + * 审题: + * 1 x,n有取值范围,都是整数,会有复数 + * 2 x^-n = 1/x^n + *

+ * 思路: + * 1 暴力 + * 2 分治 + *

+ * 反馈: + * 1 牛顿迭代法 + * 2 复数可以最后用1/x解决 + * + * @param x + * @param n + * @return + */ + public double myPow(double x, int n) { + // return directlySolution(x, n); + // return divideSolution(x, n); + return divideCleanSolution(x, n); + } + + /** + * 分治法简洁版 + * 1 ms 36.5 MB + * + * @param x + * @param n + * @return + */ + private double divideCleanSolution(double x, long n) { + if (n == 0) { + return 1; + } + if (n < 0) { + return 1 / divideCleanSolution(x, -n); + } + return n % 2 == 1 + ? x * divideCleanSolution(x, n - 1) + : divideCleanSolution(x * x, n / 2); + } + + /** + * 分治法 + * 1 ms 36.8 MB + * + * @param x + * @param n + * @return + */ + private double divideSolution(double x, int n) { + if (n == 0) { + return 1; + } + double v = divideGenerate(x, Math.abs((long) n)); + return n >= 0 ? v : 1 / v; + } + + private double divideGenerate(double x, long n) { + // 1 终止条件 + if (n < 2) { + return x; + } + // 2 准备数据 + // 3 子问题 + double sub = divideGenerate(x, n / 2); + // 4 合并 + // 5 清理 + if (n % 2 == 0) { + return sub * sub; + } else { + return sub * sub * x; + } + } + + /** + * 暴力法 + * 2775 ms 37.4 MB + * + * @param x + * @param n + * @return + */ + private double directlySolution(double x, int n) { + if (x == 1) { + return x; + } + double ret = 1; + + // 对 int 型数据 -2147483648 求绝对值,结果仍为 -2147483648 + if (n <= -2147483648) { + n = -2147483647; + if (x < 0) { + // -1.00000 -2147483648 预期结果 1.0 + return 1.0; + } + } + for (int i = 0; i < Math.abs(n); i++) { + if (ret == 0) { + return ret; + } + ret = n >= 0 ? ret * x : ret / x; + } + return ret; + } + + +} diff --git a/Week_03/G20200343030567/LeetCode_589_567.java b/Week_03/G20200343030567/LeetCode_589_567.java new file mode 100644 index 00000000..64aba4c0 --- /dev/null +++ b/Week_03/G20200343030567/LeetCode_589_567.java @@ -0,0 +1,66 @@ +package com.aizain.jhome.computer.data.tree; + +import java.util.LinkedList; +import java.util.List; +import java.util.Objects; + +/** + * Preorder + * 589. N叉树的前序遍历 + *

+ * 给定一个 N 叉树,返回其节点值的前序遍历。 + * 例如,给定一个 3叉树 : + * 返回其前序遍历: [1,3,5,6,2,4]。 + * 说明: 递归法很简单,你可以使用迭代法完成此题吗? + *

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

+ * 第一遍:2020/2/23 + * + * @author Zain + * @date 2020/2/23 + * @see Postorder + */ +public class Preorder { + + /** + * 解题思路: + * 1、递归实现前续遍历 + * 2、迭代法完成此题 + *

+ * 前序遍历:根左右 + * 中序遍历:左根右 + * 后序遍历:左右根 + * ps: 前中后指的是根的遍历位置,这样就好记了 + * + * @param root + * @return + */ + public List preorder(Node root) { + LinkedList ret = new LinkedList<>(); + + // 1 recursion terminator + if (Objects.isNull(root)) { + return ret; + } + if (Objects.isNull(root.children) || root.children.isEmpty()) { + ret.add(root.val); + return ret; + } + + // 2 process logic in current level + + // 3 drill down + // 根左右 + ret.add(root.val); + for (Node node : root.children) { + ret.addAll(preorder(node)); + } + + // 4 reverse the current level status if needed + return ret; + } + +} diff --git a/Week_03/G20200343030567/LeetCode_590_567.java b/Week_03/G20200343030567/LeetCode_590_567.java new file mode 100644 index 00000000..9b3695fb --- /dev/null +++ b/Week_03/G20200343030567/LeetCode_590_567.java @@ -0,0 +1,100 @@ +package com.aizain.jhome.computer.data.tree; + +import java.util.LinkedList; +import java.util.List; +import java.util.Objects; + +/** + * Postorder + *

+ * 590. N叉树的后序遍历 + *

+ * 给定一个 N 叉树,返回其节点值的后序遍历。 + * 例如,给定一个 3叉树 : + *

+ * 返回其后序遍历: [5,6,3,2,4,1]. + * 说明: 递归法很简单,你可以使用迭代法完成此题吗? + *

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

+ * 第一遍:2020/2/23 + * + * @author Zain + * @date 2020/2/23 + * @see Preorder + */ +public class Postorder { + + /** + * 解题思路: + * 1、递归实现后续遍历 + * 2、迭代法完成此题 + *

+ * 前序遍历:根左右 + * 中序遍历:左根右 + * 后序遍历:左右根 + * ps: 前中后指的是根的遍历位置,这样就好记了 + * + * @param root + * @return + */ + public List postorder(Node root) { + LinkedList ret = new LinkedList<>(); + + // 1 recursion terminator + if (Objects.isNull(root)) { + return ret; + } + if (Objects.isNull(root.children) || root.children.isEmpty()) { + ret.add(root.val); + return ret; + } + + // 2 process logic in current level + + // 3 drill down + // 左右根 + for (Node node : root.children) { + ret.addAll(postorder(node)); + } + ret.add(root.val); + + // 4 reverse the current level status if needed + return ret; + } + + /** + * 迭代法常见套路,反向顺序处理 + * + * @param root + * @return + */ + public List postorderLoop(Node root) { + LinkedList ret = new LinkedList<>(); + + // 1 recursion terminator + if (Objects.isNull(root)) { + return ret; + } + if (Objects.isNull(root.children) || root.children.isEmpty()) { + ret.add(root.val); + return ret; + } + + LinkedList deque = new LinkedList<>(); + // 左右根 --> 根右左 + deque.push(root); + while (!deque.isEmpty()) { + Node current = deque.pollFirst(); + ret.push(current.val); + for (Node node : current.children) { + deque.push(node); + } + } + + return ret; + } + +} diff --git a/Week_03/G20200343030567/LeetCode_70_567.java b/Week_03/G20200343030567/LeetCode_70_567.java new file mode 100644 index 00000000..03b1ed95 --- /dev/null +++ b/Week_03/G20200343030567/LeetCode_70_567.java @@ -0,0 +1,126 @@ +package com.aizain.jhome.computer.data.list; + +/** + * ClimbStairs + * 70. 爬楼梯 + *

+ * 假设你正在爬楼梯。需要 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 阶 + *

+ * 来源:力扣(LeetCode) + * 链接:https://leetcode-cn.com/problems/climbing-stairs + * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + * + * @author Zain + * @date 2020/2/29 + */ +public class ClimbStairs { + + private int[] fnCache = null; + + /** + * 审题: + * 1 n是正整数 + * 2 只输出不重复方法数量 + * 3 步长1、2 + * 4 结果是不超过int + *

+ * 思路: + * 1 无思路,直接看题解 + * 2 最近问题,最近重复性法,斐波拉契数列,递归 + *

+ * 反馈: + * 1 中文站题解 + * 2 国际站题解 + * + * @param n + * @return + */ + public int climbStairs(int n) { + // return fiboracciSolution(n); + // return fiboracciCacheSolution(n); + return divideAndConquerSolution(n); + } + + /** + * 分治思路 + * + * @param n + * @return + */ + private int divideAndConquerSolution(int n) { + // 1 终结条件 + if (n <= 1) { + return 1; + } + // 2 准备数据,处理当前层 + int f1 = n - 1; + int f2 = n - 2; + // 3 下探处理子问题 + int f1Ret = divideAndConquerSolution(f1); + int f2Ret = divideAndConquerSolution(f2); + // 4 合并子问题结果 + int result = f1Ret + f2Ret; + // 5 清理当前层 + return result; + } + + /** + * 斐波拉契数列,加缓存 + * 执行用时 : 0 ms, 在所有 Java 提交中击败了 100.00% 的用户 + * 内存消耗 : 36 MB, 在所有 Java 提交中击败了 5.21% 的用户 + * + * @param n + * @return + */ + private int fiboracciCacheSolution(int n) { + fnCache = new int[n]; + return fnUseCache(n); + } + + private int fnUseCache(int n) { + if (n <= 1) { + return 1; + } + int f1 = n - 1; + int f2 = n - 2; + if (fnCache[f1] <= 0) { + fnCache[f1] = fnUseCache(f1); + } + if (fnCache[f2] <= 0) { + fnCache[f2] = fnUseCache(f2); + } + return fnCache[f1] + fnCache[f2]; + } + + /** + * 斐波拉契数列 + * 能算,但是会超时 + * + * @param n + * @return + */ + private int fiboracciSolution(int n) { + if (n <= 1) { + return 1; + } + return fiboracciSolution(n - 1) + fiboracciSolution(n - 2); + } + +} diff --git a/Week_03/G20200343030569/LeetCode_122_569.java b/Week_03/G20200343030569/LeetCode_122_569.java new file mode 100644 index 00000000..8f6414c6 --- /dev/null +++ b/Week_03/G20200343030569/LeetCode_122_569.java @@ -0,0 +1,26 @@ +/* + * 122. Best Time to Buy and Sell Stock II + * 买卖股票的最佳时机 II + */ +public class LeetCode_122_569 { + + public static void main(String[] args) { + // TODO Auto-generated method stub + int[] data = { 7,1,5,3,6,4 }; + LeetCode_122_569 main = new LeetCode_122_569(); + int result = main.new Solution().maxProfit(data); + System.out.println( result ); + + } + + class Solution { + public int maxProfit(int[] prices) { + int profit = 0; + for ( int i = 1; i < prices.length; i++ ){ + if ( prices[i] > prices[i-1] ) + profit += prices[i] - prices[i-1]; + } + return profit; + } + } +} diff --git a/Week_03/G20200343030569/LeetCode_127_569.java b/Week_03/G20200343030569/LeetCode_127_569.java new file mode 100644 index 00000000..c14588b3 --- /dev/null +++ b/Week_03/G20200343030569/LeetCode_127_569.java @@ -0,0 +1,82 @@ +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; + +/* + * 127. Word Ladder + * 单词接龙 + */ +public class LeetCode_127_569 { + + public static void main(String[] args) { + // TODO Auto-generated method stub + String beginWord = "hit"; + String endWord = "cog"; + List wordList = new ArrayList(); + wordList.add("hot"); + wordList.add("dot"); + wordList.add("dog"); + wordList.add("lot"); + wordList.add("log"); + wordList.add("cog"); + wordList.add("hog"); + wordList.add("hig"); + LeetCode_127_569 main = new LeetCode_127_569(); + int result = main.new Solution().ladderLength(beginWord, endWord, wordList); + System.out.println( result ); + + } + + class Solution { + public int ladderLength(String beginWord, String endWord, List wordList) { + if (!wordList.contains(endWord)) { + return 0; + } + boolean[] visited = new boolean[wordList.size()]; + int idx = wordList.indexOf(beginWord); + if (idx != -1) { + visited[idx] = true; + } + List levelNodes = new LinkedList(); + levelNodes.add(beginWord); + int level = 0; + while( levelNodes.size() > 0 ) { + List nextLevelNodes = new LinkedList(); + level++; + for( String node : levelNodes ) { + + for (int i = 0; i < wordList.size(); ++i) { + if (visited[i]) { + continue; + } + String s = wordList.get(i); + if (!canConvert(node, s)) { + continue; + } + if (s.equals(endWord)) { + return level + 1; + } + visited[i] = true; + nextLevelNodes.add(s); + } + } + levelNodes = nextLevelNodes; + } + return 0; + } + + public boolean canConvert(String s1, String s2) { + int count = 0; + for (int i = 0; i < s1.length(); ++i) { + if (s1.charAt(i) != s2.charAt(i)) { + ++count; + if (count > 1) { + return false; + } + } + } + return count == 1; + } + + } +} diff --git a/Week_03/G20200343030569/LeetCode_455_569.java b/Week_03/G20200343030569/LeetCode_455_569.java new file mode 100644 index 00000000..1dc71eaf --- /dev/null +++ b/Week_03/G20200343030569/LeetCode_455_569.java @@ -0,0 +1,32 @@ +import java.util.Arrays; + +/* + * 455. Assign Cookies + */ +public class LeetCode_455_569 { + + public static void main(String[] args) { + // TODO Auto-generated method stub + int[] g = { 1, 2, 3 }; + int[] s = { 3 }; + LeetCode_455_569 main = new LeetCode_455_569(); + int result = main.new Solution().findContentChildren(g, s); + System.out.println( result ); + + } + + class Solution { + public int findContentChildren(int[] g, int[] s) { + int result = 0; + Arrays.sort(g); + Arrays.sort(s); + for( int gi = 0, si = 0; gi < g.length && si < s.length; si++) { + if ( g[gi] <= s[si] ) { + gi++; + result++; + } + } + return result; + } + } +} diff --git a/Week_03/G20200343030569/LeetCode_860_569.java b/Week_03/G20200343030569/LeetCode_860_569.java new file mode 100644 index 00000000..63f02a02 --- /dev/null +++ b/Week_03/G20200343030569/LeetCode_860_569.java @@ -0,0 +1,40 @@ +/* + * 860. Lemonade Change + * 柠檬水找零 + */ +public class LeetCode_860_569 { + + public static void main(String[] args) { + // TODO Auto-generated method stub + int[] data = { 5,5,5,10,20 }; + LeetCode_860_569 main = new LeetCode_860_569(); + boolean result = main.new Solution().lemonadeChange(data); + System.out.println( result ); + } + + class Solution { + public boolean lemonadeChange(int[] bills) { + int five = 0; + int ten = 0; + for( int bill: bills ) { + if ( bill == 5 ) { + five++; + } else if( bill == 10 ) { + if ( five-- <= 0 ) + return false; + ten++; + }else { + if ( five > 0 && ten > 0 ) { + five--; + ten--; + } else if ( five >= 3 ) { + five -= 3; + } else { + return false; + } + } + } + return true; + } + } +} diff --git a/Week_03/G20200343030569/LeetCode_874_569.java b/Week_03/G20200343030569/LeetCode_874_569.java new file mode 100644 index 00000000..e41cfc59 --- /dev/null +++ b/Week_03/G20200343030569/LeetCode_874_569.java @@ -0,0 +1,162 @@ +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Comparator; + +/* + * 874. Walking Robot Simulation + * 模拟行走机器人 + */ +public class LeetCode_874_569 { + + public static void main(String[] args) { + // TODO Auto-generated method stub + int[] c = { 1,2,-2,5,-1,-2,-1,8,3,-1,9,4,-2,3,2,4,3,9,2,-1,-1,-2,1,3,-2,4,1,4,-1,1,9,-1,-2,5,-1,5,5,-2,6,6,7,7,2,8,9,-1,7,4,6,9,9,9,-1,5,1,3,3,-1,5,9,7,4,8,-1,-2,1,3,2,9,3,-1,-2,8,8,7,5,-2,6,8,4,6,2,7,2,-1,7,-2,3,3,2,-2,6,9,8,1,-2,-1,1,4,7 }; + int[][] o = { {-57,-58},{-72,91},{-55,35},{-20,29},{51,70},{-61,88},{-62,99},{52,17},{-75,-32},{91,-22},{54,33},{-45,-59},{47,-48},{53,-98},{-91,83},{81,12},{-34,-90},{-79,-82},{-15,-86},{-24,66},{-35,35},{3,31},{87,93},{2,-19},{87,-93},{24,-10},{84,-53},{86,87},{-88,-18},{-51,89},{96,66},{-77,-94},{-39,-1},{89,51},{-23,-72},{27,24},{53,-80},{52,-33},{32,4},{78,-55},{-25,18},{-23,47},{79,-5},{-23,-22},{14,-25},{-11,69},{63,36}}; + LeetCode_874_569 main = new LeetCode_874_569(); + int result = main.new Solution().robotSim(c, o); + System.out.println( result ); + + } + + + + class Solution { + + class Position { + int x; + int y; + + Position( int x, int y ) { + this.x = x; + this.y = y; + } + } + + void createXYMap( Map> xMap, Map> yMap, int[][] obstacles ) { + for (int[] obstacle: obstacles) { + Position p = new Position(obstacle[0], obstacle[1]); + if ( xMap.get(p.x) == null ) + xMap.put(p.x, new ArrayList(10)); + xMap.get(p.x).add(p); + if( yMap.get(p.y) == null ) + yMap.put(p.y, new ArrayList(10)); + yMap.get(p.y).add(p); + } + } + + void sortXYMap(Map> xMap, Map> yMap) { + for( List xList: xMap.values() ) { + xList.sort( new Comparator() { + public int compare(Position o1, Position o2) { + if( o1.y < o2.y ) + return -1; + else if( o1.y == o2.y ) + return 0; + else + return 1; + } + } ); + } + for( List yList: yMap.values()) { + yList.sort( new Comparator() { + public int compare(Position o1, Position o2) { + if( o1.x < o2.x ) + return -1; + else if( o1.x == o2.x ) + return 0; + else + return 1; + } + } ); + } + } + + void getNextPosition(Position pos, int dx, int dy, int steps, Map> xMap, Map> yMap ) { + if( dx != 0 ) + getObstacleXPosition( pos, dx, steps, yMap ); + if( dy != 0 ) + getObstacleYPosition( pos,dy, steps, xMap ); + } + + //查找可以优化,getObstacleXPosition/getObstacleYPosition方法可以简化,但是事多,不想动了 + void getObstacleXPosition(Position pos, int dx, int steps, Map> yMap ) { + List xObs = yMap.get(pos.y); + if( dx > 0 ) {//向右走 + if( xObs != null ) { + for( Position ob: xObs ) { + if( pos.x < ob.x && pos.x + steps >= ob.x) { + pos.x = ob.x - 1; + return; + } + } + } + pos.x += steps; + }else { //向左走 + if( xObs != null ) { + for( int i = xObs.size() - 1; i >= 0; i-- ) { + if( pos.x > xObs.get(i).x && pos.x - steps <= xObs.get(i).x ) { + pos.x = xObs.get(i).x + 1; + return; + } + } + } + pos.x -= steps; + } + } + + void getObstacleYPosition(Position pos, int dy, int steps, Map> xMap ) { + List yObs = xMap.get(pos.x); + if( dy > 0 ) {//向上走 + if( yObs != null ) { + for( Position ob: yObs ) { + if( pos.y < ob.y && pos.y + steps >= ob.y) { + pos.y = ob.y - 1; + return; + } + } + } + pos.y += steps; + }else { //向下走 + if( yObs != null ) { + for( int i = yObs.size() - 1; i >= 0; i-- ) { + if( pos.y > yObs.get(i).y && pos.y - steps <= yObs.get(i).y ) { + pos.y = yObs.get(i).y + 1; + return; + } + } + } + pos.y -= steps; + } + } + + + public int robotSim(int[] commands, int[][] obstacles) { + int[] dx = new int[]{0, 1, 0, -1}; + int[] dy = new int[]{1, 0, -1, 0}; + int di = 0; + + Map> xMap = new HashMap>(); + Map> yMap = new HashMap>(); + createXYMap( xMap, yMap, obstacles); + sortXYMap( xMap, yMap ); + + int ans = 0; + + Position currentPos = new Position(0,0); + for (int cmd: commands) { + if (cmd == -2) //left + di = (di + 3) % 4; + else if (cmd == -1) //right + di = (di + 1) % 4; + else { + getNextPosition( currentPos, dx[di], dy[di], cmd, xMap, yMap ) ; + ans = Math.max(ans, currentPos.x * currentPos.x + currentPos.y*currentPos.y); + } + } + + return ans; + } + } +} diff --git a/Week_03/G20200343030571/main/LeetCode_102_571.go b/Week_03/G20200343030571/main/LeetCode_102_571.go new file mode 100644 index 00000000..a6f09a0f --- /dev/null +++ b/Week_03/G20200343030571/main/LeetCode_102_571.go @@ -0,0 +1,125 @@ +package main + +/* + 102. 二叉树的层次遍历 + + 给定一个二叉树,返回其按层次遍历的节点值。 (即逐层地,从左到右访问所有节点)。 + + 例如: + 给定二叉树: [3,9,20,null,null,15,7], + + 3 + / \ + 9 20 + / \ + 15 7 + 返回其层次遍历结果: + + [ + [3], + [9,20], + [15,7] + ] + +*/ +/* + BFS +*/ + +type TreeNode struct { + Val int + Left *TreeNode + Right *TreeNode +} + +func levelOrder1(root *TreeNode) [][]int { + if root == nil {return [][]int{}} + queue := make([]*TreeNode, 0) + res := make([][]int, 0) + curLev := int(0) + queue = append(queue, root) + for len(queue) > 0 { + res = append(res, []int{}) + len := len(queue) + for i := 0; i < len; i++ { + node := queue[0] + queue = queue[1:] + res[curLev] = append(res[curLev], node.Val) + if node.Left != nil { + queue = append(queue, node.Left) + } + if node.Right != nil { + queue = append(queue, node.Right) + } + } + curLev++ + } + + return res +} + + +/* + DFS 递推 +*/ + +func levelOrder2(root *TreeNode) [][]int { + res := make([][]int, 0) + help(root, 0, &res) + return res +} + +func help(node *TreeNode, curLev int, res *[][]int) { + if node == nil { return } + + if curLev >= len(*res) { + *res = append(*res, []int{}) + } + + (*res)[curLev] = append((*res)[curLev], node.Val) + + help(node.Left, curLev + 1, res) + help(node.Right, curLev + 1, res) +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Week_03/G20200343030571/main/LeetCode_126_571.go b/Week_03/G20200343030571/main/LeetCode_126_571.go new file mode 100644 index 00000000..288cee53 --- /dev/null +++ b/Week_03/G20200343030571/main/LeetCode_126_571.go @@ -0,0 +1,143 @@ +package main + +import ( + "strings" + "fmt" +) + +/* +126. 单词接龙 II + +给定两个单词(beginWord 和 endWord)和一个字典 wordList,找出所有从 beginWord 到 endWord 的最短转换序列。 + +转换需遵循如下规则: +每次转换只能改变一个字母。 +转换过程中的中间单词必须是字典中的单词。 + +说明: +如果不存在这样的转换序列,返回一个空列表。 +所有单词具有相同的长度。 +所有单词只由小写字母组成。 +字典中不存在重复的单词。 +你可以假设 beginWord 和 endWord 是非空的,且二者不相同。 + +示例 1: + +输入: +beginWord = "hit", +endWord = "cog", +wordList = ["hot","dot","dog","lot","log","cog"] + +输出: +[ + ["hit","hot","dot","dog","cog"], +  ["hit","hot","lot","log","cog"] +] + +示例 2: + +输入: +beginWord = "hit" +endWord = "cog" +wordList = ["hot","dot","dog","lot","log"] + +输出: [] + +解释: endWord "cog" 不在字典中,所以不存在符合要求的转换序列。 + +*/ + +/* + 虽然刚刷完成语接龙1的题目,自己对这题也有大概的思路。但是代码就是写不出来。 + 原因在于不知道怎么才能把所有的路径存下来。以及如何退出 + + 通过看别人的题解有了思路。 + 这道题卡了几个小时,一直有问题。直到目前这个版本还是有问题的。应该是出在golang的slice上。 + 目前有一定概率在执行 + pushPath := append(path, str) + 这句语句时,会修改到res的结果,导致最终结果错误。 + 这是因为golang后根据相同数组派生出的slice会引用同一底层数组导致。 + 但还没想好怎么改。先保留。 + +*/ +func findLadders(beginWord string, endWord string, wordList []string) [][]string { + mapWord := make(map[string]bool, len(wordList)) + for _, str := range wordList { + mapWord[str] = true + } + res := make([][]string, 0) + if !mapWord[endWord] { return res} + + pathQueue := [][]string{{beginWord}} + bFound := false + for len(pathQueue) != 0 && !bFound { + tmpQueue := pathQueue + for _, path := range tmpQueue { + pathQueue = pathQueue[1:] + popStr := path[len(path) - 1] + for str := range mapWord { + if isFoundInThisPath(path, str) || !isOnlyOneCharDiff2(str, popStr) { + continue + } + pushPath := append(path, str) + if strings.EqualFold(str, endWord) { + bFound = true + res = append(res, pushPath) + } else { + pathQueue = append(pathQueue, pushPath) + } + } + } + } + return res +} + +func isOnlyOneCharDiff2(str1, str2 string) bool { + rune1 := []rune(str1) + rune2 := []rune(str2) + diffNum := int(0) + len := len(rune1) + for i := 0; i < len; i++ { + if rune1[i] != rune2[i] { + diffNum++ + if diffNum > 1 { + return false + } + } + } + return diffNum == 1 +} + +func isFoundInThisPath(path []string, str string) bool { + for _, s := range path { + if strings.EqualFold(s, str) { + return true + } + } + return false +} +/* +"red" +"tax" +["ted","tex","red","tax","tad","den","rex","pee"] + +输出 +[["red","rex","tex","tax"],["red","ted","tad","tax"]] +预期结果 +[["red","ted","tad","tax"],["red","ted","tex","tax"],["red","rex","tex","tax"]] +*/ +func main() { + wordList := []string{"ted","tex","red","tax","tad","den","rex","pee"} + res := findLadders("red", "tax", wordList) + fmt.Println(res) +} + + + + + + + + + + diff --git a/Week_03/G20200343030571/main/LeetCode_127_571.go b/Week_03/G20200343030571/main/LeetCode_127_571.go new file mode 100644 index 00000000..50092226 --- /dev/null +++ b/Week_03/G20200343030571/main/LeetCode_127_571.go @@ -0,0 +1,292 @@ +package main + +import ( + "strings" + "fmt" +) + +/* +127. 单词接龙 + +给定两个单词(beginWord 和 endWord)和一个字典, +找到从 beginWord 到 endWord 的最短转换序列的长度。转换需遵循如下规则: + +每次转换只能改变一个字母。 +转换过程中的中间单词必须是字典中的单词。 +说明: + +如果不存在这样的转换序列,返回 0。 +所有单词具有相同的长度。 +所有单词只由小写字母组成。 +字典中不存在重复的单词。 +你可以假设 beginWord 和 endWord 是非空的,且二者不相同。 +示例 1: + +输入: +beginWord = "hit", +endWord = "cog", +wordList = ["hot","dot","dog","lot","log","cog"] + +输出: 5 + +解释: 一个最短转换序列是 "hit" -> "hot" -> "dot" -> "dog" -> "cog", + 返回它的长度 5。 + +示例 2: + +输入: +beginWord = "hit" +endWord = "cog" +wordList = ["hot","dot","dog","lot","log"] + +输出: 0 + +解释: endWord "cog" 不在字典中,所以无法进行转换。 + +*/ + +/* + 思路:回溯 + worldList 存map[string]bool bool标记是否读过 + 然后发现超时了 +*/ +func ladderLength1(beginWord string, endWord string, wordList []string) int { + wordMap := make(map[string]bool, len(wordList)) + for _, v := range wordList { + wordMap[v] = true + } + if !wordMap[endWord] {return 0} + + res := int(0) + find(endWord, beginWord, wordMap, 1, &res) + + return res +} + +func find(target, cur string, wordMap map[string]bool, n int, res *int) { + if strings.EqualFold(cur, target) { + if n < *res || *res == 0 { + *res = n + } + return + } + + for str, bNew := range wordMap { + if !bNew { + continue + } + if !isOnlyOneCharDiff(str, cur) { + continue + } + wordMap[str] = false + find(target, str, wordMap, n+1, res) + wordMap[str] = true + } +} + +func isOnlyOneCharDiff(str1, str2 string) bool { + rune1 := []rune(str1) + rune2 := []rune(str2) + diffNum := int(0) + len := len(rune1) + for i := 0; i < len; i++ { + if rune1[i] != rune2[i] { + diffNum++ + if diffNum > 1 { + return false + } + } + } + return diffNum == 1 +} + + +/* + 看过题解,BFS + 反思: + 因为是在刷完N皇后问题之后立刻看的这道题,只是单纯的感觉和N皇后有类似之处,觉得可以用回溯法解答就 + 没多想了。 + 但是这道题与N皇后有个本质区别在于,N皇后是要输出“所有解”,而此题是要求输出“最小路径解”,因此N皇后问题 + 必须遍历所有的节点,用回溯是合理的。 + 但对于本题来说,最小路径解,显然用BFS更为合理,这样可以在得出第一个解的时候就直接输出, + 而不用遍历剩余的节点。 + 而回溯,其实类似于深度遍历,虽然可以用一些方法记录所在层数,但由于不知道整体的形状,只能全部遍历之后, + 通过比较再得出最优解。 + 因此虽然两者的时间复杂度都为O(N*M),但对于平均情况,BFS比回溯法要节约一半的时间。 +*/ +func ladderLength2(beginWord string, endWord string, wordList []string) int { + wordMap := make(map[string]bool, len(wordList)) + for _, v := range wordList { + wordMap[v] = true + } + if !wordMap[endWord] { return 0 } + res := int(0) + queue := []string{ beginWord } + + for len(queue) > 0 { + len := len(queue) + res++ + for i := 0; i < len; i++ { + popStr := queue[0] + queue = queue[1:] + for str,bNew := range wordMap { + if !bNew || !isOnlyOneCharDiff(popStr, str) { + continue + } + if strings.EqualFold(str, endWord) { + return res + 1 + } + + queue = append(queue, str) + wordMap[str] = false + + } + } + } + return 0 +} + + +/* + 优化: + 双向BFS + 即从start,end两点同时向中间进行BFS。 + +*/ + +func ladderLengt3(beginWord string, endWord string, wordList []string) int { + bContain := bool(false) + for _, str := range wordList { + if str == endWord { + bContain = true + break + } + } + if !bContain { return 0 } + + queue1, queue2 := []string{beginWord}, []string{endWord} + count1, count2 := int(0), int(0) + visited1, visited2 := make(map[string]bool), make(map[string]bool) + visited1[beginWord] = true + visited2[endWord] = true + + for (len(queue1) != 0) && (len(queue2) != 0) { + count1++ + l1 := len(queue1) + for i := 0; i < l1; i++ { + popStr := queue1[0] + queue1 = queue1[1:] + for _, str := range wordList { + if visited1[str] || !isOnlyOneCharDiff(popStr, str) { + continue + } + if visited2[str] { + fmt.Println(visited1) + fmt.Println(visited2) + return count1 + count2 + 1 + } + queue1 = append(queue1, str) + visited1[str] = true + } + } + + count2++ + l2 := len(queue2) + for i := 0; i < l2; i++ { + popStr := queue2[0] + queue2 = queue2[1:] + for _, str := range wordList { + if visited2[str] || !isOnlyOneCharDiff(popStr, str) { + continue + } + if visited1[str] { + return count1 + count2 + 1 + } + queue2 = append(queue2, str) + visited2[str] = true + } + } + } + return 0 +} +/* + 再优化:每层都从节点少的一方开始进行遍历 +*/ +func ladderLength(beginWord string, endWord string, wordList []string) int { + bContain := bool(false) + for _, str := range wordList { + if str == endWord { + bContain = true + break + } + } + if !bContain { return 0 } + + queue1, queue2 := []string{beginWord}, []string{endWord} + count1, count2 := int(0), int(0) + visited1, visited2 := make(map[string]bool), make(map[string]bool) + visited1[beginWord] = true + visited2[endWord] = true + + for (len(queue1) != 0) && (len(queue2) != 0) { + l1 := len(queue1) + l2 := len(queue2) + if l1 > l2 { + queue1, queue2 = queue2, queue1 + l1, l2 = l2, l1 + visited1, visited2 = visited2, visited1 + count1, count2 = count2, count1 + } + + count1++ + for i := 0; i < l1; i++ { + popStr := queue1[0] + queue1 = queue1[1:] + for _, str := range wordList { + if visited1[str] || !isOnlyOneCharDiff(popStr, str) { + continue + } + if visited2[str] { + return count1 + count2 + 1 + } + queue1 = append(queue1, str) + visited1[str] = true + } + } + } + return 0 +} + +func main() { + start, end := "red", "tax" + wordList := []string{"ted","tex","red","tax","tad","den","rex","pee"} + res := ladderLength(start, end, wordList) + fmt.Println(res) + return +} + + + + +/* +"red" +"tax" +["ted","tex","red","tax","tad","den","rex","pee"] +*/ + + + + + + + + + + + + + + + + + diff --git a/Week_03/G20200343030571/main/LeetCode_169_571.go b/Week_03/G20200343030571/main/LeetCode_169_571.go new file mode 100644 index 00000000..f3bb7467 --- /dev/null +++ b/Week_03/G20200343030571/main/LeetCode_169_571.go @@ -0,0 +1,113 @@ +package main + +/* +169. 多数元素 + +给定一个大小为 n 的数组,找到其中的多数元素。多数元素是指在数组中出现次数大于  n/2  的元素。 + +你可以假设数组是非空的,并且给定的数组总是存在多数元素。 + +*/ +/* + 自己想的思路: + map k-v : num-count + O(n) + 开始的时候以为要遍历两遍,即给的数组遍历一遍。存好map以后再遍历map一遍, + 但写的时候想了下,其实可以在第一次遍历的时候直接得出结果。 + 每次更新次数的时候更新下count值然后和半数进行比对即可。 + 一开始没有考虑到的情况是数组里只有一个元素 + 此方法提交后,击败71% +*/ +func majorityElement1(nums []int) int { + mapCount := make(map[int]int,0) + l := len(nums) + if l == 1 { + return nums[0] + } + half := int(l / 2) + res := int(0) + for _, v := range nums { + count, ok := mapCount[v] + if !ok { + mapCount[v] = 1 + } else { + mapCount[v] = count + 1 + if count + 1 > half { + res = v + } + } + } + return res +} + +/* + 以下为看完题解的思路: + 分治法 + 将所给的数组不断地从中间断开,得出左右分别的众数,然后通过比较结果 + 如果结果一样直接返回,否则返回出现次数多的那个。 + 分支法可真正用于“求众数”即,返回结果中出现次数最多的那个,而非仅仅是出现次数>=n +*/ + +/* + 注释##处为最关键的细节,即当左右相等的情况,一定要return 右子数组中的众数。 + 原因如下: + 如果只从某一次的反还结果来看,当左右子数组中的众数出现次数一致时,无论返回哪个都是错的。 + 因为无论返回哪个,都存在一种可能,即在另外的子数组中,众数等于当前被“抛弃”的数,另外其在另外的 + 子数组出现的次数并不大于当前这个选中的数,但是若加上在当前数组的次数,就大于了。但是因为已经被“抛弃”, + 就错过了这个清算的机会,导致结果错误。 + 举例:[6,5,X] (先姑且认为X未知) + ->[6,5],[X] + ->[6],[5] [X] + 此时对于[6,5]的左右子数组,分别得出6,5的结果,且其在各自子数组出现次数一致,都是1. + 如果我们返回6而抛弃5,且X==5,那么我们最终很有可能会得出6这个错误的结果。因为5已经被抛弃,我们不会再一直 + 记得5的次数,所以不会与右侧的次数进行累加。在下一步只是左侧的6,与右侧的5进行比较,且次数都为1. + 如果我们抛弃6而返回5同理,当X==6时,也存在相同隐患 + + 这么一看,可能会给人的第一印象是这道题没办法用分治法来解,因为我们选哪一侧都有隐患。 + 但其实,如果我们站在更高的层次,即不看某一次的返回结果,我们会发现,其实错误的隐患可以描述为:一个错误的结果会被多次选择。 + 比如对于[6,5,5],6被选择了两次 + 由于我们每次选择的方向是一样的(要么都返回左边,要么都返回右边)所以其实我们可以通过返回右侧直接 + 排除掉“一个错误的结果会被多次选择”这个可能。 + 即对于[6,5,6],我们第一次返回5,那么第二次肯定就选不到5而是6.即便到最后我们得出6这个结果的依据,如果只看最后那一步似乎是 + 不靠谱的,我们认为6与5出现的次数一样多,但其实我们站在更高的层次已经确定了正确答案一定是6 + */ +func majorityElement(nums []int) int { + return majorityElementDivide(0, len(nums)-1, nums) +} + +func majorityElementDivide(lo int, hi int, nums []int) int { + if lo == hi { + return nums[lo] + } + mid := (lo + hi) / 2 + leftRes := majorityElementDivide(lo, mid, nums) + rightRes := majorityElementDivide(mid+1, hi, nums) + if leftRes == rightRes { + return leftRes + } + + leftCount := count(leftRes, lo, mid, nums) + rightCount := count(rightRes, mid+1, hi, nums) + + if leftCount > rightCount { //## + return leftRes + } + return rightRes +} + +func count(num int, lo int, hi int, nums []int) int { + res := int(0) + rangeNums := nums[lo : hi+1] + for _, v := range rangeNums { + if v == num { + res++ + } + } + return res +} + +func main() { + nums := []int {6,5,5,0,0,1,2,5} + res := majorityElement(nums) + println(res) +} \ No newline at end of file diff --git a/Week_03/G20200343030571/main/LeetCode_51_571.go b/Week_03/G20200343030571/main/LeetCode_51_571.go new file mode 100644 index 00000000..6b3188e8 --- /dev/null +++ b/Week_03/G20200343030571/main/LeetCode_51_571.go @@ -0,0 +1,78 @@ +package main +/* + 51. N 皇后 + + n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上, + 并且使皇后彼此之间不能相互攻击。 + 给定一个整数 n,返回所有不同的 n 皇后问题的解决方案。 + + 每一种解法包含一个明确的 n 皇后问题的棋子放置方案,该方案中 'Q' 和 '.' 分别代表了皇后和空位。 + + 示例: + + 输入: 4 + 输出: [ + [".Q..", // 解法 1 + "...Q", + "Q...", + "..Q."], + + ["..Q.", // 解法 2 + "Q...", + "...Q", + ".Q.."] + ] + 解释: 4 皇后问题存在两个不同的解法。 +*/ +/* + 参照国际站的代码写的。因为golang中似乎没有优雅的给string“向后拼接N个字符” + 的操作,所以直接在回溯过程中将答案打印好,整体代码会比较简洁。 + + candidate的类型为[][]rune,这里利用里[]rune类型可以和string类型相互转换。 + 因此可以用操作数组的方式,方便的修改字符串中的某个字符 +*/ +func solveNQueens(n int) [][]string { + res := make([][]string, 0) + candidate := make([][]rune, n) + + col := make([]bool, n) + pie := make([]bool, 2*n) + na := make([]bool, 2*n) + + for i := range candidate { + candidate[i] = make([]rune, n) + for j := range candidate[i] { + candidate[i][j] = '.' + } + } + + dfs(candidate,0, n, &res, col, pie, na) + return res +} + +func dfs(candidate [][]rune, row, n int, res *[][]string, col, pie, na []bool) { + if row >= n { + var arr []string + for _, v := range candidate { + arr = append(arr, string(v)) + } + *res = append(*res, arr) + return + } + + for i := 0; i < n; i++ { + curPie := row + i + curNa := n - i + row + curCol := i + if col[curCol] || na[curNa] || pie[curPie] { + continue + } + + candidate[row][i] = 'Q' + col[curCol], na[curNa], pie[curPie] = true, true, true + dfs(candidate, row+1, n, res, col, pie, na) + + candidate[row][i] = '.' + col[curCol], na[curNa], pie[curPie] = false, false, false + } +} diff --git a/Week_03/G20200343030573/LeetCode_122_573.py b/Week_03/G20200343030573/LeetCode_122_573.py new file mode 100644 index 00000000..c9246e15 --- /dev/null +++ b/Week_03/G20200343030573/LeetCode_122_573.py @@ -0,0 +1,29 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- + +import sys + +__author__ = "Onceabu" +__version__ = "v2.0" + +""" + Time + describe + copyright (c) 2019 by Abu +""" + +reload(sys) +sys.setdefaultencoding('utf-8') + + +class Solution(object): + def maxProfit(self, prices): + """ + :type prices: List[int] + :rtype: int + """ + # 这道题的难点好像并不是算法 熟悉递增数列是关键点更合适点 + # 只要子序列是递增的那么依次增加之和即该子序列的最大值减最小值 + return sum([ + prices[i + 1] - prices[i] for i in range(len(prices) - 1) if prices[i + 1] > prices[i] + ]) diff --git a/Week_03/G20200343030573/LeetCode_126_573.py b/Week_03/G20200343030573/LeetCode_126_573.py new file mode 100644 index 00000000..2658bf94 --- /dev/null +++ b/Week_03/G20200343030573/LeetCode_126_573.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- +import collections +import sys + +__author__ = "Onceabu" +__version__ = "v2.0" + +""" + Time + describe + copyright (c) 2019 by Abu +""" + +reload(sys) +sys.setdefaultencoding('utf-8') + + +class Solution(object): + # 待进一步研究 + def findLadders(self, beginWord, endWord, wordList): + """ + :type beginWord: str + :type endWord: str + :type wordList: List[str] + :rtype: List[List[str]] + """ + wordList = set(wordList) # 转换为hash实现O(1)的in判断 + if endWord not in wordList: + return [] + # 分别为答案、用于剪枝的已访问哈希,前向分支和后向分支,当前的前向分支以及后向分支中的路径和的长度 + # 前向路径分支与后向路径分支的字典结构为{结束词:到达该结束词的路径列表} + res, visited, forward, backward, _len = [], set(), {beginWord: [[beginWord]]}, {endWord: [[endWord]]}, 2 + while forward: + if len(forward) > len(backward): # 始终从路径分支较少的一端做BFS + forward, backward = backward, forward + tmp = {} # 存储新的前向分支 + while forward: + word, paths = forward.popitem() # 取出路径结束词以及到达它的所有路径 + visited.add(word) # 记录已访问 + for i in range(len(word)): + for a in 'abcdefghijklmnopqrstuvwxyz': + new = word[:i] + a + word[i + 1:] # 对结束词尝试每一位的置换 + if new in backward: # 如果在后向分支列表里发现置换后的词,则路径会和 + if paths[0][0] == beginWord: # 前向分支是从beginWord开始的,添加路径会和的笛卡尔积 + res.extend(fPath + bPath[::-1] for fPath in paths for bPath in backward[new]) + else: # 后向分支是从endWord开始的,添加路径会和的笛卡尔积 + res.extend(bPath + fPath[::-1] for fPath in paths for bPath in backward[new]) + if new in wordList and new not in visited: # 仅当wordList存在该词且该词还未碰见过才进行BFS + tmp[new] = tmp.get(new, []) + [path + [new] for path in paths] + _len += 1 + if res and _len > len(res[0]): # res已有答案,且下一次BFS的会和路径长度已超过当前长度,不是最短 + break + forward = tmp # 更新前向分支 + return res diff --git a/Week_03/G20200343030573/LeetCode_127_573.py b/Week_03/G20200343030573/LeetCode_127_573.py new file mode 100644 index 00000000..05950d77 --- /dev/null +++ b/Week_03/G20200343030573/LeetCode_127_573.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- + +import sys + +__author__ = "Onceabu" +__version__ = "v2.0" + +""" + Time + describe + copyright (c) 2019 by Abu +""" + +reload(sys) +sys.setdefaultencoding('utf-8') + +from collections import deque + + +# 这个广度优先是在建立了字典索引的基础上? +# 有待进一步研究 +class Solution(object): + def ladderLength(self, beginWord, endWord, wordList): + + def construct_dict(word_list): + d = {} + for word in word_list: + for i in range(len(word)): + s = word[:i] + "_" + word[i + 1:] + d[s] = d.get(s, []) + [word] + return d + + def bfs_words(begin, end, dict_words): + queue, visited = deque([(begin, 1)]), set() + while queue: + word, steps = queue.popleft() + if word not in visited: + visited.add(word) + if word == end: + return steps + for i in range(len(word)): + s = word[:i] + "_" + word[i + 1:] + neigh_words = dict_words.get(s, []) + for neigh in neigh_words: + if neigh not in visited: + queue.append((neigh, steps + 1)) + return 0 + + d = construct_dict(wordList) + return bfs_words(beginWord, endWord, d) diff --git a/Week_03/G20200343030573/LeetCode_153_573.py b/Week_03/G20200343030573/LeetCode_153_573.py new file mode 100644 index 00000000..1294efe2 --- /dev/null +++ b/Week_03/G20200343030573/LeetCode_153_573.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- + +import sys + +__author__ = "Onceabu" +__version__ = "v2.0" + +""" + Time + describe + copyright (c) 2019 by Abu +""" + +reload(sys) +sys.setdefaultencoding('utf-8') + + +class Solution: + def findMin(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + left, right = 0, len(nums) - 1 + + while left < right: + mid = (left + right) // 2 + if nums[mid] > nums[right]: + left = mid + 1 + else: + right = mid + return nums[left] diff --git a/Week_03/G20200343030573/LeetCode_200_573.py b/Week_03/G20200343030573/LeetCode_200_573.py new file mode 100644 index 00000000..1d9db630 --- /dev/null +++ b/Week_03/G20200343030573/LeetCode_200_573.py @@ -0,0 +1,34 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- + +import sys + +__author__ = "Onceabu" +__version__ = "v2.0" + +""" + Time + describe + copyright (c) 2019 by Abu +""" + +reload(sys) +sys.setdefaultencoding('utf-8') + + +# 有待进一步研究 +class Solution(object): + def numIslands(self, grid): + """ + :type grid: List[List[str]] + :rtype: int + """ + + def sink(i, j): + if 0 <= i < len(grid) and 0 <= j < len(grid[i]) and grid[i][j] == '1': + grid[i][j] = '0' + map(sink, (i + 1, i - 1, i, i), (j, j, j + 1, j - 1)) + return 1 + return 0 + + return sum(sink(i, j) for i in range(len(grid)) for j in range(len(grid[i]))) diff --git a/Week_03/G20200343030573/LeetCode_33_573.py b/Week_03/G20200343030573/LeetCode_33_573.py new file mode 100644 index 00000000..adeac201 --- /dev/null +++ b/Week_03/G20200343030573/LeetCode_33_573.py @@ -0,0 +1,29 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- + +import sys + +__author__ = "Onceabu" +__version__ = "v2.0" + +""" + Time + describe + copyright (c) 2019 by Abu +""" + +reload(sys) +sys.setdefaultencoding('utf-8') + + +class Solution(object): + # True ^ False 有待进一步研究 + def search(self, nums, target): + lo, hi = 0, len(nums) - 1 + while lo < hi: + mid = (lo + hi) / 2 + if (nums[0] > target) ^ (nums[0] > nums[mid]) ^ (target > nums[mid]): + lo = mid + 1 + else: + hi = mid + return lo if target in nums[lo:lo + 1] else -1 diff --git a/Week_03/G20200343030573/LeetCode_455_573.py b/Week_03/G20200343030573/LeetCode_455_573.py new file mode 100644 index 00000000..181a4999 --- /dev/null +++ b/Week_03/G20200343030573/LeetCode_455_573.py @@ -0,0 +1,34 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- + +import sys + +__author__ = "Onceabu" +__version__ = "v2.0" + +""" + Time + describe + copyright (c) 2019 by Abu +""" + +reload(sys) +sys.setdefaultencoding('utf-8') + + +class Solution(object): + # 这个算是叫贪心算法吗 + def findContentChildren(self, g, s): + """ + :type g: List[int] + :type s: List[int] + :rtype: int + """ + g.sort() + s.sort() + childi = 0 + gl = len(g) + for _s in s: + if childi < gl and _s >= g[childi]: + childi += 1 + return childi diff --git a/Week_03/G20200343030573/LeetCode_45_573.py b/Week_03/G20200343030573/LeetCode_45_573.py new file mode 100644 index 00000000..95da4dc9 --- /dev/null +++ b/Week_03/G20200343030573/LeetCode_45_573.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- + +import sys + +__author__ = "Onceabu" +__version__ = "v2.0" + +""" + Time + describe + copyright (c) 2019 by Abu +""" + +reload(sys) +sys.setdefaultencoding('utf-8') + + +class Solution(object): + def jump(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + if len(nums) <= 1: + return 0 + l, r = 0, nums[0] + times = 1 + while r < len(nums) - 1: + times += 1 + nxt = max(i + nums[i] for i in range(l, r + 1)) + l, r = r, nxt + return times diff --git a/Week_03/G20200343030573/LeetCode_529_573.py b/Week_03/G20200343030573/LeetCode_529_573.py new file mode 100644 index 00000000..c2d631d1 --- /dev/null +++ b/Week_03/G20200343030573/LeetCode_529_573.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- + +import sys + +__author__ = "Onceabu" +__version__ = "v2.0" + +""" + Time + describe + copyright (c) 2019 by Abu +""" + +reload(sys) +sys.setdefaultencoding('utf-8') + + +class Solution(object): + # 有待进一步研究 + def updateBoard(self, board, click): + """ + :type board: List[List[str]] + :type click: List[int] + :rtype: List[List[str]] + """ + if not board or not board[0]: + return [] + i, j = click[0], click[1] + if board[i][j] == "M": + board[i][j] = "X" + return board + m, n = len(board), len(board[0]) + directions = [(-1, 0), (-1, 1), (0, 1), (1, 1), (1, 0), (1, -1), (0, -1), (-1, -1)] + self.dfs(i, j, m, n, board, directions) + return board + + def dfs(self, i, j, m, n, board, directions): + if board[i][j] != "E": + return + mine_count = 0 + for d in directions: + di, dj = i + d[0], j + d[1] + if 0 <= di < m and 0 <= dj < n and board[di][dj] == "M": + mine_count += 1 + if mine_count == 0: + board[i][j] = "B" + else: + board[i][j] = str(mine_count) + return + for d in directions: + di, dj = i + d[0], j + d[1] + if 0 <= di < m and 0 <= dj < n: + self.dfs(di, dj, m, n, board, directions) diff --git a/Week_03/G20200343030573/LeetCode_55_573.py b/Week_03/G20200343030573/LeetCode_55_573.py new file mode 100644 index 00000000..dc8fceab --- /dev/null +++ b/Week_03/G20200343030573/LeetCode_55_573.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- + +import sys + +__author__ = "Onceabu" +__version__ = "v2.0" + +""" + Time + describe + copyright (c) 2019 by Abu +""" + +reload(sys) +sys.setdefaultencoding('utf-8') + + +class Solution(object): + def canJump(self, nums): + """ + :type nums: List[int] + :rtype: bool + """ + + # 方法一 + # m = 0 + # for i, n in enumerate(nums): + # if i > m: + # return False + # m = max(m, i + n) + # return True + + # 贪心算法? + def canJump(self, nums): + goal = len(nums) - 1 + for i in range(len(nums))[::-1]: + if i + nums[i] >= goal: + goal = i + return not goal diff --git a/Week_03/G20200343030573/LeetCode_74_573.py b/Week_03/G20200343030573/LeetCode_74_573.py new file mode 100644 index 00000000..a1a856bc --- /dev/null +++ b/Week_03/G20200343030573/LeetCode_74_573.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- + +import sys + +__author__ = "Onceabu" +__version__ = "v2.0" + +""" + Time + describe + copyright (c) 2019 by Abu +""" + +reload(sys) +sys.setdefaultencoding('utf-8') + + +class Solution(object): + # 同样是借助二分法 + def searchMatrix(self, matrix, target): + """ + :type matrix: List[List[int]] + :type target: int + :rtype: bool + """ + if matrix: + n = len(matrix[0]) + lo, hi = 0, len(matrix) * n + while lo < hi: + mid = (lo + hi) / 2 + x = matrix[mid / n][mid % n] + if x < target: + lo = mid + 1 + elif x > target: + hi = mid + else: + return True + return False diff --git a/Week_03/G20200343030573/LeetCode_860_573.py b/Week_03/G20200343030573/LeetCode_860_573.py new file mode 100644 index 00000000..7e3f23b2 --- /dev/null +++ b/Week_03/G20200343030573/LeetCode_860_573.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- + +import sys + +__author__ = "Onceabu" +__version__ = "v2.0" + +""" + Time + describe + copyright (c) 2019 by Abu +""" + +reload(sys) +sys.setdefaultencoding('utf-8') + + +class Solution(object): + # 不怎么pythonic的写法 + # def lemonadeChange(self, bills): + # """ + # :type bills: List[int] + # :rtype: bool + # """ + # if bills[0] > 5: + # return False + # c5 = 0 + # c10 = 0 + # for b in bills: + # if b == 5: + # c5 += 1 + # continue + # if b == 10: + # if c5 >= 1: + # c5 -= 1 + # c10 += 1 + # continue + # return False + # if b == 20: + # if c5 >= 1 and c10 >= 1: + # c5 -= 1 + # c10 -= 1 + # continue + # elif c10 == 0 and c5 >= 3: + # c5 -= 3 + # continue + # return False + # return True + + # pythonic的写法 + def lemonadeChange(self, bills): + five = ten = 0 + for i in bills: + if i == 5: + five += 1 + elif i == 10: + five, ten = five - 1, ten + 1 + elif ten > 0: + five, ten = five - 1, ten - 1 + else: + five -= 3 + if five < 0: return False + return True diff --git a/Week_03/G20200343030573/LeetCode_874_573.py b/Week_03/G20200343030573/LeetCode_874_573.py new file mode 100644 index 00000000..9976ff3e --- /dev/null +++ b/Week_03/G20200343030573/LeetCode_874_573.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- + +import sys + +__author__ = "Onceabu" +__version__ = "v2.0" + +""" + Time + describe + copyright (c) 2019 by Abu +""" + +reload(sys) +sys.setdefaultencoding('utf-8') + + +# 0 北方 +# 1 东方 +# 2 南方 +# 3 西方 +class Solution(object): + # 一开始思路有问题 还是借助字典走一步验证一步比较靠谱 + def robotSim(self, commands, obstacles): + """ + :type commands: List[int] + :type obstacles: List[List[int]] + :rtype: int + """ + i = j = mx = d = 0 + move, obstacles = [(0, 1), (-1, 0), (0, -1), (1, 0)], set(map(tuple, obstacles)) + for command in commands: + if command == -2: + d = (d + 1) % 4 + elif command == -1: + d = (d - 1) % 4 + else: + x, y = move[d] + while command and (i + x, j + y) not in obstacles: + i += x + j += y + command -= 1 + mx = max(mx, i ** 2 + j ** 2) + return mx diff --git a/Week_03/G20200343030575/LeetCode_122_575.swift b/Week_03/G20200343030575/LeetCode_122_575.swift new file mode 100644 index 00000000..9449dd6f --- /dev/null +++ b/Week_03/G20200343030575/LeetCode_122_575.swift @@ -0,0 +1,14 @@ +/* + * @lc app=leetcode.cn id=122 lang=swift + * + * [122] 买卖股票的最佳时机 II + */ + +// @lc code=start +class Solution { + func maxProfit(_ prices: [Int]) -> Int { + + } +} +// @lc code=end + diff --git a/Week_03/G20200343030575/LeetCode_455_575.swift b/Week_03/G20200343030575/LeetCode_455_575.swift new file mode 100644 index 00000000..a125b8cd --- /dev/null +++ b/Week_03/G20200343030575/LeetCode_455_575.swift @@ -0,0 +1,32 @@ +/* + * @lc app=leetcode.cn id=455 lang=swift + * + * [455] 分发饼干 + */ + +// @lc code=start +class Solution { + func findContentChildren(_ g: [Int], _ s: [Int]) -> Int { + var result = 0 + let greedFactors = g.sorted() + let sizes = s.sorted() + + var greedIndex = 0, sizeIndex = 0 + let greedFactorsCount = greedFactors.count + let sizesCount = sizes.count + while greedIndex < greedFactorsCount && sizeIndex < sizesCount { + if greedFactors[greedIndex] <= sizes[sizeIndex] { + greedIndex += 1 + sizeIndex += 1 + result += 1 + }else{ + //饼干太小,不能满足了 + sizeIndex += 1 + } + } + return result + } +} + +// @lc code=end + diff --git a/Week_03/G20200343030575/LeetCode_860_575.swift b/Week_03/G20200343030575/LeetCode_860_575.swift new file mode 100644 index 00000000..45f58fe8 --- /dev/null +++ b/Week_03/G20200343030575/LeetCode_860_575.swift @@ -0,0 +1,39 @@ +/* + * @lc app=leetcode.cn id=860 lang=swift + * + * [860] 柠檬水找零 + */ + +// @lc code=start +class Solution { + func lemonadeChange(_ bills: [Int]) -> Bool { + guard bills.count > 0 else { + return true + } + + var fiveDollarCount = 0, tenDollarCount = 0; + for bill in bills { + if bill == 5 { + fiveDollarCount += 1 + }else if bill == 10 { + fiveDollarCount -= 1 + tenDollarCount += 1 + }else if bill == 20 { + if tenDollarCount > 0 { + tenDollarCount -= 1 + fiveDollarCount -= 1 + }else{ + fiveDollarCount -= 3 + } + } + + if fiveDollarCount < 0 || tenDollarCount < 0 { + return false + } + } + return true + } +} + +// @lc code=end + diff --git a/Week_03/G20200343030577/LeetCode_153_577.go b/Week_03/G20200343030577/LeetCode_153_577.go new file mode 100644 index 00000000..1b561933 --- /dev/null +++ b/Week_03/G20200343030577/LeetCode_153_577.go @@ -0,0 +1,99 @@ +package leetcode + +/* + * @lc app=leetcode.cn id=153 lang=golang + * + * [153] 寻找旋转排序数组中的最小值 + * + * https://leetcode-cn.com/problems/find-minimum-in-rotated-sorted-array/description/ + * + * algorithms + * Medium (50.18%) + * Likes: 143 + * Dislikes: 0 + * Total Accepted: 33.7K + * Total Submissions: 67.2K + * Testcase Example: '[3,4,5,1,2]' + * + * 假设按照升序排序的数组在预先未知的某个点上进行了旋转。 + * + * ( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。 + * + * 请找出其中最小的元素。 + * + * 你可以假设数组中不存在重复元素。 + * + * 示例 1: + * + * 输入: [3,4,5,1,2] + * 输出: 1 + * + * 示例 2: + * + * 输入: [4,5,6,7,0,1,2] + * 输出: 0 + * + */ + +// create time: 2020-02-29 23:28 +// @lc code=start +func findMin(nums []int) int { + return findMin1(nums) + // return findMin2(nums) +} + +// 通过二分法查找最大值间接找到最小值 +func findMin1(nums []int) int { + if len(nums) == 0 { + return 0 + } + return nums[indexOfMin(nums)] +} + +// 通过二分法查找最小值的索引 +func indexOfMin(nums []int) int { + if len(nums) <= 1 { + return 0 + } + if len(nums) == 2 { + if nums[0] > nums[1] { + return 1 + } + return 0 + } + + lo, hi := 0, len(nums)-1 + for lo < hi-1 { + mid := lo + (hi-lo)/2 + if nums[mid] > nums[hi] { + lo = mid + continue + } + + if nums[mid] <= nums[lo] { + hi = mid + continue + } + return 0 + } + return hi +} + +// 二分法直接查找最小值 +func findMin2(nums []int) int { + if len(nums) == 0 { + return 0 + } + lo, hi := 0, len(nums)-1 + for lo < hi { + mid := lo + (hi-lo)/2 + if nums[mid] > nums[hi] { + lo = mid + 1 + } else { + hi = mid + } + } + return nums[lo] +} + +// @lc code=end diff --git a/Week_03/G20200343030577/LeetCode_55_577.go b/Week_03/G20200343030577/LeetCode_55_577.go new file mode 100644 index 00000000..16c34929 --- /dev/null +++ b/Week_03/G20200343030577/LeetCode_55_577.go @@ -0,0 +1,114 @@ +package leetcode + +/* + * @lc app=leetcode.cn id=55 lang=golang + * + * [55] 跳跃游戏 + * + * https://leetcode-cn.com/problems/jump-game/description/ + * + * algorithms + * Medium (37.94%) + * Likes: 481 + * Dislikes: 0 + * Total Accepted: 64.1K + * Total Submissions: 167.9K + * Testcase Example: '[2,3,1,1,4]' + * + * 给定一个非负整数数组,你最初位于数组的第一个位置。 + * + * 数组中的每个元素代表你在该位置可以跳跃的最大长度。 + * + * 判断你是否能够到达最后一个位置。 + * + * 示例 1: + * + * 输入: [2,3,1,1,4] + * 输出: true + * 解释: 我们可以先跳 1 步,从位置 0 到达 位置 1, 然后再从位置 1 跳 3 步到达最后一个位置。 + * + * + * 示例 2: + * + * 输入: [3,2,1,0,4] + * 输出: false + * 解释: 无论怎样,你总会到达索引为 3 的位置。但该位置的最大跳跃长度是 0 , 所以你永远不可能到达最后一个位置。 + * + * + */ + +// create time: 2020-03-01 14:37 +// @lc code=start +func canJump(nums []int) bool { + // return canJumpUseBack(nums) + // return canJumpUseGreedy(nums) + return canJumpUseGreedy2(nums) +} + +// 通过回溯+记录位置状态 +func canJumpUseBack(nums []int) bool { + if len(nums) <= 1 { + return true + } + + var flag bool + var jump func(cur,end int) int + badIndex := make([]int,len(nums)) + jump = func(cur,end int) int{ + if flag { + return 0 + } + + if cur >= end { + flag = true + return 0 + } + + if badIndex[cur] == 1{ + return 1 + } + + + if nums[cur] <= 0 { + return 1 + } + + failed := 0 + for step := nums[cur];step > 0;step-- { + failed += jump(cur+step,end) + } + if failed == nums[cur]{ + badIndex[cur] = 1 + return 1 + } + return 0 + } + jump(0,len(nums)-1) + return flag +} + +// 从后向前的贪心算法 +func canJumpUseGreedy(nums []int) bool { + goodIndex := len(nums)-1 + for i := len(nums)-1;i>=0;i--{ + if nums[i]+i >= goodIndex{ + goodIndex = i + } + } + return goodIndex <= 0 +} + +// 从前向后的贪心算法 +func canJumpUseGreedy2(nums []int) bool { + maxReached := 0 + for i := 0;i maxReached { + maxReached = nums[i] + i + } + } + return maxReached >= len(nums)-1 +} + +// @lc code=end diff --git a/Week_03/G20200343030577/NOTE.md b/Week_03/G20200343030577/NOTE.md index 50de3041..5788df08 100644 --- a/Week_03/G20200343030577/NOTE.md +++ b/Week_03/G20200343030577/NOTE.md @@ -1 +1,29 @@ -学习笔记 \ No newline at end of file +# 第3周学习心得 +### 创建时间:2020-03-01 22:56 + +## 分治算法 +- 分解,解决,合并 +- 把数据切分成大小不同的数据片进行递归+合并处理,同层递归的数据片相互独立且互不影响 +## 回溯算法 +- 状态枚举 +- 状态只能从上层递归向下层递归传递,下层状态不会影响上层状态 +- 可以回溯 +- DFS +## 贪心算法 +- 状态只能从上层递归向下层递归传递(或循环方式下状态迭代),下层状态不会影响上层状态 +- 不能回溯,不是枚举 +## DFS & BFS +- DFS:使用栈来保存递归状态,回溯 +- BFS:使用队列来保存为遍历节点,分层向下循环 +## 二分查找 +- 必须是有序的数组 +- 数据量适合 +- 特别要注意边界溢出以及lo,mid,hi 之间的迭代关系 +- 根据实际情况有以下类型 + - 查找等于给定目标值的数据 + - 查找第一个等于给定目标值的数据 + - 查找最后一个等于给定目标值的数据 + - 查找第一个小于等于给定目标值的数据 + - 查找第一个大于等于给定目标值的数据 + + diff --git a/Week_03/G20200343030581/LeetCode_122_581.js b/Week_03/G20200343030581/LeetCode_122_581.js new file mode 100644 index 00000000..1ab93189 --- /dev/null +++ b/Week_03/G20200343030581/LeetCode_122_581.js @@ -0,0 +1,14 @@ +/** + * @param {number[]} prices + * @return {number} + */ +var maxProfit = function(prices) { + let res = 0; + for (let i = 1; i < prices.length; i++) { + if (prices[i] > prices[i - 1]) { + res += prices[i] - prices[i - 1]; + } + } + + return res; +} diff --git a/Week_03/G20200343030581/LeetCode_126_581.js b/Week_03/G20200343030581/LeetCode_126_581.js new file mode 100644 index 00000000..333b9bbc --- /dev/null +++ b/Week_03/G20200343030581/LeetCode_126_581.js @@ -0,0 +1,64 @@ +/* + * @lc app=leetcode.cn id=126 lang=javascript + * + * [126] 单词接龙 II + */ + +// @lc code=start +/** + * @param {string} beginWord + * @param {string} endWord + * @param {string[]} wordList + * @return {string[][]} + */ +// 1.BFS +var findLadders = function(beginWord, endWord, wordList) { + let L = beginWord.length; + let wordMap = new Map(); + wordList.forEach(w => { + for (let i = 0; i < L; i++) { + let nw = w.slice(0, i) + '*' + w.slice(i + 1); + if (wordMap.has(nw)) { + wordMap.get(nw).push(w); + } else { + wordMap.set(nw, [w]); + } + } + }); + + let res = []; + let queue = [[beginWord], ] + let visited = new Set(); + while(queue.length) { + let len = queue.length; + while (len-- > 0) { + let tmp = queue.shift(); + let word = tmp[tmp.length - 1]; + + if (word == endWord) { + res.push(tmp); + continue; + } + + visited.add(word); + for (let i = 0; i < L; i++) { + let nw = word.slice(0, i) + "*" + word.slice(i + 1); + if (wordMap.has(nw)) { + wordMap.get(nw).forEach(w => { + if (!visited.has(w)) + queue.push(tmp.concat(w)); + }); + } + } + } + if (res.length) + return res; + } + + return res; +}; + + +// @lc code=end + + diff --git a/Week_03/G20200343030581/LeetCode_127_581.js b/Week_03/G20200343030581/LeetCode_127_581.js new file mode 100644 index 00000000..56bd4bec --- /dev/null +++ b/Week_03/G20200343030581/LeetCode_127_581.js @@ -0,0 +1,119 @@ +/* + * @lc app=leetcode.cn id=127 lang=javascript + * + * [127] 单词接龙 + */ + +// @lc code=start +/** + * @param {string} beginWord + * @param {string} endWord + * @param {string[]} wordList + * @return {number} + */ +// 1. BFS +var ladderLength = function(beginWord, endWord, wordList) { + let L = beginWord.length; + let wordMap = new Map(); + wordList.forEach(word => { + for (let i = 0; i < L; i++) { + let nw = word.slice(0, i) + "*" + word.slice(i + 1); + if (wordMap.has(nw)) { + wordMap.get(nw).push(word); + } else { + wordMap.set(nw, [word]); + } + } + }); + + let res = 1; + let queue = [beginWord]; + let visited = new Set(); + visited.add(beginWord); + while (queue.length) { + let len = queue.length; + while (len--) { + let word = queue.pop(); + if (word == endWord) + return res; + + for (let i = 0; i < L; i++) { + let nw = word.slice(0, i) + "*" + word.slice(i + 1); + if (wordMap.has(nw)) { + wordMap.get(nw).forEach(word => { + if (!visited.has(word)) { + visited.add(word); + queue.unshift(word); + } + }) + } + } + } + res++; + } + + return 0; +}; + +// 2. 双向BFS +var ladderLength = function(beginWord, endWord, wordList) { + if (wordList.indexOf(endWord) < 0) + return false; + + let L = beginWord.length; + let wordMap = new Map(); + wordList.forEach(word => { + for(let i = 0; i < L; i++) { + let nw = word.slice(0, i) + "*" + word.slice(i + 1) + if (wordMap.has(nw)) { + wordMap.get(nw).push(word); + } else { + wordMap.set(nw, [word]); + } + } + }); + + let Q_begin = [beginWord], + visitedBegin = new Map(); + visitedBegin.set(beginWord, 1); + let Q_end = [endWord], + visitedEnd = new Map; + visitedEnd.set(endWord, 1); + + function visitWordNode(queue, visited, otherVisited) { + let word = queue.pop(); + let level = visited.get(word); + + for (let i = 0; i < L; i++) { + let nw = word.slice(0, i) + '*' + word.slice(i + 1); + if (wordMap.has(nw)) { + let words = wordMap.get(nw); + for (let j = 0; j < words.length; j++) { + let w = words[j]; + if (otherVisited.has(w)) { + return level + otherVisited.get(w); + } + + if (!visited.has(w)) { + visited.set(w, level + 1); + queue.unshift(w); + } + } + } + } + } + + while (Q_begin.length && Q_end.length) { + let ans = visitWordNode(Q_begin, visitedBegin, visitedEnd); + if (ans > -1) + return ans; + ans = visitWordNode(Q_end, visitedEnd, visitedBegin); + if (ans > -1) + return ans; + } + + return 0; +} +// @lc code=end + + diff --git a/Week_03/G20200343030581/LeetCode_153_581.js b/Week_03/G20200343030581/LeetCode_153_581.js new file mode 100644 index 00000000..ea412ad2 --- /dev/null +++ b/Week_03/G20200343030581/LeetCode_153_581.js @@ -0,0 +1,35 @@ +/* + * @lc app=leetcode.cn id=153 lang=javascript + * + * [153] 寻找旋转排序数组中的最小值 + */ + +// @lc code=start +/** + * @param {number[]} nums + * @return {number} + */ +var findMin = function(nums) { + let low = 0, + high = nums.length - 1; + if (nums[low] <= nums[high]) { + return nums[low]; + } + while (low <= high) { + let mid = low + ((high - low) >> 1); + + if (nums[mid] > nums[mid + 1]) + return nums[mid + 1]; + if (nums[mid - 1] > nums[mid]) + return nums[mid]; + + if (nums[mid] >= nums[0]) { + low = mid + 1; + } else { + high = mid - 1; + } + } +}; +// @lc code=end + + diff --git a/Week_03/G20200343030581/LeetCode_200_581.js b/Week_03/G20200343030581/LeetCode_200_581.js new file mode 100644 index 00000000..68213052 --- /dev/null +++ b/Week_03/G20200343030581/LeetCode_200_581.js @@ -0,0 +1,47 @@ +/* + * @lc app=leetcode.cn id=200 lang=javascript + * + * [200] 岛屿数量 + */ + +// @lc code=start +/** + * @param {character[][]} grid + * @return {number} + */ +var numIslands = function(grid) { + let count = 0; + let row = grid.length; + if (!row) return count; + let col = grid[0].length; + + let dx = [1, 0, -1, 0], + dy = [0, -1, 0, 1]; + + function dfs(i, j) { + grid[i][j] = "0"; + + for (let k = 0; k < 4; k++) { + let ni = i + dy[k]; + let nj = j + dx[k]; + if (ni >= 0 && ni < row && nj >= 0 && nj < col) { + if (grid[ni][nj] == "1") { + dfs(ni, nj); + } + } + } + } + for (let i = 0; i < row; i++) { + for (let j = 0; j < col; j++) { + if (grid[i][j] == "1") { + count++; + dfs(i, j); + } + } + } + + return count; +}; +// @lc code=end + + diff --git a/Week_03/G20200343030581/LeetCode_33_581.js b/Week_03/G20200343030581/LeetCode_33_581.js new file mode 100644 index 00000000..ab1628bc --- /dev/null +++ b/Week_03/G20200343030581/LeetCode_33_581.js @@ -0,0 +1,29 @@ +/** + * @param {number[]} nums + * @param {number} target + * @return {number} + */ +var search = function(nums, target) { + let low = 0, + high = nums.length - 1; + while (low <= high) { + let mid = low + ((high - low) >> 1); + if (nums[mid] == target) + return mid; + + if (nums[0] <= nums[mid]) { + if (nums[low] <= target && target < nums[mid]) { + high = mid - 1; + } else { + low = mid + 1; + } + } else { + if (nums[mid] < target && target <= nums[high]) { + low = mid + 1; + } else { + high = mid - 1; + } + } + } + return -1 +}; diff --git a/Week_03/G20200343030581/LeetCode_455_581.js b/Week_03/G20200343030581/LeetCode_455_581.js new file mode 100644 index 00000000..5824d9f6 --- /dev/null +++ b/Week_03/G20200343030581/LeetCode_455_581.js @@ -0,0 +1,17 @@ +/** + * @param {number[]} g + * @param {number[]} s + * @return {number} + */ +var findContentChildren = function(g, s) { + g = g.sort((a, b) => a - b); + s = s.sort((a, b) => a - b); + + let i = 0, + j = 0; + while (i < g.length && j < s.length) { + if (g[i] <= s[j++]) + i++; + } + return i; +}; diff --git a/Week_03/G20200343030581/LeetCode_45_581.js b/Week_03/G20200343030581/LeetCode_45_581.js new file mode 100644 index 00000000..27ab3a48 --- /dev/null +++ b/Week_03/G20200343030581/LeetCode_45_581.js @@ -0,0 +1,28 @@ +/* + * @lc app=leetcode.cn id=45 lang=javascript + * + * [45] 跳跃游戏 II + */ + +// @lc code=start +/** + * @param {number[]} nums + * @return {number} + */ +var jump = function(nums) { + let end = 0; + let max = 0; + let step = 0; + for (let i = 0; i < nums.length - 1; i++) { + max = Math.max(max, nums[i] + i); + if (i == end) { + end = max; + step++; + } + } + + return step; +}; +// @lc code=end + + diff --git a/Week_03/G20200343030581/LeetCode_529_581.js b/Week_03/G20200343030581/LeetCode_529_581.js new file mode 100644 index 00000000..8c8b4d85 --- /dev/null +++ b/Week_03/G20200343030581/LeetCode_529_581.js @@ -0,0 +1,52 @@ +/* + * @lc app=leetcode.cn id=529 lang=javascript + * + * [529] 扫雷游戏 + */ + +// @lc code=start +/** + * @param {character[][]} board + * @param {number[]} click + * @return {character[][]} + */ +var updateBoard = function(board, click) { + let row = board.length, + col = board[0].length; + function dfs(i, j) { + if (board[i][j] == "M") { + board[i][j] = "X"; + } else if (board[i][j] == "E") { + let M_count = 0; + for (let dy = -1; dy <= 1; dy++) { + for (let dx = -1; dx <= 1; dx++) { + if (!dx && !dy) continue; + let ni = i + dy; + let nj = j + dx; + if (ni >= 0 && ni < row && nj >= 0 && nj < col) { + if (board[ni][nj] == "M") + M_count++; + } + } + } + board[i][j] = M_count == 0 ? "B" : "" + M_count; + if (!M_count) { + for (let dy = -1; dy <= 1; dy++) { + for (let dx = -1; dx <= 1; dx++) { + if (!dx && !dy) continue; + let ni = i + dy; + let nj = j + dx; + if (ni >= 0 && ni < row && nj >= 0 && nj < col) { + dfs(ni, nj); + } + } + } + } + } + } + dfs(click[0], click[1]); + return board; +}; +// @lc code=end + + diff --git a/Week_03/G20200343030581/LeetCode_55_581.js b/Week_03/G20200343030581/LeetCode_55_581.js new file mode 100644 index 00000000..c2764fe2 --- /dev/null +++ b/Week_03/G20200343030581/LeetCode_55_581.js @@ -0,0 +1,43 @@ +/* + * @lc app=leetcode.cn id=55 lang=javascript + * + * [55] 跳跃游戏 + */ + +// @lc code=start +/** + * @param {number[]} nums + * @return {boolean} + */ +// 1. 暴力搜索 +var canJump = function(nums) { + function rcanJump(i) { + if (i == nums.length - 1) { + return true; + } + + for (let j = 1; j <= nums[i]; ++j) { + if (rcanJump(i + j)) + return true; + } + + return false; + } + + return rcanJump(0); +}; + +// 2. 贪心 +var canJump = function(nums) { + let endPoint = nums.length - 1; + for (let i = endPoint; i >= 0; i--) { + if (nums[i] + i >= endPoint) { + endPoint = i; + } + } + + return endPoint == 0; +} +// @lc code=end + + diff --git a/Week_03/G20200343030581/LeetCode_74_581.js b/Week_03/G20200343030581/LeetCode_74_581.js new file mode 100644 index 00000000..d9a0bef7 --- /dev/null +++ b/Week_03/G20200343030581/LeetCode_74_581.js @@ -0,0 +1,38 @@ +/* + * @lc app=leetcode.cn id=74 lang=javascript + * + * [74] 搜索二维矩阵 + */ + +// @lc code=start +/** + * @param {number[][]} matrix + * @param {number} target + * @return {boolean} + */ +var searchMatrix = function(matrix, target) { + if (!matrix.length) + return false; + let row = matrix.length, + col = matrix[0].length; + let low = 0, + high = row * col - 1; + while (low <= high) { + let mid = low + ((high - low) >> 1); + + let i = (mid / col) >> 0, + j = mid % col; + if (matrix[i][j] > target) { + high = mid - 1; + } else if (matrix[i][j] < target) { + low = mid + 1 + } else { + return true; + } + } + + return false; +}; +// @lc code=end + + diff --git a/Week_03/G20200343030581/LeetCode_860_581.js b/Week_03/G20200343030581/LeetCode_860_581.js new file mode 100644 index 00000000..c9c37478 --- /dev/null +++ b/Week_03/G20200343030581/LeetCode_860_581.js @@ -0,0 +1,27 @@ +/* + * @lc app=leetcode.cn id=860 lang=javascript + * + * [860] 柠檬水找零 + */ + +// @lc code=start +/** + * @param {number[]} bills + * @return {boolean} + */ +var lemonadeChange = function(bills) { + let five = 0, + ten = 0; + for (let bill of bills) { + if (bill == 5) five++; + else if (bill == 10) ten++, five--; + else if (ten > 0) ten--, five--; + else five -= 3; + if (five < 0) return false; + } + + return true; +}; +// @lc code=end + + diff --git a/Week_03/G20200343030581/LeetCode_874_581.js b/Week_03/G20200343030581/LeetCode_874_581.js new file mode 100644 index 00000000..c44edf15 --- /dev/null +++ b/Week_03/G20200343030581/LeetCode_874_581.js @@ -0,0 +1,48 @@ +/* + * @lc app=leetcode.cn id=874 lang=javascript + * + * [874] 模拟行走机器人 + */ + +// @lc code=start +/** + * @param {number[]} commands + * @param {number[][]} obstacles + * @return {number} + */ +var robotSim = function(commands, obstacles) { + let dx = [0, 1, 0, -1], + dy = [1, 0, -1, 0], + dir = 0, + x = 0, + y = 0; + + let set = new Set(); + obstacles.forEach(e => set.add(e.join(','))); + + let res = 0; + + for (let cmd of commands) { + if (cmd == '-2') + dir = (dir + 3) % 4; + else if (cmd == '-1') + dir = (dir + 1) % 4; + else { + for (let step = 1; step <= cmd; step++) { + let nx = x + dx[dir]; + let ny = y + dy[dir]; + if (set.has(nx + ',' + ny)) { + break; + } else { + x = nx, y = ny; + res = Math.max(res, x * x + y * y); + } + } + } + } + + return res +}; +// @lc code=end + + diff --git a/Week_03/G20200343030581/NOTE.md b/Week_03/G20200343030581/NOTE.md index 50de3041..801086b7 100644 --- a/Week_03/G20200343030581/NOTE.md +++ b/Week_03/G20200343030581/NOTE.md @@ -1 +1,29 @@ -学习笔记 \ No newline at end of file +##使用二分查找,寻找一个半有序数组[4, 5, 6, 7, 0, 1, 2] 中间无序的地方 +将这个数组分成两部分来看,[4,5,6,7] 和 [0,1,2]。这两部分都是有序的,只有值为0的位置比前一个位置小,值为7的位置比后一个位置大。那么我们只要找出这样的一个位置,就能找到答案。 + +```javascript +var find = function (nums) { + let low = 0, + high = nums.length - 1; + while (low <= high) { + let mid = low + ((high - low) >> 1); + + // 如果位置mid的值比后一个大 + if (nums[mid] > nums[mid + 1]) + return mid + 1; + // 如果位置mid的值比前一个小 + if (nums[mid] < nums[mid - 1]) + return mid; + + if (nums[mid] >= nums[0]) { + // 0到mid这个区间是单调递增区间 + // 无序的位置在后半部分 + low = mid + 1; + } else { + high = mid - 1; + } + } + + return -1; +} +``` \ No newline at end of file diff --git a/Week_03/G20200343030583/LeetCode_122_583.py b/Week_03/G20200343030583/LeetCode_122_583.py new file mode 100644 index 00000000..db10c216 --- /dev/null +++ b/Week_03/G20200343030583/LeetCode_122_583.py @@ -0,0 +1,25 @@ +# +# @lc app=leetcode id=122 lang=python +# +# [122] Best Time to Buy and Sell Stock II +# + +# @lc code=start +class Solution(object): + def maxProfit(self, prices): + """ + :type prices: List[int] + :rtype: int + """ + if not prices and len(prices) == 1: + return 0 + profit = 0 + for i in range(len(prices) - 1): + if prices[i] < prices[i+1]: + profit += prices[i+1] - prices[i] + + return profit + # 1 line solution + # return sum([y - x for x, y in zip(prices[:-1], prices[1:]) if x < y]) +# @lc code=end + diff --git a/Week_03/G20200343030583/LeetCode_126_583.py b/Week_03/G20200343030583/LeetCode_126_583.py new file mode 100644 index 00000000..211762da --- /dev/null +++ b/Week_03/G20200343030583/LeetCode_126_583.py @@ -0,0 +1,42 @@ +# +# @lc app=leetcode id=126 lang=python +# +# [126] Word Ladder II +# + +# @lc code=start +from collections import defaultdict +from collections import deque +# bfs, path +# use dict to store every shortest path to the everyword it goes through +class Solution(object): + def findLadders(self, beginWord, endWord, wordList): + """ + :type beginWord: str + :type endWord: str + :type wordList: List[str] + :rtype: List[List[str]] + """ + if endWord not in wordList: + return [] + + ans = [] + wordSet = set(wordList) + layer = dict() + layer[beginWord] = [[beginWord]] + while layer: + newlayer = defaultdict(list) + for w in layer: + if w == endWord: + ans.extend(k for k in layer[w]) + else: + for i in range(len(w)): + for c in "abcdefghijklmnopqrstuvwxyz": + s = w[:i] + c + w[i+1:] + if s in wordSet: + newlayer[s] += [j + [s] for j in layer[w]] + wordSet -= set(newlayer.keys()) + layer = newlayer + return ans +# @lc code=end + diff --git a/Week_03/G20200343030583/LeetCode_127_583.py b/Week_03/G20200343030583/LeetCode_127_583.py new file mode 100644 index 00000000..e9fc369e --- /dev/null +++ b/Week_03/G20200343030583/LeetCode_127_583.py @@ -0,0 +1,52 @@ +# +# @lc app=leetcode id=127 lang=python +# +# [127] Word Ladder +# + +# @lc code=start +import collections +class Solution(object): + def ladderLength(self, beginWord, endWord, wordList): + """ + :type beginWord: str + :type endWord: str + :type wordList: List[str] + :rtype: int + """ + if endWord not in wordList: + return 0 + + wordDict = self.constructwordDict(beginWord,wordList) + return self.bfs(beginWord,wordDict,wordList,endWord) + + + def constructwordDict(self,beginWord,wordList): + TempwordList = [beginWord] + wordList + wordDict = {} + n = len(beginWord) + for word in TempwordList: + for i in range(n): + s = word[:i] + "_" + word[i+1:] + wordDict[s] = wordDict.get(s,[]) + [word] + + return wordDict + + def bfs(self,beginWord,wordDict,wordList,endWord): + queue = collections.deque(([(beginWord,1)])) + visited = set() + while queue: + word, step = queue.popleft() + if word not in visited: + if word == endWord: + return step + visited.add(word) + for i in range(len(word)): + s = word[:i] + "_" + word[i+1:] + neighWords = wordDict.get(s,[]) + for negihword in neighWords: + queue.append((negihword,step + 1)) + return 0 + +# @lc code=end + diff --git a/Week_03/G20200343030583/LeetCode_200_583.py b/Week_03/G20200343030583/LeetCode_200_583.py new file mode 100644 index 00000000..f6043e57 --- /dev/null +++ b/Week_03/G20200343030583/LeetCode_200_583.py @@ -0,0 +1,115 @@ +# +# @lc app=leetcode id=200 lang=python +# +# [200] Number of Islands +# 1. dfs Time:O(row*col) Space:O(row*col) +# 2. bfs Time:O(row*col) Space:O(min(row,col)) +# 3. union find Time:O(row*col) Space:O(row*col) + +# @lc code=start +# dfs +class Solution(object): + def numIslands(self, grid): + """ + :type grid: List[List[str]] + :rtype: int + """ + if not grid: + return 0 + count = 0 + for i in range(len(grid)): + for j in range(len(grid[i])): + if grid[i][j] == '1': + self.dfs(i,j,grid) + count += 1 + + return count + + def dfs(self,i,j,grid): + if i < 0 or j < 0 or i >= len(grid) or j >= len(grid[i]) or grid[i][j] != '1': + return + + grid[i][j] = '0' + self.dfs(i+1,j,grid) + self.dfs(i-1,j,grid) + self.dfs(i,j+1,grid) + self.dfs(i,j-1,grid) + +# bfs +import collections +class Solution(object): + def numIslands(self, grid): + """ + :type grid: List[List[str]] + :rtype: int + """ + if not grid: + return 0 + count = 0 + queue = collections.deque([]) + for i in range(len(grid)): + for j in range(len(grid[i])): + if grid[i][j] == '1': + queue.append((i,j)) + self.bfs(i,j,grid,queue) + count += 1 + return count + + def bfs(self,i,j,grid,queue): + while queue: + x, y = queue.popleft() + if x >= 0 and y >= 0 and x < len(grid) and y < len(grid[0]) and grid[x][y] == '1': + grid[x][y] = '0' + queue.extend([(x+1,y),(x-1,y),(x,y+1),(x,y-1)]) + +# bfs by Stefanochmann +def numIslands(self, grid): + def sink(i, j): + if 0 <= i < len(grid) and 0 <= j < len(grid[i]) and grid[i][j] == '1': + grid[i][j] = '0' + map(sink, (i+1, i-1, i, i), (j, j, j+1, j-1)) + return 1 + return 0 + return sum(sink(i, j) for i in range(len(grid)) for j in range(len(grid[i]))) + + +# Union find +class Solution(object): + def numIslands(self, grid): + """ + :type grid: List[List[str]] + :rtype: int + """ + if not grid: + return 0 + + row,col = len(grid),len(grid[0]) + self.count = sum(grid[i][j]=='1' for i in range(row) for j in range(col)) + parent = [i for i in range(row*col)] + + def find(index): + while index != parent[index]: + index = parent[index] + return index + + def union(i,j): + root_i, root_j = find(i),find(j) + if root_i == root_j: + return + parent[root_j] = root_i + self.count -= 1 + return + + for i in range(row): + for j in range(col): + if grid[i][j] == '1': + index = i*col+j + if j+1 < col and grid[i][j+1] == '1': + union(index,index+1) + if i+1 < row and grid[i+1][j] == '1': + union(index,index+col) + + return self.count + +# @lc code=end + diff --git a/Week_03/G20200343030583/LeetCode_33_583.py b/Week_03/G20200343030583/LeetCode_33_583.py new file mode 100644 index 00000000..b02bbce7 --- /dev/null +++ b/Week_03/G20200343030583/LeetCode_33_583.py @@ -0,0 +1,67 @@ +# +# @lc app=leetcode id=33 lang=python +# +# [33] Search in Rotated Sorted Array +# + +# @lc code=start +class Solution(object): + def search(self, nums, target): + """ + :type nums: List[int] + :type target: int + :rtype: int + """ + left = 0 + right = len(nums) - 1 + if target not in nums: + return -1 + while left <= right: + mid = left + (right - left) / 2 + if nums[mid] == target: + break + if nums[left] <= nums[mid]: + if target >= nums[mid]: + left = mid + 1 + else: + if target >= nums[left]: + right = mid - 1 + else: + left = mid + 1 + else: + if target >= nums[mid]: + if target >= nums[left]: + right = mid - 1 + else: + left = mid + 1 + else: + right = mid - 1 + + return mid + +# use xor to check how to move next step +# https://leetcode.com/problems/search-in-rotated-sorted-array/discuss/14419/Pretty-short-C%2B%2BJavaRubyPython +class Solution(object): + def search(self, nums, target): + """ + :type nums: List[int] + :type target: int + :rtype: int + """ + left = 0 + right = len(nums) - 1 + if target not in nums: + return -1 + while left <= right: + mid = left + (right - left) / 2 + if nums[mid] == target: + break + if (nums[0] > target) ^ (nums[0] > nums[mid]) ^ (target > nums[mid]): + left = mid + 1 + else: + right = mid + + return mid + +# @lc code=end + diff --git a/Week_03/G20200343030583/LeetCode_455_583.py b/Week_03/G20200343030583/LeetCode_455_583.py new file mode 100644 index 00000000..00a672d5 --- /dev/null +++ b/Week_03/G20200343030583/LeetCode_455_583.py @@ -0,0 +1,31 @@ +# +# @lc app=leetcode id=455 lang=python +# +# [455] Assign Cookies +# + +# @lc code=start +class Solution(object): + def findContentChildren(self, g, s): + """ + :type g: List[int] + :type s: List[int] + :rtype: int + """ + if len(s) == 0: + return 0 + #.sort() is faster than sorted() + s.sort() + g.sort() + count = 0 + i,j = 0,0 + while i < len(s) and j < len(g): + if s[i] >= g[j]: + count += 1 + i += 1 + j += 1 + else: + i += 1 + return count +# @lc code=end + diff --git a/Week_03/G20200343030583/LeetCode_45_583.py b/Week_03/G20200343030583/LeetCode_45_583.py new file mode 100644 index 00000000..3ba30c65 --- /dev/null +++ b/Week_03/G20200343030583/LeetCode_45_583.py @@ -0,0 +1,49 @@ +# +# @lc app=leetcode id=45 lang=python +# +# [45] Jump Game II +# use greedy + +# @lc code=start +# TLE!! because nums[i] may be very large +from collections import deque +class Solution(object): + def jump(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + queue = deque([(0,0)]) + while queue: + index, step = queue.popleft() + if index == len(nums) - 1: + return step + if index > len(nums) - 1: + continue + for i in range(1, nums[index] + 1): + queue.append((index + i,step + 1)) + return -1 + +# divide into segment +# Solution 3: Greedy +# The range of the current jump is [begin, end], +# the furthest is the furthest point all [begin, end] can reach. When i == end, then trigger another jump +class Solution(object): + def jump(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + n,start,end,maxend = len(nums), 0 ,0 ,0 + step = 0 + while end < n - 1: + step += 1 + maxend = end + 1 + for i in range(start,end+1): + if i + nums[i] > n - 1: + return step + maxend = max(maxend,i+nums[i]) + start,end = end + 1, maxend + return step +# @lc code=end + diff --git a/Week_03/G20200343030583/LeetCode_529_583.py b/Week_03/G20200343030583/LeetCode_529_583.py new file mode 100644 index 00000000..97b74931 --- /dev/null +++ b/Week_03/G20200343030583/LeetCode_529_583.py @@ -0,0 +1,67 @@ +# +# @lc app=leetcode id=529 lang=python +# +# [529] Minesweeper +# use dfs O(row*col) + +# @lc code=start +class Solution(object): + def updateBoard(self, board, click): + """ + :type board: List[List[str]] + :type click: List[int] + :rtype: List[List[str]] + """ + if not board: + return [] + i,j = click[0],click[1] + if board[i][j] == 'M': + board[i][j] = 'X' + + self.dfs(i,j,board) + return board + + def dfs(self,i,j,board): + # Terminator + if i < 0 or j < 0 or i >= len(board) or j >= len(board[0]) or board[i][j] != 'E': + return + + # Better to build a direction list for iteration later + directions = [(-1,-1),(-1,0),(-1,1),(0,-1),(0,1),(1,-1),(1,0),(1,1)] + mine_count = 0 + for d in directions: + # Remember to check the boundary + if 0 <= i+d[0] < len(board) and 0 <= j+d[1] < len(board[0]): + if board[i + d[0]][j + d[1]] == 'M': + mine_count += 1 + + if mine_count == 0: + board[i][j] = 'B' + else: + board[i][j] = str(mine_count) + # if find mine near the block, no need to deep dive any more + return + + for d in directions: + self.dfs(i + d[0],j + d[1],board) + +# dfs by playboy9817 +## https://leetcode.com/problems/minesweeper/discuss/99897/10-line-python-solution +class Solution(object): + def updateBoard(self, board, click): + """ + :type board: List[List[str]] + :type click: List[int] + :rtype: List[List[str]] + """ + row,col, directions = click[0],click[1], ((-1,-1),(-1,0),(-1,1),(0,-1),(0,1),(1,-1),(1,0),(1,1)) + if 0 <= row < len(board) and 0<= col 0: + for i in range(target_idx - 1, -1,-1): + if nums[i] >= (target_idx - i): + target_idx = i + break + if i == 0 and target_idx > 0: + return False + return True + +# StefanPochmann's solution +class Solution(object): + def canJump(self, nums): + """ + :type nums: List[int] + :rtype: bool + """ + goal = len(nums) - 1 + for i in range(len(nums))[::-1]: + if i + nums[i] >= goal: + goal = i + return not goal + +# StefanPochmann's solution2 greedy foward +class Solution(object): + def canJump(self, nums): + """ + :type nums: List[int] + :rtype: bool + """ + m = 0 + for i in range(len(nums)): + if i > m: + return False + m = max(m,i+nums[i]) + return True +# Check if there are steps left for us to jumps every time. +class Solution(object): + def canJump(self, nums): + """ + :type nums: List[int] + :rtype: bool + """ + stepLeft = nums[0] + if not stepLeft and len(nums) > 1: + return False + for num in nums[1:-1]: + stepLeft = max(stepLeft - 1,num) + if not stepLeft: + return False + return True +# @lc code=end + diff --git a/Week_03/G20200343030583/LeetCode_74_583.py b/Week_03/G20200343030583/LeetCode_74_583.py new file mode 100644 index 00000000..2d7fd208 --- /dev/null +++ b/Week_03/G20200343030583/LeetCode_74_583.py @@ -0,0 +1,81 @@ +# +# @lc app=leetcode id=74 lang=python +# +# [74] Search a 2D Matrix +# 1. check the first element of each row frist then check exact row +# 2. flatten matrix + +# @lc code=start +# 1. +class Solution(object): + def searchMatrix(self, matrix, target): + """ + :type matrix: List[List[int]] + :type target: int + :rtype: bool + """ + left = 0 + right = len(matrix) - 1 + hit = False + if not matrix: + return False + while left <= right: + mid = left + (right - left)/2 + # [[]] case + if not matrix[mid]: + return False + if matrix[mid][0] == target: + return True + if matrix[mid][0] < target: + if mid + 1 < len(matrix) and target >=matrix[mid + 1][0]: + left = mid + 1 + else: + hit = True + # matrix[mid] may contain targets + break + elif matrix[mid][0] > target: + if mid - 1 >= 0 and matrix[mid - 1][0] > target: + right = mid - 1 + else: + mid = mid - 1 + hit = True + break + if hit: + left = 0 + right = len(matrix[mid]) - 1 + while left <= right: + mid_mid = left + (right - left)/2 + if matrix[mid][mid_mid] == target: + return True + if matrix[mid][mid_mid] > target: + right = mid_mid - 1 + else: + left = mid_mid + 1 + return False + +# 2. flatten matrix +class Solution(object): + def searchMatrix(self, matrix, target): + """ + :type matrix: List[List[int]] + :type target: int + :rtype: bool + """ + if not matrix or not matrix[0]: + return False + row = len(matrix) + col = len(matrix[0]) + left, right = 0, row * col - 1 + while left <= right: + mid = left + (right - left)/2 + num = matrix[mid/col][mid%col] + if num == target: + return True + elif num < target: + left = mid + 1 + else: + right = mid - 1 + + return False +# @lc code=end + diff --git a/Week_03/G20200343030583/LeetCode_860_583.py b/Week_03/G20200343030583/LeetCode_860_583.py new file mode 100644 index 00000000..f92e63da --- /dev/null +++ b/Week_03/G20200343030583/LeetCode_860_583.py @@ -0,0 +1,125 @@ +# +# @lc app=leetcode id=860 lang=python +# +# [860] Lemonade Change +# special solution: +# calculate the needs of five +# we need $5 for one $10 and three $5 for $20, +# However, if we have many $10, then we can save two $5 +# the number of $5 saved is min(count of $20, count of $10) +# Because if count($20) > count($10), we can just save 2*count($10) +# if count($10) > count($20), we have enough $ 10 and just need to consider the $20 cases +#https://leetcode.com/problems/lemonade-change/discuss/392612/Very-simple-O(n)-Python-solution + +# @lc code=start +# too slow +class Solution(object): + def lemonadeChange(self, bills): + """ + :type bills: List[int] + :rtype: bool + """ + if bills[0] > 5: + return False + # because you have not change in hand, so the first bill should be 5 + self.bills_count = {5:1,10:0,20:0} + return self.provide_change(1,bills) + + def provide_change(self,index,bills): + if index == len(bills): + return True + result = False + if bills[index] - 5 == 0: + self.bills_count[5] += 1 + # print("receive $5") + result = self.provide_change(index + 1, bills) + self.bills_count[5] -= 1 + return result + + if bills[index] - 5 == 5: + if self.bills_count[5] != 0: + self.bills_count[10] += 1 + self.bills_count[5] -= 1 + # print("receive $10") + result = self.provide_change(index + 1, bills) + self.bills_count[10] -= 1 + self.bills_count[5] += 1 + return result + + else: + return result + if bills[index] - 5 == 15: + # two ways to provide change + i = 2 + WAY_ONE = False + WAY_TWO = False + while(i > 0): + if self.bills_count[5] >= 1 and self.bills_count[10] != 0 and not WAY_TWO: + self.bills_count[20] += 1 + self.bills_count[5] -= 1 + self.bills_count[10] -= 1 + WAY_TWO = True + # print("receive $20, change with one $5 and one $10") + result = self.provide_change(index + 1, bills) + # reset status + self.bills_count[20] -= 1 + self.bills_count[5] += 1 + self.bills_count[10] += 1 + if result: + return result + elif self.bills_count[5] >= 3 and not WAY_ONE: + self.bills_count[20] += 1 + self.bills_count[5] -= 3 + WAY_ONE = True + # print("receive $20, change with three $5") + result = self.provide_change(index + 1, bills) + # reset status + self.bills_count[20] -= 1 + self.bills_count[5] += 3 + if result: + return result + else: + WAY_ONE = False + WAY_TWO = False + return False + i -= 1 + WAY_ONE = False + WAY_TWO = False + return result + +# official solution +class Solution(object): + def lemonadeChange(self, bills): + five, ten = 0, 0 + for bill in bills: + if bill == 5: + five += 1 + elif bill == 10: + if five > 0: + five -= 1 + ten += 1 + else: + return False + else: + if ten > 0 and five > 0: + five -= 1 + ten -= 1 + elif five >= 3: + five -= 3 + else: + return False + + return True + +# special solution +class Solution(object): + def lemonadeChange(self, bills): + bill_counts = {5:0,10:0,20:0} + for bill in bills: + bill_counts[bill] += 1 + if bill_counts[5] < (bill_counts[10] + 3 * bill_counts[20] - 2 * min(bill_counts[20],bill_counts[10])): + return False + + return True +# @lc code=end + diff --git a/Week_03/G20200343030583/LeetCode_874_583.py b/Week_03/G20200343030583/LeetCode_874_583.py new file mode 100644 index 00000000..d3d7a22a --- /dev/null +++ b/Week_03/G20200343030583/LeetCode_874_583.py @@ -0,0 +1,37 @@ +# +# @lc app=leetcode id=874 lang=python +# +# [874] Walking Robot Simulation +# + +# @lc code=start +class Solution(object): + def robotSim(self, commands, obstacles): + """ + :type commands: List[int] + :type obstacles: List[List[int]] + :rtype: int + """ + # draw a square with arrows and you will know the array + dx = [0,1,0,-1] + dy = [1,0,-1,0] + obstacleSet = set(map(tuple,obstacles)) + x,y= 0,0 + di = 0 + max_disatance = 0 + for c in commands: + if c == -2: + di = (di - 1) % 4 + elif c == -1: + di = (di + 1) % 4 + else: + for _ in xrange(c): + if (x+dx[di], y +dy[di]) not in obstacleSet: + x += dx[di] + y += dy[di] + max_disatance = max(max_disatance, x*x+y*y) + else: + break + return max_disatance +# @lc code=end + diff --git a/Week_03/G20200343030583/NOTE.md b/Week_03/G20200343030583/NOTE.md index 50de3041..965a24ab 100644 --- a/Week_03/G20200343030583/NOTE.md +++ b/Week_03/G20200343030583/NOTE.md @@ -1 +1,120 @@ -学习笔记 \ No newline at end of file +# Week 03 学习笔记 +## Divide & conquer and Backtracking +```python +def divide_conquer(problem,param1,param2,…): + # recursion terminator + if problem is None: + print_result + return + + #prepare data + data = prepare_data(problem) + subproblems = split_problem(problem,data) + + #conquer subproblems (drill down) + subresult1 = self.divide_conquer(subproblem[0],p1,…) + subresult2 = self.divide_conquer(subproblem[1],p1,…) + subresult3 = self.divide_conquer(subproblem[2],p1,…) + ... + + #process and generate the final result 与范型递归不同的地方,就是最后结果需要组合 + result = process_result(subresult1, subresult2, subresult3,…) +``` + +`Leetcode 50. pow(x,n)` +1. Brute force O(n) +2. Divide & conquer
+ * 注意n为负数的情况
+ * Subproblem: pow(x,n/2)
+ * Merge:
+ ``` python + if n % 2 == 1: + result = subresult * subresult * x + else: result = subresult * subresult + ``` +3. 牛顿迭代 + +`Leetcode 78 subset`: 注意迭代的写法 + +`Leetcode N-queen`: +注意左右对角线的表达方式 (注意表格数值的增长方向与平常坐标轴不同)
+| | 0 | 1 | 2 | 3 | +|---|---|---|---|---| +| **0** | | | | | +| **1** | | | | | +| **2** | | | | | +| **3** | | | | | + +`\` 对角线: x-y = const
+`/` 对角线: x+y = const + +## Traversal +- Every node needs to be accessed +- Every node can just be accessed once + +### DFS template +```python +visited = set() +def dfs(node, visited): + if node in visited: + return + visited.add(node) + # process current node here + ... + for next_node in node.children(): + if not next_node in visited: + dfs(next_node,visited) +``` + +### BFS template +BFS use `queue` +```python +def BFS(graph, start, end): + queue = [] + queue.append(start) + visited = set() + while queue: + node = queue.pop() + visited.add(node) + + process(node) + nodes = generate_related_nodes(node) + queue.push(nodes) + # other processing work + ... +``` +## Greedy +**Difference between Greedy and Dynamic Programming**
+`Geedy`: 当下做局部最优判断,不能回退
+`动态规划`:最优判断并保存运算结果 + 回退 + +一般能用贪心解决的问题都为最优,但是条件需要比较特殊:子问题的最优解能够递推到最终问题的最优解 + +## 二分查找 +前提条件: +1. 目标函数单调性(单调递增或者递减) +2. 存在上下界(bounded) +3. 能够通过索引访问(index accessible) + +### Binary Search Template +```python +left, right = 0, len(array) - 1 +while left <= right: + mid = (left + right)/2 + if array[mid] == target: + #find the target + break or return result + elif array[mid] < target: + # (假设上升) + left = mid + 1 (integer的情况) + else: + right = mid - 1 +``` +**注意有时候 (left+right)/2 有可能会越界 —> `left + (right - left)/2`** + +`Leetcode 33 search in rotated sorted array` +1. Brute force: resume O(log N) -> ascending -> binary search: O(log N) +2. Binary search + * Monotone + * Boundary + * Index \ No newline at end of file diff --git a/Week_03/G20200343030585/LeetCode_102_585.py b/Week_03/G20200343030585/LeetCode_102_585.py new file mode 100644 index 00000000..d239f9d0 --- /dev/null +++ b/Week_03/G20200343030585/LeetCode_102_585.py @@ -0,0 +1,100 @@ +# +# @lc app=leetcode.cn id=102 lang=python +# +# [102] 二叉树的层次遍历 +# +# 解题思路 +# 1.就是广度优先遍历所有二叉树节点 +# 1.定义一个队列来记录所有需要遍历的二叉树节点 +# 2.首先添加根节点 +# 3.循环弹出根节点,记录其所有子节点 +# 4.直到所有节点都输出,返回 +# 复杂度分析 +# 时间复杂度:O(N),因为每个节点恰好会被运算一次。 +# 空间复杂度:O(N),保存输出结果的数组包含 N 个节点的值。 +# +# 2. 迭代实现 +# 1.主要解决一个是level的问题,要确定是哪个层的元素,就要保证每次出来的元素都是这一层的元素 +# 2.要确定每次循环的层的大小,这样就可以限制每次只循环这些元素,再通过循环把下一层的元素都加进来 +# 3.比如这一层有2个元素,同时下一层有4个元素,在循环的时候,这一层的元素个数已经确定了,所以只有2次循环, +# 下一层按照先进先出的顺序,从右进从左出,这样就能保证出栈顺序不错,每次输出不错 +# 复杂度分析 + +# 时间复杂度:O(N),因为每个节点恰好会被运算一次。 +# 空间复杂度:O(N),保存输出结果的数组包含 N 个节点的值。 + +# @lc code=start +# Definition for a binary tree node. +# class TreeNode(object): +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +from collections import deque + +class Solution: + def levelOrder(self, root): + """ + :type root: TreeNode + :rtype: List[List[int]] + """ + levels = [] + if not root: + return levels + + level = 0 + queue = deque([root,]) + while queue: + # start the current level + levels.append([]) + # number of elements in the current level + level_length = len(queue) + + for i in range(level_length): + node = queue.popleft() + # fulfill the current level + levels[level].append(node.val) + + # add child nodes of the current level + # in the queue for the next level + if node.left: + queue.append(node.left) + if node.right: + queue.append(node.right) + + # go to next level + level += 1 + + return levels + + +# class Solution(object): +# def levelOrder(self, root): +# """ +# :type root: TreeNode +# :rtype: List[List[int]] +# """ +# res = [[]] +# if root is None: +# return [] + +# def bfs(node, level): +# if len(res) == level: +# res.append([]) + +# res[level].append(node.val) + +# if node.left: +# bfs(node.left, level+1) +# if node.right: +# bfs(node.right, level+1) + +# bfs(root, 0) +# return res + + + + +# @lc code=end + diff --git a/Week_03/G20200343030585/LeetCode_126_585.py b/Week_03/G20200343030585/LeetCode_126_585.py new file mode 100644 index 00000000..45fd2d33 --- /dev/null +++ b/Week_03/G20200343030585/LeetCode_126_585.py @@ -0,0 +1,155 @@ +# +# @lc app=leetcode.cn id=126 lang=python +# +# [126] 单词接龙 II +# +# 解题思路 +# 1.广度优先搜索 +# 1.构建每个单词的变换链 +# 2.跳过已经存在于当前链里面的节点 +# 3.跳过已经用过的节点,避免重复逻辑导致无限递归 +# 4.加速过程,添加word到word list的映射关系 + + +# @lc code=start +# from collections import deque +# from collections import defaultdict + +# class Solution(object): +# def findLadders(self, beginWord, endWord, wordList): +# res = [] +# if beginWord == endWord: +# return [] +# if endWord not in wordList: +# return [] + +# queue = deque() +# queue.append([beginWord, [beginWord]]) + + +# # 构建一个word到word list的映射 +# # for w in wordList: +# # for i in range(len(w)): +# # word_dict[w[:i] + "*" + w[i+1:]] += [w] +# # queue.append([beginWord, [beginWord]]) +# while queue: +# word, level = queue.popleft() +# if word == endWord: +# res.append(level) +# else: +# for i in range(len(word)): +# # d = word_dict[word[:i] + '*' + word[i+1:]] +# for c in 'abcdefghijklmnopqrstuvwxyz': +# newword = word[:i] + c + word[i+1:] +# if newword in wordList: +# queue.append([newword, level + [newword]]) + +# minVal = float('inf') +# temp = [] +# for i in res: +# minVal = min(len(i), minVal) + +# for i in res: +# if len(i) == minVal: +# temp.append(i) + +# return temp + +import collections + +class Solution(object): + def findLadders(self, beginWord, endWord, wordList): + + wordList = set(wordList) + res = [] + layer = {} + layer[beginWord] = [[beginWord]] + + while layer: + newlayer = collections.defaultdict(list) + for w in layer: + if w == endWord: + res.extend(k for k in layer[w]) + else: + for i in range(len(w)): + for c in 'abcdefghijklmnopqrstuvwxyz': + neww = w[:i]+c+w[i+1:] + if neww in wordList: + newlayer[neww]+=[j+[neww] for j in layer[w]] + + wordList -= set(newlayer.keys()) + layer = newlayer + + return res + +# from collections import defaultdict +# from collections import deque + + +# class Solution(object): +# def findLadders(self, beginWord, endWord, wordList): +# """ +# :type beginWord: str +# :type endWord: str +# :type wordList: List[str] +# :rtype: List[List[str]] +# """ +# res = [] +# if beginWord == endWord: +# return [] +# if endWord not in wordList: +# return [] + +# # # 由于单词相同,只需要遍历一次就可以了 +# # def changeStep(word1, word2): +# # change = 0 +# # for i in range(len(word1)): +# # if word1[i] != word2[i]: +# # change+=1 +# # return change == 1 + +# L = len(beginWord) +# # 通过单词的通用规则比如hit可以变换为h*t,*it,hi* 等情况找到字典里面所有的word对应关系 +# # 这样就可以利用索引的方式来查找结果,时间复杂度O(1),这里的两遍循环的时间复杂度是O(n*m),m为单词的长度 +# all_combo_dict = defaultdict(list) +# for word in wordList: +# for i in range(L): +# # Key is the generic word +# # Value is a list of words which have the same intermediate generic word. +# all_combo_dict[word[:i] + "*" + word[i+1:]].append(word) + +# # Queue for BFS +# queue = deque() +# # current, previous, step +# queue.append([beginWord, [beginWord]]) +# # 为了防止出现环,使用访问数组记录 +# visited = {beginWord: True} +# while queue: +# current, step = queue.popleft() +# for i in range(L): +# intermediate_word = current[:i] + "*" + current[i+1:] + +# for node in all_combo_dict[intermediate_word]: +# if node == endWord: +# res.append(step + [endWord]) +# continue + +# if node not in visited: +# visited[node] = True +# queue.append([node, step + [node]]) + +# # 避免重复计算 +# # all_combo_dict[intermediate_word] = [] + +# val = float('inf') +# ret = [] +# for l in res: +# val = min(len(l), val) +# if val == len(l): +# ret.append([l,val]) + +# return [l for l,v in ret if v==val] + + +# @lc code=end + diff --git a/Week_03/G20200343030585/LeetCode_127_585.py b/Week_03/G20200343030585/LeetCode_127_585.py new file mode 100644 index 00000000..d5d473a2 --- /dev/null +++ b/Week_03/G20200343030585/LeetCode_127_585.py @@ -0,0 +1,83 @@ +# +# @lc app=leetcode.cn id=127 lang=python +# +# [127] 单词接龙 +# +# 1.广度优先遍历 +# 1.从beginword开始顺序遍历字典,如果出现一个单词能从begin一步变化到wordlist里面的单词 +# 就将这个单词设置为begin单词继续循环 +# 2.单词和单词比较只能变化一个字母,就是单词1和单词2只有1个字母的差别, +# 所以比较单词的差别个数就可以 +# 3.将所有可能的转化次数都记录下来,比较最小值 +# 复杂度分析 +# 时间复杂度:O(M*N),其中 M 是单词的长度 N 是单词表中单词的总数。找到所有的变换需要对每个单词做 M次操作。 +# 同时,最坏情况下广度优先搜索也要访问所有的 N 个单词。 +# 空间复杂度:O(M*N),要在 all_combo_dict 字典中记录每个单词的 M 个通用状态。访问数组的大小是 N。 +# 广搜队列最坏情况下需要存储 N 个单词。 + +# @lc code=start +from collections import deque +from collections import defaultdict + +class Solution(object): + def ladderLength(self, beginWord, endWord, wordList): + """ + :type beginWord: str + :type endWord: str + :type wordList: List[str] + :rtype: int + """ + res = [] + if beginWord == endWord: + return 0 + if endWord not in wordList: + return 0 + + # # 由于单词相同,只需要遍历一次就可以了 + # def changeStep(word1, word2): + # change = 0 + # for i in range(len(word1)): + # if word1[i] != word2[i]: + # change+=1 + # return change == 1 + + L = len(beginWord) + #通过单词的通用规则比如hit可以变换为h*t,*it,hi* 等情况找到字典里面所有的word对应关系 + #这样就可以利用索引的方式来查找结果,时间复杂度O(1),这里的两遍循环的时间复杂度是O(n*m),m为单词的长度 + all_combo_dict = defaultdict(list) + for word in wordList: + for i in range(L): + # Key is the generic word + # Value is a list of words which have the same intermediate generic word. + all_combo_dict[word[:i] + "*" + word[i+1:]].append(word) + + # Queue for BFS + queue = deque() + # current, previous, step + queue.append([beginWord, 1]) + #为了防止出现环,使用访问数组记录 + visited = {beginWord:True} + while queue: + current, step = queue.popleft() + for i in range(L): + intermediate_word = current[:i] + "*" + current[i+1:] + + for node in all_combo_dict[intermediate_word]: + if node == endWord: + return step + 1 + if node not in visited: + visited[node] = True + queue.append([node, step + 1]) + # 避免重复计算 + all_combo_dict[intermediate_word] = [] + + if len(res) > 0: return min(res) + return 0 + + + + + + +# @lc code=end + diff --git a/Week_03/G20200343030585/LeetCode_169_585.py b/Week_03/G20200343030585/LeetCode_169_585.py new file mode 100644 index 00000000..9fb184f1 --- /dev/null +++ b/Week_03/G20200343030585/LeetCode_169_585.py @@ -0,0 +1,96 @@ +# +# @lc app=leetcode.cn id=169 lang=python +# +# [169] 多数元素 +#给定一个大小为 n 的数组,找到其中的多数元素。多数元素是指在数组中出现次数大于 ⌊ n/2 ⌋ 的元素。 +# 你可以假设数组是非空的,并且给定的数组总是存在多数元素。 + +# 示例 1: + +# 输入: [3,2,3] +# 输出: 3 + +# +# 解题思路 +# 1.暴力法 +# 时间复杂度O(n^2) +# 2.哈希表 +# 依次循环计算所有元素的出现次数,如果次数大于 n/2就是 +# 时间复杂度O(n) +# 3.排序法 +# 由于众数元素的次数是大于一半元素的,所有排序后中间的元素肯定是它 +# 时间复杂度O(nlgn),python 和java排序是nlogn的时间复杂度 +# 4.递归 分治 +# 1. 子问题是划分左右两边,找其中的多数元素,如果左右相同取其一,左右不同就再计算两边的多数都出现了多数次比大小 +# 时间复杂度O(nlogn) 通过主定理推导 +# 空间复杂度O(lgn) 通过递归最长路径获得logn,就是二叉树的高度 + + +# @lc code=start +# class Solution: +# def majorityElement(self, nums): +# majority_count = len(nums)//2 +# for num in nums: +# # 语法糖太有趣 +# # 1是实际输出的内容,后面是迭代器,确定1输出多少次 +# # (1 for elem in nums if elem == num) +# count = sum(1 for elem in nums if elem == num) +# if count > majority_count: +# return num + +# class Solution: +# def majorityElement(self, nums): +# half = len(nums)/2 +# #使用counter计算出每个元素的出现次数 +# counts = collections.Counter(nums) +# # 默认出现次数最大的输出,但是如果最大的不满足1半呢? +# for k,v in counts.items(): +# if v > half: +# return k +# # 特别简洁的写法,直接高地迭代取最大值 +# # return max(counts.keys(), key=counts.get) + +# class Solution: +# def majorityElement(self, nums): +# nums.sort() +# return nums[len(nums)/2] + + +class Solution(object): + def majorityElement(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + length = len(nums) + if length == 0: + return 0 + + def recur(start, end): + # check terminator + # 因为要用end的值来返回,所以end不能是length + if start == end: + return nums[start] + + # current level logic + idx = (start + end) // 2 + # drill down + left = recur(start, idx) + right = recur(idx + 1, end) + + if left == right: + return left + + # 计算左右两边的出现最多的数在一边出现了多少次,这里有个问题要注意,就是比较两边的值,range是不包含end的结果循环的 + # 所以只用end会导致少一个循环比较 + left_compare = sum(1 for i in range(start, idx + 1) if nums[i] == left) + right_compare = sum(1 for j in range(idx + 1, end + 1) if nums[j] == right) + + return left if left_compare > right_compare else right + + # recover state + + return recur(0, length - 1) + +# @lc code=end + diff --git a/Week_03/G20200343030585/LeetCode_17_585.py b/Week_03/G20200343030585/LeetCode_17_585.py new file mode 100644 index 00000000..e96f6bab --- /dev/null +++ b/Week_03/G20200343030585/LeetCode_17_585.py @@ -0,0 +1,51 @@ +# +# @lc app=leetcode.cn id=17 lang=python +# +# [17] 电话号码的字母组合 +# 解题思路 +# 1. 回溯 +# 1. 设置字典转化所有可能的数字和字母关系 +# 2. 递归当前数字的每个字母,然后把上一次的结果加上这次的结果,再钻到下一层 +# 3. 当第一个字母的元素都递归后,再递归第二个字母的元素,依次到最后一个字母 +# 这递归过程就是回溯,因为,当前层的递归数据不会在循环里面累加,就是 +# 不会出现ab bc de这样连续的情况 + +# @lc code=start +class Solution(object): + def letterCombinations(self, digits): + """ + :type digits: str + :rtype: List[str] + """ + + if len(digits) == 0: + return [] + + res = [] + d = { + '2':'abc', + '3':'def', + '4':'ghi', + '5':'jkl', + '6':'mno', + '7':'pqrs', + '8':'tuv', + '9':'wxyz' + } + + nums = [x for x in digits if x in d] + + def combine(ret, next_digits): + # terminator + if len(next_digits) == 0: + res.append(ret) + return + for i in d[next_digits[0]]: + combine(ret + i, next_digits[1:]) + + combine("", nums) + + return res + +# @lc code=end + diff --git a/Week_03/G20200343030585/LeetCode_200_585.py b/Week_03/G20200343030585/LeetCode_200_585.py new file mode 100644 index 00000000..6d35237f --- /dev/null +++ b/Week_03/G20200343030585/LeetCode_200_585.py @@ -0,0 +1,64 @@ +# +# @lc app=leetcode.cn id=200 lang=python +# +# [200] 岛屿数量 +# +# 解题思路 +# 1.深度优先搜索 +# 1.线性扫描整个二维网格,如果一个结点包含 1,则以其为根结点启动深度优先搜索。 +# 2.在深度优先搜索过程中,每个访问过的结点被标记为 0。计数启动深度优先搜索的根结点的数量,即为岛屿的数量。 +# 3.把格子为1的自己和周边等于1的格子都设置为0 + +# +# @lc code=start +# +# @lc app=leetcode.cn id=200 lang=python +# +# [200] 岛屿数量 +# +# 解题思路 +# 1.深度优先搜索 +# 1.线性扫描整个二维网格,如果一个结点包含 1,则以其为根结点启动深度优先搜索。 +# 2.在深度优先搜索过程中,每个访问过的结点被标记为 0。计数启动深度优先搜索的根结点的数量,即为岛屿的数量。 +# 3.把格子为1的自己和周边等于1的格子都设置为0 + +# +# @lc code=start +class Solution(object): + def numIslands(self, grid): + """ + :type grid: List[List[str]] + :rtype: int + """ + if not grid: + return 0 + + row = len(grid) + col = len(grid[0]) + + res = 0 + + # 设置当前元素值为0,方便计算 + def DFS(grid, r, c): + # terminator + grid[r][c] = '0' + + # 检查上下左右, 注意r-1 or c -1存在等于0的情况 + if r - 1 >= 0 and grid[r - 1][c] == '1': DFS(grid, r - 1, c) + if r + 1 < row and grid[r + 1][c] == '1': DFS(grid, r + 1, c) + if c - 1 >= 0 and grid[r][c - 1] == '1': DFS(grid, r, c - 1) + if c + 1 < col and grid[r][c + 1] == '1': DFS(grid, r, c + 1) + + for i in range(row): + for j in range(col): + if grid[i][j] == '1': + res += 1 + DFS(grid, i, j) + return res + +# @lc code=end + + + +# @lc code=end + diff --git a/Week_03/G20200343030585/LeetCode_22_585.py b/Week_03/G20200343030585/LeetCode_22_585.py new file mode 100644 index 00000000..157282b3 --- /dev/null +++ b/Week_03/G20200343030585/LeetCode_22_585.py @@ -0,0 +1,74 @@ +# +# @lc app=leetcode.cn id=22 lang=python +# +# [22] 括号生成 +# 解题思路 +# 1 递归 深度优先搜索 +# 1. 先遍历左括号,然后左括号减一 +# 2.判断右括号是否大于左括号,如果大于就输出右括号,然后右括号减一 +# 3。判断左右括号是不是都输出了,如果是保存字符串结果 +# 2 递归 广度优先搜索 +# 解答 https://leetcode-cn.com/problems/generate-parentheses/solution/hui-su-suan-fa-by-liweiwei1419/ +# 1.一层一层的遍历节点,需要记录已经添加的节点,以及还未添加的节点 +# 2.需要在每层记录的节点信息里面记录left, right,括号字符串状态 +# @lc code=start +from collections import deque + +class Node(object): + def __init__(self, res='', left=0, right=0): + self.res = res + self.left = left + self.right = right + + +class Solution(object): + def generateParenthesis(self, n): + """ + :type n: int + :rtype: List[str] + """ + res = [] + queue = deque() + queue.append(Node('', n, n)) + + while queue: + length = len(queue) + + for i in range(length): + node = queue.pop() + if node.left == 0 and node.right == 0: + res.append(node.res) + + if node.left > 0: + queue.append(Node(node.res + '(', node.left - 1, node.right)) + if node.right > 0 and node.right > node.left: + queue.append(Node(node.res + ')', node.left, node.right - 1)) + + return res + + + + +# class Solution(object): +# def generateParenthesis(self, n): +# """ +# :type n: int +# :rtype: List[str] +# """ +# res = [] + +# def _generate(str, left, right): +# # terminator +# if left == 0 and right == 0: +# res.append(str) +# return + +# if left > 0: _generate(str + "(", left - 1, right) +# if right > left: _generate(str + ")", left, right - 1) + +# _generate('', n, n) +# return res + + +# @lc code=end + diff --git a/Week_03/G20200343030585/LeetCode_367_585.py b/Week_03/G20200343030585/LeetCode_367_585.py new file mode 100644 index 00000000..ce9e95d4 --- /dev/null +++ b/Week_03/G20200343030585/LeetCode_367_585.py @@ -0,0 +1,23 @@ +# +# @lc app=leetcode.cn id=367 lang=python +# +# [367] 有效的完全平方数 +# + +# @lc code=start +class Solution(object): + def isPerfectSquare(self, num): + """ + :type num: int + :rtype: bool + """ + if num == 1 or num == 0: + return True + r = num/2 + x = num + while r * r > x: + r = (r + x/r) / 2 + return True if r * r == num else False + +# @lc code=end + diff --git a/Week_03/G20200343030585/LeetCode_433_585.py b/Week_03/G20200343030585/LeetCode_433_585.py new file mode 100644 index 00000000..acfd6e98 --- /dev/null +++ b/Week_03/G20200343030585/LeetCode_433_585.py @@ -0,0 +1,72 @@ +# +# @lc app=leetcode.cn id=433 lang=python +# +# [433] 最小基因变化 +# +# 解题思路 +# 1.BFS 通过几步能找到你需要的元素 +# 1.而广度遍历是不断构建每层的可能性,然后搜索这层的下一层是否满足,只要找到满足就停止 +# 2.同时需要保证每次先进入的孩子,优先被弹出,然后检查它的下一层是否满足,只有这样才能保证检查的顺序是一层层的 +# 3。满足的条件就是当前字符串和变化字符串就差一个元素 + +# @lc code=start + +import collections + +class Solution(object): + def minMutation(self, start, end, bank): + """ + :type start: str + :type end: str + :type bank: List[str] + :rtype: int + """ + queue = collections.deque() + queue.append([start, start, 0]) # current , previous, step + + while queue: + current, previous, step = queue.popleft() + if current == end: + return step + + for string in bank: + if self.validMutation(current, string) and string != previous: + queue.append([string, current, step+1]) + + return -1 + + def validMutation(self, current_gene, next_gene): + changes = 0 + length = len(current_gene) + for i in range(length): + if current_gene[i] != next_gene[i]: + changes += 1 + return changes == 1 + + +# BFS 简短实现 +# class Solution(object): + +# def differOne(self, str1, str2): +# return len([c1 for c1,c2 in zip(str1,str2) if c1 != c2]) <= 1 + +# def bfs(self, start, end, bank): +# q = collections.deque() +# q.append((start, 0)) #(gene, level) +# while q: +# g = q.popleft() +# if g[0] == end: +# return g[1] +# #explore genes reachable from this one +# ex = [(gx, g[1]+1) for gx,visited in bank.items() if not visited and self.differOne(g[0], gx)] +# q.extend(ex) +# for x in ex: +# bank[x[0]] = True +# return -1 + +# def minMutation(self, start, end, bank): +# return self.bfs(start, end, {g: False for g in bank}) + + +# @lc code=end + diff --git a/Week_03/G20200343030585/LeetCode_50_585.java b/Week_03/G20200343030585/LeetCode_50_585.java new file mode 100644 index 00000000..38acb999 --- /dev/null +++ b/Week_03/G20200343030585/LeetCode_50_585.java @@ -0,0 +1,48 @@ +// 50.pow(x,n) +// 实现 pow(x, n) ,即计算 x 的 n 次幂函数。 + +// 示例 1: + +// 输入: 2.00000, 10 +// 输出: 1024.00000 + +class Solution { + public double myPow(double x, int n) { + long N = n; + + if (N < 0) { + x = 1/x; + N = -N; + } + return fastPow(x, N); + } + + public double fastPow(double x, long n) { + // terminator + if (n == 1) { + return x; + } + if (n == 0) { + return 1; + } + + // current level logic + double ret = fastPow(x, n/2); + + // drill down + + // reverse + if (n % 2 == 1) { + ret = ret * ret * x; + } else { + ret = ret * ret; + } + return ret; + } + + public static void main(String args[]) { + Solution obj = new Solution(); + + System.out.println(obj.myPow(1, -2147483648)); + } +} \ No newline at end of file diff --git a/Week_03/G20200343030585/LeetCode_515_585.py b/Week_03/G20200343030585/LeetCode_515_585.py new file mode 100644 index 00000000..fb05b6aa --- /dev/null +++ b/Week_03/G20200343030585/LeetCode_515_585.py @@ -0,0 +1,86 @@ +# +# @lc app=leetcode.cn id=515 lang=python +# +# [515] 在每个树行中找最大值 +# +# 解题思路 +# 1.广度优先遍历 +# 1.从root开始,没有其他元素就是输出自己的值 +# 2.每一行记录最大值,队列保存需要访问的节点 +# 3.队列记录下一层有哪些节点需要访问 +# 4.需要使用队列的先进先出,python deque +# +# @lc code=start +# Definition for a binary tree node. +# class TreeNode(object): +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution(object): + def largestValues(self, root): + """ + :type root: TreeNode + :rtype: List[int] + """ + if not root: + return [] + + res = [] + queue = [] + queue.append(root) + + while queue: + temp = [] + t = [] + for node in queue: + t.append(node.val) + + if node.left: + temp.append(node.left) + if node.right: + temp.append(node.right) + + res.append(max(t)) + queue = temp + + return res + +# from collections import deque + +# class Solution(object): +# def largestValues(self, root): +# """ +# :type root: TreeNode +# :rtype: List[int] +# """ +# if not root: +# return [] + +# res = [] +# queue = deque() +# queue.append(root) +# maxVal = float('-inf') + +# while queue: +# length = len(queue) + +# for i in range(length): +# node = queue.popleft() + +# maxVal = max(maxVal, node.val) +# if node.left: +# queue.append(node.left) +# if node.right: +# queue.append(node.right) + +# res.append(maxVal) +# maxVal = float('-inf') + +# return res + + + +# @lc code=end + diff --git a/Week_03/G20200343030585/LeetCode_529_585.py b/Week_03/G20200343030585/LeetCode_529_585.py new file mode 100644 index 00000000..f8d9d633 --- /dev/null +++ b/Week_03/G20200343030585/LeetCode_529_585.py @@ -0,0 +1,84 @@ +# +# @lc app=leetcode.cn id=529 lang=python +# +# [529] 扫雷游戏 +# +# 规则 +# 1.M代表为挖出的地雷 +# 2.E代表一个未挖出的空方块 +# 3.B代表没有相邻地雷的已挖出的空方块 +# 4.数字表示有多少已经挖出的有多少地雷与之相邻的方块 +# 5。X表示地雷 +# 如果一个地雷('M')被挖出,游戏就结束了- 把它改为 'X'。 +# 如果一个没有相邻地雷的空方块('E')被挖出,修改它为('B'),并且所有和其相邻的方块都应该被递归地揭露。 +# 如果一个至少与一个地雷相邻的空方块('E')被挖出,修改它为数字('1'到'8'),表示相邻地雷的数量。需要判断四周之后给出 +# 如果在此次点击中,若无更多方块可被揭露,则返回面板。 +# +# 解题思路 +# 很重要的点就是只是把方块为E的改为B or 数字 +# 1.广度优先遍历 +# 1.依据点击的位置,向四周辐射 +# 2.如果一个地雷被点击,游戏结束, M改为X +# 3.没有相邻地雷空方块挖出改为B,递归周边,E改为B +# 4.如果周边有雷的空方块被挖出,修改E改为1-8,表示雷数,需要判断四周之后给出 +# 5.递归结束条件,四周没有多余的方块了 + +# @lc code=start +# class Solution(object): +# def updateBoard(self, board, click): +# (row, col), directions = click, ((-1, 0), (1, 0), (0, 1), (0, -1), (-1, 1), (-1, -1), (1, 1), (1, -1)) +# if 0 <= row < len(board) and 0 <= col < len(board[0]): +# if board[row][col] == 'M': +# board[row][col] = 'X' +# elif board[row][col] == 'E': +# n = sum([board[row + r][col + c] == 'M' for r, c in directions if 0 <= row + r < len(board) and 0 <= col + c < len(board[0])]) +# board[row][col] = str(n or 'B') +# for r, c in directions * (not n): self.updateBoard(board, [row + r, col + c]) +# return board + +from collections import deque + +class Solution(object): + def updateBoard(self, board, click): + """ + :type board: List[List[str]] + :type click: List[int] + :rtype: List[List[str]] + """ + R, C = len(board), len(board[0]) + if board[click[0]][click[1]] == "M": + board[click[0]][click[1]] = "X" + return board + + dir = [1,0], [0,1], [-1,0],[0,-1],[1,1],[-1,-1],[1,-1],[-1,1] + q = deque() + q.append(click) + seen = set(click) + + def numBombsTangent(board, i, j): + count = 0 + for x, y in dir: + if 0 <= i + x < R and 0 <= j + y < C and board[i+x][y+j] == "M": count += 1 + return count + + while q: + for tup in range(len(q)): + x, y = q.popleft() + if board[x][y] == "E": + bombsNextTo = numBombsTangent(board, x, y) + board[x][y] = "B" if bombsNextTo == 0 else str(bombsNextTo) + if bombsNextTo == 0: + for a, b in dir: + if 0 <= a + x < R and 0 <= b + y < C and (a+x,b+y) not in seen: + q.append((a+x, b+y)) + seen.add((a+x, b+y)) + return board + + + + + + + +# @lc code=end + diff --git a/Week_03/G20200343030585/LeetCode_69_585.py b/Week_03/G20200343030585/LeetCode_69_585.py new file mode 100644 index 00000000..2632a435 --- /dev/null +++ b/Week_03/G20200343030585/LeetCode_69_585.py @@ -0,0 +1,50 @@ +# +# @lc app=leetcode.cn id=69 lang=python +# +# [69] x 的平方根 +# +# 解题思路 +# 1.二分查找 +# y=x^2, (x > 0):抛物线,在y轴右侧单调递增, x的值在0-y之间,0和y就是上下界 +# https://leetcode-cn.com/problems/sqrtx/solution/er-fen-cha-zhao-niu-dun-fa-python-dai-ma-by-liweiw/ +# 2.牛顿迭代法 +# 思想就是通过公式逐步收敛到开根号的结果 +# @lc code=start +# class Solution(object): +# def mySqrt(self, x): +# """ +# :type x: int +# :rtype: int +# """ +# if x == 0 or x == 1: +# return x + +# left , right = 0, x +# # mid随意取值,这里为1 +# mid = 1 +# while left < right: +# #防止中间值计算越界 +# # mid = left + (right - left)//2 +# # left + right + 1 加1的目的是避免掉入中值以下导致无限循环 +# mid = (left + right + 1) / 2 +# # mid过大,把查找范围减少,由于是整形,直接减一 +# if mid * mid > x: +# right = mid - 1 +# else: +# left = mid + +# return int(right) + +class Solution: + def mySqrt(self, x): + r = x + while r * r > x: + r = (r + x/r) / 2 + return r + + + + + +# @lc code=end + diff --git a/Week_03/G20200343030585/LeetCode_78_585.py b/Week_03/G20200343030585/LeetCode_78_585.py new file mode 100644 index 00000000..1eb2fdd9 --- /dev/null +++ b/Week_03/G20200343030585/LeetCode_78_585.py @@ -0,0 +1,122 @@ +# +# @lc app=leetcode.cn id=78 lang=python +# +# [78] 子集 +#给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。 + +# 说明:解集不能包含重复的子集。 + +# 示例: + +# 输入: nums = [1,2,3] +# 输出: +# [ +# [3], +#   [1], +#   [2], +#   [1,2,3], +#   [1,3], +#   [2,3], +#   [1,2], +#   [] +# ] +# 解题思路 +# 1. python库itertools方法combinations可以直接实现 +# 2. 迭代 +# 1. 由于res=[[]] 当加上个新元素[[1]],结果为res = [[],[1]] +# 2. 只要能产生后面的[2] [2,3] [1,2] [1,2,3]等依次相加就可以 +# 3. 这里设计比较巧妙,由于第一个元素为[[]],这样第一个输出总为空,就可以直接生成单个元素 +# 由于目前已经产生了[1],当产生[2]后就可以加上[1],生成[2,1] +# 4. 产生[3]后就可以产生[3,1],[3,2],[3,2,1],这里产生是不考虑顺序的,如果题目要有序排列就要再加一层排序操作 +# 3. 递归 回溯 (和迭代逻辑类似,就是把内层循环替换为递归) +# 1. 第一个是空数组,逐步添加每个单独的元素,一层循环就可以解决 +# 2. 每个单独的元素都是可以添加其他后面的元素,就是在一层循环里面加一层递归循环后面的元素 +# 3. 由于是递归就可以在后面的递归层次中依次添加上每层后面的元素,直到所有元素被循环完返回 +# 4. 这个时候最后一层结果已经添加上了,返回后再把上面各层剩下的迭代执行完 + +# 以[1,2,3]为例, 执行顺序如下 +# [] +# [1] 递归调用 +# [1,2] 递归调用 +# [1,2,3] 循环结束,方法返回 +# [1,3] 循环结束,方法返回 +# [2] 第一层循环,递归调用 +# [2,3] 循环2,循环结束 +# [3] 循环结束 +# @lc code=start + +# class Solution: +# def subsets(self, nums): +# res = [[]] +# for i in nums: +# for num in res: +# res = res + [[i] + num] +# return res + +# class Solution: +# def subsets(self, nums): +# res = [[]] +# for i in nums: +# res = res + [[i] + num for num in res] +# return res + + +# import itertools + +# class Solution: +# def subsets(self, nums): +# res = [] +# for i in range(len(nums)+1): +# for tmp in itertools.combinations(nums, i): +# res.append(tmp) +# return res + + +# 理解是最清晰的,就是每次单层循环之后下探,将指针下移一位 +# 就可以循环后面的元素,将每个元素都加上,然后再下探,类似这样的循环,每次逻辑都清晰的把当前层元素都加上 +# class Solution(object): +# def subsets(self, nums): +# """ +# :type nums: List[int] +# :rtype: List[List[int]] +# """ +# if len(nums) == 0: +# return [] +# length = len(nums) +# res = [] + +# def recur(idx, ret): +# res.append(ret) + +# for i in range(idx, length): +# recur(i + 1, ret + [nums[i]]) +# recur(0, []) +# return res + +# class Solution(object): +# def subsets(self, nums): +# """ +# :type nums: List[int] +# :rtype: List[List[int]] +# """ +# if len(nums) == 0: +# return [] +# length = len(nums) +# res = [] +# sub = [] + +# def recur(idx, sub): +# if idx == length: +# res.append(sub) +# return + +# recur(idx + 1, sub) #不选当前元素下探其他元素 +# recur(idx + 1, sub+[nums[idx]]) # 选择当前元素下探其他元素 + + +# recur(0, sub) +# return res + + +# @lc code=end + diff --git a/Week_03/G20200343030585/LeetCode_860_585.py b/Week_03/G20200343030585/LeetCode_860_585.py new file mode 100644 index 00000000..e70f37b5 --- /dev/null +++ b/Week_03/G20200343030585/LeetCode_860_585.py @@ -0,0 +1,40 @@ +# +# @lc app=leetcode.cn id=860 lang=python +# +# [860] 柠檬水找零 +# +# 解题思路 +# 1.贪心算法 +# 1.每次只找最优解,就是有5直接收 +# 2.10的情况找5,如果5没有就找零失败 +# 3.如果大于10,没有10和5的情况,找零失败 +# 如果没有10,有3个5也可以,否则找零失败 +# @lc code=start +class Solution(object): + def lemonadeChange(self, bills): + five = ten = 0 + for bill in bills: + if bill == 5: + five += 1 + elif bill == 10: + if not five: return False + five -= 1 + ten += 1 + else: + if ten and five: + ten -= 1 + five -= 1 + elif five >= 3: + five -= 3 + else: + return False + return True + + + + + + + +# @lc code=end + diff --git a/Week_03/G20200343030585/leetCode_51_585.py b/Week_03/G20200343030585/leetCode_51_585.py new file mode 100644 index 00000000..222bdb50 --- /dev/null +++ b/Week_03/G20200343030585/leetCode_51_585.py @@ -0,0 +1,88 @@ +# +# @lc app=leetcode.cn id=51 lang=python +# +# [51] N皇后 +# +# 解题思路 +# 1、回溯 +# 1。由于皇后的规则,每行每列每个对角线都只能有一个皇后存在,所以每放上一个之后这行就不能放置了; +# 2. 就可以递归一下一行然后依次放上一个棋子,如果这个位置不行就到一行的下一个位置,等于是循环这行的每个格子 +# 3. 当这个棋子把这行走完都没有一个位置是符合要求的,就退回这个棋子,重走上一颗棋子的循环 + + +# @lc code=start +class Solution: + def solveNQueens(self, n): + def DFS(queens, xy_dif, xy_sum): + # 如果queens的总量等于n,证明已经是全部queen的数量,就可以添加一次结果然后重新开始 + row = len(queens) + if row==n: + result.append(queens) + return None + for col in range(n): + # 循环每一个queen,queens里面存的就是列数据,就是那些列有queen了,就不能存了 + # row-col=const和row+col=const,可以通过坐标系做x=y,x+y=0,x-y=0,x+y=2,x-y=-2 + # 可以这样验证数据是否正确 + if col not in queens and row-col not in xy_dif and row+col not in xy_sum: + DFS(queens+[col], xy_dif+[row-col], xy_sum+[row+col]) + result = [] + DFS([],[],[]) + + # 嵌套语法糖,col是从0算起的,所以'.' * i不会影响到Q的输出 + return [ ["."*i + "Q" + "."*(n-i-1) for i in sol] for sol in result] + +# class Solution: +# def solveNQueens(self, n): +# def could_place(row, col): +# # hill diagonals 主斜线 +# # dale_diagonals 次斜线 +# # row + col 等于次斜线的数据,可以画个坐标轴来看,x+y=0, x+y=2, x+y=-2, x+y=-4 +# # row - col 等于主斜线的数据, x-y=0, x-y=2, x-y=-2, x-y=4 +# # 任何一项已经大于1就表示不能放置,所以直接用not就可以了 +# return not (cols[col] + hill_diagonals[row - col] + dale_diagonals[row + col]) + +# def place_queen(row, col): +# queens.add((row, col)) +# cols[col] = 1 +# hill_diagonals[row - col] = 1 +# dale_diagonals[row + col] = 1 + +# def remove_queen(row, col): +# queens.remove((row, col)) +# cols[col] = 0 +# hill_diagonals[row - col] = 0 +# dale_diagonals[row + col] = 0 + +# def add_solution(): +# solution = [] +# for _, col in sorted(queens): +# solution.append('.' * col + 'Q' + '.' * (n - col - 1)) +# output.append(solution) + +# def backtrack(row = 0): +# for col in range(n): +# if could_place(row, col): +# place_queen(row, col) +# # 最后一行已经成功了 +# if row + 1 == n: +# add_solution() +# else: +# # 递归下一个棋子 +# backtrack(row + 1) +# # 如果不能递归下去了,就证明这个棋子是错误的,就回退一个棋子 +# remove_queen(row, col) + +# cols = [0] * n + +# # 主对角线,为什么要这么多设置 +# hill_diagonals = [0] * (2 * n - 1) +# # 次对角线 +# dale_diagonals = [0] * (2 * n - 1) + +# queens = set() +# output = [] +# backtrack() +# return output + +# @lc code=end + diff --git a/Week_03/G20200343030585/share.md b/Week_03/G20200343030585/share.md new file mode 100644 index 00000000..2ff1ec5c --- /dev/null +++ b/Week_03/G20200343030585/share.md @@ -0,0 +1,206 @@ + # 自我介绍 +- 大家好,我叫赵勇,很高兴能与大家一起学习 +- 公司:暂时休息在家^-^ +- 语言:Python / PHP +- 工作:后端研发工程师 +- 选题原因: + - 职场除了算法技术等硬实力还有很重要的软实力,而《向上汇报》就属于这类,希望通过这次分享能够给大家带来启示和机遇 + +# 向上汇报 + +## 为什么选择这个题目分享? + 大家现在在训练营里学的我理解为 **硬实力**,然后我把组织、沟通、演讲理解为 **软实力** ,我认为两种能力都是重要的。而且软实力的提高能带动你的硬实力的发展,有个词叫“技术影响力”,软实力的提升可以更好构建个人的 **技术影响力** ,产生事半功倍的效果。 +> 这里可以给大家举个例子就是一位百度的资深技术Leader,记得有一次听他分享对产品生态的思考,从国家战略谈到公司战略,到生态发展,一路下来侃侃而谈,让人打心理感觉这人有深度,有认知,很厉害,感觉这个人做技术肯定很牛。这是一种自然联想出来的感受,就是你把一些技术、产品、生态,三者分析的很透彻,讲的清楚,大家自然就对你很认可了。 +也就是说硬实力和软实力要是结合应用好,能提升你的职业生涯上一个新的高度,加快职业发展的过程。 + + 第二点就是我读了一本叫 **《原则》** 的书,不知道大家有没有听说过这本书,很多企业大佬都推荐这本书,有兴趣的可以了解下。里面有一句话 **“做到头脑极度开放和极度透明”** ,同时他也说到 **“不要担心其他人的看法,使之成为你的障碍”** 。我自己之前就是没有做好这些,所以现在我想把我遇到的一些问题和思考告知大家,既能剖析自己让自己成长,也能告知大家怎么做会更好。 + +![](https://uploader.shimo.im/f/DyGiUPodcJ0dJgrG.png!thumbnail) + + 第三点就是这个题目是我参加的**一节公开课**,公司聘请台湾学者来给员工讲解如何做好向上汇报的问题,一个大的会议报告厅座无虚席,需求是很强烈的。所以在这里借鉴这个题目,想通过对这个主题的分享能增强我们在这方面的思考,帮助我们个人在职业道路上有更好的发展。 + + +## 汇报的目的 +#### 1、体现价值 +个人理解有三个层次的价值:个人价值、团队价值、也可以上升到企业价值观。 + +#### 2、管理品牌 +个人品牌、团队品牌,品牌对应于价值,品牌影响力提升价值也就随之提升。 + +### 向上汇报很重要(分场景) +我把这个题目解释为两个方面, +#### 1、向老板汇报工作 +#### 2、向公众汇报工作 + + 在工作中我们普遍遇到的问题是向老板汇报的情况,比如要把一周的工作做总结,然后写成PPT或文档上交。 + +>知道后面发生了什么吗,在周例会后你的老板会把你整理的工作放到他的周报里面然后上交上去。如果你没有正确的说清楚,老板也没有看到并修改就不好了(自己就遇到过一次)。 + +向公众汇报工作,有两种情况,一种是**公司内部的分享和晋升答辩**,一种是**对外的宣传发言**。我在这里把给公众的演讲也放到这类,其实他们的道理是一样的。都是通过总结整理输出符合用户需求的内容。 + +这里给大家举个反面的事例,通过事例大家就能理解向公众汇报的影响力。 + +> 记得原先公司有位设计总监,级别在管理层级里面已经算高了,有次受外部邀请去参加一个会议并做一个主题演讲,结果ppt很随意,演讲给演砸了,我理解他本来没太当回事,不成想这个事件直接让他丢了饭碗,公司内部论坛就有人爆料了,然后给推到内网首页大字标题,导致无数人跟帖要他下课,公司顺应民意就把他给干掉了。 + +这个例子也说明了《向上汇报》做好很有必要,做不好对个人很有影响,所以需要引起注意。当然我们现在可能都还没有到一定职位,没有出去汇报或演讲的要求,但是我们可以早为自己打好基础。 + +## 向上沟通的原则是什么? + +#### 1、真诚 +这一点毋容置疑的,任何的虚假都可能带来严重的后果,即使自己没有做好都要真诚以对,即使被老板提出来批评,总比问题放大带来的后果好。还是刚才哪位总监的例子,如果他认真对待这个事情,然后认真准备,而且平时也有好的素材积累,不至于到最后那一步。 + +#### 2、传递和帮助 +我们在做汇报的时候就是把我们了解的信息加工后传递给其他需要的人,给他人带来工作和生活上的帮助。 + 一些技术分享就是典型的传递和帮助一类的,比如最近极客大学组织的几次公开直播,就是在帮助有需要的同学,把握技术方向,提升技术思想和能力,引导大家的发展。 + + +## 做不好的本质的原因是什么? +我理解有三个方面的原因: +- 心理因素,担心结果不好反而受限 + +- 准备不足 + +- 训练不够 + +**心理因素**是第一个应该提出来说的,我说这个也是从我个人出发,从过去的工作经历来看,经常因为紧张忘记说什么了,更严重的时候有机会也不敢去尝试了,因为以往的经验告知你,你会内心很痛苦。这个有点类似于说的舒适区和学习区的概念,只有一脚走出舒适区,才能更好的获得成长。但是如果你走不出来,就会进入一种不好的循环里面,越是紧张越是不敢尝试,越不敢尝试就越没有机会。 + +再一点是**准备不足**,比如材料缺失,对材料认知不够,没有抓住重点,现在做项目和产品不是都经常提要抓住用户的痛点吗,放到材料里面的东西不是用户的痛点,不能表达根本的问题,这样的材料也就不能算是个好材料了。 +另外就是对准备材料的理解和认知,有时候材料都不错但是我们没有认识到哪个深度,所以表达起来也就讲的不够有深度和力量了。 + +最后一点就是**训练不够**,类似我们今天学算法做题,要用“5毒神掌”来学习,其实汇报这些也是需要经常练习的,特别是针对晋升答辩,公开演讲类的,都需要反复练习才能有足够信心和把握。这里给大家举个陆奇的例子,记得有篇文章讲陆奇作为百度CEO在百度大会作主题发言的,我把文章节选如下: + +> 勤奋严谨 这一点仿佛无需多说,但我想说的是一个细节。去年7月大会的彩排和正式召开的现场,我都在聆听。让我非常惊讶的是,他在正式开会时发表的热情洋溢的讲演和彩排时几乎一字不差。我相信只有对于讲演非常投入,深入思考,并多次练习之后才能达到这个境界。我过去曾多次在各种会议上讲演和做 MC,但这个境界令我自叹弗如。 + + +## 提升自己向上沟通能力的办法 +### 做好准备,明确重点 + +- 平时多思考产品和行业的问题(痛点) + +- 多与老板交流 + +- 平时多积累,形成文字的总结 + +从产品上来说,除非我们有高明的见解,我建议还是经常向经理和技术leader等请教为好,和老大探讨不要不好意思,担心别人不搭理你,我相信还是有很多Nice的资深工程师愿意指导其他员工成长的。然后对接触到的内容要总结和思考,一定要文字总结,大脑很多时候是记录不了多少东西的,做总结、画脑图都能帮助记忆,而且文字可以把信息整理的更符合逻辑,不是吗? + +就我个人过去的经验说一下,我平时也是白天各种开会,晚上开始写代码,一个是没有长的时间去思考产品,一个是自己确实想不到一些内容(脑子笨),所以有和Leader和经理吃饭闲聊的机会,就提点问题或听下老板们对技术和产品的认知,收获良多。 +可惜我不善于文字总结,记录下来再深入思考的不多,如果还能事后整理出一些内容,然后经常思考下,对提升产品思考能力,提升行业分析能力很有帮助,不要认为不重要,因为晋升的评委都看这些。 +这里再给大家举个小例子,是我自己的一段经历。 + +>记得原来公司一次晋升评级,8个人里面选2个,我一直认为做大项目和有技术能力的一定就能上去,所以在晋升人员里面我特别看好一位后端RD。平时看他整理技术资料很多,而且负责的都是上千台服务器的公司大型项目。后来到正式晋升结果出来,他还是落榜了,没有PK过一位核心项目的RD,原因后来了解是这位RD答辩时语言逻辑清晰流畅,产品思想表达明确,有产品思维。 +这就再次说明我们要在平时去认知思考总结,到关键时刻才能发挥作用。 + +再就是平时的团队例会周报,不想被老板说(骂),就多找老板沟通,一般老板都比较乐意给你解释的(除非你碰到特不靠谱的),我就有一些被老板开会责难的经历,主要是项目重点和业绩没有说清楚,毕竟那是他要汇报的内容,开始确实很难受,下去就开始改周报。当然次数多了,你也会练出厚脸皮,这个也是有好处的。 + +### 不断练习 +- 文字形式输出,比如公众号,博客 + +- 团队内的分享输出 + +工作和学习一样,都需要反复练习,类似我们学习算法使用“五毒神掌”。只要你想尝试做好,就应该寻找机会去输出你的知识、经验,文字形式可以通过公众号、博客等周期性整理总结,团队内部有分享计划的更好,最好让别人看到听到,参与进来给你提供反馈,这样你才能更好的成长。 +这里也给大家举个现实生活中的例子, +> 一位百度的高级经理,他的微信公众号叫“辉哥奇谭”,大家有兴趣可以搜下。他开始也是程序员,属于老牌程序员了,原来在moto工作,后来去了百度。他一直坚持文字输出自己的想法,包括公众号和朋友圈,每天一篇千字文发到公众号,已经坚持很多年。我曾今有机会听到他的一次分享会,讲了他的过去经历和发展过程,就是不断文字总结、练习和输出,提升自己。对他个人的成长帮助非常大,而且通过公众号和知识星球,现在他的粉丝已经发展到全国各地。 + +这也说明不断文字输出练习对个人帮助提升还是很有帮助的,同时还要接受反馈,从别人哪里看到自己的不足,很多时候自己是看不到自己的问题的。就类似<<刻意练习>>书里面讲一位美国医生要提升自己的技术能力,特意请一位老医生观摩自己的手术过程,然后给出反馈一样,要接受别的反馈和意见,然后再想办法提升自己。 + +这里也给大家一个tips,也是个人的经验,就是对于答辩和公开演讲类的汇报一般会有经理邀请其他人来指导,最好的情况就是安排人模拟答辩和演讲过程,然后一遍遍的过,如果真的是这样你就遇到很nice的经理了。如果没有你也不要气馁,自己一遍遍过,总结问题然后再请教leader或经理,对你绝对有帮助。(多说一点一定把你设计的通过leader认可的图表放出来,要不会被Argue的) + +### 问题复盘 +- 对每次的发言要尽量收集反馈 + +- 对问题进行复盘再刻意练习就可以提高 + +其实很多工作都是要复盘的,不仅仅是线上事故需要Case Study,自己做的PPT,分享都应该复盘分析下,哪里做的好,哪里不好,然后要加上刻意练习,只有反复针对性训练才能提高。 +很多时候反馈不会自动来到碗里来,所以需要把工作输出成文字和演讲之类的,这样你自己就有感受,同时就可以看到很多评论,这些就是反馈内容,再就是主动提出要求让对方给出意见。当然如果你不幸遇到Case Study,不要担心,这也是一次很好的成长机会,无论是心理还是技术上。 +对这些方法还想多说一点就是坚持,好的习惯如果还能坚持一直做,收获一定的加倍的,没有多少收获是靠一天的努力得到的,都是要长期去做,做一个好习惯的爱好者。 +如果还想找些其他提高自己能力的方法,就再对自己狠一点,进入全公司最难的团队,有些堪称魔鬼训练营的团队,一定对你个人提高帮助巨大,但是付出也是相对的。 + +## PPT的内容要求 + #### 给管理层看的报告 + + - 10页PPT,一页一分钟 + + - 3页讲贡献 人为因素 创新因素 + + #### 7:3原则 + + - 7是主体,3是额外(不放在ppt) + + 70% 是你一定要讲的东西,30%可讲可不讲 + + 作的差,不要说自己很努力,已经尽力了;作的好,尽力是应该的; + + 做得不好,分析原因,不要说自己尽力了; + + #### Just Enough not Just in case + + - 求质 不 求量 + + - 从年初的kpi挑百分之10-20加分工作,年底展现出来成绩 + + #### 结论才是重点,结论不是标题重写一遍 + + +## PPT的图表要求 +- 柱状图 + + 两两相比用柱状图 + +- 饼图 + + 从大到小排序,自己公司排最前面 + + 一定标百分比 + + 饼图不要用3D + + 不要超过6块 + +- 趋势图 + + 趋势表现用趋势图 + +- 做数据图表 + + 图表不超过2两个颜色 + + 不能有图例 + + 不能有横的数据线 + + 不能用3D + + 不用直接用Excel图表 + + 图的左上角标识含义和单位 + + ppt的图不要用excel画,直接用ppt画图 + + +![图片1](https://uploader.shimo.im/f/qgcp66Ue3Nogb33o.png) +![图片2](https://uploader.shimo.im/f/DMCr4XHrALwUdK4o.png) +![图片3](https://uploader.shimo.im/f/lcCCVgtrWBULaYPX.png) +![图片4](https://uploader.shimo.im/f/nKx6uR8yR1k9Uxyi.png) +![图片5](https://uploader.shimo.im/f/xSDngTtR9EQlf0s0.png) +![图片6](https://uploader.shimo.im/f/iveAkWHv3BkvPYd8.png) +![图片7](https://uploader.shimo.im/f/2xqGztA8uK0a8b7y.png) + + +## 题目的泛化 +- 怎么与人沟通 +- 敢于拒绝不合理需求 +- 如何做演讲 +- 分享的意义 + + +## 参考和推荐 + +- 《原则 principles》 http://product.dangdang.com/25204629.html +- Qi 迹 https://mp.weixin.qq.com/s/CvkESxu7aY6ZOnz89auGxw +- 公众号:辉哥奇谭 +-《刻意练习》 https://www.amazon.cn/dp/B01MDQ7RAX +- 向上汇报原文:https://www.cnblogs.com/huansky/p/7997724.html + + +## QA +## 最后祝愿每位听众都能在职场上获得成功,谢谢! diff --git a/Week_03/G20200343030587/src/main/java/com/home/work/week03/LeetCode_122_587.java b/Week_03/G20200343030587/src/main/java/com/home/work/week03/LeetCode_122_587.java new file mode 100644 index 00000000..b385d00d --- /dev/null +++ b/Week_03/G20200343030587/src/main/java/com/home/work/week03/LeetCode_122_587.java @@ -0,0 +1,14 @@ +package com.home.work.week03; + +public class LeetCode_122_587 { + + public int maxProfit(int[] prices) { + int profit = 0; + for (int i = 1; i < prices.length; i++) { + if (prices[i] > prices[i - 1]) { + profit += prices[i] - prices[i - 1]; + } + } + return profit; + } +} diff --git a/Week_03/G20200343030587/src/main/java/com/home/work/week03/LeetCode_127_587.java b/Week_03/G20200343030587/src/main/java/com/home/work/week03/LeetCode_127_587.java new file mode 100644 index 00000000..069eadfb --- /dev/null +++ b/Week_03/G20200343030587/src/main/java/com/home/work/week03/LeetCode_127_587.java @@ -0,0 +1,56 @@ +package com.home.work.week03; + +import java.util.LinkedList; +import java.util.List; +import java.util.Set; + +public class LeetCode_127_587 { + + public int ladderLength(String beginWord, String endWord, List wordList) { + if (!wordList.contains(endWord)) return 0; + //双端队列 + LinkedList sQueue = new LinkedList<>(); + LinkedList eQueue = new LinkedList<>(); + + Set v1 = new HashSet<>(); + Set v2 = new HashSet<>(); + sQueue.add(beginWord); + eQueue.add(endWord); + v1.add(beginWord); + v2.add(endWord); + + int res = 0; + while (!sQueue.isEmpty() && !eQueue.isEmpty()) { + res++; + if (sQueue.size() > eQueue.size()) { + LinkedList temp = sQueue; + sQueue = eQueue; + eQueue = temp; + Set v3 = v1; + v1 = v2; + v2 = v3; + }; + for (int k = sQueue.size(); k > 0; k--) { + String curr = sQueue.pop(); + for (int i = 0; i < wordList.size(); i++) { + if (v1.contains(wordList.get(i))) continue; + if (!diff(curr, wordList.get(i))) continue; + if (v2.contains(wordList.get(i))) return ++res; + sQueue.add(wordList.get(i)); + v1.add(wordList.get(i)); + } + } + } + return 0; + } + + private boolean diff(String str, String str2) { + int diff = 0; + for (int j = 0; j < str.length(); j++) { + if (str.charAt(j) != str2.charAt(j)) { + if (++diff > 1) return false; + } + } + return diff == 1; + } +} diff --git a/Week_03/G20200343030587/src/main/java/com/home/work/week03/LeetCode_455_587.java b/Week_03/G20200343030587/src/main/java/com/home/work/week03/LeetCode_455_587.java new file mode 100644 index 00000000..c271f371 --- /dev/null +++ b/Week_03/G20200343030587/src/main/java/com/home/work/week03/LeetCode_455_587.java @@ -0,0 +1,19 @@ +package com.home.work.week03; + +import java.util.Arrays; + +public class LeetCode_455_587 { + + public int findContentChildren(int[] g, int[] s) { + Arrays.sort(g); + Arrays.sort(s); + + int i = 0; + int j = 0; + while (i < g.length && j < s.length) { + if (g[i] <= s[j]) i++; + j++; + } + return i; + } +} diff --git a/Week_03/G20200343030587/src/main/java/com/home/work/week03/LeetCode_45_587.java b/Week_03/G20200343030587/src/main/java/com/home/work/week03/LeetCode_45_587.java new file mode 100644 index 00000000..a40c9a66 --- /dev/null +++ b/Week_03/G20200343030587/src/main/java/com/home/work/week03/LeetCode_45_587.java @@ -0,0 +1,22 @@ +package com.home.work.week03; + +public class LeetCode_45_587 { + public int jump(int[] nums) { + int k = 0; + int step = 0; + int end = 0; + //这里有个小细节,因为是起跳的时候就 + 1 了, + //如果最后一次跳跃刚好到达了最后一个位置,那么遍历到最后一个位置的时候就会再次起 + //跳,这是不允许的,因此不能遍历最后一个位置 + for (int i = 0; i < nums.length - 1; i++) { + //找能跳的最远的 + k = Math.max(k, nums[i] + i); + //遇到边界,就更新边界,并且步数加一 + if (i == end) { + step++ ; + end = k; + } + } + return step; + } +} diff --git a/Week_03/G20200343030587/src/main/java/com/home/work/week03/LeetCode_55_587.java b/Week_03/G20200343030587/src/main/java/com/home/work/week03/LeetCode_55_587.java new file mode 100644 index 00000000..7420fff4 --- /dev/null +++ b/Week_03/G20200343030587/src/main/java/com/home/work/week03/LeetCode_55_587.java @@ -0,0 +1,11 @@ +package com.home.work.week03; + +public class LeetCode_55_587 { + public boolean canJump(int[] nums) { + int lastPos = nums.length - 1; + for (int i = lastPos; i >= 0; i--) { + if (nums[i] + i >= lastPos) lastPos = i; + } + return lastPos == 0; + } +} diff --git a/Week_03/G20200343030587/src/main/java/com/home/work/week03/LeetCode_860_587.java b/Week_03/G20200343030587/src/main/java/com/home/work/week03/LeetCode_860_587.java new file mode 100644 index 00000000..83172a4d --- /dev/null +++ b/Week_03/G20200343030587/src/main/java/com/home/work/week03/LeetCode_860_587.java @@ -0,0 +1,25 @@ +package com.home.work.week03; + +public class LeetCode_860_587 { + public boolean lemonadeChange(int[] bills) { + int five = 0; + int ten = 0; + + for (int m : bills) { + if (m == 5) { + ++five; + } else if (m == 10) { + if (--five < 0) return false; + ++ten; + }else { + if (ten > 0) { + --ten; + if (--five < 0) return false; + } else { + if ((five -= 3) < 0) return false; + } + } + } + return true; + } +} diff --git a/Week_03/G20200343030587/src/main/java/com/home/work/week03/LeetCode_874_587.java b/Week_03/G20200343030587/src/main/java/com/home/work/week03/LeetCode_874_587.java new file mode 100644 index 00000000..0fb76ccb --- /dev/null +++ b/Week_03/G20200343030587/src/main/java/com/home/work/week03/LeetCode_874_587.java @@ -0,0 +1,38 @@ +package com.home.work.week03; + +import java.util.Set; + +public class LeetCode_874_587 { + public int robotSim(int[] commands, int[][] obstacles) { + //x y 移动的项量 北0 东1 南2 西3 + int[] dx = new int[]{0, 1, 0, -1}; + int[] dy = new int[]{1, 0, -1, 0}; + //方向di 初始值:北,机器人 移动的距离 x y + int di = 0, x = 0, y = 0; + //结果 + int ans = 0; + //障碍物 + Set obstacle = new HashSet<>(); + for (int[] obs : obstacles) { + obstacle.add(obs[0] + "-" + obs[1]); + } + + for (int c : commands) { + if (c == -1) di = (di + 1) % 4; + else if (c == -2) di = (di + 3) % 4; + else{ + for (int j = 0; j < c; j++) { + int nx = x + dx[di]; + int ny = y + dy[di]; + //有障碍退出 + if (obstacle.contains(nx + "-" + ny)) break; + //无障碍 计算欧式距离的平方 a = x^2 + y^2 + x = nx; + y = ny; + ans = Math.max(ans,x * x + y * y); + } + } + } + return ans; + } +} diff --git a/Week_03/G20200343030589/LeetCode_860_589.java b/Week_03/G20200343030589/LeetCode_860_589.java new file mode 100644 index 00000000..2ebf9cbf --- /dev/null +++ b/Week_03/G20200343030589/LeetCode_860_589.java @@ -0,0 +1,31 @@ + +/** + * 柠檬水找零 + * 最笨的办法 + */ +class Solution { + public boolean lemonadeChange(int[] bills) { + int five = 0, ten = 0; + for (int bill : bills) { + if (bill == 5) + five++; + else if (bill == 10) { + if (five == 0) + return false; + five--; + ten++; + } else { + if (five > 0 && ten > 0) { + five--; + ten--; + } else if (five >= 3) { + five -= 3; + } else { + return false; + } + } + } + + return true; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030589/LeetCode_874_589.java b/Week_03/G20200343030589/LeetCode_874_589.java new file mode 100644 index 00000000..0d449f5e --- /dev/null +++ b/Week_03/G20200343030589/LeetCode_874_589.java @@ -0,0 +1,39 @@ +/** + * 模拟行走机器人 + * 此题是参考官方题解 + */ +class Solution { + public int robotSim(int[] commands, int[][] obstacles) { + int[] dx = new int[] { 0, 1, 0, -1 }; + int[] dy = new int[] { 1, 0, -1, 0 }; + int x = 0, y = 0, di = 0; + + Set obstacleSet = new HashSet(); + for (int[] obstacle : obstacles) { + long ox = (long) obstacle[0] + 30000; + long oy = (long) obstacle[1] + 30000; + obstacleSet.add((ox << 16) + oy); + } + + int ans = 0; + for (int cmd : commands) { + if (cmd == -2) + di = (di + 3) % 4; + else if (cmd == -1) + di = (di + 1) % 4; + else { + for (int k = 0; k < cmd; ++k) { + int nx = x + dx[di]; + int ny = y + dy[di]; + long code = (((long) nx + 30000) << 16) + ((long) ny + 30000); + if (!obstacleSet.contains(code)) { + x = nx; + y = ny; + ans = Math.max(ans, x * x + y * y); + } + } + } + } + return ans; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030591/LeetCode_102_591.java b/Week_03/G20200343030591/LeetCode_102_591.java new file mode 100644 index 00000000..05d530dc --- /dev/null +++ b/Week_03/G20200343030591/LeetCode_102_591.java @@ -0,0 +1,74 @@ +class Solution { + + /** + * 层次遍历 + * BFS + * 一层一层的遍历 刚好符合层次遍历的题意 + * @param root + * @return + */ + public List> levelOrder(TreeNode root) { + if(root==null) { + return new ArrayList>(); + } + + List> res = new ArrayList>(); + LinkedList queue = new LinkedList(); + //将根节点放入队列中,然后不断遍历队列 + queue.add(root); + while(queue.size()>0) { + //获取当前队列的长度,这个长度相当于 当前这一层的节点个数 + int size = queue.size(); + ArrayList tmp = new ArrayList(); + //将队列中的元素都拿出来(也就是获取这一层的节点),放到临时list中 + //如果节点的左/右子树不为空,也放入队列中 + for(int i=0;i> levelOrder(TreeNode root) { + if (root == null) + return new ArrayList>(); + + List> res = new ArrayList>(); + + _helper(root, 0, res); + + return res; + } + + private void _helper(TreeNode root, int level, List> res) { + + if (root == null) { + return; + } + + if (level >= res.size()) { + res.add(new ArrayList<>()); + } + res.get(level).add(root.val); + + if (root.left != null) _helper(root.left, level+1, res); + + if (root.right != null) _helper(root.right, level+1, res); + + } + +} \ No newline at end of file diff --git a/Week_03/G20200343030591/LeetCode_122_591.java b/Week_03/G20200343030591/LeetCode_122_591.java new file mode 100644 index 00000000..0ad075ce --- /dev/null +++ b/Week_03/G20200343030591/LeetCode_122_591.java @@ -0,0 +1,20 @@ +class Solution { + + /** + * 贪心 + * 只要出现上涨就抛售获取利润 + * @param prices + * @return + */ + public int maxProfit(int[] prices) { + if (prices.length==0 || prices==null) return 0; + int profit = 0; + for (int i=1 ; i < prices.length; i++) { + if (prices[i] > prices[i - 1]) { + profit += prices[i] - prices[i - 1]; + } + } + return profit; + } + +} \ No newline at end of file diff --git a/Week_03/G20200343030591/LeetCode_153_591.java b/Week_03/G20200343030591/LeetCode_153_591.java new file mode 100644 index 00000000..65ac7a01 --- /dev/null +++ b/Week_03/G20200343030591/LeetCode_153_591.java @@ -0,0 +1,38 @@ +class Solution { + /** + * 情况1: + * 如果中间数比右界大,说明 得在 [mid+1,right]这个区间找 eg:[3,4,5,6,1] 不包含mid + * 一直在右半边找,直到 left == right后就会 停止运行,此时left就是最小值,如果要是要断开的地方则 返回right就好了 + * + * 如果中间数比右界小,说明 得在 [left,mid]这个区间找 eg:[7,8,1,2,3] 包含mid + * 先在左半边找,再在右边界找,直到 left == right 返回最左边的值即可 + * @param nums + * @return + */ + public int findMin(int[] nums) { + int len = nums.length; + if (len == 0 || nums == null) { + throw new IllegalArgumentException("数组为空"); + } + + int left = 0; + int right = len - 1; + + while (left < right) { + // 发现 可以这么写 等价于 left + (right - left) / 2 + int mid = (right + left) >>> 1; + + // 如果中间数 比 数组 右界大 说明 [mid, right] 这个区间是 递减的 被旋转过 + // 继续向 前找 看看下一个值是否满足 中间数比 右界大 + // eg [3,4,5,6,1] 第一次 中位数 为的下标位2 值为5 大于 右界的值 1 那么继续向前找 即 继续在 [mid+1, right]这个区间找 + // 第二次 mid=3 值为6 + if (nums[mid] > nums[right]) { + left = mid + 1; + } else { + // 如果中间数 比 数组 右界小 说明没被旋转过 也就是 [mid,right]这一段 没被旋转过 + right = mid; + } + } + return nums[left]; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030591/LeetCode_169_591.java b/Week_03/G20200343030591/LeetCode_169_591.java new file mode 100644 index 00000000..998511d5 --- /dev/null +++ b/Week_03/G20200343030591/LeetCode_169_591.java @@ -0,0 +1,41 @@ +class Solution { + + /** + * + * 给定一个大小为 n 的数组,找到其中的多数元素。多数元素是指在数组中出现次数大于 ⌊ n/2 ⌋ 的元素。 + * 你可以假设数组是非空的,并且给定的数组总是存在多数元素。 + * 示例 1: + * 输入: [3,2,3] + * 输出: 3 + * 示例 2: + * 输入: [2,2,1,1,1,2,2] + * 输出: 2 + * hash法 + * @param nums + * @return + */ + public int majorityElement(int[] nums) { + int result = 0; + int len = nums.length; + int target = len / 2; + Map map = new HashMap<>(); + + for (int i=0; i < len; i++) { + if (map.get(nums[i])!=null) { + map.put(nums[i], map.get(nums[i]) + 1); + } else { + map.put(nums[i], 1); + } + } + + Iterator it = map.keySet().iterator(); + while (it.hasNext()) { + Integer key = (Integer) it.next(); + Integer value = (Integer) map.get(key); + if (value > target) { + result = key; + } + } + return result; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030591/LeetCode_33_591.java b/Week_03/G20200343030591/LeetCode_33_591.java new file mode 100644 index 00000000..6880d417 --- /dev/null +++ b/Week_03/G20200343030591/LeetCode_33_591.java @@ -0,0 +1,33 @@ +class Solution { + public int search(int[] nums, int target) { + if (nums == null || nums.length == 0) { + return -1; + } + int start = 0; + int end = nums.length - 1; + int mid; + while (start <= end) { + mid = start + (end - start) / 2; + if (nums[mid] == target) { + return mid; + } + //前半部分有序,注意此处用小于等于 + if (nums[start] <= nums[mid]) { + //target在前半部分 + if (target >= nums[start] && target < nums[mid]) { + end = mid - 1; + } else { + start = mid + 1; + } + } else { + if (target <= nums[end] && target > nums[mid]) { + start = mid + 1; + } else { + end = mid - 1; + } + } + + } + return -1; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030591/LeetCode_367_591.java b/Week_03/G20200343030591/LeetCode_367_591.java new file mode 100644 index 00000000..d8c2fbb2 --- /dev/null +++ b/Week_03/G20200343030591/LeetCode_367_591.java @@ -0,0 +1,39 @@ +class Solution { + + /** + * 有效的完全平方数 + * 在求平方根的基础上 判断 最终求出的值是否是完全平方数 + * 即 1 * 1, 2 * 2, 3 * 3 + * 1、4、9 这种都属于完全平方数 + * @param num + * @return + */ + public boolean isPerfectSquare(int num) { + if (num < 2) { + return true; + } + int left = 1, right = num; + while (left <= right) { + int mid = left + (right - left) / 2; + if (mid > num / mid) { + right = mid - 1; + } else { + left = mid + 1; + } + } + return right * right == num; + } + + /** + * 牛顿迭代法 + * @param num + * @return + */ + public boolean isPerfectSquare(int num) { + long cur = num; + while (cur * cur > num) { + cur = (cur + num / cur) / 2; + } + return (int)(cur * cur) == num; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030591/LeetCode_46_591.java b/Week_03/G20200343030591/LeetCode_46_591.java new file mode 100644 index 00000000..747ba560 --- /dev/null +++ b/Week_03/G20200343030591/LeetCode_46_591.java @@ -0,0 +1,38 @@ +class Solution { + + /** + * x的平方根 + * 牛顿迭代法 + * 公式记忆方法:(要求的值 除以 当前值 + 当前值) / 2 + */ + public int mySqrt(int x) { + int cur = x; + while (cur * cur > x) { + cur = (cur + x / cur) / 2; + } + return (int) cur; + } + + /** + * 二分查找法 + * 画一条1到x的线段,每次求出线段的中间位置 + * @param x + * @return + */ + public int mySqrt(int x) { + if (x < 2) { + return x; + } + + int left = 1, right = x; + while (left <= right) { + int mid = left + (right - left) / 2; + if (mid > x / mid) { + right = mid - 1; + } else { + left = mid + 1; + } + } + return right; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030591/LeetCode_860_591.java b/Week_03/G20200343030591/LeetCode_860_591.java new file mode 100644 index 00000000..cef1beac --- /dev/null +++ b/Week_03/G20200343030591/LeetCode_860_591.java @@ -0,0 +1,36 @@ +class Solution { + + /** + * 贪心法(找零钱正好是符合贪心算法的只顾眼前就行) + * 每走一步只考虑眼前最优的就可以了,就是最优解。 + * + * 先按照正确的 正常的能找零的方式 来一步一步判断是否能找零,排除了能找零的,就都是不能找零的 + * (1)一开始没有钱,5元个数为0,10元个数也为0,20元因为无法找零所以不记录个数。 + * (2)正好是付款5元的情况,给5元的个数+1。 + * (3)按照顺序,第二个人付款是10元的,那么 10元个数+1,5元个数-1。 + * (4)如果有人付款的是20元,那么要看看当前有几个5元和几个10元,这里要想成功找零分为两种情况: + * 4.1)如果5元和10元的个数 >0,那么就可以找零 + * 4.2)如果5元的个数>2 也就是3个,那么就可以找零 + * @param bills + * @return + */ + public boolean lemonadeChange(int[] bills) { + if (bills == null | bills.length == 0) { + return false; + } + int five = 0, ten = 0; + for (int bill : bills) { + if (bill == 5) five++; + else if (bill == 10 && five > 0) { + five--; ten++; + } + else if (five > 0 && ten > 0) { + five--; ten--; + } + else if (five > 2) five -= 3; + else return false; + } + return true; + } + +} \ No newline at end of file diff --git a/Week_03/G20200343030593/Leet_code_122_593.java b/Week_03/G20200343030593/Leet_code_122_593.java new file mode 100644 index 00000000..71aa84a3 --- /dev/null +++ b/Week_03/G20200343030593/Leet_code_122_593.java @@ -0,0 +1,10 @@ +class Solution { + public int maxProfit(int[] prices) { + int profit=0; + for(int i=1;i0){profit+=temp;} + } + return profit; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030593/Leet_code_860_593.java b/Week_03/G20200343030593/Leet_code_860_593.java new file mode 100644 index 00000000..633cd88b --- /dev/null +++ b/Week_03/G20200343030593/Leet_code_860_593.java @@ -0,0 +1,16 @@ +class Solution { + public boolean lemonadeChange(int[] bills) { + int five=0; + int ten=0; + for(int i:bills){ + if(i==5){five++;} + else if(i==10){five--;ten++;} + else if(ten>0){five--;ten--;} + else{five-=3;} + if(five<0){ + return false; + } + } + return true; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030595/LeetCode_122_595.go b/Week_03/G20200343030595/LeetCode_122_595.go new file mode 100644 index 00000000..95445482 --- /dev/null +++ b/Week_03/G20200343030595/LeetCode_122_595.go @@ -0,0 +1,26 @@ +package main + +func maxProfit(prices []int) int { + length := len(prices) + if length < 1 { + return 0 + } + + dp := make([][2]int, length) + dp[0][0] = 0 // with cash + dp[0][1] = -prices[0] // with stock + + for i := 1; i < length; i++ { + dp[i][0] = max(dp[i-1][0], dp[i-1][1]+prices[i]) + dp[i][1] = max(dp[i-1][1], dp[i-1][0]-prices[i]) + } + + return max(dp[length-1][0], dp[length-1][1]) +} + +func max(a, b int) int { + if a > b { + return a + } + return b +} diff --git a/Week_03/G20200343030595/LeetCode_126_595.go b/Week_03/G20200343030595/LeetCode_126_595.go new file mode 100644 index 00000000..b881ae42 --- /dev/null +++ b/Week_03/G20200343030595/LeetCode_126_595.go @@ -0,0 +1,57 @@ +package main + +import "math" + +func findLadders(beginWord string, endWord string, wordList []string) [][]string { + words := make(map[string]struct{}) + for _, w := range wordList { + words[w] = struct{}{} + } + if _, ok := words[endWord]; !ok { + return [][]string{} + } + + result := make([][]string, 0) + + level := 1 + length := math.MaxInt32 + visited := make(map[string]struct{}) + queue := make([][]string, 0) + queue = append(queue, []string{beginWord}) + for len(queue) > 0 { + ladder := queue[0] + queue = queue[1:] + + if len(ladder) > level { + for w := range visited { + delete(words, w) + } + visited = make(map[string]struct{}) + } + lastWord := ladder[len(ladder)-1] + if len(ladder) > length { + break + } else { + level = len(ladder) + if lastWord == endWord { + result = append(result, ladder) + length = len(ladder) + } + } + + for i := 0; i < len(lastWord); i++ { + for b := 'a'; b <= 'z'; b++ { + newWord := lastWord[:i] + string(b) + lastWord[i+1:] + if _, ok := words[newWord]; !ok || newWord == lastWord { + continue + } + visited[newWord] = struct{}{} + copyPath := make([]string, 0, len(ladder)+1) + copyPath = append(copyPath, ladder...) + copyPath = append(copyPath, newWord) + queue = append(queue, copyPath) + } + } + } + return result +} diff --git a/Week_03/G20200343030595/LeetCode_127_595.go b/Week_03/G20200343030595/LeetCode_127_595.go new file mode 100644 index 00000000..9a789282 --- /dev/null +++ b/Week_03/G20200343030595/LeetCode_127_595.go @@ -0,0 +1,56 @@ +package main + +type word struct { + str string + level int +} + +func ladderLength(beginWord string, endWord string, wordList []string) int { + queue := []word{ + { + str: beginWord, + level: 1, + }, + } + pos := 0 + used := make([]bool, len(wordList)) + for pos < len(queue) { + level := queue[pos].level + 1 + for i, v := range wordList { + if used[i] { + continue + } + + if canChange(queue[pos].str, v) { + if v == endWord { + return level + } + queue = append(queue, word{ + str: v, + level: level, + }) + used[i] = true + } + } + pos++ + } + + return 0 +} + +func canChange(a, b string) bool { + if len(a) != len(b) { + return false + } + + diff := 0 + for i := 0; i < len(a); i++ { + if a[i] != b[i] { + diff++ + if diff > 1 { + return false + } + } + } + return true +} diff --git a/Week_03/G20200343030595/LeetCode_153_595.go b/Week_03/G20200343030595/LeetCode_153_595.go new file mode 100644 index 00000000..15793349 --- /dev/null +++ b/Week_03/G20200343030595/LeetCode_153_595.go @@ -0,0 +1,29 @@ +package main + +func findMin(nums []int) int { + if len(nums) == 1 { + return nums[0] + } + + left, right := 0, len(nums)-1 + if nums[right] > nums[0] { + return nums[0] + } + for left <= right { + mid := (left + right) / 2 + if (mid+1) < len(nums) && nums[mid] > nums[mid+1] { + return nums[mid+1] + } + + if (mid-1) > 0 && nums[mid-1] > nums[mid] { + return nums[mid] + } + + if nums[mid] > nums[0] { + left = mid + 1 + } else { + right = mid - 1 + } + } + return 0 +} diff --git a/Week_03/G20200343030595/LeetCode_200_595.go b/Week_03/G20200343030595/LeetCode_200_595.go new file mode 100644 index 00000000..33796675 --- /dev/null +++ b/Week_03/G20200343030595/LeetCode_200_595.go @@ -0,0 +1,65 @@ +package main + +func numIslands(grid [][]byte) int { + used := make([][]bool, len(grid)) + for i := 0; i < len(used); i++ { + used[i] = make([]bool, len(grid[0])) + } + + res := 0 + for i := 0; i < len(grid); i++ { + for j := 0; j < len(grid[i]); j++ { + if used[i][j] || grid[i][j] == '0' { + continue + } + node := Node{ + x: i, + y: j, + } + bfs(node, &grid, &used) + res++ + } + } + return res +} + +type Node struct { + x, y int +} + +func bfs(node Node, grid *[][]byte, used *[][]bool) { + arr := [][]int{ + {-1, 0}, + {1, 0}, + {0, -1}, + {0, 1}, + } + + queue := make([]Node, 0) + queue = append(queue, node) + pos := 0 + + for pos < len(queue) { + curNode := queue[pos] + for i := 0; i < len(arr); i++ { + curX := curNode.x + arr[i][0] + curY := curNode.y + arr[i][1] + if (curX < 0 || curX >= len(*grid)) || (curY < 0 || curY >= len((*grid)[0])) { + continue + } + if (*used)[curX][curY] { + continue + } + + if (*grid)[curX][curY] == '1' { + queue = append(queue, Node{ + x: curX, + y: curY, + }) + } + + (*used)[curX][curY] = true + } + pos++ + } +} diff --git a/Week_03/G20200343030595/LeetCode_33_595.go b/Week_03/G20200343030595/LeetCode_33_595.go new file mode 100644 index 00000000..edf9347c --- /dev/null +++ b/Week_03/G20200343030595/LeetCode_33_595.go @@ -0,0 +1,38 @@ +package main + +func search(nums []int, target int) int { + if len(nums) == 0 { + return -1 + } + splitPos := 0 + for i := 1; i < len(nums); i++ { + if nums[i] < nums[i-1] { + splitPos = i - 1 + break + } + } + + if pos := binarySearch(nums, target, 0, splitPos); pos != -1 { + return pos + } + + return binarySearch(nums, target, splitPos+1, len(nums)-1) +} + +func binarySearch(nums []int, target, left, right int) int { + for left <= right { + mid := (left + right) / 2 + switch { + case nums[mid] == target: + return mid + + case nums[mid] < target: + left = mid + 1 + + case nums[mid] > target: + right = mid - 1 + } + } + + return -1 +} diff --git a/Week_03/G20200343030595/LeetCode_455_595.go b/Week_03/G20200343030595/LeetCode_455_595.go new file mode 100644 index 00000000..b0f9e8f6 --- /dev/null +++ b/Week_03/G20200343030595/LeetCode_455_595.go @@ -0,0 +1,18 @@ +package main + +import "sort" + +func findContentChildren(g []int, s []int) int { + sort.Ints(g) + sort.Ints(s) + + gi, si := 0, 0 + for gi < len(g) && si < len(s) { + if g[gi] <= s[si] { + gi++ + } + si++ + } + + return gi +} diff --git a/Week_03/G20200343030595/LeetCode_45_595.go b/Week_03/G20200343030595/LeetCode_45_595.go new file mode 100644 index 00000000..f4ffda04 --- /dev/null +++ b/Week_03/G20200343030595/LeetCode_45_595.go @@ -0,0 +1,22 @@ +package main + +func jump(nums []int) int { + end := 0 + maxPos := 0 + step := 0 + for i := 0; i < len(nums)-1; i++ { + maxPos = max(maxPos, nums[i]+i) + if i == end { + end = maxPos + step++ + } + } + return step +} + +func max(a, b int) int { + if a > b { + return a + } + return b +} diff --git a/Week_03/G20200343030595/LeetCode_529_595.java b/Week_03/G20200343030595/LeetCode_529_595.java new file mode 100644 index 00000000..8c620571 --- /dev/null +++ b/Week_03/G20200343030595/LeetCode_529_595.java @@ -0,0 +1,48 @@ +public class Solution { + public char[][] updateBoard(char[][] board, int[] click) { + int m = board.length, n = board[0].length; + Queue queue = new LinkedList<>(); + queue.add(click); + + while (!queue.isEmpty()) { + int[] cell = queue.poll(); + int row = cell[0], col = cell[1]; + + if (board[row][col] == 'M') { // Mine + board[row][col] = 'X'; + } + else { // Empty + // Get number of mines first. + int count = 0; + for (int i = -1; i < 2; i++) { + for (int j = -1; j < 2; j++) { + if (i == 0 && j == 0) continue; + int r = row + i, c = col + j; + if (r < 0 || r >= m || c < 0 || c < 0 || c >= n) continue; + if (board[r][c] == 'M' || board[r][c] == 'X') count++; + } + } + + if (count > 0) { // If it is not a 'B', stop further BFS. + board[row][col] = (char)(count + '0'); + } + else { // Continue BFS to adjacent cells. + board[row][col] = 'B'; + for (int i = -1; i < 2; i++) { + for (int j = -1; j < 2; j++) { + if (i == 0 && j == 0) continue; + int r = row + i, c = col + j; + if (r < 0 || r >= m || c < 0 || c < 0 || c >= n) continue; + if (board[r][c] == 'E') { + queue.add(new int[] {r, c}); + board[r][c] = 'B'; // Avoid to be added again. + } + } + } + } + } + } + + return board; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030595/LeetCode_55_595.go b/Week_03/G20200343030595/LeetCode_55_595.go new file mode 100644 index 00000000..1d44ce83 --- /dev/null +++ b/Week_03/G20200343030595/LeetCode_55_595.go @@ -0,0 +1,34 @@ +package main + +func canJump(nums []int) bool { + lastPos := len(nums) - 1 + for i := len(nums) - 1; i >= 0; i-- { + if i+nums[i] >= lastPos { + lastPos = i + } + } + return lastPos == 0 +} + +// method 2 +// func canJump(nums []int) bool { +// maxReach := 1 +// for i:=0; i= len(nums)-i { +// return true +// } +// } +// return maxReach >= 0 +// } + +// func max(a, b int) int { +// if a > b { +// return a +// } +// return b +// } diff --git a/Week_03/G20200343030595/LeetCode_74_595.go b/Week_03/G20200343030595/LeetCode_74_595.go new file mode 100644 index 00000000..dfe1d92f --- /dev/null +++ b/Week_03/G20200343030595/LeetCode_74_595.go @@ -0,0 +1,48 @@ +package main + +func searchMatrix(matrix [][]int, target int) bool { + m := len(matrix) + if m < 1 { + return false + } + + n := len(matrix[0]) + if n < 1 { + return false + } + + for i := 0; i < m; i++ { + if n-1 > 0 && target > matrix[i][n-1] { + continue + } + + if target < matrix[i][0] { + return false + } + + for j := 0; j < n; j++ { + if binarySearch(matrix[i], target) { + return true + } + } + } + return false +} + +func binarySearch(nums []int, target int) bool { + left, right := 0, len(nums)-1 + for left <= right { + mid := (left + right) / 2 + switch { + case nums[mid] == target: + return true + + case nums[mid] < target: + left = mid + 1 + + case nums[mid] > target: + right = mid - 1 + } + } + return false +} diff --git a/Week_03/G20200343030595/LeetCode_860_595.go b/Week_03/G20200343030595/LeetCode_860_595.go new file mode 100644 index 00000000..cc57511b --- /dev/null +++ b/Week_03/G20200343030595/LeetCode_860_595.go @@ -0,0 +1,30 @@ +package main + +func lemonadeChange(bills []int) bool { + money := make(map[int]int) + for _, v := range bills { + switch v { + case 5: + money[5]++ + + case 10: + if money[5] > 0 { + money[5]-- + money[10]++ + } else { + return false + } + + case 20: + if money[10] > 0 && money[5] > 0 { + money[10]-- + money[5]-- + } else if money[5] >= 3 { + money[5] -= 3 + } else { + return false + } + } + } + return true +} diff --git a/Week_03/G20200343030595/LeetCode_874_595.go b/Week_03/G20200343030595/LeetCode_874_595.go new file mode 100644 index 00000000..cde4ca09 --- /dev/null +++ b/Week_03/G20200343030595/LeetCode_874_595.go @@ -0,0 +1,40 @@ +package main + +type point struct { + x, y int +} + +func robotSim(commands []int, obstacles [][]int) int { + dx := [4]int{0, 1, 0, -1} + dy := [4]int{1, 0, -1, 0} + set := make(map[point]bool) + for _, v := range obstacles { + set[point{v[0], v[1]}] = true + } + max := 0 + x := 0 + y := 0 + di := 0 + for _, c := range commands { + if c == -1 { + di = (di + 1) % 4 + } else if c == -2 { + di = (di - 1 + 4) % 4 + } else { + for i := 0; i < c; i++ { + nx := x + dx[di] + ny := y + dy[di] + if set[point{nx, ny}] { + break + } else { + x = nx + y = ny + if x*x+y*y > max { + max = x*x + y*y + } + } + } + } + } + return max +} diff --git a/Week_03/G20200343030597/Solution_122.java b/Week_03/G20200343030597/Solution_122.java new file mode 100644 index 00000000..ec7f1a45 --- /dev/null +++ b/Week_03/G20200343030597/Solution_122.java @@ -0,0 +1,11 @@ +public class Solution_122 { + public int maxProfit(int[] prices) { + int total = 0; + for (int index = 0; index < prices.length - 1; index++) { + if (prices[index] < prices[index + 1]) { + total += prices[index + 1] - prices[index]; + } + } + return total; + } +} diff --git a/Week_03/G20200343030597/Solution_860.java b/Week_03/G20200343030597/Solution_860.java new file mode 100644 index 00000000..44510c4c --- /dev/null +++ b/Week_03/G20200343030597/Solution_860.java @@ -0,0 +1,27 @@ +public class Solution_860 { + public boolean lemonadeChange(int[] bills) { + int fiveIndex = 0; + int tenIndex = 0; + for (int index = 0; index < bills.length; index++) { + if (bills[index] == 10) { + if (fiveIndex == 0) { + return false; + } + fiveIndex--; + tenIndex++; + } else if (bills[index] == 5) { + fiveIndex++; + } else { + if (tenIndex > 0 && fiveIndex > 0) { + tenIndex--; + fiveIndex--; + } else if (fiveIndex >= 3) { + fiveIndex -= 3; + } else { + return false; + } + } + } + return true; + } +} diff --git a/Week_03/G20200343030599/LeetCode_122_599.js b/Week_03/G20200343030599/LeetCode_122_599.js new file mode 100644 index 00000000..45c4273c --- /dev/null +++ b/Week_03/G20200343030599/LeetCode_122_599.js @@ -0,0 +1,41 @@ +/* + * @lc app=leetcode.cn id=122 lang=javascript + * + * [122] 买卖股票的最佳时机 II + */ + +// @lc code=start +/** + * @param {number[]} prices + * @return {number} + */ +var maxProfit = function (prices) { + const length = prices.length + // 总利润 + let t = 0 + // 当前持有的价格 + let h; + for (let i = 0; i < length; i++) { + const today = prices[i] + const today1 = prices[i + 1] + // 买入 + if (h === undefined && today < today1) { + h = today + continue + } + // 正常交易日卖出 + if (today > today1 && h < today && h !== undefined) { + t = today - h + t + h = undefined + continue + } + // 最后交易日卖出 + if (today1 === undefined && h < today && h !== undefined) { + t = today - h + t + h = undefined + } + + } + return t +}; +// @lc code=end diff --git a/Week_03/G20200343030599/LeetCode_455_599.js b/Week_03/G20200343030599/LeetCode_455_599.js new file mode 100644 index 00000000..76628808 --- /dev/null +++ b/Week_03/G20200343030599/LeetCode_455_599.js @@ -0,0 +1,32 @@ +/* + * @lc app=leetcode.cn id=455 lang=javascript + * + * [455] 分发饼干 + */ + +// @lc code=start +/** + * @param {number[]} g + * @param {number[]} s + * @return {number} + */ +var findContentChildren = function (g, s) { + g = g.sort((a, b) => a - b); + s = s.sort((a, b) => a - b); + let gLen = g.length; + let sLen = s.length; + let i = 0; + let j = 0; + let maxNum = 0; + while (i < gLen && j < sLen) { + if (s[j] >= g[i]) { + i++; + j++; + maxNum++; + } else { + j++; + } + } + return maxNum; +}; +// @lc code=end diff --git a/Week_03/G20200343030599/LeetCode_860_599.js b/Week_03/G20200343030599/LeetCode_860_599.js new file mode 100644 index 00000000..8e11cf63 --- /dev/null +++ b/Week_03/G20200343030599/LeetCode_860_599.js @@ -0,0 +1,39 @@ +/* + * @lc app=leetcode.cn id=860 lang=javascript + * + * [860] 柠檬水找零 + */ + +// @lc code=start +/** + * @param {number[]} bills + * @return {boolean} + */ +var lemonadeChange = function (bills) { + //贪心算法 + let five = 0; + let ten = 0; + let len = bills.length; + for (let i = 0; i < len; i++) { + if (bills[i] == 5) { + five++; + } else if (bills[i] == 10) { + if (five == 0) { + return false + }; + five--; + ten++; + } else if (bills[i] == 20) { + if (ten > 0 && five > 0) { + ten--; + five--; + } else if (five >= 3) { + five -= 3; + } else { + return false; + } + } + } + return true; +}; +// @lc code=end diff --git a/Week_03/G20200343030599/NOTE.md b/Week_03/G20200343030599/NOTE.md deleted file mode 100644 index 50de3041..00000000 --- a/Week_03/G20200343030599/NOTE.md +++ /dev/null @@ -1 +0,0 @@ -学习笔记 \ No newline at end of file diff --git "a/Week_03/G20200343030601/121.\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272.java" "b/Week_03/G20200343030601/121.\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272.java" new file mode 100644 index 00000000..ac122fe1 --- /dev/null +++ "b/Week_03/G20200343030601/121.\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272.java" @@ -0,0 +1,58 @@ +/* + * @lc app=leetcode.cn id=121 lang=java + * + * [121] 买卖股票的最佳时机 + * + * https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock/description/ + * + * algorithms + * Easy (52.37%) + * Likes: 767 + * Dislikes: 0 + * Total Accepted: 133.8K + * Total Submissions: 254.6K + * Testcase Example: '[7,1,5,3,6,4]' + * + * 给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。 + * + * 如果你最多只允许完成一笔交易(即买入和卖出一支股票),设计一个算法来计算你所能获取的最大利润。 + * + * 注意你不能在买入股票前卖出股票。 + * + * 示例 1: + * + * 输入: [7,1,5,3,6,4] + * 输出: 5 + * 解释: 在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。 + * ⁠ 注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格。 + * + * + * 示例 2: + * + * 输入: [7,6,4,3,1] + * 输出: 0 + * 解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。 + * + * + */ +/* + * 思路:一次遍历 + * 记录当前最小price和当前最大利润,遍历更新这两个值 + * PS:max利润不一定是数组中maxV - minV得到的 + * 而是“历次”最小谷之后最大峰差值中的max差值(因只允许一次交易); + */ +// @lc code=start +class Solution { + public int maxProfit(int[] prices) { + int minPrice = Integer.MAX_VALUE, maxProfit = 0; + for (int price : prices) { + if (price < minPrice) + minPrice = price; + else if (price - minPrice > maxProfit) + maxProfit = price - minPrice; + } + return maxProfit; + } +} +// @lc code=end + diff --git "a/Week_03/G20200343030601/122.\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272-ii.java" "b/Week_03/G20200343030601/122.\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272-ii.java" new file mode 100644 index 00000000..0187bf47 --- /dev/null +++ "b/Week_03/G20200343030601/122.\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272-ii.java" @@ -0,0 +1,68 @@ +/* + * @lc app=leetcode.cn id=122 lang=java + * + * [122] 买卖股票的最佳时机 II + * + * https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/description/ + * + * algorithms + * Easy (57.48%) + * Likes: 608 + * Dislikes: 0 + * Total Accepted: 122.1K + * Total Submissions: 211.5K + * Testcase Example: '[7,1,5,3,6,4]' + * + * 给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。 + * + * 设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。 + * + * 注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。 + * + * 示例 1: + * + * 输入: [7,1,5,3,6,4] + * 输出: 7 + * 解释: 在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。 + * 随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6-3 = 3 。 + * + * + * 示例 2: + * + * 输入: [1,2,3,4,5] + * 输出: 4 + * 解释: 在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 + * 。 + * 注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。 + * 因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。 + * + * + * 示例 3: + * + * 输入: [7,6,4,3,1] + * 输出: 0 + * 解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。 + * + */ + + /* + * 思路:一次遍历 + * (*)因为不限交易次数,只要有利润(nextV > currentV),即可作为一次交易(贪心),统计累计利润 + * 1. 在thirdV < nextV时,上述策略肯定可取; + * 2. 在thirdV > nextV时,thirdV - currentV = (nextV - currentV) + (thirdV - nextV),上述策略也可以; + */ + + // @lc code=start +class Solution { + public int maxProfit(int[] prices) { + int totalProfit = 0; + for (int i = 1; i < prices.length; i++) { + int profit = prices[i] - prices[i - 1]; + if (profit > 0) + totalProfit += profit; + } + return totalProfit; + } +} +// @lc code=end + diff --git "a/Week_03/G20200343030601/153.\345\257\273\346\211\276\346\227\213\350\275\254\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\346\234\200\345\260\217\345\200\274.java" "b/Week_03/G20200343030601/153.\345\257\273\346\211\276\346\227\213\350\275\254\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\346\234\200\345\260\217\345\200\274.java" new file mode 100644 index 00000000..ce3a4c98 --- /dev/null +++ "b/Week_03/G20200343030601/153.\345\257\273\346\211\276\346\227\213\350\275\254\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\346\234\200\345\260\217\345\200\274.java" @@ -0,0 +1,88 @@ +/* + * @lc app=leetcode.cn id=153 lang=java + * + * [153] 寻找旋转排序数组中的最小值 + * + * https://leetcode-cn.com/problems/find-minimum-in-rotated-sorted-array/description/ + * + * algorithms + * Medium (50.21%) + * Likes: 143 + * Dislikes: 0 + * Total Accepted: 33.5K + * Total Submissions: 66.8K + * Testcase Example: '[3,4,5,1,2]' + * + * 假设按照升序排序的数组在预先未知的某个点上进行了旋转。 + * + * ( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。 + * + * 请找出其中最小的元素。 + * + * 你可以假设数组中不存在重复元素。 + * + * 示例 1: + * + * 输入: [3,4,5,1,2] + * 输出: 1 + * + * 示例 2: + * + * 输入: [4,5,6,7,0,1,2] + * 输出: 0 + * + */ + +/* +* 思路: 二分思想 旋转数组中最小值,要么在数组的左半部分,要么在数组的右半部分 +* if 数组仅有一个元素或,lo值 < hi值 + 数据是递增的,返回第一个值即可 +* if mid值 > hi值 +* 说明从lo到mid过程中经历过增长、猛降后再增长,最小值则在右半部分; +* 递归处理右半部分; +* else +* 即最小值在左半部分; +* 递归处理左半部分; +* +* Note:注意有可能mid值恰好是最小值,所以不管左侧还是右侧递归,都带着mid值。 +* (递归改为循环,以下代码经过精简) +*/ + +// @lc code=start +class Solution { + /* + public int findMin(int[] nums) { + int lo = 0, hi = nums.length - 1; + + while (lo < hi && nums[lo] > nums[hi]) { + // 数组片段长度>=2,且中间有起伏(旋转点在中间) + int mid = (hi + lo) / 2; + if (nums[lo] <= nums[mid]) + lo = mid + 1; // mid前(含mid)递增,旋转点在mid之后 + else + hi = mid; // mid前的片段有起伏,旋转点在mid前 + } + + // 数组片段仅有一个元素,或数组是递增的,直接返回第一个值 + return nums[lo]; + } + */ + + public int findMin(int[] nums) { + return findMinCore(nums, 0, nums.length - 1); + } + + private int findMinCore(int[] nums, int lo, int hi) { + // 数组片段仅有一个元素,或数组是递增的,直接返回第一个值 + if (lo >= hi || nums[lo] < nums[hi]) + return nums[lo]; + + int mid = (lo + hi) / 2; + if (nums[lo] <= nums[mid]) + return findMinCore(nums, mid + 1, hi); + else + return findMinCore(nums, lo, mid); + } +} +// @lc code=end + diff --git "a/Week_03/G20200343030601/154.\345\257\273\346\211\276\346\227\213\350\275\254\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\346\234\200\345\260\217\345\200\274-ii.java" "b/Week_03/G20200343030601/154.\345\257\273\346\211\276\346\227\213\350\275\254\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\346\234\200\345\260\217\345\200\274-ii.java" new file mode 100644 index 00000000..bacbfc33 --- /dev/null +++ "b/Week_03/G20200343030601/154.\345\257\273\346\211\276\346\227\213\350\275\254\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\346\234\200\345\260\217\345\200\274-ii.java" @@ -0,0 +1,97 @@ +/* + * @lc app=leetcode.cn id=154 lang=java + * + * [154] 寻找旋转排序数组中的最小值 II + * + * https://leetcode-cn.com/problems/find-minimum-in-rotated-sorted-array-ii/description/ + * + * algorithms + * Hard (46.29%) + * Likes: 76 + * Dislikes: 0 + * Total Accepted: 14.1K + * Total Submissions: 30.2K + * Testcase Example: '[1,3,5]' + * + * 假设按照升序排序的数组在预先未知的某个点上进行了旋转。 + * + * ( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。 + * + * 请找出其中最小的元素。 + * + * 注意数组中可能存在重复的元素。 + * + * 示例 1: + * + * 输入: [1,3,5] + * 输出: 1 + * + * 示例 2: + * + * 输入: [2,2,2,0,1] + * 输出: 0 + * + * 说明: + * + * + * 这道题是 寻找旋转排序数组中的最小值 的延伸题目。 + * 允许重复会影响算法的时间复杂度吗?会如何影响,为什么? + * + * + */ + + /* + * 思路: + * if lo值 == hi值 + * 将hi前移,直至hi值与lo值不等,或直至仅剩一个元素; + * if array中仅有一个item 或 lo值 < hi值 + * 即递增array,直接返回lo值 + * if lo值 > mid值 + * 说明旋转点在lo和mid中间,递归处理该片段; + * if lo值 == mid值 + * 说明lo到mid段值全相等(如果旋转点在lo和mid间,则后半段全与mid值也相等,与前面处理相违背) + * 递归处理后半段 + * if mid值 > hi值 + * 说明旋转点在mid和hi中间,递归处理该片段; + * + */ + +// @lc code=start +class Solution { + public int findMin(int[] nums) { + int lo = 0, hi = nums.length - 1; + + while (lo < hi) { + while (lo < hi && nums[lo] == nums[hi]) + hi--; + if (lo == hi || nums[lo] < nums[hi]) + return nums[lo]; + + int mid = lo + (hi - lo) / 2; + if (nums[lo] > nums[mid]) + hi = mid; + else + lo = mid + 1; + } + + return nums[lo]; + } + + // public int findMin(int[] nums) { + // int lo = 0, hi = nums.length -1; + + // while (lo < hi && nums[lo] > nums[hi]) { + // // 数组片段长度>=2,且中间有起伏(旋转点在中间) + // int mid = (hi + lo) / 2; + // if (nums[lo] <= nums[mid]) + // lo = mid + 1; // mid前(含mid)递增,旋转点在mid之后 + // else + // hi = mid; // mid前的片段有起伏,旋转点在mid前 + // } + + // // 数组片段仅有一个元素,或数组是递增的,直接返回第一个值 + // return nums[lo]; + // } +} +// @lc code=end + diff --git "a/Week_03/G20200343030601/455.\345\210\206\345\217\221\351\245\274\345\271\262.java" "b/Week_03/G20200343030601/455.\345\210\206\345\217\221\351\245\274\345\271\262.java" new file mode 100644 index 00000000..61ad8e09 --- /dev/null +++ "b/Week_03/G20200343030601/455.\345\210\206\345\217\221\351\245\274\345\271\262.java" @@ -0,0 +1,78 @@ +/* + * @lc app=leetcode.cn id=455 lang=java + * + * [455] 分发饼干 + * + * https://leetcode-cn.com/problems/assign-cookies/description/ + * + * algorithms + * Easy (52.98%) + * Likes: 137 + * Dislikes: 0 + * Total Accepted: 26.6K + * Total Submissions: 50.1K + * Testcase Example: '[1,2,3]\n[1,1]' + * + * 假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。对每个孩子 i ,都有一个胃口值 gi + * ,这是能让孩子们满足胃口的饼干的最小尺寸;并且每块饼干 j ,都有一个尺寸 sj 。如果 sj >= gi ,我们可以将这个饼干 j 分配给孩子 i + * ,这个孩子会得到满足。你的目标是尽可能满足越多数量的孩子,并输出这个最大数值。 + * + * 注意: + * + * 你可以假设胃口值为正。 + * 一个小朋友最多只能拥有一块饼干。 + * + * 示例 1: + * + * + * 输入: [1,2,3], [1,1] + * + * 输出: 1 + * + * 解释: + * 你有三个孩子和两块小饼干,3个孩子的胃口值分别是:1,2,3。 + * 虽然你有两块小饼干,由于他们的尺寸都是1,你只能让胃口值是1的孩子满足。 + * 所以你应该输出1。 + * + * + * 示例 2: + * + * + * 输入: [1,2], [1,2,3] + * + * 输出: 2 + * + * 解释: + * 你有两个孩子和三块小饼干,2个孩子的胃口值分别是1,2。 + * 你拥有的饼干数量和尺寸都足以让所有孩子满足。 + * 所以你应该输出2. + * + * + */ + + /* + * 思路:(贪心)发给孩子i满足他的饼干尺寸gi的最小饼干尺寸sj; + * 否则,sj可能会满足不了其他胃口更大的孩子,导致少一位孩子被满足。 + * 实现:1.先对孩子胃口、饼干尺寸进行排序; + * 2.按上述贪心规则进行分配 + * 修正:在代码中设置了count计数,后发现和iChild始终一致,故删除; + */ +// @lc code=start +import java.util.Arrays; +class Solution { + public int findContentChildren(int[] g, int[] s) { + Arrays.sort(g); + Arrays.sort(s); + int iChild = 0, iCookie = 0; + while(iChild < g.length && iCookie < s.length) { + if (g[iChild] <= s[iCookie]) { + iChild++; + } + iCookie++; + } + + return iChild; + } +} +// @lc code=end + diff --git "a/Week_03/G20200343030601/860.\346\237\240\346\252\254\346\260\264\346\211\276\351\233\266.java" "b/Week_03/G20200343030601/860.\346\237\240\346\252\254\346\260\264\346\211\276\351\233\266.java" new file mode 100644 index 00000000..e38ebcda --- /dev/null +++ "b/Week_03/G20200343030601/860.\346\237\240\346\252\254\346\260\264\346\211\276\351\233\266.java" @@ -0,0 +1,108 @@ +/* + * @lc app=leetcode.cn id=860 lang=java + * + * [860] 柠檬水找零 + * + * https://leetcode-cn.com/problems/lemonade-change/description/ + * + * algorithms + * Easy (53.84%) + * Likes: 95 + * Dislikes: 0 + * Total Accepted: 16.3K + * Total Submissions: 30.1K + * Testcase Example: '[5,5,5,10,20]' + * + * 在柠檬水摊上,每一杯柠檬水的售价为 5 美元。 + * + * 顾客排队购买你的产品,(按账单 bills 支付的顺序)一次购买一杯。 + * + * 每位顾客只买一杯柠檬水,然后向你付 5 美元、10 美元或 20 美元。你必须给每个顾客正确找零,也就是说净交易是每位顾客向你支付 5 美元。 + * + * 注意,一开始你手头没有任何零钱。 + * + * 如果你能给每位顾客正确找零,返回 true ,否则返回 false 。 + * + * 示例 1: + * + * 输入:[5,5,5,10,20] + * 输出:true + * 解释: + * 前 3 位顾客那里,我们按顺序收取 3 张 5 美元的钞票。 + * 第 4 位顾客那里,我们收取一张 10 美元的钞票,并返还 5 美元。 + * 第 5 位顾客那里,我们找还一张 10 美元的钞票和一张 5 美元的钞票。 + * 由于所有客户都得到了正确的找零,所以我们输出 true。 + * + * + * 示例 2: + * + * 输入:[5,5,10] + * 输出:true + * + * + * 示例 3: + * + * 输入:[10,10] + * 输出:false + * + * + * 示例 4: + * + * 输入:[5,5,10,10,20] + * 输出:false + * 解释: + * 前 2 位顾客那里,我们按顺序收取 2 张 5 美元的钞票。 + * 对于接下来的 2 位顾客,我们收取一张 10 美元的钞票,然后返还 5 美元。 + * 对于最后一位顾客,我们无法退回 15 美元,因为我们现在只有两张 10 美元的钞票。 + * 由于不是每位顾客都得到了正确的找零,所以答案是 false。 + * + * + * + * + * 提示: + * + * + * 0 <= bills.length <= 10000 + * bills[i] 不是 5 就是 10 或是 20  + * + * + */ + +/* +* 思路: +* 要保证有钱可找,需要记录现有多少零钱,20的钱不可用于找零,可以不记录; +* 1. 遇到支付5的,零钱5++; +* 2. 遇到支付10的,判断零钱5有无,做对应操作; +* 3. 遇到支付20的,优先选择10 + 5,其次选择3 * 5,如果都不满足则false。 +*/ + +// @lc code=start +class Solution { + public boolean lemonadeChange(int[] bills) { + int fiveCount = 0, tenCount = 0; + for (int bill : bills) { + if (5 == bill) + fiveCount++; + else if (10 == bill) { + if (fiveCount < 0) + return false; + tenCount++; + fiveCount--; + } + else if (20 == bill) { + if (tenCount > 0 && fiveCount > 0) { + tenCount--; + fiveCount--; + } + else if (fiveCount >= 3) + fiveCount -= 3; + else + return false; + } + } + + return true; + } +} +// @lc code=end + diff --git "a/Week_03/G20200343030601/874.\346\250\241\346\213\237\350\241\214\350\265\260\346\234\272\345\231\250\344\272\272.java" "b/Week_03/G20200343030601/874.\346\250\241\346\213\237\350\241\214\350\265\260\346\234\272\345\231\250\344\272\272.java" new file mode 100644 index 00000000..ce0eaa38 --- /dev/null +++ "b/Week_03/G20200343030601/874.\346\250\241\346\213\237\350\241\214\350\265\260\346\234\272\345\231\250\344\272\272.java" @@ -0,0 +1,115 @@ + +/* + * @lc app=leetcode.cn id=874 lang=java + * + * [874] 模拟行走机器人 + * + * https://leetcode-cn.com/problems/walking-robot-simulation/description/ + * + * algorithms + * Easy (32.32%) + * Likes: 75 + * Dislikes: 0 + * Total Accepted: 5.9K + * Total Submissions: 18.1K + * Testcase Example: '[4,-1,3]\n[]' + * + * 机器人在一个无限大小的网格上行走,从点 (0, 0) 处开始出发,面向北方。该机器人可以接收以下三种类型的命令: + * + * + * -2:向左转 90 度 + * -1:向右转 90 度 + * 1 <= x <= 9:向前移动 x 个单位长度 + * + * + * 在网格上有一些格子被视为障碍物。 + * + * 第 i 个障碍物位于网格点  (obstacles[i][0], obstacles[i][1]) + * + * 如果机器人试图走到障碍物上方,那么它将停留在障碍物的前一个网格方块上,但仍然可以继续该路线的其余部分。 + * + * 返回从原点到机器人的最大欧式距离的平方。 + * + * + * + * 示例 1: + * + * 输入: commands = [4,-1,3], obstacles = [] + * 输出: 25 + * 解释: 机器人将会到达 (3, 4) + * + * + * 示例 2: + * + * 输入: commands = [4,-1,4,-2,4], obstacles = [[2,4]] + * 输出: 65 + * 解释: 机器人在左转走到 (1, 8) 之前将被困在 (1, 4) 处 + * + * + * + * + * 提示: + * + * + * 0 <= commands.length <= 10000 + * 0 <= obstacles.length <= 10000 + * -30000 <= obstacle[i][0] <= 30000 + * -30000 <= obstacle[i][1] <= 30000 + * 答案保证小于 2 ^ 31 + * + * + */ +/* + * 思路:关键点1. 如何表示方向,更方便运算; + * 2. 如何快速判断一个坐标位置是否有障碍物; + * 3. 除了一次移动一格之外,有无更快速的识别路途障碍物的办法? + * + * PS: 1.借鉴了题解中方向的表示方式; + * 2.障碍物的位置,开始使用的是Set中是String类型,性能低,转为long类型; + */ +// @lc code=start +import java.util.HashSet; +import java.util.Set; + +class Solution { + public int robotSim(int[] commands, int[][] obstacles) { + int[][] dirs = new int[][]{{0, 1}, {1, 0}, {0, -1}, {-1, 0}}; // 北,东,南,西 + int maxDistance = 0, posX = 0, posY = 0, dIndex = 0; + + // Set obstaclesSet = new HashSet(); + // for (int[] obstacle : obstacles) { + // obstaclesSet.add(String.format("%d,%d", obstacle[0], obstacle[1])); + // } + Set obstaclesSet = new HashSet(); + for (int[] obstacle : obstacles) { + long ox = (long)(obstacle[0] + 30000); + long oy = (long)(obstacle[1] + 30000); + obstaclesSet.add((ox << 16) + oy); + } + + for (int command : commands) { + if (-1 == command) + dIndex = (dIndex + 1) % 4; + else if (-2 == command) + dIndex = (dIndex + 3) % 4; + else { + int validStep = command; + for (int i = 1; i <= command; i++) { + int nextPosX = posX + i * dirs[dIndex][0]; + int nextPosY = posY + i * dirs[dIndex][1]; + long nextPos = ((long)(nextPosX + 30000) << 16) + (long)(nextPosY + 30000); + if (obstaclesSet.contains(nextPos)) { + validStep = i - 1; + break; + } + } + posX = posX + validStep * dirs[dIndex][0]; + posY = posY + validStep * dirs[dIndex][1]; + maxDistance = Math.max(maxDistance, posX * posX + posY * posY); + } + } + return maxDistance; + } +} +// @lc code=end + diff --git a/Week_03/G20200343030601/NOTE.md b/Week_03/G20200343030601/NOTE.md index 50de3041..296caecc 100644 --- a/Week_03/G20200343030601/NOTE.md +++ b/Week_03/G20200343030601/NOTE.md @@ -1 +1,68 @@ -学习笔记 \ No newline at end of file +# 学习笔记(第三周) + +**学号:** G20200343030601 + +**姓名:** 冯学智 + +**微信:** SDMrFeng + +## 本周学习总结 +- 因为发现预习资料基本都是王争老师数据结构和算法之美专栏里的内容,所以王争老师的课看了40%多了。王争老师的课更像是书本+课后题,覃超老师算法训练营更像是练习册和终点习题解读精讲。配合起来学习效果会比较好。 + +- 本周时间宽裕,做的题目也相对较多。在学习别人commit的代码的同时,对哪些代码复杂度更好、哪些代码更简洁、哪些代码更易懂进行了思考,在工程实现时,需要做相应的取舍。 + +- 对于某些题问是否有解,我会进一步思考有多少个解,每个解是什么样子;如果递增序列中允许重复值怎么来实现。多思考类似的问题,有助于巩固所学知识。 + +## 寻找旋转数组中的最小值(选招一个半有序数组中间无序的地方) + + /* + * 思路: 二分思想 旋转数组中最小值,要么在数组的左半部分,要么在数组的右半部分 + * if 数组仅有一个元素或,lo值 < hi值 + 数据是递增的,返回第一个值即可 + * if mid值 > hi值 + * 说明从lo到mid过程中经历过增长、猛降后再增长,最小值则在右半部分; + * 递归处理右半部分; + * else + * 即最小值在左半部分; + * 递归处理左半部分; + * + * Note:注意有可能mid值恰好是最小值,所以不管左侧还是右侧递归,都带着mid值。 + * (递归改为循环,以下代码经过精简) + */ + + // @lc code=start + class Solution { + /* + public int findMin(int[] nums) { + int lo = 0, hi = nums.length - 1; + + while (lo < hi && nums[lo] > nums[hi]) { + // 数组片段长度>=2,且中间有起伏(旋转点在中间) + int mid = (hi + lo) / 2; + if (nums[lo] <= nums[mid]) + lo = mid + 1; // mid前(含mid)递增,旋转点在mid之后 + else + hi = mid; // mid前的片段有起伏,旋转点在mid前 + } + + // 数组片段仅有一个元素,或数组是递增的,直接返回第一个值 + return nums[lo]; + } + */ + + public int findMin(int[] nums) { + return findMinCore(nums, 0, nums.length - 1); + } + + private int findMinCore(int[] nums, int lo, int hi) { + // 数组片段仅有一个元素,或数组是递增的,直接返回第一个值 + if (lo >= hi || nums[lo] < nums[hi]) + return nums[lo]; + + int mid = (lo + hi) / 2; + if (nums[lo] <= nums[mid]) + return findMinCore(nums, mid + 1, hi); + else + return findMinCore(nums, lo, mid); + } + } \ No newline at end of file diff --git a/Week_03/G20200343030603/LeetCode_1_603.java b/Week_03/G20200343030603/LeetCode_1_603.java new file mode 100644 index 00000000..41a556aa --- /dev/null +++ b/Week_03/G20200343030603/LeetCode_1_603.java @@ -0,0 +1,25 @@ +class Solution { + public boolean lemonadeChange(int[] bills) { + int five = 0, ten = 0; + for (int bill : bills) { + if (bill == 5) { // 支付5元 + five++; + } else if (bill == 10) { // 支付10元 + if (five == 0) return false; + five--; + ten++; + } else { // 支付20元 + if (five > 0 && ten > 0) { + five--; + ten--; + } else if (five >= 3){ + five -= 3; + } else { + return false; + } + } + } + + return true; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030603/LeetCode_2_603.java b/Week_03/G20200343030603/LeetCode_2_603.java new file mode 100644 index 00000000..719f31aa --- /dev/null +++ b/Week_03/G20200343030603/LeetCode_2_603.java @@ -0,0 +1,70 @@ +class Solution { + //方法一:暴力法,递归 + // public int maxProfit(int[] prices) { + // return calculate(prices, 0); + // } + + // public int calculate(int prices[], int s){ + // if (s >= prices.length) { + // return 0; + // } + + // int max = 0; + // for (int start = s; start < prices.length; start++){ + // int maxProfit = 0; + // for (int i = start + 1; i < prices.length; i++){ + // if (prices[start] < prices[i]) { + // int profit = calculate(prices, i + 1) + prices[i] - prices[start]; + // if (profit > maxProfit) { + // maxProfit = profit; + // } + // } + // if (maxProfit > max) { + // max = maxProfit; + // } + // } + // } + // return max; + // } + + + //第二种:峰谷法 时间复杂度O(n) 空间复杂度O(1) + public int maxProfit(int[] prices) { + if (prices.length == 0){ + return 0; + } + int i = 0; + int valley = prices[0]; + int peak = prices[0]; + int maxProfit = 0; + while(i < prices.length - 1) { + if (i < prices.length - 1 && prices[i] >= prices[i + 1]) { + i++; + } + + valley = prices[i]; + + if (i < prices.length - 1 && prices[i] <= prices[i + 1]) { + i++; + } + + peak = prices[i]; + maxProfit += peak - valley; + } + + return maxProfit; + } + + + // // 方法三:简单的一次遍历,差值相加(可以当天卖出当天买入,实际就没卖出)时间复杂度O(n) 空间复杂度O(1) + // public int maxProfit(int[] prices) { + // int maxProfit = 0; + // for (int i = 1; i < prices.length; i++){ + // if (prices[i] > prices[i - 1]) { + // maxProfit += prices[i] - prices[i - 1]; + // } + // } + // return maxProfit; + // } + +} \ No newline at end of file diff --git a/Week_03/G20200343030603/LeetCode_3_603.java b/Week_03/G20200343030603/LeetCode_3_603.java new file mode 100644 index 00000000..147e75a8 --- /dev/null +++ b/Week_03/G20200343030603/LeetCode_3_603.java @@ -0,0 +1,24 @@ +class Solution { + public int findContentChildren(int[] g, int[] s) { + // 贪心算法,双指针法 时间复杂度O(n) + if (g.length == 0 || s.length == 0){ + return 0; + } + + Arrays.sort(g); + Arrays.sort(s); + + int count = 0; + int i = 0; + int j = 0; + + while (i != g.length && j != s.length){ + if (s[j] >= g[i]){ + count++; + i++; + } + j++; + } + return count; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030611/LeetCode_102_611.java b/Week_03/G20200343030611/LeetCode_102_611.java new file mode 100644 index 00000000..b06a6602 --- /dev/null +++ b/Week_03/G20200343030611/LeetCode_102_611.java @@ -0,0 +1,45 @@ +package datast.bfs_dfs; + +import java.util.ArrayList; +import java.util.List; + +public class LeetCode_102_611 { + + /** + * 给定一个二叉树,返回其按层次遍历的节点值。 (即逐层地,从左到右访问所有节点)。 + * + * @param root + * @return + */ + public List> levelOrder(TreeNode root) { + List> res = new ArrayList<>(); + if (root == null) return res; + helper(0, res, root); + return res; + } + + private void helper(int level, List> res, TreeNode node) { + if (level == res.size()) { + res.add(new ArrayList()); + } + res.get(level).add(node.val); + if (node.left != null) { + helper(level + 1, res, node.left); + } + if (node.right != null) { + helper(level + 1, res, node.right); + } + } + + + public class TreeNode { + int val; + TreeNode left; + TreeNode right; + + TreeNode(int x) { + val = x; + } + } + +} diff --git a/Week_03/G20200343030611/LeetCode_153_611.java b/Week_03/G20200343030611/LeetCode_153_611.java new file mode 100644 index 00000000..33bf0976 --- /dev/null +++ b/Week_03/G20200343030611/LeetCode_153_611.java @@ -0,0 +1,18 @@ +package datast.binary_search; + +public class LeetCode_153_611 { + + public int findMin(int[] nums) { + int left = 0; + int right = nums.length - 1; + while (left < right) { + int mid = left + (right - left) / 2; + if (nums[mid] > nums[right]) { + left = mid + 1; + } else { + right = mid; + } + } + return nums[left]; + } +} diff --git a/Week_03/G20200343030611/LeetCode_169_611.java b/Week_03/G20200343030611/LeetCode_169_611.java new file mode 100644 index 00000000..0473c937 --- /dev/null +++ b/Week_03/G20200343030611/LeetCode_169_611.java @@ -0,0 +1,34 @@ +package datast.divide_backtrack; + +public class LeetCode_169_611 { + + /** + * \ + * 给定一个大小为 n 的数组,找到其中的多数元素。多数元素是指在数组中出现次数大于 ⌊ n/2 ⌋ 的元素。 + * + * @param nums + * @return + */ + public int majorityElement(int[] nums) { + return searchMajor(nums, 0, nums.length - 1); + } + + private int searchMajor(int[] nums, int left, int right) { + if (left == right) return nums[left]; + int mid = (right - left) / 2 + left; + int leftValue = searchMajor(nums, left, mid); + int rightValue = searchMajor(nums, mid + 1, right); + if (leftValue == rightValue) return leftValue; + int leftCount = count(nums, leftValue, left, right); + int rightCount = count(nums, rightValue, left, right); + return leftCount > rightCount ? leftValue : rightValue; + } + + private int count(int[] nums, int num, int left, int right) { + int count = 0; + for (int i = left; i <= right; i++) { + if (num == nums[i]) count++; + } + return count; + } +} diff --git a/Week_03/G20200343030611/LeetCode_17_611.java b/Week_03/G20200343030611/LeetCode_17_611.java new file mode 100644 index 00000000..4e800fe2 --- /dev/null +++ b/Week_03/G20200343030611/LeetCode_17_611.java @@ -0,0 +1,52 @@ +package datast.divide_backtrack; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class LeetCode_17_611 { + + private static Map map = new HashMap<>(); + + static { + map.put('2', "abc"); + map.put('3', "def"); + map.put('4', "ghi"); + map.put('5', "jkl"); + map.put('6', "mno"); + map.put('7', "pqrs"); + map.put('8', "tuv"); + map.put('9', "wxyz"); + } + + /** + * 给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。 + *

+ * 给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。 + * + * @param digits + * @return + */ + public List letterCombinations(String digits) { + List res = new ArrayList<>(); + if ("".equals(digits)) { + return res; + } + generate(digits, 0, res, ""); + return res; + } + + public void generate(String digits, int index, List res, String s) { + if (index == digits.length()) { + res.add(s); + return; + } + String alphabet = map.get(digits.charAt(index)); + int nextIndex = index + 1; + for (int i = 0; i < alphabet.length(); i++) { + char a = alphabet.charAt(i); + generate(digits, nextIndex, res, s + String.valueOf(a)); + } + } +} diff --git a/Week_03/G20200343030611/LeetCode_33_611.java b/Week_03/G20200343030611/LeetCode_33_611.java new file mode 100644 index 00000000..3ee5c03e --- /dev/null +++ b/Week_03/G20200343030611/LeetCode_33_611.java @@ -0,0 +1,44 @@ +package datast.binary_search; + +public class LeetCode_33_611 { + + /** + * 假设按照升序排序的数组在预先未知的某个点上进行了旋转。 + * + * @param nums + * @param target + * @return + */ + public int search(int[] nums, int target) { + if (nums.length == 0) return -1; + int left = 0; + int right = nums.length - 1; + int mid = 0; + // 求出最小值所在的索引(最小值也是反转点) + while (left < right) { + mid = left + (right - left) / 2; + if (nums[mid] > nums[right]) { + left = mid + 1; + } else { + right = mid; + } + } + if (target >= nums[left] && target <= nums[nums.length - 1]) { + right = nums.length - 1; + } else { + right = left - 1; + left = 0; + } + while (left <= right) { + mid = left + (right - left) / 2; + if (nums[mid] == target) { + return mid; + } else if (nums[mid] > target) { + right = mid - 1; + } else { + left = mid + 1; + } + } + return -1; + } +} diff --git a/Week_03/G20200343030611/LeetCode_367_611.java b/Week_03/G20200343030611/LeetCode_367_611.java new file mode 100644 index 00000000..b905af14 --- /dev/null +++ b/Week_03/G20200343030611/LeetCode_367_611.java @@ -0,0 +1,13 @@ +package datast.binary_search; + +public class LeetCode_367_611 { + + public boolean isPerfectSquare(int num) { + if (num == 0 || num == 1) return true; + long r = num / 2; + while (r * r > num) { + r = (r + num / r) / 2; + } + return r * r == num; + } +} diff --git a/Week_03/G20200343030611/LeetCode_50_611.java b/Week_03/G20200343030611/LeetCode_50_611.java new file mode 100644 index 00000000..7f23cdf9 --- /dev/null +++ b/Week_03/G20200343030611/LeetCode_50_611.java @@ -0,0 +1,26 @@ +package datast.divide_backtrack; + +public class LeetCode_50_611 { + + /** + * 实现 pow(x, n) ,即计算 x 的 n 次幂函数。 + * + * @param x + * @param n + * @return + */ + public double myPow(double x, int n) { + long N = n; + if (n < 0) { + x = 1 / x; + N = -n; + } + return fastPow(x, N); + } + + public double fastPow(double x, long n) { + if (n == 0) return 1.0; + double half = fastPow(x, n / 2); + return n % 2 == 0 ? half * half : half * half * x; + } +} diff --git a/Week_03/G20200343030611/LeetCode_51_611.java b/Week_03/G20200343030611/LeetCode_51_611.java new file mode 100644 index 00000000..23599f8b --- /dev/null +++ b/Week_03/G20200343030611/LeetCode_51_611.java @@ -0,0 +1,53 @@ +package datast.divide_backtrack; + +import java.util.ArrayList; +import java.util.List; + +public class LeetCode_51_611 { + + private List col = new ArrayList<>(); + private List master = new ArrayList<>(); + private List slave = new ArrayList<>(); + + private List> result = new ArrayList<>(); + + public List> solveNQueens(int n) { + List res = new ArrayList<>(); + backTrace(0, res, n); + return result; + } + + private void backTrace(int row, List res, int n) { + if (row == n) { + print(res, n); + return; + } + for (int i = 0; i < n; i++) { + if (!col.contains(i) && !master.contains(row + i) && !slave.contains(row - i)) { + res.add(i); + col.add(i); + master.add(row + i); + slave.add(row - i); + backTrace(row + 1, res, n); + slave.remove(slave.size() - 1); + master.remove(master.size() - 1); + col.remove(col.size() - 1); + res.remove(res.size() - 1); + } + } + } + + private void print(List res, int n) { + List list = new ArrayList<>(); + + + for (int i = 0; i < res.size(); i++) { + StringBuilder stb = new StringBuilder(); + for (int j = 0; j < n; j++) { + stb.append("."); + } + list.add(stb.replace(res.get(i), res.get(i) + 1, "Q").toString()); + } + result.add(list); + } +} diff --git a/Week_03/G20200343030611/LeetCode_69_611.java b/Week_03/G20200343030611/LeetCode_69_611.java new file mode 100644 index 00000000..cf2be002 --- /dev/null +++ b/Week_03/G20200343030611/LeetCode_69_611.java @@ -0,0 +1,14 @@ +package datast.binary_search; + +public class LeetCode_69_611 { + + public int mySqrt(int x) { + if (x == 1) return 1; + // 首先随便猜一个近似值x,然后不断令x等于x和a/x的平均数,迭代个六七次后x的值就已经相当精确了 + long r = x; + while (r * r > x) { + r = (r + x / r) / 2; + } + return (int) r; + } +} diff --git a/Week_03/G20200343030611/LeetCode_74_611.java b/Week_03/G20200343030611/LeetCode_74_611.java new file mode 100644 index 00000000..4426b52e --- /dev/null +++ b/Week_03/G20200343030611/LeetCode_74_611.java @@ -0,0 +1,24 @@ +package datast.binary_search; + +public class LeetCode_74_611 { + + public boolean searchMatrix(int[][] matrix, int target) { + int m = matrix.length; + if (m == 0) return false; + int n = matrix[0].length; + int left = 0; + int right = m * n - 1; + while (left <= right) { + int mid = left + (right - left) / 2; + int valueIndex = matrix[mid / n][mid % n]; + if (valueIndex == target) { + return true; + } else if (valueIndex < target) { + left = mid + 1; + } else { + right = mid - 1; + } + } + return false; + } +} diff --git a/Week_03/G20200343030611/LeetCode_78_611.java b/Week_03/G20200343030611/LeetCode_78_611.java new file mode 100644 index 00000000..6fbb7ebd --- /dev/null +++ b/Week_03/G20200343030611/LeetCode_78_611.java @@ -0,0 +1,30 @@ +package datast.divide_backtrack; + +import java.util.ArrayList; +import java.util.List; + +public class LeetCode_78_611 { + + /** + * 给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。 + * + * @param nums + * @return + */ + public List> subsets(int[] nums) { + List> res = new ArrayList<>(); + pick(0, nums, res, new ArrayList()); + return res; + } + + public void pick(int index, int[] nums, List res, List list) { + if (index == nums.length) { + res.add(new ArrayList(list)); + return; + } + pick(index + 1, nums, res, list); + list.add(nums[index]); + pick(index + 1, nums, res, list); + list.remove(list.size() - 1); + } +} diff --git a/Week_03/G20200343030617/LeetCode_10_617.go b/Week_03/G20200343030617/LeetCode_10_617.go new file mode 100644 index 00000000..85241f92 --- /dev/null +++ b/Week_03/G20200343030617/LeetCode_10_617.go @@ -0,0 +1,33 @@ +// 74. 搜索二维矩阵 + +package main + +func searchMatrix(matrix [][]int, target int) bool { + rowNum := len(matrix) + if rowNum == 0 { + return false + } + var lineNum int + if len(matrix[0]) > 0 { + lineNum = len(matrix[0]) + } else { + return false + } + left, right := 0, rowNum*lineNum + for left <= right { + mid := left + (right-left)/2 + i := mid / lineNum + j := mid % lineNum + if i >= rowNum || j >= lineNum { + return false + } + if matrix[i][j] == target { + return true + } else if matrix[i][j] < target { + left = mid + 1 + } else { + right = mid - 1 + } + } + return false +} diff --git a/Week_03/G20200343030617/LeetCode_5_617.go b/Week_03/G20200343030617/LeetCode_5_617.go new file mode 100644 index 00000000..8fd3e76e --- /dev/null +++ b/Week_03/G20200343030617/LeetCode_5_617.go @@ -0,0 +1,50 @@ +// 127. 单词接龙 + +package main + +func ladderLength(beginWord string, endWord string, wordList []string) int { + dict := make(map[string]bool) // 把word存入字典 + for _, word := range wordList { + dict[word] = true // 可以利用字典快速添加、删除和查找单词 + } + if _, ok := dict[endWord]; !ok { + return 0 + } + q1 := make(map[string]bool) + q2 := make(map[string]bool) + q1[beginWord] = true // 头 + q2[endWord] = true // 尾 + + l := len(beginWord) + steps := 0 + + for len(q1) > 0 && len(q2) > 0 { // 当两个集合都不为空,执行 + steps++ + // Always expend the smaller queue first + if len(q1) > len(q2) { + q1, q2 = q2, q1 + } + q := make(map[string]bool) // 临时set + for k := range q1 { + chs := []rune(k) + for i := 0; i < l; i++ { + ch := chs[i] + for c := 'a'; c <= 'z'; c++ { // 对每一位从a-z尝试 + chs[i] = c // 替换字母组成新的单词 + t := string(chs) + if _, ok := q2[t]; ok { // 看新单词是否在s2集合中 + return steps + 1 + } + if _, ok := dict[t]; !ok { // 看新单词是否在dict中 + continue // 不在字典就跳出循环 + } + delete(dict, t) // 若在字典中则删除该新的单词,表示已访问过 + q[t] = true // 把该单词加入到临时队列中 + } + chs[i] = ch // 新单词第i位复位,还原成原单词,继续往下操作 + } + } + q1 = q // q1修改为新扩展的q + } + return 0 +} diff --git a/Week_03/G20200343030627/LeetCode_1_627.js b/Week_03/G20200343030627/LeetCode_1_627.js new file mode 100644 index 00000000..376594e3 --- /dev/null +++ b/Week_03/G20200343030627/LeetCode_1_627.js @@ -0,0 +1,28 @@ +// lemonade-change + +var lemonadeChange = function(bills) { + var fiveCount = 0; + var tenCount = 0; + for (var i=0; i < bills.length; i++) { + if (bills[i] == 5) { + fiveCount += 1; + } else if (bills[i] == 10) { + if (fiveCount > 0) { + fiveCount -= 1; + tenCount += 1; + } else { + return false; + } + } else { + if (fiveCount > 0 && tenCount > 0) { + fiveCount -= 1; + tenCount -= 1; + } else if (fiveCount > 2) { + fiveCount -= 3; + } else { + return false; + } + } + } + return true; +}; \ No newline at end of file diff --git a/Week_03/G20200343030627/LeetCode_2_627.js b/Week_03/G20200343030627/LeetCode_2_627.js new file mode 100644 index 00000000..e7dd858f --- /dev/null +++ b/Week_03/G20200343030627/LeetCode_2_627.js @@ -0,0 +1,11 @@ +// best-time-to-buy-and-sell-stock-ii + +var maxProfit = function(prices) { + var result = 0; + for (var i=1; i< prices.length; i++) { + if (prices[i] > prices[i-1]) { + result += prices[i] - prices[i-1]; + } + } + return result; +}; \ No newline at end of file diff --git a/Week_03/G20200343030627/LeetCode_3_627.js b/Week_03/G20200343030627/LeetCode_3_627.js new file mode 100644 index 00000000..8a1f11dc --- /dev/null +++ b/Week_03/G20200343030627/LeetCode_3_627.js @@ -0,0 +1,20 @@ +// assign-cookies + +var findContentChildren = function(g, s) { + var feedCount = 0; + var gSort = g.sort((a,b) => a> b? 1: -1); + var sSort = s.sort((a,b) => a> b? 1: -1); + + for (var i=0; i< g.length; i++) { + while (sSort[0]< gSort[i] && sSort.length > 0) { + sSort.shift(); + } + if (sSort.length == 0) { + return feedCount; + } + sSort.shift(); + feedCount += 1; + } + + return feedCount; +}; \ No newline at end of file diff --git a/Week_03/G20200343030631/Leetcode_122_631.java b/Week_03/G20200343030631/Leetcode_122_631.java new file mode 100644 index 00000000..f3061bc9 --- /dev/null +++ b/Week_03/G20200343030631/Leetcode_122_631.java @@ -0,0 +1,11 @@ +class Solution { + public int maxProfit(int[] prices) { + int result = 0; + for (int i = 1; i < prices.length; i++) { + if (prices[i] > prices[i-1]){ + result += prices[i] - prices[i-1]; + } + } + return result; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030631/Leetcode_153_631.java b/Week_03/G20200343030631/Leetcode_153_631.java new file mode 100644 index 00000000..36e80aa1 --- /dev/null +++ b/Week_03/G20200343030631/Leetcode_153_631.java @@ -0,0 +1,29 @@ +class Solution { + public int findMin(int[] nums) { + // 边界条件 + if (null == nums || nums.length == 0){ + throw new UnsupportedOperationException("arrays does not contains element"); + } + int low = 0; + int high = nums.length - 1; + // 特殊边界条件 + if (nums[high] >= nums[low]){ + return nums[0]; + } + while (low <= high){ + int mid = low + (high - low) / 2; + if (nums[mid] > nums[mid + 1]){ + return nums[mid + 1]; + } + if (nums[mid] < nums[mid - 1]){ + return nums[mid]; + } + if (nums[mid] > nums[low]){ + low = mid + 1; + }else { + high = mid - 1; + } + } + return -1; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030631/Leetcode_33_631.java b/Week_03/G20200343030631/Leetcode_33_631.java new file mode 100644 index 00000000..3090c8ee --- /dev/null +++ b/Week_03/G20200343030631/Leetcode_33_631.java @@ -0,0 +1,39 @@ +class Solution { + public int search(int[] nums, int target) { + // 边界条件 + if (null == nums || nums.length == 0){ + return -1; + } + // 二分法左右边界 + int low = 0; + int high = nums.length - 1; + while (low <= high){ + int mid = low + (high - low) / 2; + // 对比mid low high的值是否等于target + if (nums[mid] == target){ + return mid; + } + if (nums[low] == target){ + return low; + } + if (nums[high] == target){ + return high; + } + // 找不到情况下移动左右边界 + if (nums[low] <= nums[mid]){ + if (target > nums[low] && target < nums[mid]){ + high = mid - 1; + }else { + low = mid + 1; + } + }else { + if (target < nums[high] && target > nums[mid]){ + low = mid + 1; + }else { + high = mid - 1; + } + } + } + return -1; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030631/Leetcode_455_631.java b/Week_03/G20200343030631/Leetcode_455_631.java new file mode 100644 index 00000000..54b7711c --- /dev/null +++ b/Week_03/G20200343030631/Leetcode_455_631.java @@ -0,0 +1,25 @@ +class Solution { + public int findContentChildren(int[] g, int[] s) { + // 结果 + int result = 0; + // 边界条件 + if (null == g || g.length == 0 + || null == s || s.length == 0){ + return result; + } + // 排序,减少后续循环对比工作量 + Arrays.sort(g); + Arrays.sort(s); + + for (int i = 0, j = 0; i < s.length && j < g.length; ) { + // 如果当前饼干大小满足当前小孩胃口,则结果+1,继续下一个小孩 + if (g[j] <= s[i]){ + result++; + j++; + } + // 不管当前饼干是否满足都要取下一个饼干:如果不满足,则加大饼干的大小,取下一个看是否满足;如果满足,进行下一个饼干判断 + i++; + } + return result; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030631/Leetcode_55_631.java b/Week_03/G20200343030631/Leetcode_55_631.java new file mode 100644 index 00000000..30a69821 --- /dev/null +++ b/Week_03/G20200343030631/Leetcode_55_631.java @@ -0,0 +1,29 @@ +package com.dsx.fifty.five; + +/** + * 解题思路: 贪心算法,从末端开始标记。根据每一个元素走自己的最大步数后,是否能到达上一个可以达到末尾的元素分类元素, + * 如果能到达第一个元素,说明可以第一个元素可以达到最后位置 + * 时间复杂度: O(n) + * 空间复杂度: O(1) + */ +class Solution { + public static void main(String[] args) { + int[] testCase = new int[]{2,3,1,1,4}; + System.out.println(canJump(testCase)); + } + + public static boolean canJump(int[] nums) { + // 边界条件 + if (null == nums || nums.length == 0){ + return false; + } + // 保存最后一个可跳到末尾的元素位置 + int lastCanJumpPos = nums.length - 1; + for (int i = nums.length - 1; i >= 0 ; i--) { + if (nums[i] + i >= lastCanJumpPos){ + lastCanJumpPos = i; + } + } + return lastCanJumpPos == 0; + } +} diff --git a/Week_03/G20200343030631/Leetcode_74_631.java b/Week_03/G20200343030631/Leetcode_74_631.java new file mode 100644 index 00000000..2800402d --- /dev/null +++ b/Week_03/G20200343030631/Leetcode_74_631.java @@ -0,0 +1,41 @@ +class Solution { + public boolean searchMatrix(int[][] matrix, int target) { + // 边界条件 + if (null == matrix || matrix.length == 0 ) { + return false; + } + // 获取多维数组维数及每一维元素个数 + int rowCount = matrix.length; + int columnCount = matrix[0].length; + int searchRowAt = rowCount - 1; + // 特殊边界,如果最后一个元素还小于target或者第一个元素大于target,直接返回false + if (columnCount == 0 || matrix[0][0] > target || matrix[searchRowAt][columnCount - 1] < target) { + return false; + } + // 找到target在哪一行内 + while (searchRowAt > 0) { + if (matrix[searchRowAt][0] > target) { + searchRowAt--; + }else if (matrix[searchRowAt][columnCount - 1] >= target && matrix[searchRowAt][0] <= target){ + break; + }else { + searchRowAt--; + } + } + // 在行内进行二分查找 + int low = 0; + int high = columnCount - 1; + while (low <= high) { + int mid = low + (high - low) / 2; + if (matrix[searchRowAt][mid] == target || matrix[searchRowAt][low] == target + || matrix[searchRowAt][high] == target) { + return true; + } else if (matrix[searchRowAt][mid] > target) { + high = mid - 1; + } else { + low = mid + 1; + } + } + return false; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030631/Leetcode_860_631.java b/Week_03/G20200343030631/Leetcode_860_631.java new file mode 100644 index 00000000..91ed492f --- /dev/null +++ b/Week_03/G20200343030631/Leetcode_860_631.java @@ -0,0 +1,39 @@ +class Solution { + public boolean lemonadeChange(int[] bills) { + // 边界条件 + if (null == bills || bills.length == 0){ + return false; + } + // 记录当前零钱总数 + int pocketMoney = 0; + int fiveDollarsCount = 0; + int tenDollarsCount = 0; + for (int i = 0; i < bills.length; i++) { + // 每次交易计算支付额减去单价后,是否有足够零钱找零,不够则返回false,足够则将零钱+5 + // v2 提交失败,零钱有5 10 20之分,加入统计数字,统计5 10的个数 + if ((bills[i] - 5) > pocketMoney){ + return false; + } + if ((bills[i] - 5) > 0 && fiveDollarsCount <= 0){ + return false; + } + if (bills[i] == 5){ + fiveDollarsCount ++; + }else if (bills[i] == 10){ + fiveDollarsCount--; + tenDollarsCount++; + }else { + if (fiveDollarsCount > 0 && tenDollarsCount > 0){ + fiveDollarsCount--; + tenDollarsCount--; + }else if (fiveDollarsCount >= 3){ + fiveDollarsCount -= 3; + }else { + return false; + } + } + pocketMoney += 5; + } + return true; + } +} \ No newline at end of file diff --git a/Week_03/G20200343030631/NOTE.md b/Week_03/G20200343030631/NOTE.md index 50de3041..d7cae057 100644 --- a/Week_03/G20200343030631/NOTE.md +++ b/Week_03/G20200343030631/NOTE.md @@ -1 +1,76 @@ -学习笔记 \ No newline at end of file +# 学习笔记 + +## 寻找一个半有序数组中间无序的地方 + +### 1. 分析思路 + +- 已知条件: + 1. 数组有序,旋转后两半分别有序 + 2. 旋转点具备以下特征,即旋转点是当前数组最大的元素 + 1. 旋转点前存在两种可能 + 1. 数据有序,小于旋转点; + 2. 无数据,为数组第一个元素; + 2. 旋转点后存在数据,与旋转点之间无序,小于旋转点; +- 样例数据:4, 5, 6, 7, 0, 1, 2 + +### 2. 解题思路 + +#### 2.1 暴力解题法 + +- 根据分析思路,只需遍历一次数组,找到第一个大于后一个值的元素即可; + + ```java + // 边界条件 + if (null == testCase || testCase.length == 0) { + return -1; + } + // 循环判断数据大小 + for (int i = 0; i < testCase.length - 1; i++) { + if (i == testCase.length - 1){ + return -1; + } + if (testCase[i] > testCase[i + 1]) { + return i; + } + } + return -1; + ``` +#### 2.2 二分查找法 + +- 使用二分查找法,根据旋转点位置,存在两种可能性: + + 1. 旋转点位于mid或者左侧,此时: + 1. mid小于low + 2. high移动至左侧区间,`high = mid - 1`; + 2. 旋转点位于mid右侧: + 1. mid大于low + 2. left移动至右侧区间,`left= mid + 1`; + +- 结合旋转点的特点:旋转点所在区间中,第一个大于后一个值的元素,每次二分比较mid值; + + ```java + // 边界条件 + if (null == testCase || testCase.length == 0) { + return -1; + } + int low = 0; + int high = testCase.length - 1; + while (low <= high) { + int mid = low + (high - low) / 2; + if (testCase[mid] > testCase[mid + 1]) { + return mid; + } + if (testCase[mid] < testCase[mid - 1]) { + return mid - 1; + } + // 右侧有序,移动右边界至左侧区间 + if (testCase[mid] < testCase[low]) { + high = mid - 1; + } else { // 左侧有序,移动右边界至右侧区间 + low = mid + 1; + } + } + return -1; + ``` + + \ No newline at end of file diff --git a/Week_03/G20200343030633/leetcode_102.py b/Week_03/G20200343030633/leetcode_102.py new file mode 100644 index 00000000..c56af9a2 --- /dev/null +++ b/Week_03/G20200343030633/leetcode_102.py @@ -0,0 +1,52 @@ +import week02.leetcode_236 + + +class TreeNode(object): + def __init__(self, x): + self.val = x + self.left = None + self.right = None + + +class Solution(object): + + def bsf(self, nodes): + if len(nodes) == 0: + return [] + vals = [] + temp = [] # 存储下一层 + tempvals = [] + for node in nodes: + if node.val is not None: + tempvals.append(node.val) + if node.left: + temp.append(node.left) + if node.right: + temp.append(node.right) + vals.append(tempvals) + children = self.bsf(temp) + if len(children) > 0: + vals = vals + children + return vals + + + def levelOrder(self, root): + """ + :type root: TreeNode + :rtype: List[List[int]] + """ + children = [root] + return self.bsf(children) + + +l = [3, 5, 1, 6, 2, 0, 8, None, None, 7, 4] +# l = [3, 9, 20, None, None, 15, 7] +if len(l): + r = TreeNode(l[0]) + week02.leetcode_236.buildtree([r], l[1:]) + solution = Solution() + print("------------------") + print("result:", solution.levelOrder(r)) + +# result: [[3], [5, 1], [6, 2, 0, 8], [7, 4]] +# result: [[3], [9, 20], [15, 7]] \ No newline at end of file diff --git a/Week_03/G20200343030633/leetcode_33.py b/Week_03/G20200343030633/leetcode_33.py new file mode 100644 index 00000000..bc34219f --- /dev/null +++ b/Week_03/G20200343030633/leetcode_33.py @@ -0,0 +1,21 @@ +class Solution: + def search(self, nums, target): + left, right = 0, len(nums) - 1 + while left < right: + mid = (left + right) // 2 + if nums[0] <= nums[mid] and (target > nums[mid] or target < nums[0]): + left = mid + 1 + elif nums[mid] < target < nums[0]: + left = mid + 1 + else: + right = mid + if left == right and nums[left] == target: + return left + else: + return -1 + + +array = [4, 5, 6, 7, 0, 1, 2, 3] +solution = Solution() +print(solution.search(array, 0)) + diff --git a/Week_03/G20200343030635/id_635/122.py b/Week_03/G20200343030635/id_635/122.py new file mode 100644 index 00000000..53a2e4b6 --- /dev/null +++ b/Week_03/G20200343030635/id_635/122.py @@ -0,0 +1,7 @@ +class Solution: + def maxProfit(self, prices: List[int]) -> int: + profit = 0 + for i in range(1, len(prices)): + tmp = prices[i] - prices[i - 1] + if tmp > 0: profit += tmp + return profit diff --git a/Week_03/G20200343030635/id_635/860.py b/Week_03/G20200343030635/id_635/860.py new file mode 100644 index 00000000..67dfcf0a --- /dev/null +++ b/Week_03/G20200343030635/id_635/860.py @@ -0,0 +1,21 @@ +class Solution(object): #aw + def lemonadeChange(self, bills): + five = ten = 0 + for bill in bills: + if bill == 5: + five += 1 + elif bill == 10: + if not five: return False + five -= 1 + ten += 1 + else: + if ten and five: + ten -= 1 + five -= 1 + elif five >= 3: + five -= 3 + else: + return False + return True + + diff --git a/Week_05/.DS_Store b/Week_05/.DS_Store new file mode 100644 index 00000000..d11df3a4 Binary files /dev/null and b/Week_05/.DS_Store differ diff --git a/Week_05/G20190282010007/NOTE.md b/Week_05/G20190282010007/NOTE.md index 50de3041..374830b0 100644 --- a/Week_05/G20190282010007/NOTE.md +++ b/Week_05/G20190282010007/NOTE.md @@ -1 +1,40 @@ -学习笔记 \ No newline at end of file +学习笔记 + +本周学习总结 + 动态规划不是特别懂,感觉就是数学归纳法 + 递归的综合运用,但是还没想出个所以然来。 + 关于递归倒是比以前理解的更深刻了一些。曾经对递归的认识,就是自己调用自己。这个解释的非常的浅,仅仅是一种 + 形式上的解释。老师的总结中的“重复子问题”这个词,更贴切的说明了递归。需要解决的问题是同样的或者是类似的, + 那么使用同一种(同一个)方法,就是理所当然的了,但是有一点不能搞错的是,即使是“自己调用自己”,其实也是 + 独立的。 + +动态规划篇 + 动态规划和递归、分治并没有根本上的区别(关键在于看是否有最优子结构) + 共性:找到重复子问题 + 差异性: 最优子结构、中途可以淘汰次优解 + +斐波拉契数列的第N项 + 公式: f(n) = f(n-1) + f(n-2) + + 暴力递归 + f(n) { + return n <= 1 ? n :f(n-1) + f(n-2) + } + + 优化解 + f (n, array:[]) { + if (n <= 1) { + return n + } + if (array[n] == 0) { + array[n] = array[n-1] + array[n-2] + } + return array[n] + } + + 优化解2 + a[0] = 0; + a[1] = 1; + for (i=2; i<=n; i++) { + a[i] = a[i-1] + a[i-2] + } + a[n] \ No newline at end of file diff --git a/Week_05/G20190282010007/leetcode_64_007.js b/Week_05/G20190282010007/leetcode_64_007.js new file mode 100644 index 00000000..a0aa23c1 --- /dev/null +++ b/Week_05/G20190282010007/leetcode_64_007.js @@ -0,0 +1,42 @@ +// 题目: 最小路径和 +/** + * 题目描述: +给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。 + +说明:每次只能向下或者向右移动一步。 + */ + +// 解题语言: javaScript + +// 解题 + +/** + * @param {number[][]} grid + * @return {number} + */ +var minPathSum = function (grid) { + let l = grid.length, h = grid[0].length; + let temp = []; + for (let i = 0; i < l; i++) { + temp[i] = []; + } + // console.log(temp) + for (let i = 0; i < l; i++) { + for (let j = 0; j < h; j++) { + if (i == 0 && j == 0) { + temp[i][j] = grid[i][j] + } + else if (i == 0) { + temp[i][j] = temp[i][j - 1] + grid[i][j] + } + else if (j == 0) { + temp[i][j] = temp[i - 1][j] + grid[i][j] + } + else { + temp[i][j] = grid[i][j] + Math.min(temp[i][j - 1], temp[i - 1][j]) + } + } + } + // console.log(temp) + return temp[l - 1][h - 1] +} \ No newline at end of file diff --git a/Week_05/G20190282010007/leetcode_91_007.js b/Week_05/G20190282010007/leetcode_91_007.js new file mode 100644 index 00000000..e6e67c68 --- /dev/null +++ b/Week_05/G20190282010007/leetcode_91_007.js @@ -0,0 +1,42 @@ +// 题目: 解码方法 +/** + * 题目描述: +一条包含字母 A-Z 的消息通过以下方式进行了编码: + +'A' -> 1 +'B' -> 2 +... +'Z' -> 26 +给定一个只包含数字的非空字符串,请计算解码方法的总数。 + + */ + + // 解题语言: javaScript + + // 解题 + +/** + * @param {string} s + * @return {number} + */ +var numDecodings = function(s) { + if(s[0] == "0") return 0; + let dp = [1, 1], len = s.length; + for(let i=1; i < len; ++i) { + if(s[i - 1] != "0") { + let num = (s[i - 1] + s[i] | 0); + if(num >= 1 && num <= 26) { + dp[i + 1] = s[i] != "0"? dp[i - 1] + dp[i]: dp[i - 1]; + } else if(s[i] != "0") { + dp[i + 1] = dp[i]; + } else { + return 0; + } + } else if(s[i] != "0") { + dp[i + 1] = dp[i]; + } else { + return 0; + } + } + return dp[len]; +} \ No newline at end of file diff --git a/Week_05/G20190343010191/LeetCode_221_191.py b/Week_05/G20190343010191/LeetCode_221_191.py new file mode 100644 index 00000000..5731b36b --- /dev/null +++ b/Week_05/G20190343010191/LeetCode_221_191.py @@ -0,0 +1,42 @@ +""" +221. Maximal Square +Given a 2D binary matrix filled with 0's and 1's, find the largest square containing only 1's and return its area. + +Example: + +Input: + +1 0 1 0 0 +1 0 1 1 1 +1 1 1 1 1 +1 0 0 1 0 + +Output: 4 + + +""" + +class Solution(object): + def maximalSquare(self, matrix): + if (not matrix) or (not matrix[0]): + return 0 + n = len(matrix) + m = len(matrix[0]) + widths = [0] * n + k = 0 + for j in range(0, m): + max_continous_k = 0 + continous_k = 0 + for i in range(0, n): + if matrix[i][j] == '1': + widths[i] += 1 + else: + widths[i] = 0 + if widths[i] > k: + continous_k += 1 + max_continous_k = max(continous_k, max_continous_k) + else: + continous_k = 0 + if max_continous_k > k: + k += 1 + return k * k \ No newline at end of file diff --git a/Week_05/G20190343010191/LeetCode_621_191.py b/Week_05/G20190343010191/LeetCode_621_191.py new file mode 100644 index 00000000..4e3fd1ec --- /dev/null +++ b/Week_05/G20190343010191/LeetCode_621_191.py @@ -0,0 +1,30 @@ +""" +Given a char array representing tasks CPU need to do. It contains capital letters A to Z where different letters represent different tasks. Tasks could be done without original order. Each task could be done in one interval. For each interval, CPU could finish one task or just be idle. + +However, there is a non-negative cooling interval n that means between two same tasks, there must be at least n intervals that CPU are doing different tasks or just be idle. + +You need to return the least number of intervals the CPU will take to finish all the given tasks. + + + +Example: + +Input: tasks = ["A","A","A","B","B","B"], n = 2 +Output: 8 +Explanation: A -> B -> idle -> A -> B -> idle -> A -> B. + + +Note: + +The number of tasks is in the range [1, 10000]. +The integer n is in the range [0, 100]. + +""" +class Solution(object): + def leastInterval(self, tasks, n): + c = collections.defaultdict(int) + for t in tasks: + c[t] += 1 + m = max(c.values()) + l = len([k for k in c if c[k] == m]) + return max(len(tasks), (m - 1) * (n + 1) + l) \ No newline at end of file diff --git a/Week_05/G20190343010191/LeetCode_64_191.py b/Week_05/G20190343010191/LeetCode_64_191.py new file mode 100644 index 00000000..92c227a4 --- /dev/null +++ b/Week_05/G20190343010191/LeetCode_64_191.py @@ -0,0 +1,45 @@ +""" +Given a m x n grid filled with non-negative numbers, find a path from top left to bottom right which minimizes the sum of all numbers along its path. + +Note: You can only move either down or right at any point in time. + +Example: + +Input: +[ + [1,3,1], + [1,5,1], + [4,2,1] +] +Output: 7 +Explanation: Because the path 1→3→1→1→1 minimizes the sum. + +""" + +class Solution1: + def minPathSum(self, grid: [[int]]) -> int: + for i in range(len(grid)): + for j in range(len(grid[0])): + if i == j == 0: continue + elif i == 0: grid[i][j] = grid[i][j - 1] + grid[i][j] + elif j == 0: grid[i][j] = grid[i - 1][j] + grid[i][j] + else: grid[i][j] = min(grid[i - 1][j], grid[i][j - 1]) + grid[i][j] + return grid[-1][-1] + + + +class Solution2: + def minPathSum(self, grid): + if not grid: + return + r, c = len(grid), len(grid[0]) + cur = [0] * c + cur[0] = grid[0][0] + for i in range(1, c): + cur[i] = cur[i-1] + grid[0][i] + for i in range(1, r): + cur[0] += grid[i][0] + for j in range(1, c): + cur[j] = min(cur[j-1], cur[j]) + grid[i][j] + return cur[-1] + diff --git a/Week_05/G20190343010191/LeetCode_91_191.py b/Week_05/G20190343010191/LeetCode_91_191.py new file mode 100644 index 00000000..14870608 --- /dev/null +++ b/Week_05/G20190343010191/LeetCode_91_191.py @@ -0,0 +1,64 @@ +""" +A message containing letters from A-Z is being encoded to numbers using the following mapping: + +'A' -> 1 +'B' -> 2 +... +'Z' -> 26 +Given a non-empty string containing only digits, determine the total number of ways to decode it. + +Example 1: + +Input: "12" +Output: 2 +Explanation: It could be decoded as "AB" (1 2) or "L" (12). +Example 2: + +Input: "226" +Output: 3 +Explanation: It could be decoded as "BZ" (2 26), "VF" (22 6), or "BBF" (2 2 6). +""" + +class Solution: + def numDecodings(self, s: str) -> int: + n=len(s) + if(not s or s[0]=="0"): + return 0 + pre=1 + cur=1 + for i in range(1,n): + if(s[i]=="0"): + if(s[i-1]=="1" or s[i-1]=="2"): + cur=pre + else: + return 0 + else: + if(s[i-1]=="1" or (s[i-1]=="2" and "1"<=s[i]<="6")): + tmp=cur + cur+=pre + pre=tmp + else: + pre=cur + cur=cur + return cur + +class Solution2: + def numDecodings(self, s: str) -> int: + n=len(s) + if(not s or s[0]=="0"): + return 0 + dp=[0]*(n+1) + dp[0]=1 + dp[1]=1 + for i in range(1,n): + if(s[i]=="0"): + if(s[i-1]=="1" or s[i-1]=="2"): + dp[i+1]=dp[i-1] + else: + return 0 + else: + if(s[i-1]=="1" or (s[i-1]=="2" and "1"<=s[i]<="6")): + dp[i+1]=dp[i]+dp[i-1] + else: + dp[i+1]=dp[i] + return dp[-1] diff --git a/Week_05/G20190379010083/LeetCode_062_083.swift b/Week_05/G20190379010083/LeetCode_062_083.swift new file mode 100644 index 00000000..f0a4d040 --- /dev/null +++ b/Week_05/G20190379010083/LeetCode_062_083.swift @@ -0,0 +1,38 @@ +// +// 0062_UniquePaths.swift +// AlgorithmPractice +// +// https://leetcode-cn.com/problems/unique-paths/ +// 第一遍总结: +// 可以像uniquePaths ii那样创建一个m+1,n+1的数组,这样代码更简洁 +// Created by Ryeagler on 2020/3/15. +// Copyright © 2020 Ryeagle. All rights reserved. +// + +import Foundation + +class UniquePaths { + func uniquePaths(_ row: Int, _ column: Int) -> Int { + var dp = [[Int]](repeating: [Int](repeating: 0, count: column), count: row) + for i in 0.. Int { + var dp = [[Int]](repeating: [Int](repeating: 0, count: n + 1), count: m + 1) + dp[0][1] = 1 + for i in 1...m { + for j in 1...n { + dp[i][j] = dp[i - 1][j] + dp[i][j - 1] + } + } + return dp[m][n] + } +} diff --git a/Week_05/G20190379010083/LeetCode_063_083.swift b/Week_05/G20190379010083/LeetCode_063_083.swift new file mode 100644 index 00000000..f2e64439 --- /dev/null +++ b/Week_05/G20190379010083/LeetCode_063_083.swift @@ -0,0 +1,32 @@ +// +// 0063_UniquePathsII.swift +// AlgorithmPractice +// +// https://leetcode-cn.com/problems/unique-paths-ii/ +// 第一遍总结: +// 1、创建一个m+1与n+1的数组,且dp[0][1] = 1 +// 2、遇到障碍物0,则不进行动态递推 +// Created by Ryeagler on 2020/3/15. +// Copyright © 2020 Ryeagle. All rights reserved. +// + +import Foundation + +class UniquePathsII { + func uniquePathsWithObstacles(_ obstacleGrid: [[Int]]) -> Int { + if obstacleGrid.count == 0 || obstacleGrid[0].count == 0 { + return 0 + } + let row = obstacleGrid.count, column = obstacleGrid[0].count + var dp = [[Int]](repeating: [Int](repeating: 0, count: column + 1), count: row + 1) + dp[0][1] = 1 + for i in 1...row { + for j in 1...column { + if obstacleGrid[i - 1][j - 1] == 0 { + dp[i][j] = dp[i - 1][j] + dp[i][j - 1] + } + } + } + return dp[row][column] + } +} diff --git a/Week_05/G20190379010083/LeetCode_198_083.swift b/Week_05/G20190379010083/LeetCode_198_083.swift new file mode 100644 index 00000000..63790f58 --- /dev/null +++ b/Week_05/G20190379010083/LeetCode_198_083.swift @@ -0,0 +1,27 @@ +// +// 0198_HouseRobber.swift +// AlgorithmPractice +// +// https://leetcode-cn.com/problems/house-robber/ +// 第一遍总结: +// 创建一个count + 1的数组,省去之前的一些判断条件 +// Created by Ryeagler on 2020/3/15. +// Copyright © 2020 Ryeagle. All rights reserved. +// + +import Foundation + +class HouseRobber { + func rob(_ nums: [Int]) -> Int { + if nums.count == 0 { + return 0 + } + var dp = [Int](repeating: 0, count: nums.count + 1) + dp[0] = 0 + dp[1] = nums[0] + for i in 1..= 0; i--) { + for (int j = grid[0].length - 1; j >= 0; j--) { + if(i == grid.length - 1 && j != grid[0].length - 1) { + grid[i][j] = grid[i][j] + grid[i][j + 1]; + } else if(j == grid[0].length - 1 && i != grid.length - 1) { + grid[i][j] = grid[i][j] + grid[i + 1][j]; + } else if(j != grid[0].length - 1 && i != grid.length - 1) { + grid[i][j] = grid[i][j] + Math.min(grid[i + 1][j],grid[i][j + 1]); + } + } + } + + return grid[0][0]; + } +} diff --git a/Week_05/G20200343030001/Leetcode_091_001.java b/Week_05/G20200343030001/Leetcode_091_001.java new file mode 100644 index 00000000..ff3a8476 --- /dev/null +++ b/Week_05/G20200343030001/Leetcode_091_001.java @@ -0,0 +1,22 @@ +package Week_05; + +public class Leetcode_091_001 { + public int numDecodings(String s) { + if(s.length() == 0 || s.charAt(0) == '0') { + return 0; + } + + int[] dp = new int[s.length() + 1]; + dp[0] = 1; + + for(int i = 0; i < s.length(); i++){ + dp[i + 1] = s.charAt(i) == '0' ? 0 : dp[i]; + + if(i > 0 && (s.charAt(i - 1) == '1' || (s.charAt(i - 1) == '2' && s.charAt(i) <= '6'))){ + dp[i + 1] += dp[i - 1]; + } + } + + return dp[s.length()]; + } +} diff --git a/Week_05/G20200343030001/Leetcode_621_001.java b/Week_05/G20200343030001/Leetcode_621_001.java new file mode 100644 index 00000000..24bab807 --- /dev/null +++ b/Week_05/G20200343030001/Leetcode_621_001.java @@ -0,0 +1,28 @@ +package Week_05; + +import java.util.Arrays; + +public class Leetcode_621_001 { + class Solution { + public int leastInterval(char[] tasks, int n) { + int[] count = new int[26]; + + for (int i = 0; i < tasks.length; i++) { + count[tasks[i] - 'A']++; + } + + Arrays.sort(count); + int maxCount = 0; + + for (int i = 25; i >= 0; i--) { + if(count[i] != count[25]){ + break; + } + maxCount++; + } + + return Math.max((count[25] - 1) * (n + 1) + maxCount , tasks.length); + } + } + +} diff --git a/Week_05/G20200343030001/Leetcode_647_001.java b/Week_05/G20200343030001/Leetcode_647_001.java new file mode 100644 index 00000000..3c0611ec --- /dev/null +++ b/Week_05/G20200343030001/Leetcode_647_001.java @@ -0,0 +1,22 @@ +package Week_05; + +public class Leetcode_647_001 { + private int num = 0; + + public int countSubstrings(String s) { + for (int i = 0; i < s.length(); i++){ + count(s, i, i); + count(s, i, i + 1); + } + + return num; + } + + private void count(String s, int start, int end){ + while(start >= 0 && end < s.length() && s.charAt(start) == s.charAt(end)){ + num++; + start--; + end++; + } + } +} diff --git a/Week_05/G20200343030005/Leetcode_647_001.js b/Week_05/G20200343030005/Leetcode_647_001.js new file mode 100644 index 00000000..19d68e89 --- /dev/null +++ b/Week_05/G20200343030005/Leetcode_647_001.js @@ -0,0 +1,25 @@ +// 647. 回文子串 https://leetcode-cn.com/problems/palindromic-substrings/ + +/** + * @param {string} s + * @return {number} + */ +var countSubstrings = function(s) { + let s2 = s + .split("") + .reverse() + .join(""); + let sum = 0; + const len = s.length; + for (let i = 0; i < len; i++) { + for (let j = i + 1; j <= len; j++) { + if (s.substr(i, j - i) === s2.substr(len - j, j - i)) { + sum += 1; + } + } + } + return sum; +}; +var str = "abc"; +var str = "aaa"; +console.log(countSubstrings(str)); diff --git a/Week_05/G20200343030005/Leetcode_91_001.js b/Week_05/G20200343030005/Leetcode_91_001.js new file mode 100644 index 00000000..daa2d37c --- /dev/null +++ b/Week_05/G20200343030005/Leetcode_91_001.js @@ -0,0 +1,26 @@ +// 91. 解码方法 https://leetcode-cn.com/problems/decode-ways/ + +/** + * @param {string} s + * @return {number} + */ +var numDecodings = function(s) { + if (s[0] == 0) { + return 0; + } + let n = s.length; + let dp = new Array(n + 1).fill(0); + dp[0] = dp[1] = 1; + for (let i = 2; i <= n; i++) { + if (s[i - 1] != 0) { + dp[i] += dp[i - 1]; + } + if (s[i - 2] == 1 || (s[i - 2] == 2 && s[i - 1] <= 6)) { + dp[i] += dp[i - 2]; + } + } + return dp[n]; +}; +var str = "12"; +var str = "226"; +console.log(numDecodings(str)); diff --git a/Week_05/G20200343030007/Leetcode_007_64.java b/Week_05/G20200343030007/Leetcode_007_64.java new file mode 100644 index 00000000..8740c21d --- /dev/null +++ b/Week_05/G20200343030007/Leetcode_007_64.java @@ -0,0 +1,18 @@ +public class Solution { + public int minPathSum(int[][] grid) { + int[][] dp = new int[grid.length][grid[0].length]; + for (int i = grid.length - 1; i >= 0; i--) { + for (int j = grid[0].length - 1; j >= 0; j--) { + if(i == grid.length - 1 && j != grid[0].length - 1) + dp[i][j] = grid[i][j] + dp[i][j + 1]; + else if(j == grid[0].length - 1 && i != grid.length - 1) + dp[i][j] = grid[i][j] + dp[i + 1][j]; + else if(j != grid[0].length - 1 && i != grid.length - 1) + dp[i][j] = grid[i][j] + Math.min(dp[i + 1][j], dp[i][j + 1]); + else + dp[i][j] = grid[i][j]; + } + } + return dp[0][0]; + } +} diff --git a/Week_05/G20200343030007/Leetcode_007_91.java b/Week_05/G20200343030007/Leetcode_007_91.java new file mode 100644 index 00000000..36ef8210 --- /dev/null +++ b/Week_05/G20200343030007/Leetcode_007_91.java @@ -0,0 +1,29 @@ + public class Solution { + public int numDecodings(String s) { + if (s == null || s.length() == 0) { + return 0; + } + int len = s.length(); + + int help = 1; + int res = 0; + if (s.charAt(len - 1) != '0') { + res = 1; + } + for (int i = len - 2; i >= 0; i--) { + if (s.charAt(i) == '0') { + help = res; + res = 0; + continue; + } + if ((s.charAt(i) - '0') * 10 + (s.charAt(i + 1) - '0') <= 26) { + res += help; + help = res-help; + } else { + help = res; + } + + } + return res; + } + } diff --git a/Week_05/G20200343030009/LeetCode_221_009.js b/Week_05/G20200343030009/LeetCode_221_009.js new file mode 100644 index 00000000..904735c8 --- /dev/null +++ b/Week_05/G20200343030009/LeetCode_221_009.js @@ -0,0 +1,44 @@ +/* + 221. 最大正方形 + 难度: 中等 + 在一个由 0 和 1 组成的二维矩阵内,找到只包含 1 的最大正方形,并返回其面积。 + + 示例: + 输入: + 1 0 1 0 0 + 1 0 1 1 1 + 1 1 1 1 1 + 1 0 0 1 0 + 输出: 4 +*/ +/** + * @param {character[][]} matrix + * @return {number} + */ +var maximalSquare = function(matrix) { + // 1. 重复性(分治) problem[i][j] = + // 2. 定义状态数组 + // 3. DP方程 dp(i, j) = min(dp(i−1, j), dp(i−1, j−1), dp(i, j−1)) + 1 + let rows = matrix.length, cols = rows > 0 ? matrix[0].length : 0 + // 初始化状态数组(二维),每个元素为0, 用于之后的Math.min计算,否则二维数组默认元素为undefined,得到结果为NaN + let dp = [] + for (let i = 0; i <= rows; i++) { + dp[i] = [] + } + for (let i = 0; i <= rows; i++) { + for (let j = 0; j <= cols; j++) { + dp[i][j] = 0 + } + } + + let maxslen = 0 + for (let i = 1; i <= rows; i++) { + for (let j = 1; j <= cols; j++) { + if (matrix[i-1][j-1] === '1') { + dp[i][j] = Math.min(Math.min(dp[i-1][j], dp[i][j-1]), dp[i-1][j-1]) + 1 + maxslen = Math.max(maxslen, dp[i][j]) + } + } + } + return maxslen * maxslen +}; \ No newline at end of file diff --git a/Week_05/G20200343030009/LeetCode_64_009.js b/Week_05/G20200343030009/LeetCode_64_009.js new file mode 100644 index 00000000..a288f90f --- /dev/null +++ b/Week_05/G20200343030009/LeetCode_64_009.js @@ -0,0 +1,36 @@ +/* + 64. 最小路径和 + 难度:简单 + 给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。 + 说明:每次只能向下或者向右移动一步。 + + 示例: + 输入: + [ + [1,3,1], + [1,5,1], + [4,2,1] + ] + 输出: 7 + 解释: 因为路径 1→3→1→1→1 的总和最小。 +*/ +var minPathSum = function(grid) { + // 1. 重复性(分治) problem[i][j] = grid[i, j] + min(problem(i-1, j), problem(i, j-1)) + // 2. 定义状态数组 f[i, j] + // 3. DP方程 dp[i][j] = dp[i][j] + min(dp[i-1][j], dp[i][j-1]) + + if (!grid.length) return 0 + let dp = [] + for (let i = 0; i < grid.length; i++) { + dp[i] = [] + } + for (let i = 0; i < grid.length; i++) { + for (let j = 0; j < grid[0].length; j++) { + if (i === 0 && j === 0) dp[i][j] = grid[i][j] // 起点 + else if (i === 0) dp[i][j] = dp[i][j-1] + grid[i][j] // 最上面一行 + else if (j === 0) dp[i][j] = dp[i-1][j] + grid[i][j] // 最左边一列 + else dp[i][j] = Math.min(dp[i][j-1], dp[i-1][j]) + grid[i][j] // DP方程 + } + } + return dp[dp.length-1][dp[0].length-1] +}; \ No newline at end of file diff --git a/Week_05/G20200343030015/LeetCode_64_015.java b/Week_05/G20200343030015/LeetCode_64_015.java new file mode 100644 index 00000000..faec1547 --- /dev/null +++ b/Week_05/G20200343030015/LeetCode_64_015.java @@ -0,0 +1,29 @@ +package G20200343030015.week_05; + +/** + * Created by majiancheng on 2020/3/15. + * + * 64. 最小路径和 + * + * 给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。 + + 说明:每次只能向下或者向右移动一步。 + */ +public class LeetCode_64_015 { + public int minPathSum(int[][] grid) { + for(int i = 0; i < grid.length; i++) { + for(int j = 0; j < grid[0].length; j++) { + if(i == 0 && j == 0) { + continue; + } else if(i == 0) { + grid[i][j] = grid[i][j - 1] + grid[i][j]; + } else if(j == 0) { + grid[i][j] = grid[i - 1][j] + grid[i][j]; + } else { + grid[i][j] = Math.min(grid[i - 1][j], grid[i][j - 1]) + grid[i][j]; + } + } + } + return grid[grid.length - 1][grid[0].length - 1]; + } +} diff --git a/Week_05/G20200343030015/LeetCode_91_015.java b/Week_05/G20200343030015/LeetCode_91_015.java new file mode 100644 index 00000000..1b80c097 --- /dev/null +++ b/Week_05/G20200343030015/LeetCode_91_015.java @@ -0,0 +1,39 @@ +package G20200343030015.week_05; + +/** + * Created by majiancheng on 2020/3/15. + * + * 91. 解码方法 + * + * 一条包含字母 A-Z 的消息通过以下方式进行了编码: + */ +public class LeetCode_91_015 { + public int numDecodings(String s) { + if (s == null || s.length() == 0) { + return 0; + } + int len = s.length(); + + int help = 1; + int res = 0; + if (s.charAt(len - 1) != '0') { + res = 1; + } + for (int i = len - 2; i >= 0; i--) { + if (s.charAt(i) == '0') { + help = res; + res = 0; + continue; + } + if ((s.charAt(i) - '0') * 10 + (s.charAt(i + 1) - '0') <= 26) { + res += help; + //help用来存储res以前的值 + help = res-help; + } else { + help = res; + } + + } + return res; + } +} diff --git a/Week_05/G20200343030017/aaa.txt b/Week_05/G20200343030017/aaa.txt new file mode 100644 index 00000000..5c1d5ab8 --- /dev/null +++ b/Week_05/G20200343030017/aaa.txt @@ -0,0 +1,6 @@ + +动态规划果然名声在外啊,真的难,看着题解都搞不懂的难。 +动态规划最重要的就是想出状态方程,然后就循环+照抄状态方程就行了 +中等难度的问题很容易想,可以画个图帮助理解 +但是困难问题真的已经在知识体系之外了,比如编辑距离,真的想不到,百度了下,发现是有统一算法的,那就很简单了。 +但是还是有大量问题看着都看不懂,只能一遍遍的看了。 \ No newline at end of file diff --git a/Week_05/G20200343030017/decode_ways/Solution.java b/Week_05/G20200343030017/decode_ways/Solution.java new file mode 100644 index 00000000..ea92c7ed --- /dev/null +++ b/Week_05/G20200343030017/decode_ways/Solution.java @@ -0,0 +1,29 @@ +package week5.decode_ways; + +public class Solution { + // a[n]=a[n-1]+a[n-2] (1<26) + // a[n]=a[n-1] (>26) + public int numDecodings(String s) { + if (s.length()==0) return 0; + int[] sum = new int[s.length()+1]; + sum[0]=1; + sum[1]=s.charAt(0)!='0'?1:0; + for (int n=2;n<=s.length();n++){ + String t = s.substring(n-1,n); + String pre = s.substring(n-2,n); + if (Integer.valueOf(t)>0){ + sum[n]=sum[n]+sum[n-1]; + } + if (Integer.valueOf(pre)>=10&&Integer.valueOf(pre)<27){ + sum[n]=sum[n]+sum[n-2]; + } + } + return sum[s.length()]; + } + + public static void main(String[] args) { + String aaa = "226"; + Solution s = new Solution(); + System.out.println(s.numDecodings(aaa)); + } +} diff --git a/Week_05/G20200343030017/edit_distance/Solution.java b/Week_05/G20200343030017/edit_distance/Solution.java new file mode 100644 index 00000000..42ec6299 --- /dev/null +++ b/Week_05/G20200343030017/edit_distance/Solution.java @@ -0,0 +1,41 @@ +package week5.edit_distance; + +public class Solution { + //dp(i,j)=min(dp(i-1,j),dp(i,j-1),dp(i-1,j-1))+d + + public int minDistance(String word1, String word2) { + int l1 = word1.length(); + int l2 = word2.length(); + if (l1==0) return l2; + if (l2==0) return l1; + + int[][] dp = new int[l1+1][l2+1]; + // inital + dp[0][0] = 0; + for (int n=0;n stack = new Stack<>(); + stack.push(-1); + for (int n=0;n=0&&right=0&&right map = new HashMap<>(); + int max = 0; + for (char a:tasks){ + if (map.containsKey(a)){ + map.put(a,map.get(a)+1); + }else{ + map.put(a,1); + } + max=Math.max(map.get(a),max); + } + int time = (max-1)*(n+1); + + for (Character key:map.keySet()){ + int value = map.get(key); + if (value==max){ + time=time+1; + } + } + return Math.max(time,tasks.length); + } + + public static void main(String[] args) { + char[] tasks = {'A','A','A','B','B','B'}; + int n = 50; + Solution s = new Solution(); + System.out.println(s.leastInterval(tasks,n)); + } +} diff --git a/Week_05/G20200343030019/LeetCode_221_019.java b/Week_05/G20200343030019/LeetCode_221_019.java new file mode 100644 index 00000000..49479824 --- /dev/null +++ b/Week_05/G20200343030019/LeetCode_221_019.java @@ -0,0 +1,21 @@ +class Solution { + public int maximalSquare(char[][] matrix) { + if (matrix == null || matrix.length <= 0) return 0; + int[] arr = new int[matrix[0].length + 1]; + int max = 0; + int pre = 0; + for (int i = 1; i <= matrix.length; i ++) { + for (int j = 1; j <= matrix[0].length; j ++) { + int temp = arr[j]; + if (matrix[i - 1][j - 1] != '1') { + arr[j] = 0; + continue; + } + arr[j] = 1 + Math.min(Math.min(arr[j - 1], pre), arr[j]); + if (arr[j] > max) max = Math.max(arr[j], max); + pre = temp; + } + } + return max * max; + } +} \ No newline at end of file diff --git a/Week_05/G20200343030019/LeetCode_32_019.java b/Week_05/G20200343030019/LeetCode_32_019.java new file mode 100644 index 00000000..02d8f0a4 --- /dev/null +++ b/Week_05/G20200343030019/LeetCode_32_019.java @@ -0,0 +1,19 @@ +class Solution { + public int longestValidParentheses(String s) { + int[] arr = new int[s.length()]; + int right = 0; + int max = 0; + int cur = 0; + for (int index = 1; index < s.length(); index ++) { + if (s.charAt(index) == ')') { + if (s.charAt(index - 1) == '(') { + arr[index] = 2 + (index > 1 ? arr[index - 2] : 0); + } else if (index - 1 - arr[index - 1] >= 0 && s.charAt(index - 1 - arr[index - 1]) == '(') { + arr[index] = 2 + arr[index - 1] + (index - 2 - arr[index - 1] > 0 ? arr[index - 2 - arr[index - 1]] : 0); + } + max = Math.max(max, arr[index]); + } + } + return max; + } +} \ No newline at end of file diff --git a/Week_05/G20200343030019/LeetCode_621_019.java b/Week_05/G20200343030019/LeetCode_621_019.java new file mode 100644 index 00000000..44fbc14d --- /dev/null +++ b/Week_05/G20200343030019/LeetCode_621_019.java @@ -0,0 +1,15 @@ +class Solution { + public int leastInterval(char[] tasks, int n) { + int[] arr = new int[26]; + for (char c: tasks) { + arr[c - 'A'] ++; + } + Arrays.sort(arr); + int max_val = arr[25] - 1; + int all_space = max_val * n; + for (int i = 24; i >= 0; i --) { + all_space -= Math.min(arr[i], max_val); + } + return all_space > 0 ? tasks.length + all_space : tasks.length; + } +} \ No newline at end of file diff --git a/Week_05/G20200343030019/LeetCode_647_019.java b/Week_05/G20200343030019/LeetCode_647_019.java new file mode 100644 index 00000000..221fca16 --- /dev/null +++ b/Week_05/G20200343030019/LeetCode_647_019.java @@ -0,0 +1,23 @@ +class Solution { + public int countSubstrings(String s) { + if (s == null || s.length() <= 0) return 0; + int[] arr = new int[s.length()]; + char[] carr = s.toCharArray(); + arr[0] = 1; + for (int i = 1; i < s.length(); i ++) { + arr[i] = 1 + arr[i - 1]; + for (int j = 0; j < i; j ++) { + int lo = j, hi = i; + while (lo < hi) { + if (carr[lo] == carr[hi]) { + lo ++; hi --; + } else { + break; + } + } + if (lo >= hi) arr[i] += 1; + } + } + return arr[arr.length - 1]; + } +} \ No newline at end of file diff --git a/Week_05/G20200343030019/LeetCode_64_019.java b/Week_05/G20200343030019/LeetCode_64_019.java new file mode 100644 index 00000000..d6e61253 --- /dev/null +++ b/Week_05/G20200343030019/LeetCode_64_019.java @@ -0,0 +1,22 @@ +class Solution { + public int minPathSum(int[][] grid) { + int[] dp = new int[grid[0].length + 1]; + dp[grid[0].length] = Integer.MAX_VALUE; + for (int j = dp.length - 2, i = grid.length - 1; j >= 0; j --) { + if (i == grid.length - 1) { + if (j == dp.length - 2) { + dp[j] = grid[i][j]; + continue; + } + dp[j] = grid[i][j] + dp[j + 1]; + continue; + } + } + for (int i = grid.length - 2; i >= 0; i --) { + for (int j = dp.length - 2; j >= 0; j --) { + dp[j] = grid[i][j] + Math.min(dp[j], dp[j + 1]); + } + } + return dp[0]; + } +} \ No newline at end of file diff --git a/Week_05/G20200343030019/LeetCode_72_019.java b/Week_05/G20200343030019/LeetCode_72_019.java new file mode 100644 index 00000000..9158bd1d --- /dev/null +++ b/Week_05/G20200343030019/LeetCode_72_019.java @@ -0,0 +1,22 @@ +class Solution { + public int minDistance(String word1, String word2) { + if (word1 == null || word1.length() ==0) return word2 != null ? word2.length() : 0; + if (word2 == null || word2.length() ==0) return word1 != null ? word1.length() : 0; + int[] arr = new int[word2.length() + 1]; + char[] w1 = word1.toCharArray(); + char[] w2 = word2.toCharArray(); + for (int i = 1; i <= w2.length; i ++) arr[i] = i; + int pre = 0; + int temp = 0; + for (int i = 1; i <= w1.length; i ++) { + pre = arr[0]; + arr[0] = i; + for (int j = 1; j <= w2.length; j ++) { + temp = arr[j]; + arr[j] = w1[i - 1] == w2[j - 1] ? pre : Math.min(Math.min(pre, arr[j]), arr[j - 1]) + 1; + pre = temp; + } + } + return arr[w2.length]; + } +} \ No newline at end of file diff --git a/Week_05/G20200343030019/LeetCode_91_019.java b/Week_05/G20200343030019/LeetCode_91_019.java new file mode 100644 index 00000000..49204fab --- /dev/null +++ b/Week_05/G20200343030019/LeetCode_91_019.java @@ -0,0 +1,16 @@ +class Solution { + public int numDecodings(String s) { + if (s.charAt(0) == '0') return 0; + char[] arr = s.toCharArray(); + int[] nums = new int[s.length() + 1]; + nums[0] = 1; + nums[1] = 1; + for (int index = 2; index <= s.length(); index ++) { + if (arr[index - 1] > '0') + nums[index] = nums[index - 1]; + if ((arr[index - 2] <= '2' && arr[index - 2] > '0') && !(arr[index - 1] > '6' && arr[index - 2] == '2' )) + nums[index] += nums[index - 2]; + } + return nums[s.length()]; + } +} \ No newline at end of file diff --git a/Week_05/G20200343030021/LeetCode_64_021.java b/Week_05/G20200343030021/LeetCode_64_021.java new file mode 100644 index 00000000..290e5dc8 --- /dev/null +++ b/Week_05/G20200343030021/LeetCode_64_021.java @@ -0,0 +1,57 @@ +package dynamicprogramming; + +/** + * #### [64. 最小路径和](https://leetcode-cn.com/problems/minimum-path-sum/) + * 动态规划 + * 1.重复性 f(i,j) = min(f(i-1,j),f(i,j-1)) + f(i,j) + * 2.定义状态函数 f(i,j) 表示当前位置 和为最小 + * 3.DP方程:F[i,j] = min(F[i-1,j],F[i,j-1])+F[i,j] + */ +public class MinimumPathSum { + // 注意点:最左侧和最上侧 + public int minPathSum(int[][] grid) { + for (int i = 0; i < grid.length; i++) { + for (int j = 0; j < grid[0].length; j++) { + if (i == 0 && j == 0) continue; +// 左侧所有的最小和 + else if (i == 0) grid[i][j] = grid[i][j - 1] + grid[i][j]; +// 右侧所有的最小和 + else if (j == 0) grid[i][j] = grid[i - 1][j] + grid[i][j]; + else grid[i][j] = Math.min(grid[i - 1][j], grid[i][j - 1]) + grid[i][j]; + } + } + return grid[grid.length - 1][grid[0].length - 1]; + } + + //使用一维数组空间 + public int minPathSum2(int[][] grid) { + int[] ints = new int[grid[0].length]; + + for (int i = 0; i < grid.length; i++) { + for (int j = 0; j < grid[0].length; j++) { + if (j == 0) ints[j] = ints[j] + grid[i][j]; + else if (i == 0) ints[j] = ints[j - 1] + grid[i][j]; + else ints[j] = Math.min(ints[j], ints[j - 1]) + grid[i][j]; + } + } + return ints[grid[0].length - 1]; + } + + + // 暴力递归 + public int minPathSum3(int[][] grid) { + return calculate(grid, 0, 0); + } + + private int calculate(int[][] grid, int i, int j) { + if (i == grid.length || j == grid[0].length) { + return Integer.MAX_VALUE; + } +// 递归终止条件 + if (i == grid.length - 1 && j == grid[0].length - 1) { + return grid[i][j]; + } +// 当期层逻辑,下探下一层 + return Math.min(calculate(grid, i + 1, j), calculate(grid, i, j + 1)) + grid[i][j]; + } +} diff --git a/Week_05/G20200343030021/LeetCode_91_021.java b/Week_05/G20200343030021/LeetCode_91_021.java new file mode 100644 index 00000000..c12be278 --- /dev/null +++ b/Week_05/G20200343030021/LeetCode_91_021.java @@ -0,0 +1,43 @@ +package dynamicprogramming; + +/** + * #### [91. 解码方法](https://leetcode-cn.com/problems/decode-ways/) + * 动态规划 从后向前 + * 1.重复性 爬楼梯问题,当前情况数 = 当前后一位 + 后两位的情况 + * 2.定义状态 dp[i] 标明当前情况数 + * 3.DP方程 dp[i] = dp[i + 1] + dp[i + 2] + * + * 注意点:特情判断 + */ +public class DecodeWays { + + public int numDecodings(String s) { + int len = s.length(); + if (s == null || len == 0) { + return 0; + } + int[] dp = new int[len + 1]; + dp[len] = 1; + if (s.charAt(len - 1) == '0') { + dp[len - 1] = 0; + } else { + dp[len - 1] = 1; + } + + for (int i = len - 2; i >= 0; i--) { +// 特殊情况 为 0 时 + if (s.charAt(i) == '0') { + dp[i] = 0; + continue; + } +// 特殊情况 一位和两位的情况 + if ((s.charAt(i) - '0') * 10 + (s.charAt(i + 1) - '0') <= 26) { + dp[i] = dp[i + 1] + dp[i + 2]; + } else { + dp[i] = dp[i + 1]; + } + } + return dp[0]; + } + +} diff --git a/Week_05/G20200343030025/LeetCode_1_025.java b/Week_05/G20200343030025/LeetCode_1_025.java new file mode 100644 index 00000000..99f47a2f --- /dev/null +++ b/Week_05/G20200343030025/LeetCode_1_025.java @@ -0,0 +1,38 @@ +/** + * 64. 最小路径和 + * 给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。 + * + * 说明:每次只能向下或者向右移动一步。 + * + * 示例: + * + * 输入: + * [ + * [1,3,1], + * [1,5,1], + * [4,2,1] + * ] + * 输出: 7 + * 解释: 因为路径 1→3→1→1→1 的总和最小。 + */ +public class LeetCode_1_025 { + + // a. 最优子结构:opt[i,j] = Math.min(opt[i-1, j],opt[i,j-1]) + a[i,j] + // b. 状态空间 opt[i,j] + // c. DP 方程 f[i,j] = Math.min(f[i-1, j],f[i,j-1]) + a[i,j] + + public int minPathSum(int[][] grid) { + for (int i = 0; i < grid.length; i++) { + for (int j = 0; j < grid[0].length; j++) { + if (i > 0 && j > 0) { + grid[i][j] = Math.min(grid[i - 1][j], grid[i][j - 1]) + grid[i][j]; + } else if (j <= 0 && i > 0) { + grid[i][j] = grid[i - 1][j] + grid[i][j]; + } else if (j > 0) { + grid[i][j] = grid[i][j - 1] + grid[i][j]; + } + } + } + return grid[grid.length - 1][grid[0].length - 1]; + } +} \ No newline at end of file diff --git a/Week_05/G20200343030025/LeetCode_2_025.java b/Week_05/G20200343030025/LeetCode_2_025.java new file mode 100644 index 00000000..21dc15a3 --- /dev/null +++ b/Week_05/G20200343030025/LeetCode_2_025.java @@ -0,0 +1,48 @@ +/** + * 91. 解码方法 + * 一条包含字母 A-Z 的消息通过以下方式进行了编码: + *

+ * 'A' -> 1 + * 'B' -> 2 + * ... + * 'Z' -> 26 + * 给定一个只包含数字的非空字符串,请计算解码方法的总数。 + *

+ * 示例 1: + *

+ * 输入: "12" + * 输出: 2 + * 解释: 它可以解码为 "AB"(1 2)或者 "L"(12)。 + * 示例 2: + *

+ * 输入: "226" + * 输出: 3 + * 解释: 它可以解码为 "BZ" (2 26), "VF" (22 6), 或者 "BBF" (2 2 6) 。 + */ +public class LeetCode_2_025 { + // a. 重复子问题 opt[i] = opt[i-1] + opt[i-2] + // b. 状态空间 opt[i] + // c. DP 方程 f(n) = f(n-1) + f(n-2) + + public int numDecodings(String s) { + if (s.charAt(0) == '0') { + return 0; + } + + int[] opt = new int[s.length() + 1]; + opt[0] = opt[1] = 1; + + for (int i = 2; i <= s.length(); i++) { + //如果该位不为'0',说明该位单独成字母合法 + if (s.charAt(i - 1) != '0') { + opt[i] += opt[i - 1]; + } + + //如果后两位能组成"1x"(x为任意数字)或者"2x"(x小于7),说明最后两位组成字母合法 + if ((s.charAt(i - 2) == '1') || (s.charAt(i - 2) == '2' && s.charAt(i - 1) <= '6')) { + opt[i] += opt[i - 2]; + } + } + return opt[s.length()]; + } +} \ No newline at end of file diff --git a/Week_05/G20200343030029/LeetCode_1_029.java b/Week_05/G20200343030029/LeetCode_1_029.java new file mode 100644 index 00000000..dc666854 --- /dev/null +++ b/Week_05/G20200343030029/LeetCode_1_029.java @@ -0,0 +1,46 @@ +class LeetCode_1_029 { + /** + * 题目描述: + * 给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。 + * + * 说明:每次只能向下或者向右移动一步。 + * + * 示例: + * + * 输入: + * [ + *   [1,3,1], + * [1,5,1], + * [4,2,1] + * ] + * 输出: 7 + * 解释: 因为路径 1→3→1→1→1 的总和最小。 + * + * 来源:力扣(LeetCode) + * 链接:https://leetcode-cn.com/problems/minimum-path-sum + * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + */ + + public static int minPathSum(int[][] grid) { + for(int i = grid.length - 1; i >= 0; i--) { + for(int j = grid[0].length -1; j >= 0; j--) { + if(i == grid.length - 1 && j != grid[0].length - 1) { + // 最底下一行处理 + grid[i][j] = grid[i][j] + grid[i][j + 1]; + }else if(j == grid[0].length - 1 && i != grid.length -1) { + // 最右一行的处理 + grid[i][j] = grid[i][j] + grid[i + 1][j]; + }else if(j != grid[0].length -1 && i != grid.length - 1) { + // 中间节点处理 + grid[i][j] = grid[i][j] + Math.min(grid[i + 1][j], grid[i][j+ 1]); + } + } + } + return grid[0][0]; + } + + public static void main(String args[]) { + int[][] grid = {{1,3,1},{1,5,1},{4,2,1}}; + System.out.println(minPathSum(grid)); + } +} \ No newline at end of file diff --git a/Week_05/G20200343030029/LeetCode_2_029.java b/Week_05/G20200343030029/LeetCode_2_029.java new file mode 100644 index 00000000..75f4baab --- /dev/null +++ b/Week_05/G20200343030029/LeetCode_2_029.java @@ -0,0 +1,34 @@ +class LeetCode_2_029 { + + /** + * 题目描述:一条包含字母 A-Z 的消息通过以下方式进行了编码: + *

+ * 'A' -> 1 'B' -> 2 ... 'Z' -> 26 给定一个只包含数字的非空字符串,请计算解码方法的总数。 + *

+ * 示例 1: + *

+ * 输入: "12" 输出: 2 解释: 它可以解码为 "AB"(1 2)或者 "L"(12)。 + *

+ * 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/decode-ways 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + */ + + public int numDecodings(String s) { + if (s.charAt(0) == '0') + return 0; + + int[] dp = new int[s.length() + 1]; + dp[0] = dp[1] = 1; + + for (int i = 2; i <= s.length(); i++) { + //如果该位不为'0',说明该位单独成字母合法 + if (s.charAt(i - 1) != '0') { + dp[i] += dp[i - 1]; + } + //如果后两位能组成"1x"(x为任意数字)或者"2x"(x小于7),说明最后两位组成字母合法 + if ((s.charAt(i - 2) == '1') || (s.charAt(i - 2) == '2' && s.charAt(i - 1) <= '6')) { + dp[i] += dp[i - 2]; + } + } + return dp[s.length()]; + } +} \ No newline at end of file diff --git a/Week_05/G20200343030035/LeetCode_221_035.py b/Week_05/G20200343030035/LeetCode_221_035.py new file mode 100644 index 00000000..b94b51f0 --- /dev/null +++ b/Week_05/G20200343030035/LeetCode_221_035.py @@ -0,0 +1,24 @@ +''' +221. 最大正方形 +在一个由 0 和 1 组成的二维矩阵内,找到只包含 1 的最大正方形,并返回其面积。 + +''' + + +class Solution: + def maximalSquare(self, matrix: List[List[str]]) -> int: + m = len(matrix) + n = len(matrix[0]) + if m < 1: + return 0 + dp = [[0 if matrix[i][j] == '0' else 1 for j in range(0, n)] for i in range(0, m)] + + for i in range(1, m): + for j in range(1, n): + if matrix[i][j] == '1': + dp[i][j] = min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]) + 1 + else: + dp[i][j] = 0 + + res = max(max(row) for row in dp) + return res * res \ No newline at end of file diff --git a/Week_05/G20200343030035/LeetCode_64_035.py b/Week_05/G20200343030035/LeetCode_64_035.py new file mode 100644 index 00000000..6cb41720 --- /dev/null +++ b/Week_05/G20200343030035/LeetCode_64_035.py @@ -0,0 +1,25 @@ +''' +64. 最小路径和 + +给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。 + +说明:每次只能向下或者向右移动一步。 +''' + +class Solution: + def minPathSum(self, grid: List[List[int]]) -> int: + m = len(grid) + n = len(grid[0]) + if m < 1: + return 0 + for i in range(0, m): + for j in range(0, n): + if i == 0 and j == 0: + continue + if i == 0 and j > 0: + grid[i][j] += grid[i][j - 1] + elif j == 0 and i > 0: + grid[i][j] += grid[i - 1][j] + else: + grid[i][j] += min(grid[i - 1][j], grid[i][j - 1]) + return grid[-1][-1] \ No newline at end of file diff --git a/Week_05/G20200343030363/LeetCode_064_363.java b/Week_05/G20200343030363/LeetCode_064_363.java new file mode 100644 index 00000000..3292de85 --- /dev/null +++ b/Week_05/G20200343030363/LeetCode_064_363.java @@ -0,0 +1,34 @@ +package cn.geek.week5; + +/** + * @author lemon + * @version 1.0.0 + * @Description TODO + * @createTime 2020年03月15日 13:52:00 + */ +public class LeetCode_064_363 { + + /** + * Min path sum int. + * + * @param grid + * the grid + * @return the int + */ + public int minPathSum(int[][] grid) { + for (int i = 0; i < grid.length; i++) { + for (int j = 0; j < grid[0].length; j++) { + if (i == 0 && j == 0) { + continue; + } else if (i == 0) { + grid[i][j] = grid[i][j - 1] + grid[i][j]; + } else if (j == 0) { + grid[i][j] = grid[i - 1][j] + grid[i][j]; + } else { + grid[i][j] = Math.min(grid[i - 1][j], grid[i][j - 1]) + grid[i][j]; + } + } + } + return grid[grid.length - 1][grid[0].length - 1]; + } +} diff --git a/Week_05/G20200343030363/LeetCode_091_363.java b/Week_05/G20200343030363/LeetCode_091_363.java new file mode 100644 index 00000000..8ee810fb --- /dev/null +++ b/Week_05/G20200343030363/LeetCode_091_363.java @@ -0,0 +1,45 @@ +package cn.geek.week5; + +/** + * @author lemon + * @version 1.0.0 + * @Description TODO + * @createTime 2020年03月15日 11:51:00 + */ +public class LeetCode_091_363 { + + /** + * Num decodings int. + * + * @param s + * the s + * @return the int + */ + public int numDecodings(String s) { + int len = s.length(); + int end = 1; + int cur = 0; + if (s.charAt(len - 1) != '0') { + cur = 1; + } + for (int i = len - 2; i >= 0; i--) { + if (s.charAt(i) == '0') { + // end 前移 + end = cur; + cur = 0; + continue; + } + int ans1 = cur; + int ans2 = 0; + int ten = (s.charAt(i) - '0') * 10; + int one = s.charAt(i + 1) - '0'; + if (ten + one <= 26) { + ans2 = end; + } + // end 前移 + end = cur; + cur = ans1 + ans2; + } + return cur; + } +} diff --git "a/Week_05/G20200343030369/64.\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214.swift" "b/Week_05/G20200343030369/64.\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214.swift" new file mode 100644 index 00000000..1c98bc00 --- /dev/null +++ "b/Week_05/G20200343030369/64.\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214.swift" @@ -0,0 +1,61 @@ +/* + * @lc app=leetcode.cn id=64 lang=golang + * + * [64] 最小路径和 + * + * https://leetcode-cn.com/problems/minimum-path-sum/description/ + * + * algorithms + * Medium (64.49%) + * Likes: 403 + * Dislikes: 0 + * Total Accepted: 66.4K + * Total Submissions: 102.3K + * Testcase Example: '[[1,3,1],[1,5,1],[4,2,1]]' + * + * 给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。 + * + * 说明:每次只能向下或者向右移动一步。 + * + * 示例: + * + * 输入: + * [ + * [1,3,1], + * ⁠ [1,5,1], + * ⁠ [4,2,1] + * ] + * 输出: 7 + * 解释: 因为路径 1→3→1→1→1 的总和最小。 + * + * + */ + +// @lc code=start +class Solution { + func minPathSum(_ grid: [[Int]]) -> Int { + + } + + func minPathSumDP(_ grid: [[Int]]) -> Int { + guard grid.count > 0 && grid[0].count > 0 else {return 0} + let n = grid.count, m = grid[0].count + var minPath = Array(repeating: Array(repeating: 0, count: m), count: n) + minPath[0][0] = grid[0][0] + for i in 1.. rorse (将 'h' 替换为 'r') + * rorse -> rose (删除 'r') + * rose -> ros (删除 'e') + * + * + * 示例 2: + * + * 输入: word1 = "intention", word2 = "execution" + * 输出: 5 + * 解释: + * intention -> inention (删除 't') + * inention -> enention (将 'i' 替换为 'e') + * enention -> exention (将 'n' 替换为 'x') + * exention -> exection (将 'n' 替换为 'c') + * exection -> execution (插入 'u') + * + * + */ + +// @lc code=start +class Solution { + func minDistance(_ word1: String, _ word2: String) -> Int { + + } + + func minDistanceBT(_ word1: String, _ word2: String) -> Int { + let word1 = [Character](word1), word2 = [Character](word2) + let n = word1.count, m = word2.count + var ans = max(n, m) + func lwsBT(_ i: Int, _ j: Int, _ editest: Int) { + if i == n || j == m { + var editest = editest + if i < n {editest += n - i} + if j < m {editest += m - j} + if editest < ans {ans = editest} + } + + // 字符相等就跳过 + if word1[i] == word2[i] { + lwsBT(i+1, j+1, editest) + } else { // 字符不等的处理方法 + // 删除 i 或者在 i 位置插入 + lwsBT(i+1, j, editest+1) + // 删除 j 或者在 j 位置插入 + lwsBT(i, j+1, editest+1) + // 替换 i 或者 j + lwsBT(i+1, j+1, editest+1) + } + } + + lwsBT(0, 0, 0) + return ans + } + + func minDistanceDP(_ word1: String, _ word2: String) -> Int { + let word1 = [Character](word1), word2 = [Character](word2) + let n = word1.count, m = word2.count + var minDist = Array(repeating: Array(repeating: 0, count: m), count: n) + for i in 0.. Int { + var minv = Int.max + if dist1 < minv {minv = dist1} + if dist2 < minv {minv = dist2} + if dist3 < minv {minv = dist3} + return minv + } + + for i in 1.. b { + return b + } + return a +} + +func minimumTotal(triangle [][]int) int { + return method3(triangle) +} + +//状态定义:dp[i,j]:底层到当前点路径的最小值 - 最终结果:dp[0,0] +//状态方程:dp[i,j] = min(dp[i+1,j],dp[i+1,j+1]) + triangle[i,j] +//初始状态:dp[n-1, j] = triangle[n-1,j],则dp可直接复用triangle,无需再额外初始化 +//TC: O(n2), SC: O(n2) - 题目要求SC: O(n),即使用一维数组 +func method1(triangle [][]int) int { + if len(triangle) == 0 { + return 0 + } + + dp := triangle + for i := len(triangle) - 2; i >= 0; i-- { + for j := 0; j < len(triangle[i]); j++ { + dp[i][j] = min(dp[i+1][j], dp[i+1][j+1]) + triangle[i][j] + } + } + + return dp[0][0] +} + +//也可不新申请二维数组,直接原地修改 - triangle被修改了,不可重复测试 +//TC: O(n2), SC: O(n2) - 题目要求SC: O(n),即使用一维数组 +func method2(triangle [][]int) int { + if len(triangle) == 0 { + return 0 + } + + for i := len(triangle) - 2; i >= 0; i-- { + for j := 0; j < len(triangle[i]); j++ { + triangle[i][j] = min(triangle[i+1][j], triangle[i+1][j+1]) + triangle[i][j] + } + } + + return triangle[0][0] +} + +//降维:自底向上递推时,只需要使用上一层(i较大那一层)的比较结果,不需要使用m层 +//dp被修改,triangle相应行也会被修改 +//SC: O(n) +func method3(triangle [][]int) int { + if len(triangle) == 0 { + return 0 + } + + dp := triangle[len(triangle)-1] + for i := len(triangle) - 2; i >= 0; i-- { + for j := 0; j < len(triangle[i]); j++ { + dp[j] = min(dp[j], dp[j+1]) + triangle[i][j] //容易写错,是j不是i + } + } + return dp[0] +} + +//BruteForce: DFS - TimeOut +func method4(triangle [][]int) int { + if len(triangle) == 0 { + return 0 + } + + return dfs1(triangle, 0, 0) +} + +func dfs1(triangle [][]int, i int, j int) int { + //terminator + if i == len(triangle)-1 { + return triangle[i][j] + } + + //process + //No Process, can print `path` + + //drill down + left := dfs1(triangle, i+1, j) + right := dfs1(triangle, i+1, j+1) + + //clear status + //Note: no need to clear status of `path` + //if like visited[][], need recover + + return min(left, right) + triangle[i][j] +} + +//DFS+Memorize - AC +//构建一个triangle大小的二维数组,用来记忆最小值,再递归到此值时直接返回 +//测试用例中:比如递归到3时需要看6和5,递归到4时需要看5和7,则5就可以直接返回 +func method5(triangle [][]int) int { + if len(triangle) == 0 { + return 0 + } + + memo := make([][]int, len(triangle)) //len(triangle)行 + for i := range memo { + memo[i] = make([]int, len(triangle[i])) //每行跟triangle行相同列 + } + return dfs2(triangle, 0, 0, memo) +} + +func dfs2(triangle [][]int, i int, j int, memo [][]int) int { + //terminator + if i == len(triangle)-1 { + memo[i][j] = triangle[i][j] + return memo[i][j] + } + + //if not calculated + if memo[i][j] == 0 { + left := dfs2(triangle, i+1, j, memo) + right := dfs2(triangle, i+1, j+1, memo) + memo[i][j] = min(left, right) + triangle[i][j] + } + + return memo[i][j] +} diff --git a/Week_05/G20200343030373/LeetCode_152_373/LeetCode_152_373_test.go b/Week_05/G20200343030373/LeetCode_152_373/LeetCode_152_373_test.go new file mode 100644 index 00000000..7576829d --- /dev/null +++ b/Week_05/G20200343030373/LeetCode_152_373/LeetCode_152_373_test.go @@ -0,0 +1,105 @@ +//https://leetcode-cn.com/problems/maximum-product-subarray/description/ +package max_product_subarray_test + +import ( + "github.com/stretchr/testify/assert" + "testing" +) + +func TestMaxProductSubarray(t *testing.T) { + t.Log("Maximum Product Subarray: DP") + + nums1 := []int{2, 3, -2, 4} + nums2 := []int{-2, 0, -1} + nums3 := []int{2, -5, -2, -4, 3} + assert.Equal(t, 6, maxProduct(nums1)) + assert.Equal(t, 0, maxProduct(nums2)) + assert.Equal(t, 24, maxProduct(nums3)) + assert.Equal(t, 6, method1(nums1)) + assert.Equal(t, 0, method1(nums2)) + assert.Equal(t, 24, method1(nums3)) + assert.Equal(t, 6, method2(nums1)) + assert.Equal(t, 0, method2(nums2)) + assert.Equal(t, 24, method2(nums3)) +} + +func maxProduct(nums []int) int { + return method2(nums) +} + +func method1(nums []int) int { + if len(nums) == 0 { + return 0 + } + + //dp状态定义:到当前位置,最大值、最小值 + //每次递推只需要和前一次递推的结果比较,所以第一维只需要长度为2 + //第二维:0表示最大值,1表示最小值 + var dp [2][2]int + //dp初始值:第一个元素 + //如果就只有一个元素,即使是负值,则 最大、最小、结果 都是这个值 + dp[0][0], dp[0][1] = nums[0], nums[0] + res := nums[0] + + for i := 1; i < len(nums); i++ { + //x,y 以 (1,0), (0,1), (1,0) ... 轮转滚动 + x, y := i%2, (i-1)%2 + //x,y滚动:这一次是1存储,0运算;下一次就是0存储,上一次存储的1参与运算 + //与当前值进行比较,因为 最大、最小、本身 之间还要比较出个大小 + //而不需要去判断当前值为正还是为负 + dp[x][0] = max3(dp[y][0]*nums[i], dp[y][1]*nums[i], nums[i]) + dp[x][1] = min3(dp[y][0]*nums[i], dp[y][1]*nums[i], nums[i]) + //dp最终值:当前值 与 过程中比较得到的最大值 的较大值 + res = max2(res, dp[x][0]) + } + + return res +} + +func method2(nums []int) int { + if len(nums) == 0 { + return 0 + } + + curMax, curMin, res := nums[0], nums[0], nums[0] + + for i := 1; i < len(nums); i++ { + curMax, curMin = max3(curMax*nums[i], curMin*nums[i], nums[i]), min3(curMax*nums[i], curMin*nums[i], nums[i]) + res = max2(res, curMax) + } + + return res +} + +func max2(a, b int) int { + if a > b { + return a + } + return b +} + +func max3(a, b, c int) int { + max := 0 + if a > b { + max = a + } else { + max = b + } + if c > max { + max = c + } + return max +} + +func min3(a, b, c int) int { + min := 0 + if a < b { + min = a + } else { + min = b + } + if c < min { + min = c + } + return min +} diff --git a/Week_05/G20200343030373/LeetCode_322_373/LeetCode_322_373_test.go b/Week_05/G20200343030373/LeetCode_322_373/LeetCode_322_373_test.go new file mode 100644 index 00000000..40828068 --- /dev/null +++ b/Week_05/G20200343030373/LeetCode_322_373/LeetCode_322_373_test.go @@ -0,0 +1,44 @@ +//https://leetcode-cn.com/problems/coin-change/ +package coin_change_test + +import ( + "github.com/stretchr/testify/assert" + "testing" +) + +func TestCoinChange(t *testing.T) { + assert.Equal(t, 3, coinChange([]int{1, 2, 5}, 11)) + assert.Equal(t, -1, coinChange([]int{2}, 3)) +} + +func coinChange(coins []int, amount int) int { + //状态定义:dp[i]为凑成i元需要的最小硬币数 + //最终结果:dp[amount] + dp := make([]int, amount+1) //假设都是1元,凑2元,则遍历的i为0\1\2,长度为3 + dp[0] = 0 //初始值:凑成0元需要0个 + for i := 1; i <= amount; i++ { //将初始值设置为不可达的数字 + dp[i] = amount + 1 + } + + //状态方程:dp[i] = min{dp[i-a], dp[i-b], dp[i-c]} + 1 + //凑成当前数值nowAmount,等于之前凑成数值nowAmount-coin的最小值再加1 + for nowAmount := 1; nowAmount <= amount; nowAmount++ { + for _, coin := range coins { + if nowAmount >= coin { //当前要凑的数值要大于等于硬币面额 + dp[nowAmount] = min(dp[nowAmount], dp[nowAmount-coin]+1) + } + } + } + + if dp[amount] > amount { + return -1 + } + return dp[amount] +} + +func min(a, b int) int { + if a < b { + return a + } + return b +} diff --git a/Week_05/G20200343030373/LeetCode_509_373/LeetCode_509_373_test.go b/Week_05/G20200343030373/LeetCode_509_373/LeetCode_509_373_test.go new file mode 100644 index 00000000..611f24c0 --- /dev/null +++ b/Week_05/G20200343030373/LeetCode_509_373/LeetCode_509_373_test.go @@ -0,0 +1,213 @@ +//https://leetcode-cn.com/problems/fibonacci-number/ +//https://leetcode-cn.com/problems/powx-n/ +//https://leetcode-cn.com/problems/sqrtx/ +package fibonacci_test + +import ( + "github.com/stretchr/testify/assert" + "math" + "testing" +) + +func TestFib(t *testing.T) { + //Fibonacci + //0,1,1,2,3,5,8,13 + assert.Equal(t, 13, fib(7)) + assert.Equal(t, 13, recursionFib(7)) + assert.Equal(t, 13, memorizeFib(7)) + assert.Equal(t, 13, dpFib(7)) + assert.Equal(t, 13, dpSpaceFib(7)) + assert.Equal(t, 13, formulaFib(7)) + assert.Equal(t, 13, tableFib(7)) + assert.Equal(t, 13, matrixFib(7)) + assert.Equal(t, 13, tailRecursionFib(7, 0, 1, 2)) + + //公式法举例 + //1+2+3+4=10 + n := 4 + sum1 := 0 + for i := 1; i <= n; i++ { + sum1 += i + } + sum2 := n * (n + 1) / 2 + assert.Equal(t, 10, sum1) //O(n) + assert.Equal(t, 10, sum2) //O(1) + + //power(x,n) + //sqrt(x) +} + +func fib(N int) int { + return matrixFib(N) +} + +//method1: recursion +//Go中无三目运算符 +//TC: O(2^n), SC:O(n) - 递归调用栈的空间 +//AC, 12ms +func recursionFib(n int) int { + //terminator + if n <= 1 { + return n + } + //process + //drill down + return recursionFib(n-1) + recursionFib(n-2) + //clear +} + +//method2: speedup2-1 - space to time - memorize or cache +//if n >= 2, 算过一次就存储起来,递归下次使用时直接取(缓存的概念,O(1)) +//TC: O(n), SC: O(n) +//AC, 0ms +var hash = make(map[int]int) + +func memorizeFib(n int) int { + if n <= 1 { + return n + } + if _, ok := hash[n]; !ok { + hash[n] = memorizeFib(n-1) + memorizeFib(n-2) + } + return hash[n] +} + +//method3: dp = recursion + memorize = transition +//recursion: 下沉后,反向返回结果 +//transition: 正向递推 +//TC: O(n), SC: O(n) +func dpFib(n int) int { + //状态定义: dp[i], 累加到当前位置的结果值 + //初始值: dp[0], dp[1] + //最终值: dp[n] + //状态方程: dp[i]=dp[i-1]+dp[i-2] + if n <= 1 { + return n + } + dp := make([]int, n+1) //因为要使用n,所以长度是n+1 + dp[0], dp[1] = 0, 1 + for i := 2; i <= n; i++ { + dp[i] = dp[i-1] + dp[i-2] + } + return dp[n] +} + +//method4: dp - space decrease +//dp[]存储了每个步骤的值,但最终结果只需要比它小前两个的结果,所以可以通过变量滚动 +//TC: O(n), SC: O(1) +func dpSpaceFib(n int) int { + //prePre, pre + //0, 1 + //pre + //prePre, pre = pre, prePre+pre + if n <= 1 { + return n + } + prePre, pre := 0, 1 + for i := 2; i <= n; i++ { + pre, prePre = prePre+pre, pre + } + return pre +} + +//method5: 通项公式法 +//f(n) = a1(b1)^n + a2(b2)^n +//b1 = (1 + √5)/2 (goldenRatio) +//b2 = (1 - √5)/2 +//a1 = 1/√5 +//a2 = -1/√5 +//b2^n , b2是小于1的数,幂次会在最后四舍五入时省略 +//最终结果:f(n) = (goldenRation^n)/√5 +//TC: O(logn), SC: O(logn) - math.Pow的实现 +func formulaFib(n int) int { + goldenRatio := (1 + math.Sqrt(5)) / 2 + fn := math.Pow(goldenRatio, float64(n)) / math.Sqrt(5) + return int(math.Round(fn)) +} + +//method6: 矩阵求幂 +//线代公式: +//x y = a b * e f +//z w c d g h +//则 +//x = ae + bg +//y = af + bh +//z = ce + dg +//w = cf + dh +//代入fib: +//f(n) 0 = f(n-1) 0 * 1 1 = f(1) * 1 1 ^n-1 +//f(n-1) 0 f(n-2) 0 1 0 f(0) 1 0 +//最终方案:求power(A,N) +//最终结果:可见f(n)在最终的A[0,0]上 +//TC: O(logn) SC: O(logn) - x^n递归时使用栈空间 +//speedup2-2: 升维 +func matrixFib(n int) int { + if n <= 1 { + return n + } + A := [2][2]int{ + {1, 1}, + {1, 0}, + } + A = matrixPower(A, n-1) + return A[0][0] +} + +//x^n +//method1: recursion + divide&conquer +//power(a,n), a是正数,n是自然数,只需要考虑n的奇偶性 +//递归+分治,O(logn) +func matrixPower(A [2][2]int, n int) [2][2]int { + //terminator + if n <= 1 { + return A + } + //process + //drill down + R := matrixPower(A, n/2) + //clear + if n&1 == 1 { + return multiply(A, multiply(R, R)) + } + return multiply(R, R) +} + +//线代公式 +func multiply(A [2][2]int, B [2][2]int) [2][2]int { + x := A[0][0]*B[0][0] + A[0][1]*B[1][0] + y := A[0][0]*B[0][1] + A[0][1]*B[1][1] + z := A[1][0]*B[0][0] + A[1][1]*B[0][1] + w := A[1][0]*B[0][1] + A[1][1]*B[1][1] + + A[0][0] = x + A[0][1] = y + A[1][0] = z + A[1][1] = w + + return A +} + +//method7: table +//leetcode: 0 <= n <= 30 +//TC: O(1) :) +var fibs = [31]int{0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946, 17711, 28657, 46368, 75025, 121393, 196418, 317811, 514229, 832040} + +func tableFib(n int) int { + return fibs[n] +} + +//method8: tail recursion +//对递归的优化手段一般是尾递归 +//尾递归是指,在函数返回的时候,调用自身本身,并且return语句不能包含表达式 +//这样,编译器就可以对尾递归做优化,使递归无论调用多少次,都只占用一个栈帧,栈不会增长,不会出现栈溢出 +//recursionFib(4), 6次调用 +//tailRecursionFib(4), 2次调用 +func tailRecursionFib(n int, b1, b2 int, c int) int { + if n <= 1 { + return n + } + if n == c { + return b1 + b2 + } + return tailRecursionFib(n, b2, b1+b2, c+1) +} diff --git a/Week_05/G20200343030373/LeetCode_70_373/LeetCode_70_373_test.go b/Week_05/G20200343030373/LeetCode_70_373/LeetCode_70_373_test.go new file mode 100644 index 00000000..9d96fce5 --- /dev/null +++ b/Week_05/G20200343030373/LeetCode_70_373/LeetCode_70_373_test.go @@ -0,0 +1,142 @@ +//https://leetcode-cn.com/problems/climbing-stairs/description/ +package climb_stair_test + +import ( + "github.com/stretchr/testify/assert" + "math" + "testing" +) + +func TestDP(t *testing.T) { + t.Log("Climbing Stairs: DP Fibonacci") + //题目描述,给定n是一个正整数,即n从1开始 + //n: 1, 2, 3, 4, 5... + //f: 1, 2, 3, 5, 8... + //区别Fibonacci, 爬楼梯n从1开始,斐波那次n从0开始;爬楼梯题目的 i和n 分别要比斐波那契 多1 + assert.Equal(t, 2, climbStairs(2)) + assert.Equal(t, 5, climbStairs(4)) + assert.Equal(t, 5, resOriginal(4)) + assert.Equal(t, 5, resMemoOut(4)) + assert.Equal(t, 5, resMemoIn(4)) + assert.Equal(t, 5, dpOriginal(4)) + assert.Equal(t, 5, dpShrink(4)) + assert.Equal(t, 5, formula(4)) + assert.Equal(t, 5, matrix(4)) +} + +func climbStairs(n int) int { + return matrix(n) +} + +//1. original recursion +//Not AC, TimeOut +func resOriginal(n int) int { + if n <= 2 { //区别Fibonacci + return n + } + return resOriginal(n-1) + resOriginal(n-2) +} + +//2.1. recursion + memory +var hash = make(map[int]int) + +func resMemoOut(n int) int { + if n <= 2 { + return n + } + if _, ok := hash[n]; !ok { + hash[n] = resMemoOut(n-1) + resMemoOut(n-2) + } + return hash[n] +} + +//2.2. recursion + memory + drill down the memory +func resMemoIn(n int) int { + hash := make(map[int]int) + return resMemo(n, hash) +} + +func resMemo(n int, hash map[int]int) int { + if n <= 2 { + hash[n] = n + return hash[n] + } + if _, ok := hash[n]; !ok { + hash[n] = resMemo(n-1, hash) + resMemo(n-2, hash) + } + return hash[n] +} + +//3. dp original +func dpOriginal(n int) int { + if n <= 2 { + return n + } + dp := make([]int, n+1) + dp[1], dp[2] = 1, 2 //区别Fibonacci + for i := 3; i <= n; i++ { //区别Fibonacci + dp[i] = dp[i-1] + dp[i-2] + } + return dp[n] +} + +//4. dp + shrink space +func dpShrink(n int) int { + if n <= 2 { + return n + } + low, high := 1, 2 + for i := 3; i <= n; i++ { + high, low = high+low, high + } + return high +} + +//5. formula +func formula(n int) int { + goldenRation := (1 + math.Sqrt(5)) / 2 + res := math.Pow(goldenRation, float64(n+1)) / math.Sqrt(5) //区别 Fibonacci + return int(math.Round(res)) +} + +//6. matrix +func matrix(n int) int { + if n <= 2 { + return n + } + + A := [2][2]int{ + {1, 1}, + {1, 0}, + } + + A = pow(A, n) //区别Fibonacci + return A[0][0] +} + +func pow(A [2][2]int, n int) [2][2]int { + if n <= 1 { + return A + } //递归终止条件,n<=1;与Power n==0 不同 + + R := pow(A, n/2) + + if n&1 == 1 { + return mul(A, mul(R, R)) + } + return mul(R, R) +} + +func mul(A, B [2][2]int) [2][2]int { + x := A[0][0]*B[0][0] + A[0][1]*B[1][0] + y := A[0][0]*B[0][1] + A[0][1]*B[1][1] + z := A[1][0]*B[0][0] + A[1][1]*B[0][1] + w := A[1][0]*B[0][1] + A[1][1]*B[1][1] + + A[0][0] = x + A[0][1] = y + A[1][0] = z + A[1][1] = w + + return A +} diff --git a/Week_05/G20200343030373/LeetCode_72_373/LeetCode_72_373_test.go b/Week_05/G20200343030373/LeetCode_72_373/LeetCode_72_373_test.go new file mode 100644 index 00000000..c8cb5718 --- /dev/null +++ b/Week_05/G20200343030373/LeetCode_72_373/LeetCode_72_373_test.go @@ -0,0 +1,59 @@ +//https://leetcode-cn.com/problems/edit-distance/ +package edit_distance_test + +import ( + "github.com/stretchr/testify/assert" + "testing" +) + +func TestStringMatch(t *testing.T) { + assert.Equal(t, 3, minDistance("horse", "ros")) + assert.Equal(t, 5, minDistance("intention", "execution")) +} + +func minDistance(word1 string, word2 string) int { + //状态定义:dp[i][j],word1的前i个字符 与 word2的前j个字符 相同 所需的最少操作数 + //最终结果:m是word1的长度,则最终结果要放在dp[m][n]中 - 则数组长度为m+1 + m, n := len(word1), len(word2) + dp := make([][]int, m+1) //初始化二维数组,否则会出现`未将对象引用到对象的实例` + for i := range dp { + dp[i] = make([]int, n+1) + } + + //初始值 + //word1的i个字符转化成word2的0个字符,只能word1删除i次 + //word1的0个字符转化成word2的j个字符,只能word1插入j次 + for i := 0; i <= m; i++ { + dp[i][0] = i + } + for j := 0; j <= n; j++ { + dp[0][j] = j + } + + //状态方程 + //删除操作 从而相等 所以先让前i-1个字符变为j字符,然后在第i处删除 即dp[i-1][j]+1 + //插入操作 从而相等 所以先让前i个字符变为j-1字符,然后在第i处插入j代表的字符 即dp[i][j-1]+1 + //替换操作 从而相等 if(i处等于j处 不需要替换) 即dp[i-1][j-1], else 需要替换 dp[i-1][j-1]+1 + //上述取个最小值即可 + for i := 1; i <= m; i++ { + for j := 1; j <= n; j++ { + dp[i][j] = 1 + min(dp[i-1][j], dp[i][j-1]) //删除、插入时 + + temp := 0 + if word1[i-1] == word2[j-1] { + temp = 0 + } else { + temp = 1 + } + dp[i][j] = min(dp[i][j], dp[i-1][j-1]+temp) //替换时 + } + } + return dp[m][n] +} + +func min(a, b int) int { + if a < b { + return a + } + return b +} diff --git a/Week_05/G20200343030375/Leetcode_221_375.java b/Week_05/G20200343030375/Leetcode_221_375.java new file mode 100644 index 00000000..0c297d5e --- /dev/null +++ b/Week_05/G20200343030375/Leetcode_221_375.java @@ -0,0 +1,32 @@ +package G20200343030375; + +public class Leetcode_221_375 { + public int maximalSquare(char[][] matrix) { + int rs = matrix.length; + if (rs == 0) { + return 0; + } + int cols = matrix[0].length; + int[][] dp = new int[rs + 1][cols + 1]; + int ms = 0; + for (int i = 1; i <= rs; i++) { + for (int j = 1; j <= cols; j++) { + //因为多申请了一行一列,所以这里下标要减 1 + if (matrix[i - 1][j - 1] == '0') { + dp[i][j] = 0; + } else { + dp[i][j] = Math.min(dp[i - 1][j], Math.min(dp[i][j - 1], dp[i - 1][j - 1])) + 1; + ms = Math.max(dp[i][j], ms); + } + } + } + return ms * ms; + } + public static void main(String[] args){ + char[][] matrix = new char[][]{{'1','0','1','0','0'},{'1','0','1','1','1'},{'1','1','1','1','1'},{'1','0','0','1','0'}}; + + Leetcode_221_375 ltc = new Leetcode_221_375(); + + System.out.println(ltc.maximalSquare(matrix)); + } +} diff --git a/Week_05/G20200343030375/Leetcode_621_375.java b/Week_05/G20200343030375/Leetcode_621_375.java new file mode 100644 index 00000000..85fccb12 --- /dev/null +++ b/Week_05/G20200343030375/Leetcode_621_375.java @@ -0,0 +1,27 @@ +package G20200343030375; + +public class Leetcode_621_375 { + public int leastInterval(char[] tasks, int n) { + int[] c = new int[26]; + int max = 0; + int maxCount = 0; + for(char task : tasks) { + c[task - 'A']++; + if(max == c[task - 'A']) { + maxCount++; + } + else if(max < c[task - 'A']) { + max = c[task - 'A']; + maxCount = 1; + } + } + + int pCount = max - 1; + int pLength = n - (maxCount - 1); + int cp = pCount * pLength; + int availableTasks = tasks.length - max * maxCount; + int i = Math.max(0, cp - availableTasks); + + return tasks.length + i; + } +} diff --git a/Week_05/G20200343030377/Leetcode_64_377.java b/Week_05/G20200343030377/Leetcode_64_377.java new file mode 100644 index 00000000..7e3fe86f --- /dev/null +++ b/Week_05/G20200343030377/Leetcode_64_377.java @@ -0,0 +1,20 @@ +class Solution { + public int minPathSum(int[][] grid) { + int m = grid.length; + int n = grid[0].length; + for(int i=0; i=1 && first<=9){ + dp[i]+=dp[i-1]; + } + if(second>=10 && second <=26){ + dp[i]+=dp[i-2]; + } + } + return dp[n]; + } +} diff --git a/Week_05/G20200343030377/Leetcode_91_377.java b/Week_05/G20200343030377/Leetcode_91_377.java new file mode 100644 index 00000000..410b2257 --- /dev/null +++ b/Week_05/G20200343030377/Leetcode_91_377.java @@ -0,0 +1,22 @@ +class Solution { + public int numDecodings(String s) { + if(s==null || s.length()==0){ + return 0; + } + int n = s.length(); + int[] dp = new int[n+1]; + dp[0] = 1; + dp[1] = s.charAt(0) != '0' ? 1 : 0; + for(int i=2; i<=n; i++){ + int first = Integer.valueOf(s.substring(i-1, i)); + int second = Integer.valueOf(s.substring(i-2, i)); + if(first>=1 && first<=9){ + dp[i]+=dp[i-1]; + } + if(second>=10 && second <=26){ + dp[i]+=dp[i-2]; + } + } + return dp[n]; + } +} diff --git a/Week_05/G20200343030379/LeetCode_64_379.java b/Week_05/G20200343030379/LeetCode_64_379.java new file mode 100644 index 00000000..d88ba23a --- /dev/null +++ b/Week_05/G20200343030379/LeetCode_64_379.java @@ -0,0 +1,94 @@ +package G20200343030379; +/** + * 64. С· + * + * һǸ m?x?n?ҳһϽǵ½ǵ·ʹ·ϵܺΪС + * + * ˵ÿֻ»ƶһ + * + * ʾ: + * + * : + * [ + * ? [1,3,1], + * [1,5,1], + * [4,2,1] + * ] + * : 7 + * : Ϊ· 13111 ܺС + * + * ԴۣLeetCode + * ӣhttps://leetcode-cn.com/problems/minimum-path-sum + * ȨСҵתϵٷȨҵתע + * + */ +public class LeetCode_64_379 { + //̬滮 ά Զ + /** ظԣMin(dp[i,j-1],dp[i-1,j])+grip[i,j]; + * ״̬ dp[i,j] + * DP̣dp[i,j]=Min(dp[i,j-1],dp[i-1,j])+grip[i,j]; + * + * ִʱ : 3 ms , Java ύл 86.46% û + * ڴ : 41.7 MB , Java ύл 39.54% û + */ + public int minPathSum(int[][] grid) { + if(grid==null || grid.length==0) return 0; + + int dp[][]=new int [grid.length][grid[0].length]; + + + + for (int i = 0; i < grid.length; i++) { + for (int j = 0; j < grid[i].length; j++) { + //Եж + if(i==0 && j==0){ + //һλ + //ʼһλ + dp[0][0]=grid[0][0]; + } + // + else if(i==0 && j>0){ + dp[i][j]= dp[i][j-1]+grid[i][j]; + }else if(i>0 && j==0){ + //ж + dp[i][j]= dp[i-1][j]+grid[i][j]; + }else{ + //λ + dp[i][j]= Math.min(dp[i][j-1],dp[i-1][j])+grid[i][j]; + } + //System.out.println(i+"===="+j+"==="+dp[i][j]); + } + } + return dp[grid.length-1][grid[0].length-1]; + } + + /** + * һά̬淶Զ + * ظԣ Min(dp[j-1],dp[j]])+grip[i,j]; + * ״̬ dp[i,j] + * DP̣dp[j]=Min(dp[j-1],dp[j])+grip[i,j]; + * + * ִʱ : 3 ms , Java ύл 86.46% û + * ڴ : 42.4 MB , Java ύл 23.65% û + */ + public int minPathSum2(int[][] grid) { + if(grid==null || grid.length==0) return 0; + + int dp[]=new int[grid[0].length]; + + for (int i = 0; i < grid.length; i++) { + for (int j = 0; j < grid[i].length; j++) { + // System.out.println(i+"===="+j+"==="+dp[i]); + if(i==0 && j>0){ + dp[j]=grid[i][j]+dp[j-1]; + } + else if(j==0){ + dp[j]=grid[i][j]+dp[j]; + }else{ + dp[j]=Math.min(dp[j-1],dp[j])+grid[i][j]; + } + } + } + return dp[grid[0].length-1]; + } +} diff --git a/Week_05/G20200343030379/LeetCode_91_379.java b/Week_05/G20200343030379/LeetCode_91_379.java new file mode 100644 index 00000000..5111d48b --- /dev/null +++ b/Week_05/G20200343030379/LeetCode_91_379.java @@ -0,0 +1,158 @@ +package G20200343030379; +/** + * 91. 뷽 + * + * һĸ?A-Z Ϣͨ·ʽ˱룺 + * + * 'A' -> 1 + * 'B' -> 2 + * ... + * 'Z' -> 26 + * һֵֻķǿַ뷽 + * + * ʾ 1: + * + * : "12" + * : 2 + * :?ԽΪ "AB"1 2 "L"12 + * ʾ?2: + * + * : "226" + * : 3 + * :?ԽΪ "BZ" (2 26), "VF" (22 6), "BBF" (2 2 6) + * + * ԴۣLeetCode + * ӣhttps://leetcode-cn.com/problems/decode-ways + * ȨСҵתϵٷȨҵתע + * + */ +public class LeetCode_91_379 { + public static void main(String[] args) { + new LeetCode_91_379().numDecodings2("100"); + //new LeetCode_91_379().numDecodings2("126"); + } + //̬滮 ҵ + /** + * dp[i]=dp[i+1]+dp[i+2] + * + * 룺1212 + * 2 + * 12 + * 212= 2 12 + * 1212=1 212 12 12 + * + * 0: + * <=26 dp[i]=dp[i+1]+dp[i+2] + * >26 dp[i]=dp[i+1] + * + * + * /** + * Ϊ7Ȼ17->G + * Ϊ67Ȼ167->FG + * Ϊ067Ϊ0 + * Ϊ2067 ΪnumDecodings20 67+ numDecodings2 067= numDecodings20 67->TFG + * Ϊ22067 ΪnumDecodings2 2067+ numDecodings22 067= numDecodings2 2067->BTFG + * + * ߣreedfan + * ӣhttps://leetcode-cn.com/problems/decode-ways/solution/java-di-gui-dong-tai-gui-hua-kong-jian-ya-suo-by-r/ + * ԴۣLeetCode + * ȨСҵתϵ߻Ȩҵתע// + * + * + * ִʱ : 1 ms , Java ύл 100.00% û + * ڴ : 38.1 MB , Java ύл 5.01% û + * + * ο⣺https://leetcode-cn.com/problems/decode-ways/solution/java-di-gui-dong-tai-gui-hua-kong-jian-ya-suo-by-r/ + * https://leetcode.com/problems/decode-ways/discuss/30357/DP-Solution-(Java)-for-reference + * @param s + * @return + */ + public int numDecodings(String s) { + int[] dp=new int[s.length()+1]; + + // + dp[s.length()]=1; + //ʼַ + + + if(s.charAt(s.length()-1)=='0'){ + dp[s.length()-1]=0; + }else{ + dp[s.length()-1]=1; + } + + + for (int i = s.length()-2; i >= 0; i--) { + //ⳡ "00" ,0 + if(s.charAt(i)=='0'){ + dp[i]=0; + continue; + } + + //С26 + if((s.charAt(i)-'0')*10+(s.charAt(i+1)-'0')<=26){ + dp[i]=dp[i+1]+dp[i+2]; + }else{ + dp[i]=dp[i+1]; + //System.out.println("=="); + } + } + return dp[0]; + } + + + //̬滮 ,˼·Dzͬ + /** + * dp[i]=dp[i+1]+dp[i+2] + * + * 룺1212 + * 2 + * 12 + * 212= 2 12 212 + * 1212=1 212 12 12 + * + * 0: + * <=26 dp[i]=dp[i+1]+dp[i+2] + * >26 dp[i]=dp[i+1] + * + * ο⣺https://leetcode.com/problems/decode-ways/discuss/30358/Java-clean-DP-solution-with-explanation + * + * ִʱ : 1 ms , Java ύл 100.00% û + * ڴ : 38.4 MB , Java ύл 5.01% û + * @param s + * @return + */ + public int numDecodings2(String s) { + int[] dp=new int[s.length()+1]; + + // + dp[0]=1; + //ʼַ + + + //һ0Ƿ + if(s.charAt(0)=='0'){ + dp[1]=0; + }else{ + dp[1]=1; + } + + for (int i = 2; i <= s.length(); i++) { + /* û뵽עleetcodeӰʱ临Ӷȣע͵ʱ临Ӷȼ1ms + if(s.charAt(i-1)=='0'){ + dp[i]=dp[i-1]; + continue; + }*/ + if(s.charAt(i-1)-'0'>=1 && (s.charAt(i-1)-'0')<=9){ + dp[i]=dp[i]+dp[i-1]; + } + + int send=(s.charAt(i-2)-'0')*10+(s.charAt(i-1)-'0'); + if(send>=10 && send<=26){ + dp[i]=dp[i]+dp[i-2]; + } + + } + return dp[s.length()]; + } +} diff --git a/Week_05/G20200343030379/NOTE.md b/Week_05/G20200343030379/NOTE.md index 50de3041..3b4da150 100644 --- a/Week_05/G20200343030379/NOTE.md +++ b/Week_05/G20200343030379/NOTE.md @@ -1 +1,5 @@ -学习笔记 \ No newline at end of file +学习笔记 + +这周的动态规划确实难很多,光看一个视频要花1、2小时才理解。 +但是感觉总是没有思路,然后我索性直接先不做题,直接看作业题,看题解分析别人怎么想这些题, +花了很多时间,发现每个道也是思路不断,但是时间也不够,做了两道题,先搁置准备下一节课了。 \ No newline at end of file diff --git a/Week_05/G20200343030379/testm.java b/Week_05/G20200343030379/testm.java new file mode 100644 index 00000000..b7d7f465 --- /dev/null +++ b/Week_05/G20200343030379/testm.java @@ -0,0 +1,24 @@ +package G20200343030379;/** + * @ClassName: + * @Description: TODO + * @author linyb3 + * @date + */ + +import com.sun.org.apache.xpath.internal.operations.String; + +import java.util.function.Consumer; + +/** + * @ClassName: + * @Description: TODO + * @author linyb3 + * @date + * + */ +public class testm { + + public static void main(String[] args) { + System.out.println(1!=1); + } +} diff --git a/Week_05/G20200343030383/LeetCode_221_383.go b/Week_05/G20200343030383/LeetCode_221_383.go new file mode 100644 index 00000000..07665f04 --- /dev/null +++ b/Week_05/G20200343030383/LeetCode_221_383.go @@ -0,0 +1,46 @@ +// https://leetcode-cn.com/problems/decode-ways/ +package leetcode + +func maximalSquare(matrix [][]byte) int { + var s byte = '0' + for i := 1; i < len(matrix); i++ { + for j := 1; j < len(matrix[0]); j++ { + if matrix[i][j] == '0' { + continue + } + if l := int(min(matrix[i-1][j], matrix[i][j-1]) - '0'); matrix[i-l][j-l] != '0' { + matrix[i][j] = byte(l+1) + '0' + } else { + matrix[i][j] = byte(l) + '0' + } + if matrix[i][j] > s { + s = matrix[i][j] + } + } + } + if s == '0' && len(matrix) > 0 && len(matrix[0]) > 0 { + for _, v := range matrix[0] { + if v != '0' { + s = v + break + } + } + } + if s == '0' && len(matrix) > 0 && len(matrix[0]) > 0 { + for i := 0; i < len(matrix); i++ { + if v := matrix[i][0]; v != '0' { + s = v + break + } + } + } + l := int(s - '0') + return l * l +} + +func min(a, b byte) byte { + if a < b { + return a + } + return b +} diff --git a/Week_05/G20200343030383/LeetCode_64_383.go b/Week_05/G20200343030383/LeetCode_64_383.go new file mode 100644 index 00000000..863e7303 --- /dev/null +++ b/Week_05/G20200343030383/LeetCode_64_383.go @@ -0,0 +1,24 @@ +// https://leetcode-cn.com/problems/minimum-path-sum/submissions/ +package leetcode + +func minPathSum(grid [][]int) int { + for i := 1; i < len(grid[0]); i++ { + grid[0][i] += grid[0][i-1] + } + for i := 1; i < len(grid); i++ { + grid[i][0] += grid[i-1][0] + } + for i := 1; i < len(grid); i++ { + for j := 1; j < len(grid[0]); j++ { + grid[i][j] = min(grid[i-1][j], grid[i][j-1]) + grid[i][j] + } + } + return grid[len(grid)-1][len(grid[0])-1] +} + +func min(a, b int) int { + if a > b { + return b + } + return a +} diff --git a/Week_05/G20200343030387/LeetCode_1143_387.js b/Week_05/G20200343030387/LeetCode_1143_387.js new file mode 100644 index 00000000..aa834ee5 --- /dev/null +++ b/Week_05/G20200343030387/LeetCode_1143_387.js @@ -0,0 +1,20 @@ +/** + * @param {string} text1 + * @param {string} text2 + * @return {number} + */ +var longestCommonSubsequence = function (text1, text2) { + const m = text1.length + const n = text2.length + const dp = Array(m + 1).fill(0).map(t1 => Array(n + 1).fill(0)) + for (let i = 1; i < m + 1; i++) { + for (let j = 1; j < n + 1; j++) { + if (text1[i - 1] === text2[j - 1]) { + dp[i][j] = dp[i - 1][j - 1] + 1 + } else { + dp[i][j] = Math.max(dp[i][j - 1], dp[i - 1][j]) + } + } + } + return dp[m][n] +}; \ No newline at end of file diff --git a/Week_05/G20200343030387/LeetCode_152_387.js b/Week_05/G20200343030387/LeetCode_152_387.js new file mode 100644 index 00000000..cc3bfcc2 --- /dev/null +++ b/Week_05/G20200343030387/LeetCode_152_387.js @@ -0,0 +1,22 @@ +/** + * @param {number[]} nums + * @return {number} + */ +// 动态规划: +// 每步都需要记录当前的最大值max和最小值min,因为乘积会受符号影响; +// dp[i] >= 0, dp[i] = Math.max(nums[i], max * nums[i]) +// dp[i] < 0, swap(max, min), dp[i] = Math.max(nums[i], max * nums[i]) +var maxProduct = function (nums) { + let res = min = max = nums[0] + for (let i = 1; i < nums.length; i++) { + if (nums[i] < 0) { + let tmp = max + max = min + min = tmp + } + max = Math.max(nums[i], nums[i] * max) + min = Math.min(nums[i], nums[i] * min) + res = Math.max(max, res) + } + return res +}; \ No newline at end of file diff --git a/Week_05/G20200343030387/LeetCode_53_387.js b/Week_05/G20200343030387/LeetCode_53_387.js new file mode 100644 index 00000000..b16e5d45 --- /dev/null +++ b/Week_05/G20200343030387/LeetCode_53_387.js @@ -0,0 +1,12 @@ +/** + * @param {number[]} nums + * @return {number} + */ +// 动态规划:dp[i] = max(dp[i-1], 0) + nums[i] +// 用nums作为容器存dp的状态,不用新建dp数组 +var maxSubArray = function (nums) { + for (let i = 1; i < nums.length; i++) { + nums[i] = Math.max(nums[i - 1], 0) + nums[i] + } + return Math.max(...nums) +}; \ No newline at end of file diff --git a/Week_05/G20200343030387/LeetCode_64_387.js b/Week_05/G20200343030387/LeetCode_64_387.js new file mode 100644 index 00000000..ad45bf1d --- /dev/null +++ b/Week_05/G20200343030387/LeetCode_64_387.js @@ -0,0 +1,58 @@ +/** + * @param {number[][]} grid + * @return {number} + */ +// 递归 +// 超时 +var minPathSum1 = function (grid) { + const m = grid.length + const n = grid[0].length + function reversion(i, j, grid) { + if (i === m || j === n) return Infinity + if (i === m - 1 && j === n - 1) return grid[i][j] + return grid[i][j] + Math.min(reversion(i + 1, j, grid), reversion(i, j + 1, grid)) + } + return reversion(0, 0, grid) +} + +// 二维DP方程: dp[i,j] = g[i,j] + min(dp[i+1, j], dp[i, j+1]) +var minPathSum2 = function (grid) { + const m = grid.length - 1 + const n = grid[0].length - 1 + const dp = grid + for (let i = m; i >= 0; i--) { + for (let j = n; j >= 0; j--) { + if (i === m && j === n) { + dp[i][j] = grid[i][j] + } else if (i !== m && j === n) { + dp[i][j] = grid[i][j] + dp[i + 1][j] + } else if (i === m && j !== n) { + dp[i][j] = grid[i][j] + dp[i][j + 1] + } else { + dp[i][j] = Math.min(dp[i + 1][j], dp[i][j + 1]) + grid[i][j] + } + } + } + return dp[0][0] +}; + +// 一维DP方程: dp[j] = g[i,j] + min(dp[j], dp[j+1]) +var minPathSum = function (grid) { + const m = grid.length - 1 + const n = grid[0].length - 1 + const dp = [] + for (let i = m; i >= 0; i--) { + for (let j = n; j >= 0; j--) { + if (i === m && j === n) { + dp[j] = grid[i][j] + } else if (i === m && j !== n) { + dp[j] = dp[j + 1] + grid[i][j] + } else if (i !== m && j === n) { + dp[j] += grid[i][j] + } else { + dp[j] = grid[i][j] + Math.min(dp[j], dp[j + 1]) + } + } + } + return dp[0] +} \ No newline at end of file diff --git a/Week_05/G20200343030391/LeetCode_1143_391.java b/Week_05/G20200343030391/LeetCode_1143_391.java new file mode 100644 index 00000000..7efe414b --- /dev/null +++ b/Week_05/G20200343030391/LeetCode_1143_391.java @@ -0,0 +1,38 @@ +package G20200343030391; + +import java.util.Arrays; + +public class LeetCode_1143_391 { + + public static void main(String[] args) { + String text1 = "abcde"; + String text2 = "ace"; + int i = new LeetCode_1143_391().longestCommonSubsequence(text1, text2); + System.out.println(i); + + } + + /** + * + * @param text1 + * @param text2 + * @return + */ + public int longestCommonSubsequence(String text1, String text2) { + char[] textChar1 = text1.toCharArray(); + char[] textChar2 = text2.toCharArray(); + int length1 = text1.length(); + int length2 = text2.length(); + int[][] dp = new int[length1 + 1][length2 + 1]; + for (int i = 1; i <= length1; i++) { + for (int j = 1; j <= length2; j++) { + if (textChar1[i - 1] == textChar2[j - 1]) { + dp[i][j] = dp[i - 1][j - 1] + 1; + } else { + dp[i][j] = Math.max(dp[i][j - 1], dp[i - 1][j]); + } + } + } + return dp[length1][length2]; + } +} diff --git a/Week_05/G20200343030391/LeetCode_120_391.java b/Week_05/G20200343030391/LeetCode_120_391.java new file mode 100644 index 00000000..1dc8fe23 --- /dev/null +++ b/Week_05/G20200343030391/LeetCode_120_391.java @@ -0,0 +1,97 @@ +package G20200343030391; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class LeetCode_120_391 { + + public static void main(String[] args) { + List> triangle = new ArrayList<>(); + ArrayList l1 = new ArrayList<>(); + l1.add(2); + ArrayList l2 = new ArrayList<>(); + l2.add(3); + l2.add(4); + ArrayList l3 = new ArrayList<>(); + l3.add(6); + l3.add(5); + l3.add(7); + ArrayList l4 = new ArrayList<>(); + l4.add(4); + l4.add(1); + l4.add(8); + l4.add(3); + triangle.add(l1); + triangle.add(l2); + triangle.add(l3); + triangle.add(l4); + int i = new LeetCode_120_391().minimumTotal_2(triangle); + System.out.println(i); + } + + /** + * 傻递归 + * @param triangle + * @return + */ + public int minimumTotal_1(List> triangle) { + int size = triangle.size(); + return help(0, 0, size, triangle); + } + + private int help(int row, int clo, int level, List> triangle) { + //terminator 最后一行直接返回对应值 + if (row == level - 1) { + return triangle.get(row).get(clo); + } + int left = help(row + 1, clo , level, triangle); + int right = help(row + 1, clo + 1, level, triangle); + return Math.min(left, right) + triangle.get(row).get(clo); + } + + /** + * 记忆化搜索 + * @param triangle + * @return + */ + public int minimumTotal_2(List> triangle) { + int size = triangle.size(); + Integer[][] memo = new Integer[size][size]; + return help(0, 0, size, memo, triangle); + } + + private int help(int row, int clo, int level, Integer[][] memo, List> triangle) { + //取缓存结果 + if (memo[row][clo] != null) { + return memo[row][clo]; + } + //terminator 最后一行直接返回对应值 + if (row == level - 1) { + return memo[row][clo] = triangle.get(row).get(clo); + } + int left = help(row + 1, clo, level, triangle); + int right = help(row + 1, clo + 1, level, triangle); + return memo[row][clo] = Math.min(left, right) + triangle.get(row).get(clo); + } + + /** + * 动态规划,自底向上 + * + * @param triangle + * @return + */ + public int minimumTotal_3(List> triangle) { + //层数 + int row = triangle.size(); + int[] dp = new int[row + 1]; + //底部开始查找 + for (int level = row - 1; level >= 0; level--) { + //当前行找下一行相邻的最小值+当前值 + for (int i = 0; i <= level; i++) { + dp[i] = Math.min(dp[i], dp[i + 1]) + triangle.get(level).get(i); + } + } + return dp[0]; + } +} diff --git a/Week_05/G20200343030391/LeetCode_152_391.java b/Week_05/G20200343030391/LeetCode_152_391.java new file mode 100644 index 00000000..64112b4f --- /dev/null +++ b/Week_05/G20200343030391/LeetCode_152_391.java @@ -0,0 +1,42 @@ +package G20200343030391; + + +public class LeetCode_152_391 { + + public static void main(String[] args) { + int[] nums = {2, 3, -2, -9, 4}; + int i = new LeetCode_152_391().maxProduct(nums); + System.out.println(i); + } + + /** + * 动态规划 + * @param nums + * @return + */ + public int maxProduct(int[] nums) { + if (nums == null || nums.length == 0) { + return 0; + } + // 存在负数 分别维护以i结尾的最大最小dp状态空间 + int[] maxDp = new int[nums.length]; + int[] minDp = new int[nums.length]; + int ans = nums[0]; + minDp[0] = nums[0]; + maxDp[0] = nums[0]; + + for (int i = 1; i < nums.length; i++) { + //当前值为负数,交换最大最小值 + if (nums[i] < 0) { + int temp = minDp[i - 1]; + minDp[i - 1] = maxDp[i - 1]; + maxDp[i - 1] = temp; + } + minDp[i] = Math.min(nums[i], minDp[i - 1] * nums[i]); + maxDp[i] = Math.max(nums[i], maxDp[i - 1] * nums[i]); + ans = Math.max(maxDp[i], ans); + } + return ans; + } + +} diff --git a/Week_05/G20200343030391/LeetCode_198_391.java b/Week_05/G20200343030391/LeetCode_198_391.java new file mode 100644 index 00000000..c83fe10f --- /dev/null +++ b/Week_05/G20200343030391/LeetCode_198_391.java @@ -0,0 +1,54 @@ +package G20200343030391; + +public class LeetCode_198_391 { + + public static void main(String[] args) { + int[] nums = {2, 7, 9, 3, 1}; + int rob = new LeetCode_198_391().rob_2(nums); + System.out.println(rob); + + } + + /** + * 动态规划 二维数组状态空间 + * @param nums + * @return + */ + public int rob_1(int[] nums) { + if (nums == null || nums.length == 0) { + return 0; + } + int[][] dp = new int[nums.length][2]; + dp[0][0] = 0; + dp[0][1] = nums[0]; + for (int i = 1; i < nums.length; i++) { + dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1]); + dp[i][1] = dp[i - 1][0] + nums[i]; + } + return Math.max(dp[nums.length - 1][0], dp[nums.length - 1][1]); + } + + /** + * 动态规划 一维数组状态空间 + * @param nums + * @return + */ + public int rob_2(int[] nums) { + if (nums == null || nums.length == 0) { + return 0; + } + if (nums.length == 1) { + return nums[0]; + } + + int[] dp = new int[nums.length]; + dp[0] = nums[0]; + dp[1] = Math.max(nums[0], nums[1]); + int res = Math.max(nums[0], nums[1]); + for (int i = 2; i < nums.length; i++) { + dp[i] = Math.max(dp[i - 1], dp[i - 2] + nums[i]); + res = Math.max(res, dp[i]); + } + return res; + } +} diff --git a/Week_05/G20200343030391/LeetCode_213_391.java b/Week_05/G20200343030391/LeetCode_213_391.java new file mode 100644 index 00000000..334d0462 --- /dev/null +++ b/Week_05/G20200343030391/LeetCode_213_391.java @@ -0,0 +1,85 @@ +package G20200343030391; + +public class LeetCode_213_391 { + + public static void main(String[] args) { + int[] nums = {1, 2, 3, 1}; + int rob = new LeetCode_213_391().rob_2(nums); + System.out.println(rob); + + } + + /** + * 动态规划 + * 二维数组状态空间 dp[i][j] i代表对应房间,j代表是否偷0房间 + * 状态转移方式: + * 1. i房间之前 + * i. 不偷0: dp[i][0] = max(dp[i-1][0],dp[i-2][0]+nums[i]) + * ii. 偷0 : dp[i][1] = max(dp[i-1][1],dp[i-2][1]+nums[i]) + * 2. i房间: + * i. 不偷0,i可以正常取: dp[i][0] = max(dp[i-1][0],dp[i-2][0]+nums[i]) + * ii. 偷0,i房间不能取 : dp[i][1] = dp[i-1][1] + * @param nums + * @return + */ + public int rob_1(int[] nums) { + if (nums == null || nums.length == 0) { + return 0; + } + if (nums.length == 1) { + return nums[0]; + } + int[][] dp = new int[nums.length][2]; + // + dp[0][1] = nums[0]; + dp[0][0] = 0; + dp[1][1] = nums[0]; + dp[1][0] = nums[1]; + + int max = Math.max(dp[1][0], dp[1][1]); + + for (int i = 2; i < nums.length; i++) { + if (i < nums.length - 1) { + dp[i][0] = Math.max(dp[i - 1][0], dp[i - 2][0] + nums[i]); + dp[i][1] = Math.max(dp[i - 1][1], dp[i - 2][1] + nums[i]); + } else { + //如果第一个房间没有被偷,那么最后一个房间就是个正常的房间。 + dp[i][0] = Math.max(dp[i - 1][0], dp[i - 2][0] + nums[i]); + //如果第一个房间被偷了,那么最后一个房间就不能偷了,此时我们只有一个选择,就是不偷,只能等于dp[i-1][1]; + dp[i][1] = dp[i - 1][1]; + + } + max = Math.max(max, Math.max(dp[i][0], dp[i][1])); + + } + return max; + } + /** + * 动态规划:是否偷0房间拆分为两个数组取最大值 + * 一维数组状态空间 dp[i] + * 状态转移方程:dp[i]=max(dp[i-1],dp[i-2]+nums[i]) + * @param nums + * @return + */ + public int rob_2(int[] nums) { + if (nums == null || nums.length == 0) { + return 0; + } + if (nums.length == 1) { + return nums[0]; + } + return Math.max(help(0, nums.length - 2, nums), help(1, nums.length - 1, nums)); + } + + private int help(int start, int end, int[] nums) { + int[] dp = new int[nums.length]; + dp[0] = nums[start]; + dp[1] = Math.max(nums[start], nums[start + 1]); + int max = Math.max(dp[0], dp[1]); + for (int i = 2; i <= end; i++) { + dp[i] = Math.max(dp[i - 1], dp[i - 2] + nums[i]); + max = Math.max(dp[i], max); + } + return max; + } +} diff --git a/Week_05/G20200343030391/LeetCode_221_391.java b/Week_05/G20200343030391/LeetCode_221_391.java new file mode 100644 index 00000000..6c3453c0 --- /dev/null +++ b/Week_05/G20200343030391/LeetCode_221_391.java @@ -0,0 +1,75 @@ +package G20200343030391; + +public class LeetCode_221_391 { + public static void main(String[] args) { + char[][] matrix = { + {'1', '0', '1', '0', '0'}, + {'1', '0', '1', '1', '1'}, + {'1', '1', '1', '1', '1'}, + {'1', '0', '0', '1', '0'}, + }; + int maximalSquare = new LeetCode_221_391().maximalSquare_2(matrix); + System.out.println(maximalSquare); + } + + /** + * 暴力 + * @param matrix + * @return + */ + public int maximalSquare_1(char[][] matrix) { + int row = matrix.length; + int clo = matrix[0].length; + int maxSquare = 0; + for (int i = 0; i < row; i++) { + for (int j = 0; j < clo; j++) { + if (matrix[i][j] == '1') { + int square = 1; + boolean flag = true; + while (square + i < row & square + j < clo & flag) { + for (int k = j; k <= square + j; k++) { + if (matrix[i + square][k] == '0') { + flag = false; + break; + } + } + for (int k = i; k <= square + i; k++) { + if (matrix[k][j + square] == '0') { + flag = false; + break; + } + } + if (flag) + square++; + } + if (maxSquare < square) { + maxSquare = square; + } + } + } + } + return maxSquare * maxSquare; + } + + /** + * 动态规划 + * @param matrix + * @return + */ + public int maximalSquare_2(char[][] matrix) { + int rows = matrix.length, cols = rows > 0 ? matrix[0].length : 0; + int[][] dp = new int[rows + 1][cols + 1]; + int maxsqlen = 0; + for (int i = 1; i <= rows; i++) { + for (int j = 1; j <= cols; j++) { + if (matrix[i-1][j-1] == '1'){ + dp[i][j] = Math.min(Math.min(dp[i][j - 1], dp[i - 1][j]), dp[i - 1][j - 1]) + 1; + maxsqlen = Math.max(maxsqlen, dp[i][j]); + } + } + } + return maxsqlen * maxsqlen; + } + + +} diff --git a/Week_05/G20200343030391/LeetCode_53_391.java b/Week_05/G20200343030391/LeetCode_53_391.java new file mode 100644 index 00000000..e15a87d9 --- /dev/null +++ b/Week_05/G20200343030391/LeetCode_53_391.java @@ -0,0 +1,31 @@ +package G20200343030391; + + +public class LeetCode_53_391 { + + public static void main(String[] args) { + int[] nums = {1}; + int i = new LeetCode_53_391().maxSubArray_1(nums); + System.out.println(i); + } + + /** + * 动态规划 + * @param nums + * @return + */ + public int maxSubArray_1(int[] nums) { + if (nums == null || nums.length == 0) return 0; + int ans = 0; + int[] dp = new int[nums.length]; + dp[0] = nums[0]; + ans = dp[0]; + + for (int i = 1; i < nums.length; i++) { + dp[i] = Math.max(dp[i - 1], 0) + nums[i]; + ans = Math.max(dp[i], ans); + } + return ans; + } + +} diff --git a/Week_05/G20200343030391/LeetCode_62_391.java b/Week_05/G20200343030391/LeetCode_62_391.java new file mode 100644 index 00000000..985c2f25 --- /dev/null +++ b/Week_05/G20200343030391/LeetCode_62_391.java @@ -0,0 +1,53 @@ +package G20200343030391; + +import java.util.Arrays; + +public class LeetCode_62_391 { + + public static void main(String[] args) { + int m = 4; + int n = 4; + int i = new LeetCode_62_391().uniquePaths_2(m, n); + System.out.println(i); + + } + + /** + * 二维数组 + * @param m + * @param n + * @return + */ + public int uniquePaths(int m, int n) { + int[][] dp = new int[m][n]; + for (int i = 0; i < n; i++) { + dp[0][i] = 1; + } + for (int i = 0; i < m; i++) { + dp[i][0] = 1; + } + for (int i = 1; i < m; i++) { + for (int j = 1; j < n; j++) { + dp[i][j] = dp[i - 1][j] + dp[i][j - 1]; + } + } + return dp[m - 1][n - 1]; + } + /** + * 一维数组 + * @param m + * @param n + * @return + */ + public int uniquePaths_2(int m, int n) { + int[] line = new int[n]; + Arrays.fill(line, 1); + for (int i = 1; i < m; i++) { + for (int j = 1; j < n; j++) { + line[j] += line[j - 1]; + } + } + return line[n - 1]; + } + +} diff --git a/Week_05/G20200343030391/LeetCode_63_391.java b/Week_05/G20200343030391/LeetCode_63_391.java new file mode 100644 index 00000000..3862ba50 --- /dev/null +++ b/Week_05/G20200343030391/LeetCode_63_391.java @@ -0,0 +1,77 @@ +package G20200343030391; + +public class LeetCode_63_391 { + + public static void main(String[] args) { + int[][] obstacleGrid = new int[30][30]; + obstacleGrid[1][1] = 1; + int i = new LeetCode_63_391().uniquePathsWithObstacles_2(obstacleGrid); + System.out.println(i); + } + + /** + * 自底向上 + * + * @param obstacleGrid + * @return + */ + public int uniquePathsWithObstacles_1(int[][] obstacleGrid) { + int m = obstacleGrid.length; + int n = obstacleGrid[0].length; + //考虑特殊情况 + if (obstacleGrid[0][0] == 1 || obstacleGrid[m - 1][n - 1] == 1) return 0; + if (obstacleGrid[0][0] == 0 && m == 1 && n == 1) return 1; + + int[][] dp = new int[m][n]; + for (int i = 0; i < m; i++) { + if (obstacleGrid[i][0] != 1) { + dp[i][0] = 1; + } else { + break; + } + } + for (int i = 0; i < n; i++) { + if (obstacleGrid[0][i] != 1) { + dp[0][i] = 1; + } else { + break; + } + } + + for (int i = 1; i < dp.length; i++) { + for (int j = 1; j < dp[i].length; j++) { + if (obstacleGrid[i][j] != 1) { + dp[i][j] = dp[i][j - 1] + dp[i - 1][j]; + } + } + } + return dp[m - 1][n - 1]; + } + /** + * 记忆化搜索自顶向下 + * + * @param obstacleGrid + * @return + */ + public int uniquePathsWithObstacles_2(int[][] obstacleGrid) { + int m = obstacleGrid.length; + int n = obstacleGrid[0].length; + Integer[][] memo = new Integer[m][n]; + return memoSearch(obstacleGrid, 0, 0,memo); + } + + + private int memoSearch(int[][] obstacleGrid, int m, int n, Integer[][] memo) { + if (m == obstacleGrid.length - 1 && n == obstacleGrid[0].length - 1 && obstacleGrid[m][n] != 1) { + return memo[m][n] = 1; + } + if (m > obstacleGrid.length - 1 || n > obstacleGrid[0].length - 1 || obstacleGrid[m][n] == 1) { + return 0; + } + if (memo[m][n] != null) { + return memo[m][n]; + } + return memo[m][n] = memoSearch(obstacleGrid, m + 1, n, memo) + memoSearch(obstacleGrid, m, n + 1, memo); + } + +} diff --git a/Week_05/G20200343030391/LeetCode_64_391.java b/Week_05/G20200343030391/LeetCode_64_391.java new file mode 100644 index 00000000..684ffc17 --- /dev/null +++ b/Week_05/G20200343030391/LeetCode_64_391.java @@ -0,0 +1,45 @@ +package G20200343030391; + +public class LeetCode_64_391 { + + public static void main(String[] args) { + int[][] grid = { + {1, 3, 1}, + {1, 5, 1}, + {4, 2, 1} + }; + int minPathSum = new LeetCode_64_391().minPathSum(grid); + System.out.println(minPathSum); + + } + + /** + * 动态规划 + * dp[i][j] = min(dp[i-1][j],dp[i][j-1])+nums[i][j] + * + * @param grid + * @return + */ + public int minPathSum(int[][] grid) { + int m = grid.length; + int n = grid[0].length; + int[][] dp = new int[m][n]; + + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + if (i == 0 && j == 0) { + dp[i][j] = grid[i][j]; + continue; + } else if (i == 0) { + dp[i][j] = dp[i][j - 1] + grid[i][j]; + } else if (j == 0) { + dp[i][j] = dp[i - 1][j] + grid[i][j]; + } else { + dp[i][j] = Math.min(dp[i - 1][j], dp[i][j - 1]) + grid[i][j]; + + } + } + } + return dp[m - 1][n - 1]; + } +} diff --git a/Week_05/G20200343030391/LeetCode_91_391.java b/Week_05/G20200343030391/LeetCode_91_391.java new file mode 100644 index 00000000..ed955da3 --- /dev/null +++ b/Week_05/G20200343030391/LeetCode_91_391.java @@ -0,0 +1,42 @@ +package G20200343030391; + +public class LeetCode_91_391 { + + public static void main(String[] args) { + String s = "12"; + int i = new LeetCode_91_391().numDecodings(s); + System.out.println(i); + } + + /** + * 动态规划 + * + * @param s + * @return + */ + public int numDecodings(String s) { + char[] chars = s.toCharArray(); + int[] dp = new int[s.length() + 1]; + dp[0] = 1; + dp[1] = chars[0] == '0' ? 0 : 1; + if (s.length() <= 1) return dp[1]; + for (int i = 2; i <= chars.length; i++) { + int n = (chars[i - 2] - '0') * 10 + (chars[i - 1] - '0'); + if (chars[i - 1] == '0' && chars[i - 2] == '0') {//00X + return 0; + } else if (chars[i - 2] == '0') {//01X + dp[i] = dp[i - 1]; + } else if (chars[i - 1] == '0') {//10X + if (n > 26) { + return 0; + } + dp[i] = dp[i - 2]; + } else if (n > 26) { + dp[i] = dp[i - 1]; + } else { + dp[i] = dp[i - 1] + dp[i - 2]; + } + } + return dp[dp.length - 1]; + } +} diff --git a/Week_05/G20200343030391/NOTE.md b/Week_05/G20200343030391/NOTE.md index 50de3041..a11256b6 100644 --- a/Week_05/G20200343030391/NOTE.md +++ b/Week_05/G20200343030391/NOTE.md @@ -1 +1,15 @@ -学习笔记 \ No newline at end of file +# 动态规划 +## 关键点 + - 动态规划和递归或者分治没有根本上的区别(关键看有无最优子结构) + - 共性:找到重复子问题 + - 差异性:最优子结构,中途可以淘汰次优解(反悔) + - 状态转移方程(DP方程) +## 解题步骤 + - 最优子结构 opt[n]=best_of(opt[n-1],opt[n-2]) + - 存储中间状态 opt[i] + - 递推公式(状态转移方程 or DP方程) + - fib:opt[n]=best_of(opt[n-1],opt[n-2]) + - 二维路径:opt[i,j]= opt[i+1,j]+opt[i,j+1] +## 总结 + - 打破思维惯性,形成及其思维,找重复性 + - 理解复杂逻辑的关键 \ No newline at end of file diff --git a/Week_05/G20200343030393/LeetCode_198_393.py b/Week_05/G20200343030393/LeetCode_198_393.py new file mode 100644 index 00000000..00e02959 --- /dev/null +++ b/Week_05/G20200343030393/LeetCode_198_393.py @@ -0,0 +1,15 @@ +class Solution(object): + def rob(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + last = now = 0 + for i in nums: + last, now = now, max(last + i, now) + return now + + +nums = [1, 2, 3, 1] +aa = Solution() +print(aa.rob(nums)) \ No newline at end of file diff --git a/Week_05/G20200343030393/LeetCode_32_393.py b/Week_05/G20200343030393/LeetCode_32_393.py new file mode 100644 index 00000000..58351f1c --- /dev/null +++ b/Week_05/G20200343030393/LeetCode_32_393.py @@ -0,0 +1,16 @@ +class Solution: + def longestValidParentheses(self, s: str) -> int: + dp, stack = [0] * (len(s) + 1), [] + for i in range(len(s)): + if s[i] == "(": + stack.append(i) + else: + if stack: + p = stack.pop() + dp[i + 1] = dp[p] + i - p + 1 + return max(dp) + + +s = "()(()" +aa = Solution() +print(aa.longestValidParentheses(s)) \ No newline at end of file diff --git a/Week_05/G20200343030393/LeetCode_64_393.py b/Week_05/G20200343030393/LeetCode_64_393.py new file mode 100644 index 00000000..625fb501 --- /dev/null +++ b/Week_05/G20200343030393/LeetCode_64_393.py @@ -0,0 +1,26 @@ +class Solution(object): + def minPathSum(self, grid): + """ + :type grid: List[List[int]] + :rtype: int + """ + for i in range(len(grid)): + for j in range(len(grid[0])): + if i == j == 0: + continue + elif i == 0: + grid[i][j] += grid[i][j - 1] + elif j == 0: + grid[i][j] += grid[i - 1][j] + else: + grid[i][j] += min(grid[i - 1][j], grid[i][j - 1]) + return grid[-1][-1] + + +grid = [ + [1, 3, 1], + [1, 5, 1], + [4, 2, 1] +] +aa = Solution() +print(aa.minPathSum(grid)) diff --git a/Week_05/G20200343030395/LeetCode_1143_395.java b/Week_05/G20200343030395/LeetCode_1143_395.java new file mode 100644 index 00000000..c67927b3 --- /dev/null +++ b/Week_05/G20200343030395/LeetCode_1143_395.java @@ -0,0 +1,20 @@ +package Week_05.G20200343030395; + +public class LeetCode_1143_395 { + public int longestCommonSubsequence(String text1, String text2) { + int l1 = text1.length(), l2 = text2.length(); + int[][] dp = new int[l1+1][l2+1]; + + for (int i=1; i<=l1; i++) { + for (int j=1; j<=l2; j++) { + if(text1.charAt(i-1) == text2.charAt(j-1)) { + dp[i][j] = dp[i-1][j-1] + 1; + } else { + dp[i][j] = Math.max(dp[i-1][j], dp[i][j-1]); + } + } + } + + return dp[l1][l2]; + } +} diff --git a/Week_05/G20200343030395/LeetCode_1_395.java b/Week_05/G20200343030395/LeetCode_1_395.java new file mode 100644 index 00000000..d91eec40 --- /dev/null +++ b/Week_05/G20200343030395/LeetCode_1_395.java @@ -0,0 +1,22 @@ +package Week_05.G20200343030395; + +public class LeetCode_1_395 { + + public int minPathSum(int[][] grid) { + for (int i=0; i < grid.length; i++) { + for (int j=0; j 0 ? matrix[0].length : 0; + + int[][] dp = new int[rows + 1][cows + 1]; + + int maxsqlen = 0; + for (int i=1; i<=rows; i++) { + for (int j=1; j<=cows; j++) { + if(matrix[i-1][j-1] == '1') { + /** + * 里面的min: 取横着的和竖着的是不是0的,是0就不是正方形,都是x就可以变成x + * 外面的min:如果可以扩展成正方形,那就是min(x, dp[i-1][j-1])+1,至少0+1; + * 如果不能,就是min(0, dp[i-1][j-1]+1), 就是0了 + */ + dp[i][j] = Math.min(Math.min(dp[i][j-1], dp[i-1][j]), dp[i-1][j-1]) + 1; + maxsqlen = Math.max(maxsqlen, dp[i][j]); + } + } + } + + return maxsqlen * maxsqlen; + } +} diff --git a/Week_05/G20200343030395/NOTE.md b/Week_05/G20200343030395/NOTE.md index 50de3041..40a85df0 100644 --- a/Week_05/G20200343030395/NOTE.md +++ b/Week_05/G20200343030395/NOTE.md @@ -1 +1,6 @@ -学习笔记 \ No newline at end of file +学习笔记 +## 2020/3/9 +动态规划(DP)关键点: +1. 动态规划和递归或者分治没有本质上的区别,主要看有没有最优子结构 +2. 共性在于找重复子问题 +3. 差异性: 动态规划有最优子结构,中途可以淘汰次优解 \ No newline at end of file diff --git a/Week_05/G20200343030401/LeetCode_312_401.java b/Week_05/G20200343030401/LeetCode_312_401.java new file mode 100644 index 00000000..5d16b06b --- /dev/null +++ b/Week_05/G20200343030401/LeetCode_312_401.java @@ -0,0 +1,23 @@ +//题目链接:https://leetcode-cn.com/problems/burst-balloons/ +class Solution{ + public int maxCoins(int[] nums){ + int dp[][] = new int[nums.length][nums.length]; + if(nums.length == 0){ + return 0; + } + for(int i = 0; inums.length-1 ? 1 : nums[end+1]) + (start>i-1 ? 0 : dp[start][i-1]) + (end < i+1 ? 0 : dp[i+1][end])); + } + dp[start][end] = max; + } +} + diff --git a/Week_05/G20200343030401/LeetCode_410_401.java b/Week_05/G20200343030401/LeetCode_410_401.java new file mode 100644 index 00000000..46a35f8a --- /dev/null +++ b/Week_05/G20200343030401/LeetCode_410_401.java @@ -0,0 +1,25 @@ +//题目链接:https://leetcode-cn.com/problems/split-array-largest-sum/ +class Solution { + public int splitArray(int[] nums, int m) { + int n = nums.length; + int[][] f = new int[n + 1][m + 1]; + int[] sub = new int[n + 1]; + for (int i = 0; i <= n; i++) { + for (int j = 0; j <= m; j++) { + f[i][j] = Integer.MAX_VALUE; + } + } + for (int i = 0; i < n; i++) { + sub[i + 1] = sub[i] + nums[i]; + } + f[0][0] = 0; + for (int i = 1; i <= n; i++) { + for (int j = 1; j <= m; j++) { + for (int k = 0; k < i; k++) { + f[i][j] = Math.min(f[i][j], Math.max(f[k][j - 1], sub[i] - sub[k])); + } + } + } + return f[n][m]; + } +} diff --git a/Week_05/G20200343030401/LeetCode_64_401.java b/Week_05/G20200343030401/LeetCode_64_401.java new file mode 100644 index 00000000..28c957b4 --- /dev/null +++ b/Week_05/G20200343030401/LeetCode_64_401.java @@ -0,0 +1,16 @@ +//题目链接:https://leetcode-cn.com/problems/minimum-path-sum/solution/zui-xiao-lu-jing-he-by-leetcode/ +public class Solution { + public int minPathSum(int[][] grid) { + for (int i = grid.length - 1; i >= 0; i--) { + for (int j = grid[0].length - 1; j >= 0; j--) { + if(i == grid.length - 1 && j != grid[0].length - 1) + grid[i][j] = grid[i][j] + grid[i][j + 1]; + else if(j == grid[0].length - 1 && i != grid.length - 1) + grid[i][j] = grid[i][j] + grid[i + 1][j]; + else if(j != grid[0].length - 1 && i != grid.length - 1) + grid[i][j] = grid[i][j] + Math.min(grid[i + 1][j],grid[i][j + 1]); + } + } + return grid[0][0]; + } +} diff --git "a/Week_05/G20200343030407/[64]\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214.py" "b/Week_05/G20200343030407/[64]\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214.py" new file mode 100644 index 00000000..3cb2a2df --- /dev/null +++ "b/Week_05/G20200343030407/[64]\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214.py" @@ -0,0 +1,45 @@ +# 给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。 +# +# 说明:每次只能向下或者向右移动一步。 +# +# 示例: +# +# 输入: +# [ +#   [1,3,1], +# [1,5,1], +# [4,2,1] +# ] +# 输出: 7 +# 解释: 因为路径 1→3→1→1→1 的总和最小。 +# +# Related Topics 数组 动态规划 +from typing import List + + +# leetcode submit region begin(Prohibit modification and deletion) +class Solution: + def minPathSum(self, grid: List[List[int]]) -> int: + grid_copy = grid + m = len(grid) + n = len(grid[0]) + if m == 1 or n == 1: + total = 0 + for i in range(m): + for j in range(n): + total = total + grid[i][j] + return total + for i in range(m - 2, -1, -1): + grid_copy[i][n - 1] = grid[i + 1][n - 1] + grid[i][n - 1] + for j in range(n - 2, -1, -1): + grid_copy[m - 1][j] = grid[m - 1][j + 1] + grid[m - 1][j] + for i in range(m - 2, -1, -1): + row_list = grid[i] + for j in range(len(row_list) - 2, -1, -1): + grid_copy[i][j] = grid[i][j] + min(grid_copy[i + 1][j], grid_copy[i][j + 1]) + return grid_copy[0][0] + + +grid_ = [[1, 7]] +print(Solution().minPathSum(grid_)) +# leetcode submit region end(Prohibit modification and deletion) diff --git "a/Week_05/G20200343030407/[91]\350\247\243\347\240\201\346\226\271\346\263\225.py" "b/Week_05/G20200343030407/[91]\350\247\243\347\240\201\346\226\271\346\263\225.py" new file mode 100644 index 00000000..f3afa18e --- /dev/null +++ "b/Week_05/G20200343030407/[91]\350\247\243\347\240\201\346\226\271\346\263\225.py" @@ -0,0 +1,43 @@ +# 一条包含字母 A-Z 的消息通过以下方式进行了编码: +# +# 'A' -> 1 +# 'B' -> 2 +# ... +# 'Z' -> 26 +# +# +# 给定一个只包含数字的非空字符串,请计算解码方法的总数。 +# +# 示例 1: +# +# 输入: "12" +# 输出: 2 +# 解释: 它可以解码为 "AB"(1 2)或者 "L"(12)。 +# +# +# 示例 2: +# +# 输入: "226" +# 输出: 3 +# 解释: 它可以解码为 "BZ" (2 26), "VF" (22 6), 或者 "BBF" (2 2 6) 。 +# +# Related Topics 字符串 动态规划 + + +# leetcode submit region begin(Prohibit modification and deletion) +class Solution: + def numDecodings(self, s: str) -> int: + if s == '': + return 0 + # dp[i] = (dp[i-1] if s[i] != '0') + (dp[i-2] if "09" < s[i-1:i+1] < "27") + dp = [0 for _ in range(len(s) + 1)] + dp[0] = 1 + for i in range(1, len(s)+1): + if s[i - 1] != '0': + dp[i] += dp[i - 1] + if i != 1 and "09" < s[i - 2:i] < "27": # "01"ways = 0 + dp[i] += dp[i - 2] + return dp[len(s)] + + +# leetcode submit region end(Prohibit modification and deletion) diff --git a/Week_05/G20200343030409/LeetCode_221_409.java b/Week_05/G20200343030409/LeetCode_221_409.java new file mode 100644 index 00000000..4bf622cc --- /dev/null +++ b/Week_05/G20200343030409/LeetCode_221_409.java @@ -0,0 +1,37 @@ +/* + 如果 matrix[i-1][j-1] == 0 ,DP[i, j] 也是 0,因為 square 不存在 + + 如果 matrix[i-1][j-1] == 1,那麼 DP[i, j] 就有以下幾種可能 + 1)從DP [i-1,j] 這個形狀 加上一行 + 2)從DP [i, j-1] 這個形狀 加上一列 + 3)從DP [i-1, j-1] 這個正方形加上一行和一列 + + 子問題 + dp array: dp[i][j] = Math.min(Math.min(dp[i-1][j], dp[i][j-1]), dp[i-1][j-1]) + 1; + dp 方程 + + + time complexity: O(m*n), space complexity: O(m*n), m is matrix's width, n is matrix's height + +*/ + +class Solution { + public int maximalSquare(char[][] matrix) { + int m = matrix.length; + if (m == 0) return 0; + int n = matrix[0].length; + + int dp[][] = new int[m+1][n+1]; + int maxLen = 0; + + for (int i = 1 ; i <= m; i++) { + for (int j = 1; j <= n; j++) { + if (matrix[i-1][j-1] == '1') { + dp[i][j] = Math.min(Math.min(dp[i-1][j], dp[i][j-1]), dp[i-1][j-1]) + 1; + maxLen = Math.max(maxLen, dp[i][j]); + } + } + } + return maxLen*maxLen; + } +} \ No newline at end of file diff --git a/Week_05/G20200343030409/LeetCode_91_409.java b/Week_05/G20200343030409/LeetCode_91_409.java new file mode 100644 index 00000000..9a7a3ec1 --- /dev/null +++ b/Week_05/G20200343030409/LeetCode_91_409.java @@ -0,0 +1,31 @@ +/* + + time complexity: O(n), space complexity: O(n) + +*/ +class Solution { + public int numDecodings(String s) { + int n = s.length(); + int dp[] = new int[n+1]; + + dp[0] = 1; // empty string + dp[1] = s.charAt(0) == '0' ? 0 : 1; + + for(int i = 2; i <= n; i++) { + // 枚舉最後一個字母對應2位, 成立代表在 i-2 位置上可以有方法 + int twoDigit = Integer.parseInt(s.substring(i-2, i)); + if(twoDigit >= 10 && twoDigit <= 26) { + dp[i] += dp[i-2]; + } + + // 枚舉最後一個字母對應1位, 成立代表在 i-1 位置上可以有方法 + int oneDigit = Integer.parseInt(s.substring(i-1, i)); + + if(oneDigit >= 1 && oneDigit <= 9) { + dp[i] += dp[i-1]; + } + } + + return dp[n]; + } +} \ No newline at end of file diff --git a/Week_05/G20200343030411/LeetCode_1143_441.java b/Week_05/G20200343030411/LeetCode_1143_441.java new file mode 100644 index 00000000..0b98708a --- /dev/null +++ b/Week_05/G20200343030411/LeetCode_1143_441.java @@ -0,0 +1,45 @@ +/* + * @lc app=leetcode.cn id=1143 lang=java + * + * [1143] 最长公共子序列 + */ + +// @lc code=start +class Solution { + // 自己的解法,效率低 + public int longestCommonSubsequence(String text1, String text2) { + int[][] states = new int[text1.length()][text2.length()]; + + int flag = 0; + for (int i = 0; i < text1.length(); ++i){ + if (flag == 1) states[i][0] = 1; + else if (text1.charAt(i) == text2.charAt(0)){ + states[i][0] = 1; + flag = 1; + } + } + + flag = 0; + for (int i = 0; i < text2.length(); ++i){ + if (flag == 1) states[0][i] = 1; + else if (text2.charAt(i) == text1.charAt(0)){ + states[0][i] = 1; + flag = 1; + } + } + + for (int i = 1; i < text1.length(); ++i){ + for (int j = 1; j < text2.length(); ++j){ + if (text1.charAt(i) == text2.charAt(j)){ + states[i][j] = states[i-1][j-1] + 1; + }else { + states[i][j] = Math.max(states[i][j-1], states[i-1][j]); + } + } + } + + return states[text1.length()-1][text2.length()-1]; + } +} +// @lc code=end + diff --git a/Week_05/G20200343030411/LeetCode_120_441.java b/Week_05/G20200343030411/LeetCode_120_441.java new file mode 100644 index 00000000..ce2e109f --- /dev/null +++ b/Week_05/G20200343030411/LeetCode_120_441.java @@ -0,0 +1,29 @@ +/* + * @lc app=leetcode.cn id=120 lang=java + * + * [120] 三角形最小路径和 + */ + +// @lc code=start +class Solution { + public int minimumTotal(List> triangle) { + + int m = triangle.size(); + + if (m == 0) return 0; + + int[][] states = new int[m][m]; + + for (int i = 0; i < m; ++i) states[i][m-1] = triangle.get(m-1).get(i); + + for (int j = m-2; j >= 0; --j){ + for (int i = j; i >=0; --i){ + states[i][j] = Math.min(states[i][j+1], states[i+1][j+1]) + triangle.get(j).get(i); + } + } + + return states[0][0]; + } +} +// @lc code=end + diff --git a/Week_05/G20200343030411/LeetCode_121_441.java b/Week_05/G20200343030411/LeetCode_121_441.java new file mode 100644 index 00000000..37ad86e7 --- /dev/null +++ b/Week_05/G20200343030411/LeetCode_121_441.java @@ -0,0 +1,33 @@ +/* + * @lc app=leetcode.cn id=121 lang=java + * + * [121] 买卖股票的最佳时机 + */ + +// @lc code=start +class Solution { + public int maxProfit(int[] prices) { + int max_profit = 0; + int in_index = 0; + int out_index = 0; + + for (int i = 1; i < prices.length; ++i){ + if (in_index == out_index && prices[i] < prices[in_index]){ + out_index = i; + in_index = i; + } + if (prices[i] > prices[out_index]){ + out_index = i; + max_profit = Math.max(max_profit, prices[out_index] - prices[in_index]); + } + if (prices[i] < prices[in_index]){ + out_index = i; + in_index = i; + } + } + + return max_profit; + } +} +// @lc code=end + diff --git a/Week_05/G20200343030411/LeetCode_122_441.java b/Week_05/G20200343030411/LeetCode_122_441.java new file mode 100644 index 00000000..801494c7 --- /dev/null +++ b/Week_05/G20200343030411/LeetCode_122_441.java @@ -0,0 +1,33 @@ +/* + * @lc app=leetcode.cn id=122 lang=java + * + * [122] 买卖股票的最佳时机 II + */ + +// @lc code=start +class Solution { + public int maxProfit(int[] prices) { + + int profit = 0; + + int in_index = 0; + int out_index = 0; + + while (out_index < prices.length){ + if (out_index == prices.length-1){ + profit += prices[out_index] - prices[in_index]; + break; + } + + out_index++; + if (prices[out_index] <= prices[out_index-1]){ + profit += prices[out_index-1] - prices[in_index]; + in_index = out_index; + } + } + + return profit; + } +} +// @lc code=end + diff --git a/Week_05/G20200343030411/LeetCode_152_441.java b/Week_05/G20200343030411/LeetCode_152_441.java new file mode 100644 index 00000000..8b163e6d --- /dev/null +++ b/Week_05/G20200343030411/LeetCode_152_441.java @@ -0,0 +1,30 @@ +/* + * @lc app=leetcode.cn id=152 lang=java + * + * [152] 乘积最大子序列 + */ + +// @lc code=start +class Solution { + public int maxProduct(int[] nums) { + if (nums.length == 0) return 0; + + int[] states = new int[nums.length]; // 记录最大 + int[] states_minus = new int[nums.length]; // 记录最小 + + states[0] = nums[0]; + states_minus[0] = nums[0]; + + for (int i = 1; i < nums.length; ++i){ + states[i] = Math.max(nums[i], Math.max(nums[i]*states[i-1], nums[i]*states_minus[i-1])); + states_minus[i] = Math.min(nums[i], Math.min(nums[i]*states[i-1], nums[i]*states_minus[i-1])); + } + + int res = states[0]; + for (int s : states) if (res < s) res = s; + + return res; + } +} +// @lc code=end + diff --git a/Week_05/G20200343030411/LeetCode_198_441.java b/Week_05/G20200343030411/LeetCode_198_441.java new file mode 100644 index 00000000..89c75409 --- /dev/null +++ b/Week_05/G20200343030411/LeetCode_198_441.java @@ -0,0 +1,34 @@ +import java.util.HashMap; + +/* + * @lc app=leetcode.cn id=198 lang=java + * + * [198] 打家劫舍 + */ + +// @lc code=start +class Solution { + public int rob(int[] nums) { + int[] states = new int[nums.length]; + + if (nums.length == 0) return 0; + + if (nums.length == 1) return nums[0]; + + if (nums.length == 2)return Math.max(nums[0], nums[1]); + + if (nums.length == 3) return Math.max(nums[2] + nums[0], nums[1]); + + states[0] = nums[0]; + states[1] = nums[1]; + states[2] = nums[2] + nums[0]; + + for (int i = 3; i < nums.length; ++i){ + states[i] = Math.max(states[i-2], states[i-3]) + nums[i]; + } + + return Math.max(states[nums.length-1], states[nums.length-2]); + } +} +// @lc code=end + diff --git a/Week_05/G20200343030411/LeetCode_213_441.java b/Week_05/G20200343030411/LeetCode_213_441.java new file mode 100644 index 00000000..454122e1 --- /dev/null +++ b/Week_05/G20200343030411/LeetCode_213_441.java @@ -0,0 +1,57 @@ +/* + * @lc app=leetcode.cn id=213 lang=java + * + * [213] 打家劫舍 II + */ + +// @lc code=start +class Solution { + public int rob(int[] nums) { + + int n = nums.length; + if (n == 0) return 0; + if (n == 1) return nums[0]; + if (n == 2) return Math.max(nums[0], nums[1]); + + return Math.max(myRob(1,n-1,nums), myRob(0,n-2,nums)); + } + + private int myRob(int start, int end, int[] nums){ + int n = nums.length; + int state_2 = nums[start]; + int state_1 = Math.max(nums[start], nums[start+1]); + int state_i = 0; + + for (int i = 2; i < n-1; ++i){ + state_i = Math.max(state_1, state_2+nums[start+i]); + state_2 = state_1; + state_1 = state_i; + } + + return Math.max(state_2, Math.max(state_1, state_i)); + } + + // 国内站高票方法 + // public int rob(int[] nums) { + // int n = nums.length; + // if (n == 1) return nums[0]; + // return Math.max(robRange(nums, 0, n - 2), + // robRange(nums, 1, n - 1)); + // } + + // // 仅计算闭区间 [start,end] 的最优结果 + // int robRange(int[] nums, int start, int end) { + // int n = nums.length; + // int dp_i_1 = 0, dp_i_2 = 0; + // int dp_i = 0; + // for (int i = end; i >= start; i--) { + // dp_i = Math.max(dp_i_1, nums[i] + dp_i_2); + // dp_i_2 = dp_i_1; + // dp_i_1 = dp_i; + // } + // return dp_i; + // } + +} +// @lc code=end + diff --git a/Week_05/G20200343030411/LeetCode_221_441.java b/Week_05/G20200343030411/LeetCode_221_441.java new file mode 100644 index 00000000..012a2c94 --- /dev/null +++ b/Week_05/G20200343030411/LeetCode_221_441.java @@ -0,0 +1,25 @@ +/* + * @lc app=leetcode.cn id=221 lang=java + * + * [221] 最大正方形 + */ + +// @lc code=start +class Solution { + public int maximalSquare(char[][] matrix) { + int rows = matrix.length, cols = rows > 0 ? matrix[0].length : 0; + int[][] dp = new int[rows + 1][cols + 1]; + int maxsqlen = 0; + for (int i = 1; i <= rows; i++) { + for (int j = 1; j <= cols; j++) { + if (matrix[i-1][j-1] == '1'){ + dp[i][j] = Math.min(Math.min(dp[i][j - 1], dp[i - 1][j]), dp[i - 1][j - 1]) + 1; + maxsqlen = Math.max(maxsqlen, dp[i][j]); + } + } + } + return maxsqlen * maxsqlen; + } +} +// @lc code=end + diff --git a/Week_05/G20200343030411/LeetCode_53_441.java b/Week_05/G20200343030411/LeetCode_53_441.java new file mode 100644 index 00000000..468d39c8 --- /dev/null +++ b/Week_05/G20200343030411/LeetCode_53_441.java @@ -0,0 +1,27 @@ +/* + * @lc app=leetcode.cn id=53 lang=java + * + * [53] 最大子序和 + */ + +// @lc code=start +class Solution { + public int maxSubArray(int[] nums) { + if (nums.length == 0) return 0; + int[] states = new int[nums.length]; + + states[0] = nums[0]; + + for (int i = 1; i < nums.length; ++i){ + if (states[i-1] + nums[i] < nums[i]) states[i] = nums[i]; + else states[i] = states[i-1] + nums[i]; + } + + int res = states[0]; + for (int s : states) if (res < s) res = s; + + return res; + } +} +// @lc code=end + diff --git a/Week_05/G20200343030411/LeetCode_62_441.java b/Week_05/G20200343030411/LeetCode_62_441.java new file mode 100644 index 00000000..26d2c655 --- /dev/null +++ b/Week_05/G20200343030411/LeetCode_62_441.java @@ -0,0 +1,25 @@ +/* + * @lc app=leetcode.cn id=62 lang=java + * + * [62] 不同路径 + */ + +// @lc code=start +class Solution { + public int uniquePaths(int m, int n) { + int[][] state = new int[m][n]; + + for (int i = 0; i < m; ++i) state[i][0] = 1; + for (int j = 0; j < n; ++j) state[0][j] = 1; + + for (int i = 1; i < m; ++i){ + for (int j = 1; j < n; ++j){ + state[i][j] = state[i-1][j] + state[i][j-1]; + } + } + + return state[m-1][n-1]; + } +} +// @lc code=end + diff --git a/Week_05/G20200343030411/LeetCode_63_441.java b/Week_05/G20200343030411/LeetCode_63_441.java new file mode 100644 index 00000000..90e90222 --- /dev/null +++ b/Week_05/G20200343030411/LeetCode_63_441.java @@ -0,0 +1,35 @@ +/* + * @lc app=leetcode.cn id=63 lang=java + * + * [63] 不同路径 II + */ + +// @lc code=start +class Solution { + public int uniquePathsWithObstacles(int[][] obstacleGrid) { + if (obstacleGrid.length == 0) return 0; + int m = obstacleGrid.length, n = obstacleGrid[0].length; + + int[][] states = new int[m][n]; + + for (int i = 0; i < m; ++i){ + if (obstacleGrid[i][0] == 1) break; + states[i][0] = 1; + } + for (int j = 0; j < n; ++j){ + if (obstacleGrid[0][j] == 1) break; + states[0][j] = 1; + } + + for (int i = 1; i < m; ++i){ + for (int j = 1; j < n; ++j){ + if (obstacleGrid[i][j] == 1) states[i][j] = 0; + else states[i][j] = states[i-1][j] + states[i][j-1]; + } + } + + return states[m-1][n-1]; + } +} +// @lc code=end + diff --git a/Week_05/G20200343030411/LeetCode_64_441.java b/Week_05/G20200343030411/LeetCode_64_441.java new file mode 100644 index 00000000..23745ce7 --- /dev/null +++ b/Week_05/G20200343030411/LeetCode_64_441.java @@ -0,0 +1,24 @@ +/* + * @lc app=leetcode.cn id=64 lang=java + * + * [64] 最小路径和 + */ + +// @lc code=start +class Solution { + public int minPathSum(int[][] grid) { + for (int i = grid.length - 1; i >= 0; i--) { + for (int j = grid[0].length - 1; j >= 0; j--) { + if(i == grid.length - 1 && j != grid[0].length - 1) + grid[i][j] = grid[i][j] + grid[i][j + 1]; + else if(j == grid[0].length - 1 && i != grid.length - 1) + grid[i][j] = grid[i][j] + grid[i + 1][j]; + else if(j != grid[0].length - 1 && i != grid.length - 1) + grid[i][j] = grid[i][j] + Math.min(grid[i + 1][j],grid[i][j + 1]); + } + } + return grid[0][0]; + } +} +// @lc code=end + diff --git a/Week_05/G20200343030411/LeetCode_91_441.java b/Week_05/G20200343030411/LeetCode_91_441.java new file mode 100644 index 00000000..6852bf64 --- /dev/null +++ b/Week_05/G20200343030411/LeetCode_91_441.java @@ -0,0 +1,31 @@ +/* + * @lc app=leetcode.cn id=91 lang=java + * + * [91] 解码方法 + */ + +// @lc code=start +class Solution { + public int numDecodings(String s) { + if(s == null || s.length() == 0) { + return 0; + } + int n = s.length(); + int[] dp = new int[n+1]; + dp[0] = 1; + dp[1] = s.charAt(0) != '0' ? 1 : 0; + for(int i = 2; i <= n; i++) { + int first = Integer.valueOf(s.substring(i-1, i)); + int second = Integer.valueOf(s.substring(i-2, i)); + if(first >= 1 && first <= 9) { + dp[i] += dp[i-1]; + } + if(second >= 10 && second <= 26) { + dp[i] += dp[i-2]; + } + } + return dp[n]; + } +} +// @lc code=end + diff --git a/Week_05/G20200343030415/LeetCode-221-415.java b/Week_05/G20200343030415/LeetCode-221-415.java new file mode 100644 index 00000000..0b2eb33e --- /dev/null +++ b/Week_05/G20200343030415/LeetCode-221-415.java @@ -0,0 +1,18 @@ +class Solution { + + public int maximalSquare(char[][] matrix) { + int rows = matrix.length,cols = rows > 0 ? matrix[0].length : 0; + int[] dp = new int[cols + 1]; + int maxsqlen = 0,prev = 0; + for (int i = 1; i <= rows; i++) { + for (int j = 1; j <= cols; j++) { + int temp = dp[j]; + if(matrix[i-1][j-1] == '1'){ + dp[j] = Math.min(Math.min(dp[j],prev),dp[j-1]) + 1; + } + prev = temp; + } + } + return dp[0]; + } +} \ No newline at end of file diff --git a/Week_05/G20200343030415/LeetCode-32-415.java b/Week_05/G20200343030415/LeetCode-32-415.java new file mode 100644 index 00000000..d062d1e0 --- /dev/null +++ b/Week_05/G20200343030415/LeetCode-32-415.java @@ -0,0 +1,19 @@ +class Solution { + public int longestValidParentheses(String s) { + int maxans = 0; + int[] dp = new int[s.length()]; + for (int i = 1; i < s.length(); i++) { + if(s.charAt(i) == ')'){ + if(s.charAt(i - 1) == '('){ + dp[i] = (i >= 2 ? dp[i-2] : 0) + 2; + }else if(i - dp[i - 1] > 0 && s.charAt(i - dp[i - 1] - 1) == '('){ + // ( ) ( ( ) ) + dp[i] = dp[i - 1] + ((i - dp[i - 1]) >= 2 ? dp[i -dp[i - 1] - 2] : 0) + 2; + } + maxans = Math.max(maxans,dp[i]); + } + + } + return maxans; + } +} \ No newline at end of file diff --git a/Week_05/G20200343030415/LeetCode-64-415.java b/Week_05/G20200343030415/LeetCode-64-415.java new file mode 100644 index 00000000..182e63ac --- /dev/null +++ b/Week_05/G20200343030415/LeetCode-64-415.java @@ -0,0 +1,22 @@ +class Solution { + + public int minPathSum(int[][] grid) { + int[] dp = new int[grid[0].length]; + for (int i = grid.length - 1; i >= 0; i--) { + for (int j = grid[0].length - 1; j >= 0; j--) { + if(i == grid.length - 1 && j != grid[0].length - 1){ + //dp[j+1]是右边的 + dp[j] = grid[i][j] + dp[j+1]; + }else if(i != grid.length - 1 && j == grid[0].length - 1){ + + dp[j] = grid[i][j] + dp[j];//dp[j]是上一行的 + }else if(i != grid.length - 1 && j != grid[0].length - 1){ + dp[j] = Math.min(dp[j],dp[j+1]) + grid[i][j]; + }else { + dp[j] = grid[i][j]; + } + } + } + return dp[0][0]; + } +} \ No newline at end of file diff --git a/Week_05/G20200343030415/LeetCode-91-415.java b/Week_05/G20200343030415/LeetCode-91-415.java new file mode 100644 index 00000000..c29f2600 --- /dev/null +++ b/Week_05/G20200343030415/LeetCode-91-415.java @@ -0,0 +1,27 @@ +class Solution { + + public int numDecodings(String s) { + int len = s.length(); + int[] dp = new int[len + 1]; + if(s.charAt(len - 1) == '0'){ + dp[len-1] = 1; + } + + for (int i = len - 2; i >= 0; i--) { + if(s.charAt(i) == '0'){ + continue; + } + int ans1 = dp[i + 1]; + int ans2 = 0; + int ten = (s.charAt(i) - '0') * 10; + int one = s.charAt(i + 1) - '0'; + if(ten + one <= 26){ + ans2 = dp[i + 2]; + } + dp[i] = ans1 + ans2; + } + return dp[0]; + } + + +} \ No newline at end of file diff --git a/Week_05/G20200343030417/417-week05-homework.py b/Week_05/G20200343030417/417-week05-homework.py new file mode 100644 index 00000000..cf63861c --- /dev/null +++ b/Week_05/G20200343030417/417-week05-homework.py @@ -0,0 +1,20 @@ +# 青蛙过河 +class Solution: + def canCross(self, stones): + dp = dict() + + for s in stones: + dp.setdefault(s,set()) + + dp.get(0).add(0) + + for s in stones: + for pre_step in dp.get(s): + for step in [pre_step-1,pre_step,pre_step+1]: + if step > 0 and (s+step) in dp: + dp.get(s+step).add(step) + return len(dp.get(stones[-1])) > 0 + + + + diff --git a/Week_05/G20200343030417/homework2.py b/Week_05/G20200343030417/homework2.py new file mode 100644 index 00000000..50fcc6fb --- /dev/null +++ b/Week_05/G20200343030417/homework2.py @@ -0,0 +1,18 @@ +# 最长有效括号 +class Solution: + def longestValidParentheses(self, s: str) -> int: + n = len(s) + if not s: return 0 + + dp = [0]*n + res = 0 + for i in range(n): + if i > 0 and s[i] == ')': + if s[i-1] == '(': + dp[i] = dp[i-1] + 2 + elif s[i-1] == ')' and i - dp[i-1] -1 >= 0 and s[i-dp[i-1]-1] == '(': + dp[i] = dp[i-1]+2+dp[i-dp[i-1]-2] + + if dp[i] > res: res = dp[i] + + return res \ No newline at end of file diff --git a/Week_05/G20200343030423/LeetCode_64_423.java b/Week_05/G20200343030423/LeetCode_64_423.java new file mode 100644 index 00000000..56647ca9 --- /dev/null +++ b/Week_05/G20200343030423/LeetCode_64_423.java @@ -0,0 +1,23 @@ +public class LeetCode_64_423 { +} + +class Solution64 { + public int minPathSum(int[][] grid) { + int m = grid.length; + int n = grid[0].length; + // init row + for (int i = 1; i < m; i++) { + grid[i][0] = grid[i-1][0] + grid[i][0]; + } + // init clols + for (int j = 1; j < n; j++) { + grid[0][j] = grid[0][j-1] + grid[0][j]; + } + for (int i = 1; i < m; i++) { + for (int j = 1; j < n; j++) { + grid[i][j] = Math.min(grid[i][j-1],grid[i-1][j]) + grid[i][j]; + } + } + return grid[m-1][n-1]; + } +} \ No newline at end of file diff --git a/Week_05/G20200343030423/LeetCode_91_423.java b/Week_05/G20200343030423/LeetCode_91_423.java new file mode 100644 index 00000000..9ed19bc0 --- /dev/null +++ b/Week_05/G20200343030423/LeetCode_91_423.java @@ -0,0 +1,30 @@ +public class LeetCode_91_423 { +} + +class Solution91 { + public int numDecodings(String s) { + if (s == null || s.length() == 0) { + return 0; + } + int len = s.length(); + int[] dp = new int[len + 1]; + dp[len] = 1; + if (s.charAt(len - 1) == '0') { + dp[len - 1] = 0; + } else { + dp[len - 1] = 1; + } + for (int i = len - 2; i >= 0; i--) { + if (s.charAt(i) == '0') { + dp[i] = 0; + continue; + } + if ((s.charAt(i) - '0') * 10 + (s.charAt(i + 1) - '0') <= 26) { + dp[i] = dp[i + 1] + dp[i + 2]; + } else { + dp[i] = dp[i + 1]; + } + } + return dp[0]; + } +} \ No newline at end of file diff --git a/Week_05/G20200343030425/LeetCode_221_425/LeetCode_221_425.js b/Week_05/G20200343030425/LeetCode_221_425/LeetCode_221_425.js new file mode 100644 index 00000000..8fd7a50e --- /dev/null +++ b/Week_05/G20200343030425/LeetCode_221_425/LeetCode_221_425.js @@ -0,0 +1,36 @@ +/* +* address: https://leetcode-cn.com/problems/maximal-square/ +* +* +* */ +const maximalSquare = function(matrix) { + let dp = []; + let len = matrix.length; + if(len === 0){ + return 0; + } + let len2 = matrix[0].length; + let i,j; + let max = 0; + for(i = 0 ; i= 0; i--) { + for (int j = grid[0].length - 1; j >= 0; j--) { + if (i == grid.length && j != grid[0].length - 1) + dp[i][j] = grid[i][j] + dp[i][j+1]; + else if (j == grid[0].length - 1 && i != grid.length - 1) + dp[i][j] = grid[i][j] + dp[i + 1][j]; + else if (j != grid[0].length - 1 && i != grid.length - 1) + dp[i][j] = grid[i][j] + Math.min(dp[i + 1], dp[i][j + 1]); + else + dp[i][j] = grid[i][j]; + } + } + return dp[0][0]; + } + +} \ No newline at end of file diff --git a/Week_05/G20200343030429/LeetCode_3_429.java b/Week_05/G20200343030429/LeetCode_3_429.java new file mode 100644 index 00000000..05e50f0c --- /dev/null +++ b/Week_05/G20200343030429/LeetCode_3_429.java @@ -0,0 +1,21 @@ +package com.study.week05; + +import java.lang.Math; + +public class LeetCode_3_429 { + public int maximalSquare(char[][] matrix) { + int rows = matrix.length, cols = rows > 0 ? matrix[0].length : 0; + int[][] dp = new int[rows + 1][cols + 1]; + int maxsqlen = 0; + for (int i = 1; i < rows; i++) { + for (int j = 1; j <= cols; j++) { + if (matrix[i-1][j-1] == '1') { + dp[i][j] = Math.min(Math.min(dp[i][j - 1], dp[i - 1][j]), dp[i - 1][j - 1]) + 1; + maxsqlen = Math.max(maxsqlen, dp[i][j]); + } + } + } + + return maxsqlen * maxsqlen; + } +} \ No newline at end of file diff --git a/Week_05/G20200343030431/LeetCode_621_431.java b/Week_05/G20200343030431/LeetCode_621_431.java new file mode 100644 index 00000000..b294bb7c --- /dev/null +++ b/Week_05/G20200343030431/LeetCode_621_431.java @@ -0,0 +1,23 @@ +package Alogrithm0308; +//借助leetcode +import java.util.Arrays; + +public class Solution621 { + public int leastInterval(char[] tasks, int n) { + int[] count = new int[26]; + for (int i = 0; i < tasks.length; i++) { + count[tasks[i]-'A']++; + }//统计词频 + Arrays.sort(count);//词频排序,升序排序,count[25]是频率最高的 + int maxCount = 0; + //统计有多少个频率最高的字母 + for (int i = 25; i >= 0; i--) { + if(count[i] != count[25]){ + break; + } + maxCount++; + } + //公式算出的值可能会比数组的长度小,取两者中最大的那个 + return Math.max((count[25] - 1) * (n + 1) + maxCount , tasks.length); + } +} diff --git a/Week_05/G20200343030431/LeetCode_64_431.java b/Week_05/G20200343030431/LeetCode_64_431.java new file mode 100644 index 00000000..85ea7598 --- /dev/null +++ b/Week_05/G20200343030431/LeetCode_64_431.java @@ -0,0 +1,33 @@ +package Alogrithm0308; +//借助leetcode +public class Solution64 { + public int minPathSum(int[][] grid) { + if (grid == null || grid.length < 1 || grid[0] == null || grid[0].length < 1) { + return 0; + } + + int row = grid.length; + int col = grid[row - 1].length; + + int dp[][] = new int[row][col]; + + dp[0][0] = grid[0][0]; + + for (int i = 1;i < row;i++) { + dp[i][0] = dp[i - 1][0] + grid[i][0]; + } + + for (int i = 1;i < col;i++) { + dp[0][i] = dp[0][i - 1] + grid[0][i]; + } + + for (int i = 1;i < row;i++) { + for (int j = 1;j < col;j++) { + dp[i][j] = Math.min(dp[i - 1][j], dp[i][j - 1]) + grid[i][j]; + } + } + + return dp[row - 1][col - 1]; + } + +} diff --git a/Week_05/G20200343030431/NOTE.md b/Week_05/G20200343030431/NOTE.md index 50de3041..965e0f1a 100644 --- a/Week_05/G20200343030431/NOTE.md +++ b/Week_05/G20200343030431/NOTE.md @@ -1 +1,9 @@ -学习笔记 \ No newline at end of file +学习笔记动 +态规划(英语:Dynamic programming,简称DP)是一种在数学、计算机科学和经济学中使用的, +通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。动态规划常常适用于有重叠子问题[1]和最优子结构性质的问题, +动态规划方法所耗时间往往远少于朴素解法。动态规划背后的基本思想非常简单。大致上,若要解一个给定问题, +我们需要解其不同部分(即子问题),再合并子问题的解以得出原问题的解。 +通常许多子问题非常相似,为此动态规划法试图仅仅解决每个子问题一次, +从而减少计算量:一旦某个给定子问题的解已经算出,则将其记忆化(en:memoization)存储, +以便下次需要同一个子问题解之时直接查表。这种做法在重复子问题的数目关于输入的规模呈指数增长时特别有用. +简言之动态规划的思路是通过寻找最优子结构同时记录最优结构,从而将复杂的大问题转化为小问题的求解过程。 \ No newline at end of file diff --git a/Week_05/G20200343030433/Leetcode_221_433.py b/Week_05/G20200343030433/Leetcode_221_433.py new file mode 100644 index 00000000..5f2f8084 --- /dev/null +++ b/Week_05/G20200343030433/Leetcode_221_433.py @@ -0,0 +1,15 @@ + if not matrix: return 0 + res = 0 + for i in range(len(matrix)): + for j in range(len(matrix[0])): + if matrix[i][j] == '1': + matrix[i][j] = 1 + if i == 0 or j == 0: + res = max(matrix[i][j], res) + else: + matrix[i][j] = min(matrix[i-1][j], matrix[i-1][j-1], matrix[i][j-1])+1 + res = max(matrix[i][j], res) + else: + matrix[i][j] = 0 + return res**2 + diff --git a/Week_05/G20200343030433/Leetcode_64_433.py b/Week_05/G20200343030433/Leetcode_64_433.py new file mode 100644 index 00000000..18ad19ef --- /dev/null +++ b/Week_05/G20200343030433/Leetcode_64_433.py @@ -0,0 +1,12 @@ +m = len(grid) + n = len(grid[0]) + dp = [0]*n + dp[0] = grid[0][0] + for k in range(1,n): + dp[k] = dp[k-1] + grid[0][k] + for i in range(1,m): + for j in range(0,n): + if j == 0 : dp[j] += grid[i][j] + else: + dp[j] = min(dp[j-1],dp[j])+grid[i][j] + return dp[-1] diff --git a/Week_05/G20200343030435/LeetCode_1143_435.js b/Week_05/G20200343030435/LeetCode_1143_435.js new file mode 100644 index 00000000..b1ee43e1 --- /dev/null +++ b/Week_05/G20200343030435/LeetCode_1143_435.js @@ -0,0 +1,15 @@ +let longestCommonSubsequence = function(text1, text2) { + const n = text1.length; + const m = text2.length; + const lcs = Array.from(new Array(n + 1), () => new Array(m + 1).fill(0)); + for (let i = 1; i <= n; i++) { + for (let j = 1; j <= m; j++) { + if (text1[i - 1] === text2[j - 1]) { + lcs[i][j] = lcs[i - 1][j - 1] + 1; + } else { + lcs[i][j] = Math.max(lcs[i][j - 1], lcs[i - 1][j]); + } + } + } + return lcs[n][m]; +}; diff --git a/Week_05/G20200343030435/LeetCode_647_435.js b/Week_05/G20200343030435/LeetCode_647_435.js new file mode 100644 index 00000000..f8887a30 --- /dev/null +++ b/Week_05/G20200343030435/LeetCode_647_435.js @@ -0,0 +1,21 @@ +var countSubstrings = function(s) { + let dp = Array.from({ length: s.length }, _ => new Array(s.length).fill(0)); + for (let i = s.length - 1; i >= 0; i--) { + for (let j = i; j < s.length; j++) { + if (j == i) dp[i][j] = true; // 只有一个字符时 + if (s[i] == s[j]) { + // 两个及两个以上字符时 + if (i + 1 == j) { + dp[i][j] = true; // 如果是两个字符 + } else if (i < s.length - 1 && dp[i + 1][j - 1]) dp[i][j] = true; // 如果更小的回文存在 + } + } + } + let count = 0; + for (let i = s.length - 1; i >= 0; i--) { + for (let j = i; j < s.length; j++) { + if (dp[i][j]) count++; + } + } + return count; +}; diff --git a/Week_05/G20200343030437/maximal-square.java b/Week_05/G20200343030437/maximal-square.java new file mode 100644 index 00000000..fcc08a89 --- /dev/null +++ b/Week_05/G20200343030437/maximal-square.java @@ -0,0 +1,17 @@ +public class Solution { + public int maximalSquare(char[][] matrix) { + int rows = matrix.length, cols = rows > 0 ? matrix[0].length : 0; + int[][] dp = new int[rows + 1][cols + 1]; + int maxsqlen = 0; + for (int i = 1; i <= rows; i++) { + for (int j = 1; j <= cols; j++) { + if (matrix[i-1][j-1] == '1'){ + dp[i][j] = Math.min(Math.min(dp[i][j - 1], dp[i - 1][j]), dp[i - 1][j - 1]) + 1; + maxsqlen = Math.max(maxsqlen, dp[i][j]); + } + } + } + return maxsqlen * maxsqlen; + } +} + diff --git a/Week_05/G20200343030437/minimum-path-sum.java b/Week_05/G20200343030437/minimum-path-sum.java new file mode 100644 index 00000000..4130d4cc --- /dev/null +++ b/Week_05/G20200343030437/minimum-path-sum.java @@ -0,0 +1,13 @@ +class Solution { + public int minPathSum(int[][] grid) { + for(int i = 0; i < grid.length; i++) { + for(int j = 0; j < grid[i].length; j++) { + if (i == 0 && j == 0) continue; + else if (i == 0) grid[i][j] = grid[i][j-1] + grid[i][j]; + else if (j == 0) grid[i][j] = grid[i-1][j] + grid[i][j]; + else grid[i][j] += Math.min(grid[i-1][j], grid[i][j-1]); + } + } + return grid[grid.length-1][grid[0].length-1]; + } +} diff --git a/Week_05/G20200343030439/LeetCode_64_439.java b/Week_05/G20200343030439/LeetCode_64_439.java new file mode 100644 index 00000000..4fc83920 --- /dev/null +++ b/Week_05/G20200343030439/LeetCode_64_439.java @@ -0,0 +1,58 @@ +/* + * @lc app=leetcode.cn id=64 lang=java + * + * [64] 最小路径和 + * + * https://leetcode-cn.com/problems/minimum-path-sum/description/ + * + */ + +// @lc code=start +class Solution { + // 暴力 超时 + public int minPathSum(int[][] grid) { + return calculate(grid, 0, 0); + } + + public int calculate(int[][] grid, int i, int j) { + if (i == grid.length || j == grid[0].length) + return Integer.MAX_VALUE; + if (i == grid.length - 1 && j == grid[0].length - 1) + return grid[i][j]; + return grid[i][j] + Math.min(calculate(grid, i + 1, j), calculate(grid, i, j + 1)); + } + + // 动态规划 + public int minPathSum2(int[][] grid) { + int[][] dp = new int[grid.length][grid[0].length]; + for (int i = grid.length - 1; i >= 0; i--) { + for (int j = grid[0].length - 1; j >= 0; j--) { + if (i == grid.length - 1 && j != grid[0].length - 1) + dp[i][j] = grid[i][j] + dp[i][j + 1]; + else if (j == grid[0].length - 1 && i != grid.length - 1) + dp[i][j] = grid[i][j] + dp[i + 1][j]; + else if (j != grid[0].length - 1 && i != grid.length - 1) + dp[i][j] = grid[i][j] + Math.min(dp[i + 1][j], dp[i][j + 1]); + else + dp[i][j] = grid[i][j]; + } + } + return dp[0][0]; + } + + // 动态规划 空间复杂度 O(1) + public int minPathSum3(int[][] grid) { + for (int i = grid.length - 1; i >= 0; i--) { + for (int j = grid[0].length - 1; j >= 0; j--) { + if (i == grid.length - 1 && j != grid[0].length - 1) + grid[i][j] = grid[i][j] + grid[i][j + 1]; + else if (j == grid[0].length - 1 && i != grid.length - 1) + grid[i][j] = grid[i][j] + grid[i + 1][j]; + else if (j != grid[0].length - 1 && i != grid.length - 1) + grid[i][j] = grid[i][j] + Math.min(grid[i + 1][j], grid[i][j + 1]); + } + } + return grid[0][0]; + } +} +// @lc code=end diff --git a/Week_05/G20200343030439/LeetCode_91_439.java b/Week_05/G20200343030439/LeetCode_91_439.java new file mode 100644 index 00000000..e12797e5 --- /dev/null +++ b/Week_05/G20200343030439/LeetCode_91_439.java @@ -0,0 +1,41 @@ +/* + * @lc app=leetcode.cn id=91 lang=java + * + * [91] 解码方法 + * + * https://leetcode-cn.com/problems/decode-ways/description/ + * + */ + +// @lc code=start +class Solution { + public int numDecodings(String s) { + if (s == null || s.length() == 0) { + return 0; + } + int len = s.length(); + + int help = 1; + int res = 0; + if (s.charAt(len - 1) != '0') { + res = 1; + } + for (int i = len - 2; i >= 0; i--) { + if (s.charAt(i) == '0') { + help = res; + res = 0; + continue; + } + if ((s.charAt(i) - '0') * 10 + (s.charAt(i + 1) - '0') <= 26) { + res += help; + help = res - help; + } else { + help = res; + } + + } + return res; + + } +} +// @lc code=end diff --git a/Week_05/G20200343030443/P64MinimumPathSum.java b/Week_05/G20200343030443/P64MinimumPathSum.java new file mode 100644 index 00000000..85707a98 --- /dev/null +++ b/Week_05/G20200343030443/P64MinimumPathSum.java @@ -0,0 +1,36 @@ +//Java:最小路径和 +public class P64MinimumPathSum { + + public static void main(String[] args) { + Solution solution = new P64MinimumPathSum().new Solution(); + // TO TEST + } + + //leetcode submit region begin(Prohibit modification and deletion) + class Solution { + + public int minPathSum(int[][] grid) { + if (grid.length == 0 || grid[0].length == 0) { + return 0; + } + int row = grid.length - 1, col = grid[0].length - 1, i, j; + for (i = 0; i <= row; i++) { + for (j = 0; j <= col; j++) { + if (i == 0 && j == 0) { + continue; + } + if (i == 0) { + grid[i][j] += grid[i][j - 1]; + } else if (j == 0) { + grid[i][j] += grid[i - 1][j]; + } else { + grid[i][j] += Math.min(grid[i - 1][j], grid[i][j - 1]); + } + } + } + return grid[row][col]; + } + } +//leetcode submit region end(Prohibit modification and deletion) + +} diff --git a/Week_05/G20200343030443/P91DecodeWays.java b/Week_05/G20200343030443/P91DecodeWays.java new file mode 100644 index 00000000..ebc91039 --- /dev/null +++ b/Week_05/G20200343030443/P91DecodeWays.java @@ -0,0 +1,43 @@ +//Java:解码方法 +public class P91DecodeWays { + + public static void main(String[] args) { + Solution solution = new P91DecodeWays().new Solution(); + // TO TEST + } + + //leetcode submit region begin(Prohibit modification and deletion) + class Solution { + + public int numDecodings(String s) { + if (s.length() == 0 || s.charAt(0) == '0') { + return 0; + } + if (s.length() == 1) { + return 1; + } + int x = 1, y = 1, z = 0; + + for (int i = 1; i < s.length(); i++) { + char c1 = s.charAt(i - 1), c2 = s.charAt(i); + if (c2 == '0') { + if (c1 == '1' || c1 == '2') { + z = x; + } else { + return 0; + } + }else if (c1 == '1' || (c1 == '2' && c2 <= '6')) { + z = x + y; + }else{ + z = y; + } + x = y; + y = z; + } + + return z; + } + } +//leetcode submit region end(Prohibit modification and deletion) + +} diff --git a/Week_05/G20200343030445/LeetCode_221_445.py b/Week_05/G20200343030445/LeetCode_221_445.py new file mode 100644 index 00000000..98781cc3 --- /dev/null +++ b/Week_05/G20200343030445/LeetCode_221_445.py @@ -0,0 +1,51 @@ +# +# @lc app=leetcode.cn id=221 lang=python3 +# +# [221] 最大正方形 +# + +# @lc code=start +class Solution: + def maximalSquare(self, matrix: List[List[str]]) -> int: + # if not matrix: + # return 0 + # m = len(matrix) + # n = len(matrix[0]) + # dp = [[0] * (n) for _ in range(m)] + + # for i in range(m): + # for j in range(n): + # if matrix[i][j] == "1": + # dp[i][j] = 1 + + # if i - 1 == -1 or j - 1 == -1: + # continue + + # count = 0 + # for k in range(1, dp[i-1][j-1] + 1): + # if matrix[i-k][j] == "1" and matrix[i][j-k] == "1": + # count += 1 + # else: + # break + # dp[i][j] += count + + # return (max(map(max, dp)))**2 + + res = 0 + if matrix: + m = len(matrix) + n = len(matrix[0]) + + dp = [[0 for j in range(n + 1)] for i in range(m + 1)] + + for i in range(m): + for j in range(n): + if matrix[i][j] == '1': + dp[i + 1][j + 1] = min(dp[i][j], dp[i][j + 1], dp[i + 1][j]) + 1 + res = max(res, dp[i + 1][j + 1]) + + return res * res + + +# @lc code=end + diff --git a/Week_05/G20200343030445/LeetCode_32_445.py b/Week_05/G20200343030445/LeetCode_32_445.py new file mode 100644 index 00000000..dda944c8 --- /dev/null +++ b/Week_05/G20200343030445/LeetCode_32_445.py @@ -0,0 +1,33 @@ +# +# @lc app=leetcode.cn id=32 lang=python3 +# +# [32] 最长有效括号 +# + +# @lc code=start +class Solution: + def longestValidParentheses(self, s: str) -> int: + n = len(s) + dp = [False] * n + stack = [] + for i in range(n): + if s[i] == "(": + stack.append(i) + elif stack: + dp[stack.pop()] = True + dp[i] = True + + count = 0 + max_count = 0 + for i in dp: + if i: + count += 1 + else: + max_count = max(max_count, count) + count = 0 + return max(max_count, count) + + + +# @lc code=end + diff --git a/Week_05/G20200343030445/LeetCode_647_445.py b/Week_05/G20200343030445/LeetCode_647_445.py new file mode 100644 index 00000000..f5236a29 --- /dev/null +++ b/Week_05/G20200343030445/LeetCode_647_445.py @@ -0,0 +1,22 @@ +# +# @lc app=leetcode.cn id=647 lang=python3 +# +# [647] 回文子串 +# + +# @lc code=start +class Solution: + def countSubstrings(self, s: str) -> int: + n = len(s) + dp = [[0] * n for _ in range(n)] + count = 0 + for i in range(n): + for j in range(i, -1, -1): + if s[i] == s[j] and (i - j < 2 or dp[j+1][i-1]): + dp[j][i] = True + count += 1 + return count + + +# @lc code=end + diff --git a/Week_05/G20200343030445/LeetCode_64_445.py b/Week_05/G20200343030445/LeetCode_64_445.py new file mode 100644 index 00000000..db55e380 --- /dev/null +++ b/Week_05/G20200343030445/LeetCode_64_445.py @@ -0,0 +1,26 @@ +# +# @lc app=leetcode.cn id=64 lang=python3 +# +# [64] 最小路径和 +# + +# @lc code=start +class Solution: + def minPathSum(self, grid: List[List[int]]) -> int: + if not grid: + return 0 + m = len(grid) + n = len(grid[0]) + for i in range(m): + for j in range(n): + if i == 0 and j == 0: + continue + elif i == 0: + grid[i][j] += grid[i][j-1] + elif j == 0: + grid[i][j] += grid[i-1][j] + else: + grid[i][j] += min(grid[i-1][j], grid[i][j-1]) + return grid[m-1][n-1] +# @lc code=end + diff --git a/Week_05/G20200343030449/LeetCode_403_449.cpp b/Week_05/G20200343030449/LeetCode_403_449.cpp new file mode 100644 index 00000000..e526fef0 --- /dev/null +++ b/Week_05/G20200343030449/LeetCode_403_449.cpp @@ -0,0 +1,25 @@ +class Solution { +public: + bool canCross(vector& stones) { + unordered_set h; + for(auto x:stones) h.insert(x); + unordered_map dp; + + for(int i = 1 ; i <= 1001 ; i ++) + if(dfs(stones.back(),i,h,dp)) + return true; + return false; + } + + bool dfs(int x, int y, unordered_set &h, unordered_map &dp) { + if(y<=0 || !h.count(x)) return false; + if(x==1&&y==1) return true; + + long long t = (long long)x<<32|y; + if(dp.count(t)) return dp[t]; + + if(dfs(x-y,y,h,dp)||dfs(x-y,y-1,h,dp)||dfs(x-y,y+1,h,dp)) + return dp[t] = true; + return dp[t] = false; + }; +}; diff --git a/Week_05/G20200343030449/LeetCode_64_499.cpp b/Week_05/G20200343030449/LeetCode_64_499.cpp new file mode 100644 index 00000000..b036fe29 --- /dev/null +++ b/Week_05/G20200343030449/LeetCode_64_499.cpp @@ -0,0 +1,27 @@ +class Solution { +public: + int minPathSum(vector>& grid) { + if (grid.size()==0) return 0; + + int minPathSumArray[grid.size()][grid[0].size()] = {0}; + + //init the dynamic array + minPathSumArray[grid.size()-1][grid[0].size()-1] = grid[grid.size()-1][grid[0].size()-1]; + + for (int i = grid.size()-2; i>=0; i--) { + minPathSumArray[i][grid[0].size()-1] = grid[i][grid[0].size()-1]+minPathSumArray[i+1][grid[0].size()-1]; + } + + for (int i = grid[0].size()-2; i>=0; i--) { + minPathSumArray[grid.size()-1][i] = grid[grid.size()-1][i]+minPathSumArray[grid.size()-1][i+1]; + } + + for (int i = grid.size()-2; i>=0; i--) { + for (int j = grid[0].size()-2; j>=0; j--) { + minPathSumArray[i][j] = min(minPathSumArray[i+1][j],minPathSumArray[i][j+1])+grid[i][j]; + } + } + + return minPathSumArray[0][0]; + } +}; diff --git a/Week_05/G20200343030451/64.cpp b/Week_05/G20200343030451/64.cpp new file mode 100644 index 00000000..0285f39c --- /dev/null +++ b/Week_05/G20200343030451/64.cpp @@ -0,0 +1,29 @@ +class Solution { +public: + int minPathSum(vector>& grid) { + int n = grid.size(); + if(n==0) + return 0; + int m = grid[0].size(); + if(m==0) + return 0; + for(int i=1;i= '1' && s[i] <= '6')) + curr = curr + pre; + pre = tmp; + } + return curr; + + } +}; + diff --git a/Week_05/G20200343030451/NOTE.md b/Week_05/G20200343030451/NOTE.md index 50de3041..bb7dcd1f 100644 --- a/Week_05/G20200343030451/NOTE.md +++ b/Week_05/G20200343030451/NOTE.md @@ -1 +1,32 @@ -学习笔记 \ No newline at end of file +学习笔记 + + +【451-Week05】学习总结 + +本周学习的内容可算是目前学习到最难理解的内容。 +学习与刷题,最大感觉就是解决动态规划题目,一定要先找出重复子问题,然后确定最优子结构,当这一步确定了,dp方程也就好定义了。 +### 解决动态规划内容,可分为3步: +1、找出重复子问题 +2、定义状态数组 +3、dp方程 +另外,当一维dp数组不能解决问题,应当提升维度,这也是解决高级dp问题的关键。 +分治与动态规划 +#### 共同点:二者都要求原问题具有最优子结构性质,都是将原问题分而治之,分解成若干个规模较小(小到很容易解决的程序)的子问题.然后将子问题的解合并,形成原问题的解. + +#### 不同点:分治法将分解后的子问题看成相互独立的,通过用递归来做。 + +动态规划将分解后的子问题理解为相互间有联系,有重叠部分,需要记忆,通常用迭代来做。 + +### 问题特征 +最优子结构:当问题的最优解包含了其子问题的最优解时,称该问题具有最优子结构性质。 + +### 总结 +重叠子问题:在用递归算法自顶向下解问题时,每次产生的子问题并不总是新问题,有些子问题被反复计算多次。动态规划算法正是利用了这种子问题的重叠性质,对每一个子问题只解一次,而后将其解保存在一个表格中,在以后尽可能多地利用这些子问题的解。 + + + + + + + + diff --git a/Week_05/G20200343030457/minPathSum.php b/Week_05/G20200343030457/minPathSum.php new file mode 100644 index 00000000..30b83171 --- /dev/null +++ b/Week_05/G20200343030457/minPathSum.php @@ -0,0 +1,25 @@ + 0 && $s[1] > 0) ? 1:0; + $dp[1] = $flag + (($s[0] == 1 || ($s[0] == 2 && $s[1] <= 6)) ? 1:0); + for($i = 2;$i<$len;++$i){ + $dp[$i] = $s[$i] == 0 ? 0:$dp[$i-1]; + $dp[$i] += ($s[$i-1] == 1 || ($s[$i-1] == 2 && $s[$i] <= 6)) ? $dp[$i-2] : 0; + } + return $dp[$len-1]; + } +} diff --git a/Week_05/G20200343030459/120.triangle.py b/Week_05/G20200343030459/120.triangle.py new file mode 100644 index 00000000..3bf7a6a7 --- /dev/null +++ b/Week_05/G20200343030459/120.triangle.py @@ -0,0 +1,93 @@ +# +# @lc app=leetcode id=120 lang=python3 +# +# [120] Triangle +# +# https://leetcode.com/problems/triangle/description/ +# +# algorithms +# Medium (42.25%) +# Likes: 1611 +# Dislikes: 192 +# Total Accepted: 224.7K +# Total Submissions: 529.2K +# Testcase Example: '[[2],[3,4],[6,5,7],[4,1,8,3]]' +# +# Given a triangle, find the minimum path sum from top to bottom. Each step you +# may move to adjacent numbers on the row below. +# +# For example, given the following triangle +# +# +# [ +# ⁠ [2], +# ⁠ [3,4], +# ⁠ [6,5,7], +# ⁠ [4,1,8,3] +# ] +# +# +# The minimum path sum from top to bottom is 11 (i.e., 2 + 3 + 5 + 1 = 11). +# +# Note: +# +# Bonus point if you are able to do this using only O(n) extra space, where n +# is the total number of rows in the triangle. +# +# + +# @lc code=start +# 第一种方法 记忆化搜索 +class Solution: + def minimumTotal(self, triangle: List[List[int]]) -> int: + if not triangle: + return 0 + memo = {} + return self.dfs(memo, triangle, (0, 0)) + + def dfs(self, memo, triangle, position) -> int: + (x, y) = position + if x == len(triangle): + return 0 + if position in memo: + return memo[position] + + left = self.dfs(memo, triangle, (x + 1, y)) + right = self.dfs(memo, triangle, (x + 1, y + 1)) + + minium = min(left, right) + triangle[x][y] + memo[(x, y)] = minium + return minium + +# 第二种方法 自底向上 +class Solution: + def minimumTotal(self, triangle: List[List[int]]) -> int: + if not triangle: + return 0 + dp = triangle + for i in range(len(triangle) - 2, -1, -1): + for j in range(len(triangle[i])): + dp[i][j] = min(dp[i + 1][j], dp[i + 1][j + 1]) + triangle[i][j] + + return dp[0][0] + + +# 第三种方法 自顶向下(滚动数组优化空间) +class Solution: + def minimumTotal(self, triangle: List[List[int]]) -> int: + n = len(triangle) + dp = [[0] * n, [0] * n] + + dp[0][0] = triangle[0][0] + + for i in range(1, n): + dp[i % 2][0] = dp[(i - 1) % 2][0] + triangle[i][0] + dp[i % 2][i] = dp[(i - 1) % 2][i - 1] + triangle[i][i] + for j in range(1, i): + dp[i % 2][j] = min(dp[(i - 1) % 2][j], dp[(i - 1) % 2][j - 1]) + triangle[i][j] + + return min(dp[(n - 1) % 2]) + + +# @lc code=end + diff --git a/Week_05/G20200343030459/62.unique-paths.py b/Week_05/G20200343030459/62.unique-paths.py new file mode 100644 index 00000000..35265da2 --- /dev/null +++ b/Week_05/G20200343030459/62.unique-paths.py @@ -0,0 +1,75 @@ +# +# @lc app=leetcode id=62 lang=python3 +# +# [62] Unique Paths +# +# https://leetcode.com/problems/unique-paths/description/ +# +# algorithms +# Medium (51.23%) +# Likes: 2485 +# Dislikes: 180 +# Total Accepted: 402.6K +# Total Submissions: 782.1K +# Testcase Example: '3\n2' +# +# A robot is located at the top-left corner of a m x n grid (marked 'Start' in +# the diagram below). +# +# The robot can only move either down or right at any point in time. The robot +# is trying to reach the bottom-right corner of the grid (marked 'Finish' in +# the diagram below). +# +# How many possible unique paths are there? +# +# +# Above is a 7 x 3 grid. How many possible unique paths are there? +# +# +# Example 1: +# +# +# Input: m = 3, n = 2 +# Output: 3 +# Explanation: +# From the top-left corner, there are a total of 3 ways to reach the +# bottom-right corner: +# 1. Right -> Right -> Down +# 2. Right -> Down -> Right +# 3. Down -> Right -> Right +# +# +# Example 2: +# +# +# Input: m = 7, n = 3 +# Output: 28 +# +# +# +# Constraints: +# +# +# 1 <= m, n <= 100 +# It's guaranteed that the answer will be less than or equal to 2 * 10 ^ 9. +# +# +# + +# @lc code=start +class Solution: + def uniquePaths(self, m: int, n: int) -> int: + dp = [[0] * m, [0] * m] + + for i in range(m): + dp[0][i] = 1 + + for i in range(1, n): + dp[i % 2][0] = 1 + for j in range(1, m): + dp[i % 2][j] = dp[(i - 1) % 2][j] + dp[i % 2][j - 1] + + return dp[(n - 1) % 2][m - 1] + +# @lc code=end + diff --git a/Week_05/G20200343030459/64.minimum-path-sum.py b/Week_05/G20200343030459/64.minimum-path-sum.py new file mode 100644 index 00000000..5629babb --- /dev/null +++ b/Week_05/G20200343030459/64.minimum-path-sum.py @@ -0,0 +1,56 @@ +# +# @lc app=leetcode id=64 lang=python3 +# +# [64] Minimum Path Sum +# +# https://leetcode.com/problems/minimum-path-sum/description/ +# +# algorithms +# Medium (50.83%) +# Likes: 2178 +# Dislikes: 49 +# Total Accepted: 316.9K +# Total Submissions: 620.2K +# Testcase Example: '[[1,3,1],[1,5,1],[4,2,1]]' +# +# Given a m x n grid filled with non-negative numbers, find a path from top +# left to bottom right which minimizes the sum of all numbers along its path. +# +# Note: You can only move either down or right at any point in time. +# +# Example: +# +# +# Input: +# [ +# [1,3,1], +# ⁠ [1,5,1], +# ⁠ [4,2,1] +# ] +# Output: 7 +# Explanation: Because the path 1→3→1→1→1 minimizes the sum. +# +# +# + +# @lc code=start +class Solution: + def minPathSum(self, grid: List[List[int]]) -> int: + n, m = len(grid), len(grid[0]) + dp = [[0] * m, [0] * m] + + dp[0][0] = grid[0][0] + + for i in range(1, m): + dp[0][i] = dp[0][i - 1] + grid[0][i] + + for i in range(1, n): + dp[i % 2][0] = dp[(i - 1) % 2][0] + grid[i][0] + for j in range(1, m): + dp[i % 2][j] = min(dp[(i - 1) % 2][j], dp[i % 2][j - 1]) + grid[i][j] + + return dp[(n - 1) % 2][m - 1] + + +# @lc code=end + diff --git a/Week_05/G20200343030463/463-Week 05/LeetCode_64_463.cpp b/Week_05/G20200343030463/463-Week 05/LeetCode_64_463.cpp new file mode 100644 index 00000000..022e903d --- /dev/null +++ b/Week_05/G20200343030463/463-Week 05/LeetCode_64_463.cpp @@ -0,0 +1,16 @@ +class Solution { +public: + int minPathSum(vector>& grid) { + int m = grid.size(); + int n = grid[0].size(); + vector> res(m,vector(n,grid[0][0])); + for(int i =1;i < m;i++) + res[i][0] = res[i-1][0] + grid[i][0]; + for(int j =1;j < n;j++) + res[0][j] = res[0][j-1] + grid[0][j]; + for(int i =1;i < m; i++) + for(int j =1; j > triangle) { + int row = triangle.Count; + int[] dp = new int[row + 1]; + for (int i = row - 1; i >= 0; i--) { + int num = triangle[i].Count; + for (int j = 0; j < num; j++) { + dp[j] = Math.Min(dp[j], dp[j + 1]) + triangle[i][j]; + } + } + + return dp[0]; + } +} \ No newline at end of file diff --git a/Week_05/G20200343030485/LeetCode_322_485.cs b/Week_05/G20200343030485/LeetCode_322_485.cs new file mode 100644 index 00000000..5a423d0b --- /dev/null +++ b/Week_05/G20200343030485/LeetCode_322_485.cs @@ -0,0 +1,17 @@ +public class Solution { + public int CoinChange(int[] coins, int amount) { + int[] dp = new int[amount + 1]; + Array.Fill(dp, amount + 1); + dp[0] = 0; + + for (int i = 1; i <= amount; i++) { + for (int j = 0; j < coins.Length; j++) { + if (coins[j] <= i) { + dp[i] = Math.Min(dp[i], dp[i - coins[j]] + 1); + } + } + } + + return (dp[amount] == amount + 1) ? -1 : dp[amount]; + } +} \ No newline at end of file diff --git a/Week_05/G20200343030485/LeetCode_64_485.cs b/Week_05/G20200343030485/LeetCode_64_485.cs new file mode 100644 index 00000000..c247efba --- /dev/null +++ b/Week_05/G20200343030485/LeetCode_64_485.cs @@ -0,0 +1,27 @@ +public class Solution { + public int MinPathSum(int[][] grid) { + int row = grid.Length; + int col = grid[0].Length; + for (int i = 0; i < row; i++) { + for (int j = 0; j < col; j++) { + if (i == 0 || j == 0) { + if (i == 0 && j == 0) { + continue; + } + + if (i == 0) { + grid[i][j] = grid[i][j] + grid[i][j - 1]; + } + else if (j == 0) { + grid[i][j] = grid[i][j] + grid[i - 1][j]; + } + } + else { + grid[i][j] = grid[i][j] + Math.Min(grid[i - 1][j], grid[i][j - 1]); + } + } + } + + return grid[row - 1][col - 1]; + } +} \ No newline at end of file diff --git a/Week_05/G20200343030485/LeetCode_72_485.cs b/Week_05/G20200343030485/LeetCode_72_485.cs new file mode 100644 index 00000000..2f1bc5cf --- /dev/null +++ b/Week_05/G20200343030485/LeetCode_72_485.cs @@ -0,0 +1,29 @@ +public class Solution { + public int MinDistance(string word1, string word2) { + int len1 = word1.Length; + int len2 = word2.Length; + int[,] dp = new int[len1 + 1, len2 + 1]; + dp[0, 0] = 0; + + for (int i = 1; i <= len1; i++) { + dp[i, 0] = i; + } + + for (int i = 1; i <= len2; i++) { + dp[0, i] = i; + } + + for (int i = 1; i <= len1; i++) { + for (int j = 1; j <= len2; j++) { + if (word1[i - 1] == word2[j - 1]) { + dp[i, j] = dp[i - 1, j - 1]; + } + else { + dp[i, j] = 1 + Math.Min(Math.Min(dp[i - 1, j], dp[i, j - 1]), dp[i - 1, j - 1]); + } + } + } + + return dp[len1, len2]; + } +} \ No newline at end of file diff --git a/Week_05/G20200343030487/leetcode_64_487.js b/Week_05/G20200343030487/leetcode_64_487.js new file mode 100644 index 00000000..12de51d2 --- /dev/null +++ b/Week_05/G20200343030487/leetcode_64_487.js @@ -0,0 +1,18 @@ +/** + * @param {number[][]} grid + * @return {number} + */ +var minPathSum = function (grid) { + if (!grid.length || !grid[0].length) { + return 0 + } + const arr = new Array(grid[0].length).fill(Infinity) + arr[0] = 0 + for (let i = 0; i < grid.length; i++) { + arr[0] += grid[i][0] + for (let j = 1; j < grid[i].length; j++) { + arr[j] = Math.min(arr[j], arr[j - 1]) + grid[i][j] + } + } + return arr[arr.length - 1] +} diff --git a/Week_05/G20200343030487/leetcode_91_487.js b/Week_05/G20200343030487/leetcode_91_487.js new file mode 100644 index 00000000..f42f3b42 --- /dev/null +++ b/Week_05/G20200343030487/leetcode_91_487.js @@ -0,0 +1,27 @@ +/** + * @param {string} s + * @return {number} + */ +var numDecodings = function (s) { + if (s[0] === '0') { + return 0 + } + let len = s.length + let res = [1, 1] + for (let i = 1; i < len; i++) { + if (s[i] === '0') { + if (s[i - 1] === '1' || s[i - 1] === '2') { + res[i + 1] = res[i - 1] + } else { + return 0 + } + } else { + if (s[i - 1] === '1' || (s[i - 1] === '2' && s[i] <= '6')) { + res[i + 1] = res[i] + res[i - 1] + } else { + res[i + 1] = res[i] + } + } + } + return res[len] +} diff --git a/Week_05/G20200343030489/LeetCode_221_489.cpp b/Week_05/G20200343030489/LeetCode_221_489.cpp new file mode 100644 index 00000000..a5743866 --- /dev/null +++ b/Week_05/G20200343030489/LeetCode_221_489.cpp @@ -0,0 +1,49 @@ +/* + * @lc app=leetcode.cn id=221 lang=cpp + * + * [221] 最大正方形 + */ + +// @lc code=start +// class Solution { +// public: +// int maximalSquare(vector>& matrix) { +// if(matrix.empty()) +// return 0; +// int m=matrix.size(),n=matrix[0].size(),size=0; +// vector> dp(m,vector(n,0)); +// for(int i=0;i>& matrix) { + if(matrix.empty()) + return 0; + int m=matrix.size(),n=matrix[0].size(),size=0; + vector pre(n,0),cur(n,0); + for(int i=0;i dp(s.size(),0); + for(int i=1;i=0&&s[i-dp[i-1]-1]=='('){ + dp[i]=dp[i-1]+2+((i-dp[i-1]-2>=0)?dp[i-dp[i-1]-2]:0); + cmax=max(dp[i],cmax); + } + } + return cmax; + } +}; +// @lc code=end + diff --git a/Week_05/G20200343030489/LeetCode_410_489.cpp b/Week_05/G20200343030489/LeetCode_410_489.cpp new file mode 100644 index 00000000..1e763f34 --- /dev/null +++ b/Week_05/G20200343030489/LeetCode_410_489.cpp @@ -0,0 +1,24 @@ +/* + * @lc app=leetcode.cn id=410 lang=cpp + * + * [410] 分割数组的最大值 + */ + +// @lc code=start +class Solution { +public: + int splitArray(vector& nums, int m) { + int n=nums.size(); + vector> f(n+1,vector(m+1,INT_MAX)); + vector sub(n+1,0); + for(int i=0;i& tasks, int n) { + unordered_map map; + int count=0; + for(auto e:tasks){ + map[e]++; + count=max(count,map[e]); + } + int res=(count-1)*(n+1); + for(auto e:map) + if(e.second==count) + res++; + return max((int)tasks.size(),res); + } +}; +// @lc code=end + diff --git a/Week_05/G20200343030489/LeetCode_647_489.cpp b/Week_05/G20200343030489/LeetCode_647_489.cpp new file mode 100644 index 00000000..39c3715e --- /dev/null +++ b/Week_05/G20200343030489/LeetCode_647_489.cpp @@ -0,0 +1,34 @@ +/* + * @lc app=leetcode.cn id=647 lang=cpp + * + * [647] 回文子串 + */ + +// @lc code=start +class Solution { +public: + int countSubstrings(string s) { + int res=0; + for(int i=0;i=0&&end>& grid) { + int n=grid.size(); + int m=grid[0].size(); + if(n==0||m==0) + return 0; + for(int i=1;i> dp(n+1,vector(m+1)); + for(int i=0;i<=n;i++) + dp[i][0]=i; + for(int j=0;j<=m;j++) + dp[0][j]=j; + for(int i=1;i<=n;i++){ + for(int j=1;j<=m;j++){ + dp[i][j]=min(dp[i][j-1],dp[i-1][j])+1; + dp[i][j]=min(dp[i][j],dp[i-1][j-1]+(word1[i-1]==word2[j-1]?0:1)); + } + } + return dp[n][m]; + } +}; +// @lc code=end + diff --git a/Week_05/G20200343030489/LeetCode_91_489.cpp b/Week_05/G20200343030489/LeetCode_91_489.cpp new file mode 100644 index 00000000..0b3dbef2 --- /dev/null +++ b/Week_05/G20200343030489/LeetCode_91_489.cpp @@ -0,0 +1,29 @@ +/* + * @lc app=leetcode.cn id=91 lang=cpp + * + * [91] 解码方法 + */ + +// @lc code=start +class Solution { +public: + int numDecodings(string s) { + if(s[0]=='0') + return 0; + int pre=1,cur=1; + for(int i=1;i='1'&&s[i]<='6')) + cur=cur+pre; + pre=tmp; + } + return cur; + } +}; +// @lc code=end + diff --git a/Week_05/G20200343030491/LeetCode_221_491.py b/Week_05/G20200343030491/LeetCode_221_491.py new file mode 100644 index 00000000..2ea1eb10 --- /dev/null +++ b/Week_05/G20200343030491/LeetCode_221_491.py @@ -0,0 +1,17 @@ +class Solution: + def maximalSquare(self, matrix: List[List[str]]) -> int: + if not matrix or not matrix[0]: + return 0 + + m, n = len(matrix), len(matrix[0]) + + dp = [[0] * (n+1) for _ in range(m+1)] + + for i in range(1,m+1): + for j in range(1,n+1): + if matrix[i-1][j-1]=='1': + dp[i][j] = min(dp[i-1][j-1], dp[i-1][j], dp[i][j-1]) + 1 + + maxVal = max(max([i for i in j]) for j in dp) + + return maxVal*maxVal \ No newline at end of file diff --git a/Week_05/G20200343030491/LeetCode_32_491.py b/Week_05/G20200343030491/LeetCode_32_491.py new file mode 100644 index 00000000..c9dc4ce1 --- /dev/null +++ b/Week_05/G20200343030491/LeetCode_32_491.py @@ -0,0 +1,38 @@ +class Solution: + def longestValidParentheses(self, s: str) -> int: + if len(s)<=1: + return 0 + + stack = [-1] + maxlength = 0 + for i in range(len(s)): + if s[i] =='(': + stack.append(i) + elif stack: + stack.pop() + if not stack: + stack.append(i) + else: + maxlength = max(maxlength,i-stack[-1]) + + return maxlength + + +class Solution: + def longestValidParentheses(self, s: str) -> int: + if len(s)<=1: + return 0 + + s = '))' + s + dp = [0] * len(s) + for i in range(2,len(s)): + if s[i] == ')': + if s[i-1] == '(': + dp[i] = dp[i-2] + 2 + elif s[i-dp[i-1]-1] == '(': + dp[i] = dp[i-dp[i-1]-2] + 2 + dp[i-1] + + + return max(dp) + + \ No newline at end of file diff --git a/Week_05/G20200343030491/LeetCode_33_491.py b/Week_05/G20200343030491/LeetCode_33_491.py new file mode 100644 index 00000000..731730eb --- /dev/null +++ b/Week_05/G20200343030491/LeetCode_33_491.py @@ -0,0 +1,22 @@ +class Solution: + def search(self, nums: List[int], target: int) -> int: + if not nums: + return -1 + left, right = 0, len(nums)-1 + + while left<=right: + mid = (left+right)>>1 + + if nums[mid]==target: + return mid + elif nums[mid] < nums[right]: + if nums[mid] < target and target <= nums[right]: + left = mid + 1 + else: + right = mid - 1 + else: + if nums[left] <= target and target < nums[mid]: + right = mid -1 + else: + left = mid + 1 + return -1 \ No newline at end of file diff --git a/Week_05/G20200343030491/LeetCode_621_491.py b/Week_05/G20200343030491/LeetCode_621_491.py new file mode 100644 index 00000000..b45da37d --- /dev/null +++ b/Week_05/G20200343030491/LeetCode_621_491.py @@ -0,0 +1,34 @@ +from collections import Counter +def leastInterval(tasks, n): + if len(tasks)<=1: return len(tasks) + dic = Counter(tasks) + dic = dic.most_common() + rows = dic[0][1] + cols = n + 1 + res = (rows-1) * cols + + for task in dic: + if task[1] == rows: + res += 1 + print(res) + return res if res>len(tasks) else len(tasks) + +leastInterval(["A","A","A","B","B","B"],2) + +class Solution: + def leastInterval(self, tasks: List[str], n: int) -> int: + if len(tasks)<=1: return len(tasks) + array = [0]*26 + for task in tasks: + array[ord(task)-ord('A')] += 1 + array.sort() + time = 0 + while array[-1] > 0: + for i in range(n+1): + if array[-1] == 0: break + elif i<26 and array[26-i-1]>0: + array[25-i] -= 1 + time += 1 + array.sort() + + return time \ No newline at end of file diff --git a/Week_05/G20200343030491/LeetCode_647_491.py b/Week_05/G20200343030491/LeetCode_647_491.py new file mode 100644 index 00000000..b4f4d404 --- /dev/null +++ b/Week_05/G20200343030491/LeetCode_647_491.py @@ -0,0 +1,31 @@ +class Solution: + def countSubstrings(self, s: str) -> int: + if not str: return 0 + count = 0 + for i in range(2*len(s)-1): + if i%2 == 0: + left, right = i//2, i//2 + else: + left, right = i//2, i//2 + 1 + + while left >=0 and right <=len(s)-1 and s[left] == s[right]: + count += 1 + left -= 1 + right += 1 + + return count + + +class Solution: + def countSubstrings(self, s: str) -> int: + if not str: return 0 + n = len(s) + dp = [[False] * n for _ in range(n) ] + count = 0 + for j in range(0,n): + for i in range(j,-1,-1): + if s[i]==s[j] and (j-i<2 or dp[i+1][j-1]): + dp[i][j] = True + count += 1 + + return count \ No newline at end of file diff --git a/Week_05/G20200343030491/LeetCode_64_491.py b/Week_05/G20200343030491/LeetCode_64_491.py new file mode 100644 index 00000000..9d2e83ff --- /dev/null +++ b/Week_05/G20200343030491/LeetCode_64_491.py @@ -0,0 +1,41 @@ + +def minPathSum(grid): + if not grid: + return 0 + + m = len(grid) + n = len(grid[0]) + + dp = grid.copy() + for i in range(1,m): + dp[i][0] += dp[i-1][0] + for i in range(1,n): + dp[0][i] += dp[0][i-1] + + for i in range(1,m): + for j in range(1,n): + dp[i][j] = min(dp[i-1][j], dp[i][j-1]) + dp[i][j] + + return dp[m-1][n-1] + + +def minPathSumDFS(grid): + if not grid or not grid[0]: + return 0 + m, n = len(grid), len(grid[0]) + memo = [[-1] * n for _ in range(m)] + + def dfs(r,c): + if r==m-1 and c==n-1:return grid[r][c] + if r < m and c < n and memo[r][c] != -1: return memo[r][c] + elif c >= n-1: + memo[r][c] = dfs(r+1,c) + grid[r][c] + elif r >= m-1: + memo[r][c] = dfs(r,c+1) + grid[r][c] + else: + memo[r][c] = min(dfs(r+1,c), dfs(r,c+1)) + grid[r][c] + + return memo[r][c] + + return dfs(0,0) + \ No newline at end of file diff --git a/Week_05/G20200343030491/LeetCode_72_491.py b/Week_05/G20200343030491/LeetCode_72_491.py new file mode 100644 index 00000000..c9dc4ce1 --- /dev/null +++ b/Week_05/G20200343030491/LeetCode_72_491.py @@ -0,0 +1,38 @@ +class Solution: + def longestValidParentheses(self, s: str) -> int: + if len(s)<=1: + return 0 + + stack = [-1] + maxlength = 0 + for i in range(len(s)): + if s[i] =='(': + stack.append(i) + elif stack: + stack.pop() + if not stack: + stack.append(i) + else: + maxlength = max(maxlength,i-stack[-1]) + + return maxlength + + +class Solution: + def longestValidParentheses(self, s: str) -> int: + if len(s)<=1: + return 0 + + s = '))' + s + dp = [0] * len(s) + for i in range(2,len(s)): + if s[i] == ')': + if s[i-1] == '(': + dp[i] = dp[i-2] + 2 + elif s[i-dp[i-1]-1] == '(': + dp[i] = dp[i-dp[i-1]-2] + 2 + dp[i-1] + + + return max(dp) + + \ No newline at end of file diff --git a/Week_05/G20200343030493/best_time_stock.java b/Week_05/G20200343030493/best_time_stock.java new file mode 100644 index 00000000..486e8a13 --- /dev/null +++ b/Week_05/G20200343030493/best_time_stock.java @@ -0,0 +1,13 @@ +public class Solution { + public int maxProfit(int prices[]) { + int maxprofit = 0; + for (int i = 0; i < prices.length - 1; i++) { + for (int j = i + 1; j < prices.length; j++) { + int profit = prices[j] - prices[i]; + if (profit > maxprofit) + maxprofit = profit; + } + } + return maxprofit; + } +} diff --git a/Week_05/G20200343030493/house_robber.java b/Week_05/G20200343030493/house_robber.java new file mode 100644 index 00000000..f483970d --- /dev/null +++ b/Week_05/G20200343030493/house_robber.java @@ -0,0 +1,12 @@ +class Solution { + public int rob(int[] num) { + int prevMax = 0; + int currMax = 0; + for (int x : num) { + int temp = currMax; + currMax = Math.max(prevMax + x, currMax); + prevMax = temp; + } + return currMax; + } +} \ No newline at end of file diff --git a/Week_05/G20200343030497/LeetCode_221_497.cpp b/Week_05/G20200343030497/LeetCode_221_497.cpp new file mode 100644 index 00000000..0739553f --- /dev/null +++ b/Week_05/G20200343030497/LeetCode_221_497.cpp @@ -0,0 +1,26 @@ +class Solution { +public: + // 时间复杂度:O(mn) + // 空间复杂度:O(n) + int maximalSquare(vector>& matrix) { + if (matrix.empty()) { + return 0; + } + + int m = matrix.size(), n = matrix[0].size(), sz = 0, pre; + vector cur(n, 0); + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + int temp = cur[j]; + if (i==0 || j==0 || matrix[i][j]=='0') { + cur[j] = matrix[i][j] - '0'; + } else { + cur[j] = min(pre, min(cur[j], cur[j - 1])) + 1; + } + sz = max(cur[j], sz); + pre = temp; + } + } + return sz * sz; + } +}; \ No newline at end of file diff --git a/Week_05/G20200343030497/LeetCode_647_497.cpp b/Week_05/G20200343030497/LeetCode_647_497.cpp new file mode 100644 index 00000000..da8dc590 --- /dev/null +++ b/Week_05/G20200343030497/LeetCode_647_497.cpp @@ -0,0 +1,23 @@ +class Solution { +public: + // 时间复杂度:O(n) + // 空间复杂度:O(1) + int countSubstrings(string s) { + int n = s.size(); + int cnt = 0; + for(int i = 0; i < n; i++) { + palindromic(s, i, i, cnt); // 偶数 + palindromic(s, i, i+1, cnt); // 奇数 + } + return cnt; + } + +private: + void palindromic(string s, int left, int right, int& cnt) { + while(left >=0 && right < s.size() && s[left] == s[right]) { + cnt++; + left--; + right++; + } + } +}; \ No newline at end of file diff --git a/Week_05/G20200343030497/LeetCode_64_497.cpp b/Week_05/G20200343030497/LeetCode_64_497.cpp new file mode 100644 index 00000000..cecea4c3 --- /dev/null +++ b/Week_05/G20200343030497/LeetCode_64_497.cpp @@ -0,0 +1,22 @@ +class Solution { +public: + // 时间复杂度:O(mn) + // 空间复杂度:O(n) + int minPathSum(vector>& grid) { + int m = grid.size(); + int n = grid[0].size(); + + vector cur(m, grid[0][0]); + for (int i = 1; i < m; i++) + cur[i] = cur[i - 1] + grid[i][0]; + + for (int j = 1; j < n; j++) { + cur[0] += grid[0][j]; + + for (int i = 1; i < m; i++) + cur[i] = min(cur[i - 1], cur[i]) + grid[i][j]; + } + + return cur[m - 1]; + } +}; \ No newline at end of file diff --git a/Week_05/G20200343030499/LeetCode_64_499.java b/Week_05/G20200343030499/LeetCode_64_499.java new file mode 100644 index 00000000..7bb21fb6 --- /dev/null +++ b/Week_05/G20200343030499/LeetCode_64_499.java @@ -0,0 +1,23 @@ +class Solution { + public int minPathSum(int[][] grid) { + int m = grid.length; + int n = grid[0].length; + + int[][] dp = new int[m][n]; + + dp[m - 1][n - 1] = grid[m - 1][n - 1]; + for (int i = m - 2; i >= 0; i--) { + dp[i][n - 1] = grid[i][n - 1] + dp[i + 1][n - 1]; + } + for (int i = n - 2; i >= 0; i--) { + dp[m - 1][i] = grid[m - 1][i] + dp[m - 1][i + 1]; + } + + for (int i = m - 2; i >= 0; i--) { + for (int j = n - 2; j >= 0; j--) { + dp[i][j] = Math.min(dp[i + 1][j], dp[i][j + 1]) + grid[i][j]; + } + } + return dp[0][0]; + } +} \ No newline at end of file diff --git a/Week_05/G20200343030499/LeetCode_91_499.java b/Week_05/G20200343030499/LeetCode_91_499.java new file mode 100644 index 00000000..f0301178 --- /dev/null +++ b/Week_05/G20200343030499/LeetCode_91_499.java @@ -0,0 +1,25 @@ +class Solution { + Set codeSet = new HashSet<>(Arrays.asList("1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", + "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26")); + private int res = 0; + + public int numDecodings(String s) { + int len = s.length(); + int[] dp = new int[len + 1]; + dp[0] = 1; + dp[1] = codeSet.contains(s.substring(0, 1)) ? 1 : 0; + + for (int i = 2; i <= len; i++) { + int currSolutionCount = 0; + if (codeSet.contains(s.substring(i - 1, i))) { + currSolutionCount += dp[i - 1]; + } + if (codeSet.contains(s.substring(i - 2, i))) { + currSolutionCount += dp[i - 2]; + } + dp[i] = currSolutionCount; + } + + return dp[len]; + } +} \ No newline at end of file diff --git a/Week_05/G20200343030501/LeetCode_64_501.go b/Week_05/G20200343030501/LeetCode_64_501.go new file mode 100644 index 00000000..29737df4 --- /dev/null +++ b/Week_05/G20200343030501/LeetCode_64_501.go @@ -0,0 +1,27 @@ +package G20200343030501 + +func minPathSum(grid [][]int) int { + rowLength := len(grid) + colLength := len(grid[0]) + + for i := 1; i < rowLength; i++ { + grid[i][0] += grid[i - 1][0] + } + for i := 1; i < colLength; i++ { + grid[0][i] += grid[0][i - 1] + } + for row := 1; row < rowLength; row++ { + for col := 1; col < colLength; col++ { + grid[row][col] += min(grid[row - 1][col], grid[row][col - 1]) + } + } + return grid[rowLength - 1][colLength - 1] +} + +func min(a int, b int) int { + if a > b { + return b + } else { + return a + } +} \ No newline at end of file diff --git a/Week_05/G20200343030501/LeetCode_91_501.go b/Week_05/G20200343030501/LeetCode_91_501.go new file mode 100644 index 00000000..6db28d35 --- /dev/null +++ b/Week_05/G20200343030501/LeetCode_91_501.go @@ -0,0 +1,44 @@ +package G20200343030501 + +func numDecodings(s string) int { + var nums []int + base := int('0') + for _, digit := range s { + nums = append(nums, int(digit)-base) + } + length := len(nums) + lastOne := 0 + lastTwo := 0 + if nums[length - 1] == 0 { + lastOne = 0 + } else { + lastOne = 1 + } + if length == 1 { + return lastOne + } + lastTwo = lastOne + if nums[length-2] == 0 { + lastOne = 0 + } else if exists(nums, length - 2) { + lastOne = lastTwo + 1 + } + for index := length - 3; index >= 0; index-- { + if nums[index] == 0 { + lastTwo = lastOne + lastOne = 0 + continue + } + current := lastOne + if exists(nums, index) { + current += lastTwo + } + lastTwo = lastOne + lastOne = current + } + return lastOne +} + +func exists(nums []int, index int) bool { + return nums[index] * 10 + nums[index + 1] <= 26 +} diff --git a/Week_05/G20200343030503/LeetCode_120_503.java b/Week_05/G20200343030503/LeetCode_120_503.java new file mode 100644 index 00000000..8cdb41a1 --- /dev/null +++ b/Week_05/G20200343030503/LeetCode_120_503.java @@ -0,0 +1,45 @@ +/** + * 三角形的最小路径和 + * DP + * a. 重复性(分治) problem(i,j) = min(sub(i+1,j),sub(i+1,j+1)) + a(i,j); + * b. 定义状态数组(状态数组是一维还是二维的) f[i,j] + * c. DP方程 f[i,j] = min(f[i+1,j],f[i+1,j+1]) + a[i,j]; + * + * + * + */ +/** + * DP + * a. 重复性(分治) problem(i,j) = min(sub(i+1,j),sub(i+1,j+1)) + a(i,j); + * b. 定义状态数组(状态数组是一维还是二维的) f[i,j] + * c. DP方程 f[i,j] = min(f[i+1,j],f[i+1,j+1]) + a[i,j]; + * + */ +class Solution { + //动态规划 + public int minimumTotal(List> triangle) { + int[] a = new int[triangle.size()+1]; + for (int i = triangle.size()-1; i >= 0; i--) { + for (int j = 0; j < triangle.get(i).size(); j++ ) { + a[j] = Math.min(a[j],a[j+1]) + triangle.get(i).get(j);; + } + } + return a[0]; + } + //递归 + int row; + public int minimumTotal(List> triangle) { + row=triangle.size(); + return helper(0,0, triangle); + } + private int helper(int level, int c, List> triangle){ + // System.out.println("helper: level="+ level+ " c=" + c); + if (level==row-1){ + return triangle.get(level).get(c); + } + int left = helper(level+1, c, triangle); + int right = helper(level+1, c+1, triangle); + return Math.min(left, right) + triangle.get(level).get(c); + } + +} \ No newline at end of file diff --git a/Week_05/G20200343030503/LeetCode_152_503.java b/Week_05/G20200343030503/LeetCode_152_503.java new file mode 100644 index 00000000..0269481e --- /dev/null +++ b/Week_05/G20200343030503/LeetCode_152_503.java @@ -0,0 +1,25 @@ +/** + * 乘积最大子序列 + * + * + * + */ +class Solution { + public int maxProduct(int[] nums) { + int size = nums.length; + if (size == 0) + return 0; + else if (size == 1) + return nums[0]; + int p = nums[0]; + int maxP = nums[0]; + int minP = nums[0]; + for (int i = 1; i < size; i++) { + int temp = maxP; + maxP = Math.max(Math.max(maxP*nums[i],nums[i]),minP*nums[i]); + minP = Math.min(Math.min(temp*nums[i],nums[i]),minP*nums[i]); + p = Math.max(maxP,p); + } + return p; + } +} \ No newline at end of file diff --git a/Week_05/G20200343030503/LeetCode_53_503.java b/Week_05/G20200343030503/LeetCode_53_503.java new file mode 100644 index 00000000..17bc5793 --- /dev/null +++ b/Week_05/G20200343030503/LeetCode_53_503.java @@ -0,0 +1,31 @@ +/** + * + * 最大自序和 + * + */ +class Solution { + //贪心 + public int maxSubArray(int[] nums) { + int len = nums.length; + int currSum = nums[0]; + int maxSum = nums[0]; + + for (int i = 1; i < len; i++) { + currSum = Math.max(nums[i],currSum + nums[i]); + maxSum = Math.max(maxSum,currSum); + } + return maxSum; + } + + //动态规划 + public int maxSubArray(int[] nums) { + int len = nums.length; + int maxSum = nums[0]; + for (int i = 1; i < len; i++) { + if (nums[i - 1] > 0) + nums[i] += nums[i - 1]; + maxSum = Math.max(nums[i],maxSum); + } + return maxSum; + } +} \ No newline at end of file diff --git a/Week_05/G20200343030503/NOTE.md b/Week_05/G20200343030503/NOTE.md index 50de3041..aca8a6f8 100644 --- a/Week_05/G20200343030503/NOTE.md +++ b/Week_05/G20200343030503/NOTE.md @@ -1 +1,1754 @@ -学习笔记 \ No newline at end of file +知识储备 + +## 参考链接 + +- [Java 源码分析(ArrayList)](http://developer.classpath.org/doc/java/util/ArrayList-source.html) +- [Linked List 的标准实现代码](http://www.geeksforgeeks.org/implementing-a-linked-list-in-java-using-class/) +- [Linked List 示例代码](http://www.cs.cmu.edu/~adamchik/15-121/lectures/Linked Lists/code/LinkedList.java) +- [Java 源码分析(LinkedList)](http://developer.classpath.org/doc/java/util/LinkedList-source.html) +- LRU Cache - Linked list:[ LRU 缓存机制](http://leetcode-cn.com/problems/lru-cache) +- Redis - Skip List:[跳跃表](http://redisbook.readthedocs.io/en/latest/internal-datastruct/skiplist.html)、[为啥 Redis 使用跳表(Skip List)而不是使用 Red-Black?](http://www.zhihu.com/question/20202931) + +- [Java 的 PriorityQueue 文档](http://docs.oracle.com/javase/10/docs/api/java/util/PriorityQueue.html) +- [Java 的 Stack 源码](http://developer.classpath.org/doc/java/util/Stack-source.html) +- [Java 的 Queue 源码](http://fuseyism.com/classpath/doc/java/util/Queue-source.html) +- [Python 的 heapq](http://docs.python.org/2/library/heapq.html) +- [高性能的 container 库](http://docs.python.org/2/library/collections.html) + +- [Java Set 文档](http://docs.oracle.com/en/java/javase/12/docs/api/java.base/java/util/Set.html) +- [Java Map 文档](http://docs.oracle.com/en/java/javase/12/docs/api/java.base/java/util/Map.html) + + + +## Array、Linked List 实战题目 + +- https://leetcode-cn.com/problems/container-with-most-water/ + + ```java + /** + * 盛最多水的容器 + * 采用双指针左右向中间收敛 + * 1. 遍历数组 并且定义2个指针 rear和head 如果head < rear 就遍历 + * 2. 求面积 s = x * y + * x = (rear - head) + * y = Math.min(nums[rear],nums[head]); + * 3. 取出最大的面积 + */ + public int maxArea(int[] nums) { + int maxArea = 0; + for (int head = 0,rear = nums.length - 1; head < rear; ) { + int minHeight = nums[head] > nums[rear] ? nums[rear--] : nums[head++] ; + int area = (rear - head + 1) * minHeight; + maxArea = Math.max(maxArea,area); + } + return maxArea; + } + ``` + + + +- https://leetcode-cn.com/problems/move-zeroes/ + + ```java + //移动0 + //思想就是快慢指针 : 如果快不为0并且2个指针的不想等就用慢指针记录快指针的值,将快指针置为0 + public void moveZeroes(int[] nums) { + 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 void moveZeroes(int[] nums) { + if (nums == null || nums.length == 0) return; + int insertPos = 0; + for (int num: nums) { + if (num != 0) nums[insertPos++] = num; + } + while (insertPos < nums.length) { + nums[insertPos++] = 0; + } + } + ``` + +- https://leetcode.com/problems/climbing-stairs/ + + ```java + /** + * + * 方式一、 爬楼梯 + * 方式二、 初始化3个值,每次修改前2个值,第三个值等于前两个值只和 + * + */ + public int climbStairs(int n) { + if (n <= 2) { + return n; + } + return climbStairs(n - 1) + climbStairs(n - 2); + } + public int climbStairs(int n) { + if (n == 1) return 1; + if (n == 2) return 2; + + int first = 1; + int second = 2; + int result = 0; + for (int i = 3; i <= n; i++) { + result = first + second; + first = second; + second = result; + } + return result; + } + ``` + + + +- [https://leetcode-cn.com/problems/3sum/ ](https://leetcode-cn.com/problems/3sum/)(高频老题) + + ```java + /** + * + * 三数只和 + * 双指针向内收敛 + * + */ + public List> threeSum(int[] nums) { + //结果保存在list集合中 + List> result = new ArrayList<>(); + //排序 + Arrays.sort(nums); + //遍历集合 + //定义2个指针 i、j + int i; + int j; + for (int k = 0; k < nums.length; k++) { + // 因为已经排好序nums[k],nums[i],nums[j]中nums[k]最小,如果nums[k]大于0那么三数只和就不可能等于0,直接返回 + if (nums[k] > 0) break; + //k对应元素去重 + if (k > 0 && nums[k] == nums[k-1]) continue; + i = k + 1; //i从k的下一个元素开始 + j = nums.length - 1;//j从最后一个元素开始 + while (i < j) { + int sum = nums[k] + nums[i] + nums[j]; + if ( sum == 0) { + result.add(Arrays.asList(nums[k],nums[i],nums[j])); + //i、j元素去重 + while (i < j && nums[i] == nums[i+1]) { i++; } + while (i < j && nums[j] == nums[j-1]) { j--; } + i++; + j--; + } + else if (sum < 0) i ++; + else j --; + } + } + return result; + } + ``` + +- https://leetcode.com/problems/reverse-linked-list/ + + ```java + /** + * 反转链表 + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode(int x) { val = x; } + * } + */ + class Solution { + public ListNode reverseList(ListNode head) { + ListNode cur = head; + ListNode pre = null; + while (cur != null) { + ListNode temp = cur.next; + cur.next = pre; + pre = cur; + cur = temp; + } + return pre; + } + } + ``` + +- https://leetcode.com/problems/swap-nodes-in-pairs + + ```java + /** + * 两两交换链表中的节点 + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode(int x) { val = x; } + * } + * 知识储备 + * 链表的第一个node,因为没有前驱节点,所以该node需要特殊处理,会导致额外的代码量。 + * 如果创建一个dummy,将其作为第一个node的前驱节点,这样链表中所有的node都可以也能够同样的逻辑来处理了 + */ + class Solution { + //非递归 time complexity O(n) space complexity O(1) + public ListNode swapPairs(ListNode head) { + //1. 定义一个虚拟节点(为什么? 看上述知识储备) + ListNode dummy = new ListNode(-1); + dummy.next = head; //将虚拟节点作为链表第一个节点的前驱节点 + ListNode pre = dummy; //取出前驱节点 + //原链表的第一个节点和第二个节点不为空,取出并且交换 + while (head != null && head.next != null) { + ListNode first = head; + ListNode second = head.next; + //相邻节点进行交换 + pre.next = second; + first.next = second.next; + second.next = first; + //指针后移 + pre = first; + head = first.next; + } + return dummy.next; + } + + //递归 time complexity O(n) space complexity O(n) + public ListNode swapPairs(ListNode head) { + if (head == null || head.next == null) { + return head; + } + ListNode first = head; + ListNode second = head.next; + + first.next = swapPairs(second.next); + second.next = first; + return second; + + } + + } + ``` + +- https://leetcode.com/problems/linked-list-cycle + + ```java + /** + * 环形链表 + * Definition for singly-linked list. + * class ListNode { + * int val; + * ListNode next; + * ListNode(int x) { + * val = x; + * next = null; + * } + * } + * + * 方式一、使用哈希表记录 + * 判断是否存在环,不能根据链表中的值来判断,因为值可能有重复,哈希表的范型应该是链表中的节点 + * 方式二、快慢指针 + * + * + */ + + public class Solution { + public boolean hasCycle(ListNode head) { + //List nums = new ArrayList(); + Set set = new HashSet(); + while (head != null) { + if (set.contains(head)) { + return true; + } + set.add(head); + head = head.next; + } + return false; + } + public boolean hasCycle(ListNode head) { + if (head == null || head.next == null) { + return false; + } + ListNode slow = head; + ListNode fast = head.next; + while (slow != fast) { + if (fast == null || fast.next == null) { + return false; + } + slow = slow.next; + fast = fast.next.next; + } + return true; + } + } + ``` + + + +- https://leetcode.com/problems/linked-list-cycle-ii + + ```java + /** + * 环形链表二 + * Definition for singly-linked list. + * class ListNode { + * int val; + * ListNode next; + * ListNode(int x) { + * val = x; + * next = null; + * } + * } + */ + public class Solution { + //方式一、借助哈希表 + public ListNode detectCycle(ListNode head) { + Set set = new HashSet(); + while (head != null) { + if (set.contains(head)) { + return head; + } + set.add(head); + head = head.next; + } + return null; + } + // 方式二、快慢指针,查看高手解答 膜拜的感觉 请看代码块下方解释 + public ListNode detectCycle(ListNode head) { + if (head == null || head.next == null) { + return null; + } + ListNode fast = head; //定义一个快指针 + ListNode slow = head; //定义一个慢指针 + + while (fast.next != null && fast.next.next != null) { + fast = fast.next.next; + slow = slow.next; + + if (fast == slow) { + // 新定义一个指针从头节点开始一次走一步,慢指针从快慢指针相遇的地方开始一次走一步 + ListNode meetNode = head; + while (slow != meetNode) { + slow = slow.next; + meetNode = meetNode.next; + } + return meetNode; + } + } + return null; + + } + + } + ``` + + https://leetcode.com/problems/linked-list-cycle-ii/discuss/44774/Java-O(1)-space-solution-with-detailed-explanation. + Is this diagram help you understand? + When fast and slow meet at point p, the length they have run are 'a+2b+c' and 'a+b'. + Since the fast is 2 times faster than the slow. So a+2b+c == 2(a+b), then we get 'a==c'. + So when another slow2 pointer run from head to 'q', at the same time, previous slow pointer will run from 'p' to 'q', so they meet at the pointer 'q' together. + + image-20200307172330680 + +- 🌟 https://leetcode.com/problems/reverse-nodes-in-k-group/ + + ```java + /** + * + * K 个一组翻转链表 + */ + class Solution { + //第一种方式: 递归 看不懂 + public ListNode reverseKGroup(ListNode head, int k) { + //方式一、使用递归 + //1. 找到定义个计数器,找第k+1个节点 + ListNode curr = head; + int count = 0; + while (curr.next != null && count != k) { + curr = curr.next; + count++; + } + // 反转 + if (count == k) { + curr = reverseKGroup(curr,k); + while (count-- >0) { + ListNode temp = head.next; + head.next = curr; + curr = head; + head = temp; + } + head = curr; + } + return head; + } + } + ``` + + + +- https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array/ + + ```java + /** + * + * 删除排序数组中的重复项 + * 使用双指针,i,j其中j记录的是nums中非重复元素的下标 + * 前提: + * 1. 不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。 + * 2. 不需要考虑数组中超出新长度后面的元素 + */ + class Solution { + public int removeDuplicates(int[] nums) { + int j = 0; + for (int i = 1; i < nums.length; i++) { + if (nums[j] != nums[i]) { + nums[++j] = nums[i]; + } + } + return j + 1; + } + } + ``` + + + +- https://leetcode-cn.com/problems/rotate-array/ + + ```java + /** + * 旋转数组 + * 方式一、使用三次反转 + * 第一次: 反转整个数组 + * 第二次: 反转0~k-1个数组元素 + * 第三次: 反转k-1~len-1个数组元素 + * + * 方式二、使用旋转数组 + * + */ + class Solution { + public void rotate(int[] nums, int k) { + k = k%nums.length; //注意: 防止 nums=[1,2] k=3这种情况 + 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) { + int i = start; + int j = end; + //注意,这里应该使用的是小于号 while (i < j),不能使用不等于 while (i != j) + while (i < j) { + int temp = nums[j]; + nums[j] = nums[i]; + nums[i] = temp; + i++; + j--; + } + } + + /** + * 待研究 + */ + public class Solution { + public void rotate(int[] nums, int k) { + k = k % nums.length; + int count = 0; + for (int start = 0; count < nums.length; start++) { + int current = start; + int prev = nums[start]; + do { + int next = (current + k) % nums.length; + int temp = nums[next]; + nums[next] = prev; + prev = temp; + current = next; + count++; + } while (start != current); + } + } + } + + } + ``` + + + +- https://leetcode-cn.com/problems/merge-two-sorted-lists/ + + ```java + /** + * 合并2个有序链表 + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode(int x) { val = x; } + * } + * 思路分析: + * 创建一个新的列表,遍历链表1和链表2,分别比较每个节点的大小放入融合列表中 + */ + class Solution { + public ListNode mergeTwoLists(ListNode l1, ListNode l2) { + ListNode headNode = new ListNode(-1); + ListNode cur1 = l1; + ListNode cur2 = l2; + ListNode curMerge = headNode; + while (cur1 != null && cur2 != null) { + if (cur1.val > cur2.val) { + curMerge.next = cur2; + cur2 = cur2.next; + }else { + curMerge.next = cur1; + cur1 = cur1.next; + } + curMerge = curMerge.next; + } + curMerge.next = cur1 == null ? cur2 : cur1; + return headNode.next; + } + } + ``` + + + +- https://leetcode-cn.com/problems/merge-sorted-array/ + + ```java + /** + * 合并2个有序数组 + * 题目要点: 1. 使用取余的方式判断i+k大于len 则从头开始 arr[(i + k) % nums.length] + * 2. 需要重新开辟一个数组去存放旋转之后的值 用于改变原数组的顺序 + * 一定要注意,题干明确表示需要 有序整数数组 + */ + class Solution { + // time complexity O((n+m)log(n+m)) space complexity O(n+m) + public void merge(int[] nums1, int m, int[] nums2, int n) { + int j = 0; + for (int i = m; i < m + n; i++) { + nums1[i] = nums2[j]; + j++; + } + Arrays.sort(nums1); + } + //time complexity O(n+m) space complexity O(n) + public void merge(int[] nums1, int m, int[] nums2, int n) { + //复制nums1的数组,保留有效数据位 + int[] nums1_copy = new int[m]; + System.arraycopy(nums1,0,nums1_copy,0,m); + //定义2个指针p1 0~m p2 0~n + int p1 = 0; + int p2 = 0; + int p = 0; + while (p1 < m && p2 < n) { + if (nums1_copy[p1] < nums2[p2]) { + nums1[p++] = nums1_copy[p1++]; + }else { + nums1[p++] = nums2[p2++]; + } + } + 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); + } + } + //最优解 从A数组的后边开始插入 time complexity O(n) space complexity O(1) + public void merge(int A[], int m, int B[], int n) { + int i=m-1; + int j=n-1; + int k = m+n-1; + while(i >=0 && j>=0) + { + if(A[i] > B[j]) + A[k--] = A[i--]; + else + A[k--] = B[j--]; + } + while(j>=0) + A[k--] = B[j--]; + } + } + ``` + + + +- https://leetcode-cn.com/problems/two-sum/ + + ```java + /* + * 两数之和 + * 方式一、 暴力求解法 + * 双层for循环 + * time complexity O(n^2) + * space complexity O(1) + * 方式二、 使用哈希表 + * time complexity O(n) 只遍历了一边nums所以时间复杂度是O(n) + * space complexity O(n) 空间复杂度取决于hash表中元素的个数 + * + * + * + * 题目明确: 每种输入只会对应一个答案 + */ + 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[i] + nums[j] == target) { + return new int[] { i, j }; + } + } + } + throw new IllegalArgumentException("No two sum 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[]{i,map.get(target - nums[i])}; + } + map.put(nums[i],i); + } + throw new IllegalArgumentException("No two sum solution"); + } + } + ``` + + + +- https://leetcode-cn.com/problems/move-zeroes/ + + ```java + /** + * 移动零 + */ + class Solution { + public void moveZeroes(int[] nums) { + int index = 0; + for (int num : nums) { + if (num != 0) { + num[index++]=num; + } + } + while (index < nums.length) { + nums[index++]=0; + } + } + + public void moveZeroes(int[] nums) { + if(nums==null) { + return; + } + //两个指针i和j + int j = 0; + for(int i=0;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; + } + } + ``` + + + +## 哈希、集合题目 + +- https://leetcode-cn.com/problems/valid-anagram/description/ + + ```java + /** + * + * 是否是异位词 + * 方式1. 排序(借助字符数组进行排序) 判断内容是否相同 + * time complexity O(nlogn) + * space complexity O(n) + * 如果isAnagram中两个参数是字符数组,那么space complexity O(1) + * 方式2. 使用hash表来统计每个字符出现的次数 + * + */ + class Solution { + public boolean isAnagram(String s, String t) { + char[] sarr = s.toCharArray(); + char[] tarr = t.toCharArray(); + Arrays.sort(sarr); + Arrays.sort(tarr); + boolean flag = Arrays.equals(sarr,tarr); + if (flag) { + return true; + } + return false; + } + + public boolean isAnagram(String s, String t) { + if (s.length() != t.length()) { + return false; + } + int[] counter = new int[26]; + for (int i = 0; i < s.length(); i++) { + //s.char[i]的个数加1 t.char[i]的个数减1, 最后遍历counter的值是否都为0即可 + counter[s.charAt(i) - 'a']++; + counter[t.charAt(i) - 'a']--; + } + for (int count: counter) { + if (count != 0) { + return false; + } + } + return true; + } + } + ``` + + + +- https://leetcode-cn.com/problems/group-anagrams/ + + ```java + /** + * 1. 方式一、借助hash表,将字符数组中的元素排序之后当作key入map,值为未排序的元素的集合 + * time complexity O(nklogk) n表示的是Strs字符串数组的所有元素,每个元素的排序klogk + * space complexity O(nk) O(NK),排序存储在 ls 中的全部信息内容。 + * + */ + class Solution { + public List> groupAnagrams(String[] strs) { + Map> map = new HashMap>(); + + for (String str: strs) { + char[] chars = str.toCharArray(); + Arrays.sort(chars); + String charStr = String.valueOf(chars); + if (map.containsKey(charStr)) { + map.get(charStr).add(str); + }else { + List ls = new ArrayList<>(); + ls.add(str); + map.put(charStr,ls); + } + } + + return new ArrayList<>(map.values()); + } + } + ``` + + + + + +## 树和递归实战题目 + +二叉树动态图 https://visualgo.net/zh/bst?slide=1 + +- https://leetcode-cn.com/problems/binary-tree-inorder-traversal/ + + ```java + /** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; } + * } + * 二叉树的中序遍历 左 根 右 + * 方式一、使用递归 + * + * 方式二、非递归 (借助栈) + */ + class Solution { + //方式一、递归 + public List inorderTraversal(TreeNode root) { + List result = new ArrayList(); + helper(root,result); + return result; + } + + public void helper(TreeNode root,List result) { + if (root != null) { + //递归所有左节点 + if (root.left != null) { + helper(root.left,result); + } + result.add(root.val); + //递归所有右节点 + if(root.right != null) { + helper(root.right,result); + } + } + } + //方式二、 非递归 + public List inorderTraversal(TreeNode root) { + //定义容器用于存放返回结果 + List result = new ArrayList(); + //定义一个栈 + Stack stack = new Stack<>(); + //遍历二叉树, 根节点入栈 + TreeNode cur = root; + while (cur != null || !stack.empty()) { + while (cur != null) { + stack.push(cur); + cur = cur.left; + } + cur = stack.pop(); + result.add(cur.val); + cur = cur.right; + } + return result; + } + } + ``` + + + +- https://leetcode-cn.com/problems/binary-tree-preorder-traversal/ + + ```java + /** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; } + * } + * + * 二叉树的前序遍历 + * 使用递归 从根节点开始遍历,如果是根节点直接添加到结果的集合中,如果是左节点继续递归,同理有节点一样 + * + * 借助栈 + * LinkedList 是一个双向链表。 + * 它也可以被当作堆栈、队列或双端队列进行操作。LinkedList随机访问效率低,但随机插入、随机删除效率低。 + * 总结: 本题中LinkedList比stack快 + * + */ + class Solution { + //方式一、递归遍历 + public List preorderTraversal(TreeNode root) { + List result = new ArrayList(); + helper(root,result); + return result; + } + + public void helper(TreeNode root,List result) { + if (root != null ) { + result.add(root.val); + if (root.left != null) { + helper(root.left,result); + } + if (root.right != null) { + helper(root.right,result); + } + } + } + //方式二、非递归借助栈 + public List preorderTraversal(TreeNode root) { + //Stack stack = new Stack(); + LinkedList stack = new LinkedList(); + List result = new ArrayList(); + if (root == null) { + return result; + } + //先序遍历 先把根节点入栈 + //stack.push(root); + stack.add(root); + while (!stack.isEmpty()) { //栈不为空的时候 + //根节点出栈 + //TreeNode treeNode = stack.pop(); + TreeNode treeNode = stack.pollLast(); + + result.add(treeNode.val); + //先入右节点 + //再入左节点 + if (treeNode.right != null) { + //stack.push(treeNode.right); + stack.add(treeNode.right); + } + if (treeNode.left != null) { + //stack.push(treeNode.left); + stack.add(treeNode.left); + } + } + + return result; + + } + + } + + ``` + + + +- https://leetcode-cn.com/problems/n-ary-tree-postorder-traversal/ + + ```java + /* + * + * n叉树的遍历 - 后序遍历 + * 需要注意的就是根节点和自节点顺序与前序遍历相反 + * + * + *class Node { + * public int val; + * public List children; + * public Node() {} + * public Node(int _val) { + * val = _val; + * } + * public Node(int _val, List _children) { + * val = _val; + * children = _children; + * } + *}; + */ + class Solution { + //递归 + public List result = new ArrayList(); + public List postorder(Node root) { + if (root == null) + return result; + for (Node child: root.children) { + postorder(child); + } + result.add(root.val); + return result; + } + //非递归实现 + public List postorder(Node root) { + //定义返回结果的容器 + //(个人理解如果postorder循环很多次,建议容器传递进来,但是这个限制条件就在创建的时候加 + //,如果就循环一次创建一个容器) + List result = new ArrayList<>(); + //限制条件 + if (root == null) { + return result; + } + Stack stack = new Stack(); + stack.add(root); + + while (!stack.empty()) { + root = stack.pop(); + result.add(root.val); + for (int i = 0; i < root.children.size() ; i++) { + stack.add(root.children.get(i)); + } + + } + Collections.reverse(result); + return result; + } + } + ``` + + + +- [https://leetcode-cn.com/problems/n-ary-tree-preorder-traversal/](https://leetcode-cn.com/problems/n-ary-tree-preorder-traversal/description) + + ```java + /* + * + * n叉树的遍历 - 前序遍历 + * 非递归实现 + * 我们使用一个栈来帮助我们得到前序遍历,需要保证栈顶的节点就是我们当前遍历到的节点。 + * 我们首先把根节点入栈,因为根节点是前序遍历中的第一个节点。 + * 随后每次我们从栈顶取出一个节点 u,它是我们当前遍历到的节点,并把 u 的所有子节点逆序推入栈中。 + * 例如 u 的子节点从左到右为 v1, v2, v3,那么推入栈的顺序应当为 v3, v2, v1, + * 这样就保证了下一个遍历到的节点(即 u 的第一个子节点 v1)出现在栈顶的位置。 + * + */ + class Solution { + + //递归 + public List result = new ArrayList(); + public List preorder(Node root) { + if (root == null) { + return result; + } + result.add(root.val); + for (Node child: root.children) { + preorder(child); + } + + return result; + } + //非递归实现 + public List preorder(Node root) { + //存放返回结果的容器 + List result = new ArrayList<>(); + //限制条件 + if (root == null) return result; + //定义一个栈 + Stack stack = new Stack<>(); + stack.add(root); + + while (!stack.empty()) { + root = stack.pop(); + result.add(root.val); + for (int i = root.children.size() - 1; i >= 0; i--) { + stack.add(root.children.get(i)); + } + } + return result; + } + } + ``` + + + +- https://leetcode-cn.com/problems/n-ary-tree-level-order-traversal/ + + ```java + /* + * n叉树的层序遍历 + * class Node { + * public int val; + * public List children; + * public Node() {} + * public Node(int _val) { + * val = _val; + * } + * public Node(int _val, List _children) { + * val = _val; + * children = _children; + * } + * }; + */ + class Solution { + //递归实现 ⭐️ + public List> levelOrder(Node root) { + List> result = new ArrayList>(); + return helper(root,0,result); + } + + public List> helper(Node node, int depth, List> result) { + if (node == null) + return result; + if (result.size() < depth+1) { + result.add(new ArrayList<>()); + } + result.get(depth).add(node.val); + + //对其子节点使用递归 dirll down + for (Node child: node.children) { + helper(child, depth+1,result); + } + return result; + } + + //非递归 借助队列 + public List> levelOrder(Node root) { + List> result = new ArrayList>(); + if (root == null) return result; + Queue queue = new LinkedList(); + queue.add(root); + while (!queue.isEmpty()) { + //外层循环为一层 + List list = new ArrayList<>(); + int queueSize = queue.size(); + while(queueSize-- > 0) { + //子节点入队列 + Node head = queue.poll(); + list.add(head.val); + for (Node child: head.children) { + queue.add(child); + } + } + result.add(list); + } + return result; + } + + } + ``` + +- https://leetcode-cn.com/problems/climbing-stairs/ + + ```java + /** + * 爬楼梯 + * 方式一、 使用递归 + * 方式二、 初始化3个值,每次修改前2个值,第三个值等于前两个值只和 + * + */ + class Solution { + public int climbStairs(int n) { + // if (n <= 2) { + // return n; + // } + // return climbStairs(n - 1) + climbStairs(n - 2); + if(n <= 2) { + return n; + } + int step_one = 1; + int step_two = 2; + + int step_three = 0; + for (int i = 3 ; i <= n ;i++) { + step_three = step_two + step_one; + step_one = step_two; + step_two = step_three; + } + return step_three; + } + + } + ``` + +- https://leetcode-cn.com/problems/generate-parentheses/ + + ```java + /** + * 括号生成 + * 算法重点: 如果我们还剩一个位置,我们可以开始放一个左括号。 + * 如果它不超过左括号的数量,我们可以放一个右括号。 + * + */ + class Solution { + public List generateParenthesis(int n) { + List result = new ArrayList<>(); + backtrack(result,"",0,0,n); + return result; + } + + public void backtrack(List result,String cur,int open,int close,int max) { + //termination + if (cur.length() == max*2) { + result.add(cur); + return; + } + //process 其实就是open + 1或者close +1 cur+( 或者cur+) + //drill down + if (open < max) { + backtrack(result,cur+"(",open + 1,close,max); + } + if (close < open) { + backtrack(result,cur+")",open,close+1,max); + } + //reverse state + } + } + ``` + +- https://leetcode-cn.com/problems/invert-binary-tree/description/ + + ```java + /** + * 反转二叉树 + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; } + * } + */ + class Solution { + //递归 + public TreeNode invertTree(TreeNode root) { + if (root == null) return null; + TreeNode left = invertTree(root.left); + TreeNode right = invertTree(root.right); + root.left = right; + root.right = left; + return root; + } + //非递归 + public TreeNode invertTree(TreeNode root) { + if (root == null) return null; + Queue queue = new LinkedList(); + queue.add(root); + while (!queue.isEmpty()) { + TreeNode temp = queue.poll(); + TreeNode left = temp.left; + temp.left = temp.right; + temp.right = left; + if (temp.left != null) + queue.add(temp.left); + if (temp.right != null) + queue.add(temp.right); + } + return root; + } + + } + ``` + +- https://leetcode-cn.com/problems/maximum-depth-of-binary-tree + + ```java + /** + * 二叉树的最大深度 + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; } + * } + */ + class Solution { + //递归: 中心思想就是: max(左子树,右子树) + 1 + public int maxDepth(TreeNode root) { + //termnition + if (root == null) return 0; + //dirll down + int left = maxDepth(root.left); + int right = maxDepth(root.right); + //process + return java.lang.Math.max(left,right) + 1; + } + //非递归 核型思想: 全局变量max用于存放返回结果,每次遍历改变max的值, + // 定义2个栈存放一个用于存放所有节点,一个用于存放节点的深度 + public int maxDepth(TreeNode root) { + if (root == null) return 0; + int max = 1; + Stack nodes = new Stack(); + Stack depths = new Stack(); + nodes.push(root); + depths.push(1); + while (!nodes.empty()) { + TreeNode cur = nodes.pop(); + int depth = depths.pop(); + + if (cur.left == null && cur.right == null) { + max = java.lang.Math.max(max,depth); + } + + if (cur.left != null) { + nodes.push(cur.left); + depths.push(depth+1); + } + if (cur.right != null) { + nodes.push(cur.right); + depths.push(depth+1); + } + } + return max; + } + } + ``` + +- https://leetcode-cn.com/problems/minimum-depth-of-binary-tree + + ```java + /** + * 二叉树的最小深度 + * + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; } + * } + * + * 边界条件eg. + * 3 + * / \ + * 9 20 + * / / \ + * 8 15 7 + */ + class Solution { + //递归 + public int minDepth(TreeNode root) { + if (root == null) return 0; + int left = minDepth(root.left); + int right = minDepth(root.right); + //说明: 叶子节点是没有在子节点的节点(既没有左子节点,又没有右子节点) + // 所以此边界条件的意思就是返回非空子节点的最小深度 + if (left == 0 || right == 0) //注意边界条件 + return left + right + 1; + else + return java.lang.Math.min(left, right) + 1; + } + //非递归: 借助队列 (类似BFS) + public int minDepth(TreeNode root) { + //限制条件 + if (root == null) + return 0; + Queue queue = new LinkedList(); + queue.add(root); + int level = 1; + while (!queue.isEmpty()) { + int size = queue.size(); //当前层的元素的个数 + while (size > 0) { + TreeNode node = queue.poll(); + if (node.left == null && node.right == null) { + return level; + } + if (node.left != null) + queue.add(node.left); + if (node.right != null) + queue.add(node.right); + size--; + } + level++; + } + return level; + } + + } + ``` + +- https://leetcode-cn.com/problems/group-anagrams/ + + ```java + /** + * 字母异位词分组 + * 1. 方式一、借助hash表,将字符数组中的元素排序之后当作key入map,值为未排序的元素的集合 + * time complexity O(nklogk) n表示的是Strs字符串数组的所有元素,每个元素的排序klogk + * space complexity O(nk) O(NK),排序存储在 ls 中的全部信息内容。 + * + */ + class Solution { + public List> groupAnagrams(String[] strs) { + Map> map = new HashMap>(); + + for (String str: strs) { + char[] chars = str.toCharArray(); + Arrays.sort(chars); + String charStr = String.valueOf(chars); + if (map.containsKey(charStr)) { + map.get(charStr).add(str); + }else { + List ls = new ArrayList<>(); + ls.add(str); + map.put(charStr,ls); + } + } + + return new ArrayList<>(map.values()); + } + } + ``` + +- https://leetcode-cn.com/problems/permutations/ + + ```java + /** + * + * 全排列 + * 参考: https://leetcode-cn.com/problems/permutations/solution/hui-su-suan-fa-python-dai-ma-java-dai-ma-by-liweiw/?utm_source=LCUS&utm_medium=ip_redirect_q_uns&utm_campaign=transfer2china + * + * + * + * + */ + class Solution { + + //执行用时 :2 ms, 在所有 Java 提交中击败了60.71%的用户 + public List> permute(int[] nums) { //permute : 重新排列 + List> result = new ArrayList<>();//存放所有结果 + LinkedList path = new LinkedList(); //存放一次排列[1,2,3] + boolean[] visited = new boolean[nums.length]; + backtrack(nums,result,path,visited); + return result; + } + + public void backtrack(int[] nums,List> result,LinkedList path,boolean[] visited){ + //1. 选择结束的条件 + if (nums.length == path.size()) { + result.add(new ArrayList<>(path)); + return; + } + //2. 做选择 + for (int i = 0; i < nums.length; i++) { + if (visited[i] == true) continue; + path.add(nums[i]); + visited[i] = true; + backtrack(nums,result,path,visited); + //特别注意需要重置result + visited[i] = false; + path.removeLast(); + } + } + + } + ``` + +- https://leetcode-cn.com/problems/permutations-ii/ + + ```java + /** + * + * 全排列 || + * + */ + class Solution { + public List> permuteUnique(int[] nums) { + //特别需要注意: nums一定要排序否则下变执行nums[i] == nums[i-1]做判断的时候会出错 + Arrays.sort(nums); + + //定义一个存放结果的集合 + List> result = new ArrayList>(); + //定义一个一趟结果的存放的集合,为方便状态重置,建议使用Deque或者LinkedList , + //不推荐使用Stack,java自己的人员都不再使用Stack + Deque stack = new ArrayDeque<>(); + //定义一个数组,确定nums中的数字是否被使用过 0 未使用过,1 使用过 + int[] used = new int[nums.length]; + dfs(nums,result,stack,used); + return result; + } + + public void dfs(int[] nums,List> result,Deque stack,int[] used){ + //termination + if (stack.size() == nums.length) { + result.add(new ArrayList<>(stack)); + return; + } + + //process + for (int i = 0; i < nums.length; i++) { + if (used[i] == 1) continue; + //减枝 + if (i > 0 && nums[i] == nums[i-1] && used[i-1] == 1) continue; + + stack.add(nums[i]); + used[i] = 1; + //drill down + dfs(nums,result,stack,used); + //reverse state + used[i] = 0; + stack.removeLast(); + } + + } + + } + ``` + +- https://leetcode-cn.com/problems/combinations/ + + ```java + + ``` + +- https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-tree/ + + ```java + + ``` + +- https://leetcode-cn.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal + + ``` + + ``` + +- ⭐️ https://leetcode-cn.com/problems/validate-binary-search-tree + + ```java + + ``` + +- ⭐️https://leetcode-cn.com/problems/serialize-and-deserialize-binary-tree/ + + ``` + + ``` + + + +## 分治和回溯相关 + +- https://leetcode-cn.com/problems/powx-n/ +- https://leetcode-cn.com/problems/subsets/ + +- [https://leetcode-cn.com/problems/majority-element/description/ ](https://leetcode-cn.com/problems/majority-element/description/)(简单、但是高频) +- https://leetcode-cn.com/problems/letter-combinations-of-a-phone-number/ +- https://leetcode-cn.com/problems/n-queens/ + +## DFS、BFS + +- https://leetcode-cn.com/problems/binary-tree-level-order-traversal/#/description +- https://leetcode-cn.com/problems/minimum-genetic-mutation/#/description +- https://leetcode-cn.com/problems/generate-parentheses/#/description +- https://leetcode-cn.com/problems/find-largest-value-in-each-tree-row/#/description + +- https://leetcode-cn.com/problems/word-ladder/description/ +- https://leetcode-cn.com/problems/word-ladder-ii/description/ +- https://leetcode-cn.com/problems/number-of-islands/ +- https://leetcode-cn.com/problems/minesweeper/description/ + +## 贪心算法 + +- [coin change 题目](https://leetcode-cn.com/problems/coin-change/) + +- https://leetcode-cn.com/problems/lemonade-change/description/ +- https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/description/ +- https://leetcode-cn.com/problems/assign-cookies/description/ +- https://leetcode-cn.com/problems/walking-robot-simulation/description/ +- [https://leetcode-cn.com/problems/jump-game/ ](https://leetcode-cn.com/problems/jump-game/) +- [ https://leetcode-cn.com/problems/jump-game-ii/](https://leetcode-cn.com/problems/jump-game-ii/) + +## 二分查找 + +- https://leetcode-cn.com/problems/sqrtx/ +- https://leetcode-cn.com/problems/valid-perfect-square/ + +- https://leetcode-cn.com/problems/search-in-rotated-sorted-array/ +- https://leetcode-cn.com/problems/search-a-2d-matrix/ +- https://leetcode-cn.com/problems/find-minimum-in-rotated-sorted-array/ + +## 动态规划 + +- https://leetcode-cn.com/problems/longest-common-subsequence/ +- https://leetcode-cn.com/problems/unique-paths/ +- https://leetcode-cn.com/problems/unique-paths-ii/ +- https://leetcode-cn.com/problems/climbing-stairs/description/ +- https://leetcode-cn.com/problems/triangle/description/ +- https://leetcode.com/problems/triangle/discuss/38735/Python-easy-to-understand-solutions-(top-down-bottom-up) +- https://leetcode-cn.com/problems/maximum-subarray/ +- https://leetcode-cn.com/problems/maximum-product-subarray/description/ +- [https://leetcode-cn.com/problems/coin-change/description/](https://leetcode.com/problems/coin-change/description/) +- https://leetcode-cn.com/problems/climbing-stairs/description/ +- https://leetcode-cn.com/problems/triangle/description/ +- https://leetcode.com/problems/triangle/discuss/38735/Python-easy-to-understand-solutions-(top-down-bottom-up) +- https://leetcode-cn.com/problems/maximum-subarray/ +- https://leetcode-cn.com/problems/maximum-product-subarray/description/ +- [https://leetcode-cn.com/problems/coin-change/description/](https://leetcode.com/problems/coin-change/description/) +- https://leetcode-cn.com/problems/house-robber/ +- https://leetcode-cn.com/problems/house-robber-ii/description/ +- https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock/#/description +- https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/ +- https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-iii/ +- https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-with-cooldown/ +- https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-iv/ +- https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-with-transaction-fee/ +- https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock/solution/yi-ge-fang-fa-tuan-mie-6-dao-gu-piao-wen-ti-by-l-3/ + +- https://leetcode-cn.com/problems/minimum-path-sum/ +- https://leetcode-cn.com/problems/decode-ways +- https://leetcode-cn.com/problems/maximal-square/ +- https://leetcode-cn.com/problems/task-scheduler/ +- https://leetcode-cn.com/problems/palindromic-substrings/ + +- https://leetcode-cn.com/problems/longest-valid-parentheses/ + +- https://leetcode-cn.com/problems/edit-distance/ + +- https://leetcode-cn.com/problems/max-sum-of-rectangle-no-larger-than-k/ + +- https://leetcode-cn.com/problems/frog-jump/ + +- https://leetcode-cn.com/problems/split-array-largest-sum + +- https://leetcode-cn.com/problems/student-attendance-record-ii/ + +- https://leetcode-cn.com/problems/minimum-window-substring/ + +- https://leetcode-cn.com/problems/burst-balloons/ + +- ## 高级 DP 实战题目 + +- https://leetcode-cn.com/problems/perfect-squares/ + +- [https://leetcode-cn.com/problems/edit-distance/ ](https://leetcode-cn.com/problems/edit-distance/)(重点) + +- https://leetcode-cn.com/problems/jump-game/ + +- https://leetcode-cn.com/problems/jump-game-ii/ + +- https://leetcode-cn.com/problems/unique-paths/ + +- https://leetcode-cn.com/problems/unique-paths-ii/ + +- https://leetcode-cn.com/problems/unique-paths-iii/ + +- https://leetcode-cn.com/problems/coin-change/ + +- https://leetcode-cn.com/problems/coin-change-2/ + + + + + + + + + + + + + + + +## 代码模板总结: + +1. 递归代码模版 + + ```java + public void recur(int level, int param) { + // terminator + if (level > MAX_LEVEL) { + // process result + return; + } + + // process current logic + process(level, param); + + // drill down + recur( level: level + 1, newParam); + + // restore current status + } + ``` + +2. 分治代码模板 + + ```python + def divide_conquer(problem, param1, param2, ...): + # recursion terminator + if problem is None: + print_result + return + + # prepare data + data = prepare_data(problem) + subproblems = split_problem(problem, data) + + # conquer subproblems + subresult1 = self.divide_conquer(subproblems[0], p1, ...) + subresult2 = self.divide_conquer(subproblems[1], p1, ...) + subresult3 = self.divide_conquer(subproblems[2], p1, ...) + … + + # process and generate the final result + result = process_result(subresult1, subresult2, subresult3, …) + + # revert the current level states + ``` + +3. 深度优先代码模板DFS + + a. 递归方式 + + ```python + def divide_conquer(problem, param1, param2, ...): + # recursion terminator + if problem is None: + print_result + return + + # prepare data + data = prepare_data(problem) + subproblems = split_problem(problem, data) + + # conquer subproblems + subresult1 = self.divide_conquer(subproblems[0], p1, ...) + subresult2 = self.divide_conquer(subproblems[1], p1, ...) + subresult3 = self.divide_conquer(subproblems[2], p1, ...) + … + # process and generate the final result + result = process_result(subresult1, subresult2, subresult3, …) + + # revert the current level states + ``` + + b. 非递归方式 + + ```python + def DFS(self, tree): + + if tree.root is None: + return [] + + visited, stack = [], [tree.root] + + while stack: + node = stack.pop() + visited.add(node) + + process (node) + nodes = generate_related_nodes(node) + stack.push(nodes) + + # other processing work + ... + ``` + + + +4. 广度优先代码模板BFS + + ```python + def BFS(graph, start, end): + visited = set() + queue = [] + queue.append([start]) + + while queue: + node = queue.pop() + visited.add(node) + + process(node) + nodes = generate_related_nodes(node) + queue.push(nodes) + + # other processing work + ... + ``` + +5. 二分查找代码模板 + + ```java + left, right = 0, len(array) - 1 + while left <= right: + mid = (left + right) / 2 + if array[mid] == target: + # find the target!! + break or return result + elif array[mid] < target: + left = mid + 1 + else: + right = mid - 1 + ``` + +6. 动态规划步骤 + + ``` + a. 子问题(分治) + b. 状态数组定义 + c. DP方程 + ``` + + \ No newline at end of file diff --git a/Week_05/G20200343030505/LeetCode_221_505.java b/Week_05/G20200343030505/LeetCode_221_505.java new file mode 100644 index 00000000..359f6184 --- /dev/null +++ b/Week_05/G20200343030505/LeetCode_221_505.java @@ -0,0 +1,37 @@ +/** + * 使用栈 + * @author huangwen05 + * + * @date: 2020年2月23日 下午7:53:59 + */ +class LeetCode_221_505 { + if (matrix == null) { + return 0; + } + int row = matrix.length; + if (row == 0) { + return 0; + } + int colum = matrix[0].length; + //增加一维,方便计算 + //dp(i,j)表示右下角i,j为止的最大正方形的边长 + int[][] dp = new int[row + 1][colum + 1]; + int maxlenth = 0; + for (int i=1;i<=row;++i) { + for (int j=1;j<=colum;++j) { + if (matrix[i-1][j-1] == '1') { + //每次更新边长,取min 保证是正方向有效的 + dp[i][j] = Math.min(Math.min(dp[i][j-1], dp[i-1][j-1]), dp[i-1][j]) + 1; + if (dp[i][j] > maxlenth) { + maxlenth = dp[i][j]; + } + } + + } + + } + + return maxlenth * maxlenth; + + } +} \ No newline at end of file diff --git a/Week_05/G20200343030505/LeetCode_32_505.java b/Week_05/G20200343030505/LeetCode_32_505.java new file mode 100644 index 00000000..5c48d75c --- /dev/null +++ b/Week_05/G20200343030505/LeetCode_32_505.java @@ -0,0 +1,28 @@ +/** + * 使用栈 + * @author huangwen05 + * + * @date: 2020年2月23日 下午7:53:59 + */ +class LeetCode_32_505 { + if (s == null || s.length() < 2) { + return 0; + } + + //dpi 以i结尾的最长括号长度 + int[] dp = new int[s.length()]; + int max = 0; + for (int i=1;i1?dp[i-2] + 2:2; + //如 (()) 也就是i是),然后dp[i-1]之前的一个是(,那么就可以拼然后再加上之前的有效长度 + } else if (i>=dp[i-1]+1 && s.charAt(i-dp[i-1]-1) == '(') { + dp[i] = 2 + dp[i-1] + (i-dp[i-1] >= 2?dp[i-dp[i-1]-2]:0); + } + } + max = Math.max(max, dp[i]); + } + return max; + } +} \ No newline at end of file diff --git a/Week_05/G20200343030505/LeetCode_363_505.java b/Week_05/G20200343030505/LeetCode_363_505.java new file mode 100644 index 00000000..b67aca5f --- /dev/null +++ b/Week_05/G20200343030505/LeetCode_363_505.java @@ -0,0 +1,48 @@ +/** + * 使用栈 + * @author huangwen05 + * + * @date: 2020年2月23日 下午7:53:59 + */ +class LeetCode_363_505 { + public int search(int[] nums, int target) { + + if (matrix == null) { + return 0; + } + + int rows = matrix.length; + if (rows == 0) { + return 0; + } + int max = Integer.MIN_VALUE; + int colum = matrix[0].length; + //确定左右边界 开始计算每一行的累计值 存在curSum数组里 然后计算该数组连续累积和 不超过k + for (int i=0;i max && sum <= k) { + max = sum; + } + } + } + return max; + } +} \ No newline at end of file diff --git a/Week_05/G20200343030505/LeetCode_621_505.java b/Week_05/G20200343030505/LeetCode_621_505.java new file mode 100644 index 00000000..2f898af0 --- /dev/null +++ b/Week_05/G20200343030505/LeetCode_621_505.java @@ -0,0 +1,22 @@ +public class LeetCode_621_505 { + public int leastInterval(char[] tasks, int n) { + int[] map = new int[26]; + for (char c: tasks) + map[c - 'A']++; + Arrays.sort(map); + int time = 0; + while (map[25] > 0) { + int i = 0; + while (i <= n) { + if (map[25] == 0) + break; + if (i < 26 && map[25 - i] > 0) + map[25 - i]--; + time++; + i++; + } + Arrays.sort(map); + } + return time; + } +} \ No newline at end of file diff --git a/Week_05/G20200343030505/LeetCode_647_505.java b/Week_05/G20200343030505/LeetCode_647_505.java new file mode 100644 index 00000000..126f3c1a --- /dev/null +++ b/Week_05/G20200343030505/LeetCode_647_505.java @@ -0,0 +1,25 @@ +/** + * 使用栈 + * @author huangwen05 + * + * @date: 2020年2月23日 下午7:53:59 + */ +class LeetCode_647_505 { + int result = 0; + if (s == null || s.length() == 0) { + return result; + } + + boolean[][] dp = new boolean[s.length()][s.length()]; + for (int j=0;j 2) dp[i] = dp[i-2] + 2; + else dp[i] = 2; + } + else if (i - dp[i-1] > 0 && s.charAt(i - dp[i-1] -1) == '(') { + if (i - dp[i-1] >= 2) dp[i] = dp[i-1] + dp[i - dp[i-1] -2] + 2; + else dp[i] = dp[i-1] + 2; + } + max = Math.max(max, dp[i]); + } + } + return max; + } +} \ No newline at end of file diff --git a/Week_05/G20200343030509/Solution062_509.java b/Week_05/G20200343030509/Solution062_509.java new file mode 100644 index 00000000..5654a16d --- /dev/null +++ b/Week_05/G20200343030509/Solution062_509.java @@ -0,0 +1,46 @@ +package com.leetcode.week05; + +/* + * @lc app=leetcode.cn id=62 lang=java + * + * [62] 不同路径 + */ + +import java.util.Arrays; + +class Solution062_509 { + public static void main(String[] args) { + long startTime=System.nanoTime(); //获取开始时间 + + Solution062_509 sol = new Solution062_509(); + System.out.println(sol.uniquePaths2(3,2)); + + long endTime=System.nanoTime(); //获取结束时间 + System.out.println( "程序运行时间: " + (endTime-startTime) + "ns"); + } + + public int uniquePaths(int m, int n) { + int dp[][] = new int[m][n]; + for (int i = 0; i < m; i++) dp[i][0] = 1; + for (int i = 0; i < n; i++) dp[0][i] = 1; + for (int i = 1; i < m; i++) { + for (int j = 1; j < n; j++) { + dp[i][j] = dp[i-1][j] + dp[i][j-1]; + } + } + + return dp[m-1][n-1]; + } + + public int uniquePaths2(int m, int n) { + int[] dp = new int[n]; + Arrays.fill(dp, 1); + for (int i = 1; i < m; i++) { + for (int j = 1; j < n; j++) { + dp[j] = dp[j] + dp[j-1]; + } + } + + return dp[n-1]; + } +} \ No newline at end of file diff --git a/Week_05/G20200343030509/Solution063_509.java b/Week_05/G20200343030509/Solution063_509.java new file mode 100644 index 00000000..6e6bcabc --- /dev/null +++ b/Week_05/G20200343030509/Solution063_509.java @@ -0,0 +1,39 @@ +package com.leetcode.week05; + +/* + * @lc app=leetcode.cn id=63 lang=java + * + * [63] 不同路径 II + */ + +class Solution063_509 { + public static void main(String[] args) { + long startTime=System.nanoTime(); //获取开始时间 + + Solution063_509 sol = new Solution063_509(); + System.out.println(sol.uniquePathsWithObstacles(new int[][]{{0,0,0}, {0,1,0}, {0,0,0}})); + + long endTime=System.nanoTime(); //获取结束时间 + System.out.println( "程序运行时间: " + (endTime-startTime) + "ns"); + } + + public int uniquePathsWithObstacles(int[][] obstacleGrid) { + int m = obstacleGrid.length; + int n = obstacleGrid[0].length; + int[] dp = new int[n]; + if(obstacleGrid[0][0] == 1) return 0; + dp[0] = 1; + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + if (obstacleGrid[i][j] == 1) { + dp[j] = 0; + } + else if (j > 0) { + dp[j] = dp[j] + dp[j -1]; + } + } + } + + return dp[n-1]; + } +} \ No newline at end of file diff --git a/Week_05/G20200343030509/Solution064_509.java b/Week_05/G20200343030509/Solution064_509.java new file mode 100644 index 00000000..39f35f5d --- /dev/null +++ b/Week_05/G20200343030509/Solution064_509.java @@ -0,0 +1,41 @@ +package com.leetcode.week05; + +/* + * @lc app=leetcode.cn id=64 lang=java + * + * [64] 最小路径和 + */ + +class Solution064_509 { + public static void main(String[] args) { + long startTime=System.nanoTime(); //获取开始时间 + + Solution064_509 sol = new Solution064_509(); + System.out.println(sol.minPathSum(new int[][]{{1,3,1},{1,5,1},{4,2,1}})); + + long endTime=System.nanoTime(); //获取结束时间 + System.out.println( "程序运行时间: " + (endTime-startTime) + "ns"); + } + + public int minPathSum(int[][] grid) { + if (grid == null) return 0; + int m = grid.length; + int n = grid[0].length; + int[] dp = new int[n]; + + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + if (j == 0) { + dp[j] = dp[j] + grid[i][j]; + } + else if (i == 0){ + dp[j] = dp[j-1] + grid[i][j]; + } + else { + dp[j] = Math.min(dp[j], dp[j-1]) + grid[i][j]; + } + } + } + return dp[n-1]; + } +} diff --git a/Week_05/G20200343030511/LeetCode_211_511.java b/Week_05/G20200343030511/LeetCode_211_511.java new file mode 100644 index 00000000..5068f737 --- /dev/null +++ b/Week_05/G20200343030511/LeetCode_211_511.java @@ -0,0 +1,37 @@ +class Solution { + public int maximalSquare(char[][] matrix) { + if (matrix == null || matrix.length == 0) + return 0; + int m = matrix.length; + int n = matrix[0].length; + int[][] dp = new int[m][n]; + int max = 0; + for (int i = 0; i < m; i++) { + if (matrix[i][0] == '1'){ + dp[i][0] = 1; + max=1; + } + + else + dp[i][0] = 0; + } + for (int i = 0; i < n; i++) { + if (matrix[0][i] == '1'){ + dp[0][i] = 1; + max=1; + } + else + dp[0][i] = 0; + } + for (int i = 1; i < m; i++) { + for (int j = 1; j < n; j++) { + if (matrix[i][j] == '1') + dp[i][j] = Math.min(dp[i - 1][j - 1], Math.min(dp[i][j - 1], dp[i - 1][j])) + 1; + else + dp[i][j] = 0; + max = Math.max(max, dp[i][j]); + } + } + return max * max; + } +} \ No newline at end of file diff --git a/Week_05/G20200343030511/LeetCode_312_511.java b/Week_05/G20200343030511/LeetCode_312_511.java new file mode 100644 index 00000000..2bcffa1a --- /dev/null +++ b/Week_05/G20200343030511/LeetCode_312_511.java @@ -0,0 +1,62 @@ +class Solution { + public int maxCoins(int[] nums) { +if (nums == null || nums.length == 0) + return 0; + // 创建虚拟数组 + int[] coins = new int[nums.length + 2]; + System.arraycopy(nums, 0, coins, 1, nums.length); + coins[0] = 1; + coins[coins.length - 1] = 1; + int length = coins.length; + int[][] cached = new int[length][length]; + return maxCoins_help(coins, 0, length-1, cached); + } + + private int maxCoins_help(int[] nums, int start, int end, int[][] cached) { + // 终止条件 + if (start == end - 1) { + return 0; + } + if (cached[start][end] != 0) + return cached[start][end]; + // 当前处理 + // 维护一个最大值 + int max = 0; + for (int i = start + 1; i < end; i++) { + int temp = maxCoins_help(nums, start, i, cached) + maxCoins_help(nums, i, end, cached) + + nums[start] * nums[i] * nums[end]; + if (temp > max) + max = temp; + } + // 下一层递归 + // 状态处理 + cached[start][end] = max; + return max; +} + + +public int maxCoins2(int[] nums) { + if (nums.length == 0) { + return 0; + } + int[] coins = new int[nums.length + 2]; + System.arraycopy(nums, 0, coins, 1, nums.length); + coins[0] =coins[coins.length - 1]= 1; + int dp[][] = new int[coins.length][coins.length]; +/* for (int i = 0; i < dp.length - 1; i++) { + dp[i][i + 1] = 0; + }*/ + int n = coins.length; + for (int len = 3; len <= n; len++) { + for (int i = 0; i <= n - len; i++) { + int j = i + len - 1; + dp[i][j] = Integer.MIN_VALUE; + // 枚举中间的气球 + for (int k = i + 1; k <= j - 1; k++) { + dp[i][j] = Math.max(dp[i][j], dp[i][k] + dp[k][j] + coins[i] * coins[k] * coins[j]); + } + } + } + return dp[0][coins.length - 1]; + } +} \ No newline at end of file diff --git a/Week_05/G20200343030511/LeetCode_32_511.java b/Week_05/G20200343030511/LeetCode_32_511.java new file mode 100644 index 00000000..7527f581 --- /dev/null +++ b/Week_05/G20200343030511/LeetCode_32_511.java @@ -0,0 +1,53 @@ +class Solution { + public int longestValidParentheses(String s) { + int maxlen = 0; + Stack stack = new Stack<>(); + //第一個是)的情況。也可以直接把第一個元素壓入棧,然後從1開始。 + stack.push(-1); + for (int i = 0; i < s.length(); i++) { + if (s.charAt(i) == '(') { + stack.push(i); + } else { + stack.pop(); + if (stack.empty()) { + stack.push(i); + } else { + maxlen = Math.max(maxlen, i - stack.peek()); + } + } + } + return maxlen; + } + + + public int longestValidParentheses1(String s) { + int left = 0, right = 0, maxlength = 0; + for (int i = 0; i < s.length(); i++) { + if (s.charAt(i) == '(') { + left++; + } else { + right++; + } + if (left == right) { + maxlength = Math.max(maxlength, 2 * right); + } else if (right >= left) { + left = right = 0; + } + } + left = right = 0; + for (int i = s.length() - 1; i >= 0; i--) { + if (s.charAt(i) == '(') { + left++; + } else { + right++; + } + if (left == right) { + maxlength = Math.max(maxlength, 2 * left); + } else if (left >= right) { + left = right = 0; + } + } + return maxlength; + } + +} \ No newline at end of file diff --git a/Week_05/G20200343030511/LeetCode_363_511.java b/Week_05/G20200343030511/LeetCode_363_511.java new file mode 100644 index 00000000..ea813c11 --- /dev/null +++ b/Week_05/G20200343030511/LeetCode_363_511.java @@ -0,0 +1,27 @@ +class Solution { + public int maxSumSubmatrix(int[][] matrix, int k) { + int m = matrix.length; + int n = matrix[0].length; + int[][] dp = new int[m+1][n+1]; + for (int i = 1; i <= m; i++) { + for (int j = 1; j <= n; j++) { + dp[i][j] = dp[i-1][j] + dp[i][j-1] - dp[i-1][j-1] + matrix[i-1][j-1]; + } + } + int res = Integer.MIN_VALUE; + for (int i = 1; i <= m; i++) { + for (int j = 1; j <= n; j++) { + for (int l = 1; l <= m; l++) { + for (int o = 1; o <= n; o++) { + if(i+l-1 <= m && j+o-1 <= n){ + int ar = i+l-1, ac = j+o-1, br = i-1, bc = j-1; + int sum = dp[ar][ac] + dp[br][bc] - dp[ar][bc] - dp[br][ac]; + if(sum <= k) res = Math.max(res, sum); + } + } + } + } + } + return res; + } +} diff --git a/Week_05/G20200343030511/LeetCode_403_511.java b/Week_05/G20200343030511/LeetCode_403_511.java new file mode 100644 index 00000000..702a27eb --- /dev/null +++ b/Week_05/G20200343030511/LeetCode_403_511.java @@ -0,0 +1,21 @@ +class Solution { + + public boolean canCross(int[] stones) { + Map> map = new HashMap<>(); + for (int i = 0; i < stones.length; i++) { + map.put(stones[i], new HashSet()); + } + map.get(0).add(0); + for (int i = 0; i < stones.length; i++) { + for(int k:map.get(stones[i])){ + int step =k; + for (int j = step-1; j <= step+1; j++) { + if(j>0&&map.containsKey(stones[i]+j)){ + map.get(stones[i]+j).add(j); + } + } + } + } + return map.get(stones[stones.length-1]).size()>0; + } +} \ No newline at end of file diff --git a/Week_05/G20200343030511/LeetCode_410_511.java b/Week_05/G20200343030511/LeetCode_410_511.java new file mode 100644 index 00000000..1ba1b480 --- /dev/null +++ b/Week_05/G20200343030511/LeetCode_410_511.java @@ -0,0 +1,29 @@ +class Solution { + public int splitArray(int[] nums, int m) { + + int l=0,h=0; + for (int i = 0; i < nums.length; i++) { + h+=nums[i]; + l = Math.max(l, nums[i]); + } + + while(lmid){ + cur++; + sum=nums[i]; + }else{ + sum+=nums[i]; + } + } + if(cur<=m){ + h=mid; + }else{ + l=mid+1; + } + } + return l; + } +} \ No newline at end of file diff --git a/Week_05/G20200343030511/LeetCode_552_511.java b/Week_05/G20200343030511/LeetCode_552_511.java new file mode 100644 index 00000000..8b3a2fef --- /dev/null +++ b/Week_05/G20200343030511/LeetCode_552_511.java @@ -0,0 +1,27 @@ +public int checkRecord(int n) { + int _MOD = 1000000007; + long dp00, dp01, dp02, dp10, dp11, dp12; + dp00 = dp01 = dp10 = 1; + dp11 = dp02 = dp12 = 0; + for (int i = 2; i <= n; i++) { + long t00 = dp00, t01 = dp01, t02 = dp02, t10 = dp10, t11 = dp11, t12 = dp12; + // +P + // 0A0L = 0A0L + 0A1L + 0A2L + dp00 = (t00 + t01 + t02) % _MOD; + // 1A0L = 1A0L + 1A1L + 1A2L + dp10 = (t10 + t11 + t12) % _MOD; + // +L + // 0A1L = 0A0L + dp01 = t00; + // 0A2L = 0A1L + dp02 = t01; + // 1A1L = 1A0L + dp11 = t10; + // 1A2L = 1A1L + dp12 = t11; + // +A + // 1A0L = 0A0L + 0A1L + 0A2L + dp10 += (t00 + t01 + t02) % _MOD; + } + return (int) ((dp00 + dp01 + dp02 + dp10 + dp11 + dp12) % _MOD); +} diff --git a/Week_05/G20200343030511/LeetCode_621_511.java b/Week_05/G20200343030511/LeetCode_621_511.java new file mode 100644 index 00000000..be73a19e --- /dev/null +++ b/Week_05/G20200343030511/LeetCode_621_511.java @@ -0,0 +1,22 @@ +class Solution { + public int leastInterval(char[] tasks, int n) { + if (tasks.length <= 1 || n < 1) return tasks.length; + //步骤1 + int[] counts = new int[26]; + for (int i = 0; i < tasks.length; i++) { + counts[tasks[i] - 'A']++; + } + //步骤2 + Arrays.sort(counts); + int maxCount = counts[25]; + int retCount = (maxCount - 1) * (n + 1) + 1; + int i = 24; + //步骤3 + while (i >= 0 && counts[i] == maxCount) { + retCount++; + i--; + } + //步骤4 + return Math.max(retCount, tasks.length); + } +} \ No newline at end of file diff --git a/Week_05/G20200343030511/LeetCode_647_511.java b/Week_05/G20200343030511/LeetCode_647_511.java new file mode 100644 index 00000000..65ffd6db --- /dev/null +++ b/Week_05/G20200343030511/LeetCode_647_511.java @@ -0,0 +1,18 @@ +class Solution { + public int countSubstrings(String s) { +if (s == null || s.length() == 0) + return 0; + boolean[][] dp = new boolean[s.length()][s.length()]; + int res = 0; + for (int j = 0; j < s.length(); j++) { + for (int i = j; i >= 0; i--) { + if (s.charAt(i) == s.charAt(j) && (j - i < 2 || dp[i + 1][j - 1])) { + res++; + dp[i][j] = true; + } + + } + } + return res; + } + } \ No newline at end of file diff --git a/Week_05/G20200343030511/LeetCode_64_511.java b/Week_05/G20200343030511/LeetCode_64_511.java new file mode 100644 index 00000000..ea0b6958 --- /dev/null +++ b/Week_05/G20200343030511/LeetCode_64_511.java @@ -0,0 +1,21 @@ +class Solution { + public int minPathSum(int[][] grid) { +if(grid ==null||grid.length==0) return 0; + int m = grid.length; + int n = grid[0].length; + int[][] dp = new int[m][n]; + dp[0][0]=grid[0][0]; + for (int i = 1; i < m; i++) { + dp[i][0]=grid[i][0]+dp[i-1][0]; + } + for (int i = 1; i < n; i++) { + dp[0][i]=grid[0][i]+dp[0][i-1]; + } + for (int i = 1; i < m; i++) { + for (int j = 1; j < n; j++) { + dp[i][j] =Math.min(dp[i-1][j], dp[i][j-1])+grid[i][j]; + } + } + return dp[m-1][n-1]; + } +} \ No newline at end of file diff --git a/Week_05/G20200343030511/LeetCode_72_511.java b/Week_05/G20200343030511/LeetCode_72_511.java new file mode 100644 index 00000000..e69de29b diff --git a/Week_05/G20200343030511/LeetCode_76_511.java b/Week_05/G20200343030511/LeetCode_76_511.java new file mode 100644 index 00000000..d12f3a4e --- /dev/null +++ b/Week_05/G20200343030511/LeetCode_76_511.java @@ -0,0 +1,35 @@ +class Solution { + public String minWindow(String s, String t) { + int[] window = new int[128]; + int[] need = new int[128]; + for (int i = 0; i < t.length(); i++) { + need[t.charAt(i)]++; + } + int l = 0, r = 0, count = 0; + int minlength = s.length() + 1; + String result=""; + while (r < s.length()) { + char ch = s.charAt(r); + window[ch]++; + if (need[ch] > 0&&need[ch]>=window[ch]) { + count++; + } + while (count == t.length()) { + ch = s.charAt(l); + if (need[ch] > 0 &&need[ch]>=window[ch]) { + count--; + } + if (r - l + 1 < minlength) { + minlength = r - l + 1; + result = s.substring(l,r+1); + } + window[ch]--; + l++; + } + r++; + } + + return result; + + } +} \ No newline at end of file diff --git a/Week_05/G20200343030513/LeetCode_221_513.java b/Week_05/G20200343030513/LeetCode_221_513.java new file mode 100644 index 00000000..0e1fde93 --- /dev/null +++ b/Week_05/G20200343030513/LeetCode_221_513.java @@ -0,0 +1,34 @@ +//在一个由 0 和 1 组成的二维矩阵内,找到只包含 1 的最大正方形,并返回其面积。 +// +// 示例: +// +// 输入: +// +//1 0 1 0 0 +//1 0 1 1 1 +//1 1 1 1 1 +//1 0 0 1 0 +// +//输出: 4 +// Related Topics 动态规划 + + +//leetcode submit region begin(Prohibit modification and deletion) +class Solution { + public int maximalSquare(char[][] matrix) { + int rows = matrix.length; + int cols = rows > 0 ? matrix[0].length : 0; + int[][] dp = new int[rows + 1][cols + 1]; + int max = 0; + for (int i = 1; i <= rows; i++) { + for (int j = 1; j <= cols; j++) { + if (matrix[i - 1][j - 1] == '1') { + dp[i][j] = Math.min(Math.min(dp[i][j - 1], dp[i - 1][j]), dp[i - 1][j - 1]) + 1; + max = Math.max(max, dp[i][j]); + } + } + } + return max * max; + } +} +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week_05/G20200343030513/LeetCode_621_513.java b/Week_05/G20200343030513/LeetCode_621_513.java new file mode 100644 index 00000000..35434277 --- /dev/null +++ b/Week_05/G20200343030513/LeetCode_621_513.java @@ -0,0 +1,54 @@ +//给定一个用字符数组表示的 CPU 需要执行的任务列表。其中包含使用大写的 A - Z 字母表示的26 种不同种类的任务。任务可以以任意顺序执行,并且每个任务 +//都可以在 1 个单位时间内执行完。CPU 在任何一个单位时间内都可以执行一个任务,或者在待命状态。 +// +// 然而,两个相同种类的任务之间必须有长度为 n 的冷却时间,因此至少有连续 n 个单位时间内 CPU 在执行不同的任务,或者在待命状态。 +// +// 你需要计算完成所有任务所需要的最短时间。 +// +// 示例 1: +// +// +//输入: tasks = ["A","A","A","B","B","B"], n = 2 +//输出: 8 +//执行顺序: A -> B -> (待命) -> A -> B -> (待命) -> A -> B. +// +// +// 注: +// +// +// 任务的总个数为 [1, 10000]。 +// n 的取值范围为 [0, 100]。 +// +// Related Topics 贪心算法 队列 数组 + + +import java.util.Arrays; + +//leetcode submit region begin(Prohibit modification and deletion) +class Solution { + public int leastInterval(char[] tasks, int n) { + int[] map = new int[26]; + for (char ca: tasks) { + map[ca - 'A']++; + } + Arrays.sort(map); + int time = 0; + while (map[25] > 0) { + int i = 0; + while (i <= n) { + if (map[25] == 0) { + break; + } + if (i < 26 && map[25 - i] > 0) { + map[25 - i]--; + } + time++; + i++; + } + Arrays.sort(map); + } + return time; + } + +} +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week_05/G20200343030513/LeetCode_647_513.java b/Week_05/G20200343030513/LeetCode_647_513.java new file mode 100644 index 00000000..03e1c34d --- /dev/null +++ b/Week_05/G20200343030513/LeetCode_647_513.java @@ -0,0 +1,45 @@ +//给定一个字符串,你的任务是计算这个字符串中有多少个回文子串。 +// +// 具有不同开始位置或结束位置的子串,即使是由相同的字符组成,也会被计为是不同的子串。 +// +// 示例 1: +// +// +//输入: "abc" +//输出: 3 +//解释: 三个回文子串: "a", "b", "c". +// +// +// 示例 2: +// +// +//输入: "aaa" +//输出: 6 +//说明: 6个回文子串: "a", "a", "a", "aa", "aa", "aaa". +// +// +// 注意: +// +// +// 输入的字符串长度不会超过1000。 +// +// Related Topics 字符串 动态规划 + + +//leetcode submit region begin(Prohibit modification and deletion) +class Solution { + public int countSubstrings(String s) { + int ans = 0; + boolean dp[][] = new boolean[s.length()][s.length()]; + for (int i = 0; i < s.length(); i++) { + for (int j = i; j >= 0; j--) { + if (s.charAt(j) == s.charAt(i) && ((i - j < 2) || dp[j + 1][i - 1])) { + dp[j][i] = true; + ans++; + } + } + } + return ans; + } +} +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week_05/G20200343030519/Week 05/LeetCode_1143_519.js b/Week_05/G20200343030519/Week 05/LeetCode_1143_519.js new file mode 100644 index 00000000..02c02b6a --- /dev/null +++ b/Week_05/G20200343030519/Week 05/LeetCode_1143_519.js @@ -0,0 +1,20 @@ +// https://leetcode-cn.com/problems/longest-common-subsequence/ + +var longestCommonSubsequence = function(text1, text2) { + let temp = []; + let max = 0; + for(let i = 0; i <= text1.length; i++) { + temp.push(new Array(text2.length + 1).fill(0)); + } + for(let i = 1; i < temp.length; i++) { + for(let j = 1; j < temp[0].length; j++) { + if(text1[i - 1] === text2[j - 1]) { + temp[i][j] = temp[i - 1][j - 1] + 1 + } else { + temp[i][j] = Math.max(temp[i - 1][j], temp[i][j - 1]); + } + max = Math.max(max, temp[i][j]); + } + } + return max; +}; \ No newline at end of file diff --git a/Week_05/G20200343030519/Week 05/LeetCode_120_519.js b/Week_05/G20200343030519/Week 05/LeetCode_120_519.js new file mode 100644 index 00000000..602159e0 --- /dev/null +++ b/Week_05/G20200343030519/Week 05/LeetCode_120_519.js @@ -0,0 +1,8 @@ +// https://leetcode-cn.com/problems/triangle/description/ + +var minimumTotal = function(triangle) { + for (let i = triangle.length-2; i >= 0; i--) + for (let j = 0; j < triangle[i].length; j++) + triangle[i][j] += Math.min(triangle[i+1][j], triangle[i+1][j+1]) + return triangle[0][0] +} \ No newline at end of file diff --git a/Week_05/G20200343030519/Week 05/LeetCode_198_519.js b/Week_05/G20200343030519/Week 05/LeetCode_198_519.js new file mode 100644 index 00000000..af7b6f09 --- /dev/null +++ b/Week_05/G20200343030519/Week 05/LeetCode_198_519.js @@ -0,0 +1,16 @@ +// https://leetcode-cn.com/problems/house-robber/ + +var rob = function(nums) { + var n = nums.length; + if(n == 0){ + return 0; + } + var prevMax = 0; + var currMax = 0; + for(var i = 0; i < n; i++){ + var tmp = currMax; + currMax = Math.max(currMax,prevMax+nums[i]); + prevMax = tmp; + } + return currMax; +}; \ No newline at end of file diff --git a/Week_05/G20200343030519/Week 05/LeetCode_221_519.js b/Week_05/G20200343030519/Week 05/LeetCode_221_519.js new file mode 100644 index 00000000..10393947 --- /dev/null +++ b/Week_05/G20200343030519/Week 05/LeetCode_221_519.js @@ -0,0 +1,25 @@ +// https://leetcode-cn.com/problems/maximal-square/ + +var maximalSquare = function(matrix) { + if (matrix.length < 1) return 0; + let memo = []; + let max = 0; + for (let i = 0; i <= matrix.length; i++) { + memo.push([]); + for (let k = 0; k <= matrix[0].length; k++) { + memo[i][k] = 0; + } + } + for (let l = 1; l <= matrix.length; l++) { + for (let m = 1; m <= matrix[0].length; m++) { + if (matrix[l - 1][m - 1] !== "0") { + memo[l][m] += Math.min(memo[l - 1][m], memo[l][m - 1], memo[l - 1][m - 1]) + 1; + } + + if (max < memo[l][m]) { + max = memo[l][m]; + } + } + } + return max * max; +}; \ No newline at end of file diff --git a/Week_05/G20200343030519/Week 05/LeetCode_32_519.js b/Week_05/G20200343030519/Week 05/LeetCode_32_519.js new file mode 100644 index 00000000..53df917c --- /dev/null +++ b/Week_05/G20200343030519/Week 05/LeetCode_32_519.js @@ -0,0 +1,18 @@ +// https://leetcode-cn.com/problems/longest-valid-parentheses/ + +var longestValidParentheses = function(s) { + var max = 0; + var n = s.length; + var dp = new Array(n).fill(0); + for (var i = 1;i < n;i++) { + if(s[i] == ')'){ + if (s[i-1] == '(') { + dp[i] = ( i >= 2 ? dp[i-2] : 0) + 2; + } else if (i - dp[i-1] > 0 && s[i - dp[i-1] - 1] == '('){ + dp[i] = dp[i-1] + ( (i - dp[i-1] >= 2) ? dp[i - dp[i-1] - 2] : 0 ) + 2; + } + max = Math.max(max,dp[i]); + } + } + return max; +}; \ No newline at end of file diff --git a/Week_05/G20200343030519/Week 05/LeetCode_53_519.js b/Week_05/G20200343030519/Week 05/LeetCode_53_519.js new file mode 100644 index 00000000..a85be43a --- /dev/null +++ b/Week_05/G20200343030519/Week 05/LeetCode_53_519.js @@ -0,0 +1,8 @@ +// https://leetcode-cn.com/problems/maximum-subarray/ + +var maxSubArray = function(nums) { + for (let i = 1; i < nums.length; i++){ + nums[i] = Math.max(nums[i], nums[i] + nums[i - 1]); + } + return Math.max(...nums); +}; \ No newline at end of file diff --git a/Week_05/G20200343030519/Week 05/LeetCode_621_519.js b/Week_05/G20200343030519/Week 05/LeetCode_621_519.js new file mode 100644 index 00000000..4693bb3c --- /dev/null +++ b/Week_05/G20200343030519/Week 05/LeetCode_621_519.js @@ -0,0 +1,21 @@ +// https://leetcode-cn.com/problems/task-scheduler/ + +var leastInterval = function(tasks, n) { + if (n === 0) return tasks.length + + let map = {} + for (let key of tasks) { + map[key] = map[key] ? map[key] + 1 : 1 + } + + let max = 0, count = 0 + Object.keys(map).forEach(key => { + if (map[key] > max) { + max = map[key] + count = 1 + } else if (map[key] === max) { + count++ + } + }) + return Math.max((max - 1) * (n + 1) + count, tasks.length) + }; \ No newline at end of file diff --git a/Week_05/G20200343030519/Week 05/LeetCode_62_519.js b/Week_05/G20200343030519/Week 05/LeetCode_62_519.js new file mode 100644 index 00000000..d13f71c1 --- /dev/null +++ b/Week_05/G20200343030519/Week 05/LeetCode_62_519.js @@ -0,0 +1,13 @@ +// https://leetcode-cn.com/problems/unique-paths/ + +const uniquePaths = (m, n) => { + let dp = Array.from(Array(n), () => Array(m).fill(1)); + + for (let i = 1; i < n; i++) { + for (let j = 1; j < m; j++) { + dp[i][j] = dp[i][j - 1] + dp[i - 1][j]; + } + } + + return dp[n - 1][m - 1]; +}; \ No newline at end of file diff --git a/Week_05/G20200343030519/Week 05/LeetCode_63_519.js b/Week_05/G20200343030519/Week 05/LeetCode_63_519.js new file mode 100644 index 00000000..961038f2 --- /dev/null +++ b/Week_05/G20200343030519/Week 05/LeetCode_63_519.js @@ -0,0 +1,36 @@ +// https://leetcode-cn.com/problems/unique-paths-ii/ + +var uniquePathsWithObstacles = function(obstacleGrid) { + var n = obstacleGrid.length; + var m = obstacleGrid[0].length; + var dp = new Array(n); + for (var i = 0; i < n; i++) { + dp[i] = new Array(m).fill(0); + } + dp[0][0] = obstacleGrid[0][0] == 0 ? 1 : 0; + + if (dp[0][0] == 0) { + return 0; + } + + for (var j = 1; j < m; j++) { + if (obstacleGrid[0][j] != 1) { + dp[0][j] = dp[0][j - 1]; + } + } + + for (var r = 1; r < n; r++) { + if(obstacleGrid[r][0] != 1){ + dp[r][0] = dp[r - 1][0]; + } + } + + for(var i = 1; i < n; i++){ + for(var r = 1; r < m; r++){ + if(obstacleGrid[i][r] != 1){ + dp[i][r] = dp[i - 1][r] + dp[i][r - 1]; + } + } + } + return dp[n - 1][m - 1]; +}; \ No newline at end of file diff --git a/Week_05/G20200343030519/Week 05/LeetCode_647_519.js b/Week_05/G20200343030519/Week 05/LeetCode_647_519.js new file mode 100644 index 00000000..15cb5935 --- /dev/null +++ b/Week_05/G20200343030519/Week 05/LeetCode_647_519.js @@ -0,0 +1,20 @@ +// https://leetcode-cn.com/problems/palindromic-substrings/ + +function countSubstrings(s) { + let total = 0; + for (let i = 0; i < s.length; i++) { + total += expand(s, i, i); + total += expand(s, i, i + 1); + } + return total; + }; + + function expand(s, l, r) { + let count = 0; + while (l >= 0 && r < s.length && s[l] === s[r]) { + l--; + r++; + count++; + } + return count; + } \ No newline at end of file diff --git a/Week_05/G20200343030519/Week 05/LeetCode_64_519.js b/Week_05/G20200343030519/Week 05/LeetCode_64_519.js new file mode 100644 index 00000000..7860bbd5 --- /dev/null +++ b/Week_05/G20200343030519/Week 05/LeetCode_64_519.js @@ -0,0 +1,21 @@ +// https://leetcode-cn.com/problems/minimum-path-sum/ + +var minPathSum = function(grid) { + const m = grid.length; + const n = grid[0].length; + + for (let i = 1; i < m; i++) { + grid[i][0] += grid[i - 1][0]; + } + for (let i = 1; i < n; i++) { + grid[0][i] += grid[0][i - 1]; + } + + for (let i = 1; i < m; i++) { + for (let j = 1; j < n; j++) { + grid[i][j] += Math.min(grid[i - 1][j], grid[i][j - 1]); + } + } + + return grid[m - 1][n - 1]; +}; \ No newline at end of file diff --git a/Week_05/G20200343030519/Week 05/LeetCode_70_519.js b/Week_05/G20200343030519/Week 05/LeetCode_70_519.js new file mode 100644 index 00000000..7c2e8e67 --- /dev/null +++ b/Week_05/G20200343030519/Week 05/LeetCode_70_519.js @@ -0,0 +1,11 @@ +// https://leetcode-cn.com/problems/climbing-stairs/description/ + +var climbStairs = function(n) { + const dp = []; + dp[0] = 1; + dp[1] = 1; + for(let i = 2; i <= n; i++) { + dp[i] = dp[i - 1] + dp[i - 2]; + } + return dp[n]; +}; \ No newline at end of file diff --git a/Week_05/G20200343030519/Week 05/LeetCode_91_519.js b/Week_05/G20200343030519/Week 05/LeetCode_91_519.js new file mode 100644 index 00000000..97c826a5 --- /dev/null +++ b/Week_05/G20200343030519/Week 05/LeetCode_91_519.js @@ -0,0 +1,22 @@ +// https://leetcode-cn.com/problems/decode-ways/ + +function numDecodings(s) { + if (s.length === 0) return 0; + + const N = s.length; + const dp = Array(N + 1).fill(0); + + dp[0] = 1; + dp[1] = s[0] === '0' ? 0 : 1; + + for (let i = 2; i <= N; i++) { + if (s[i - 1 ] !== '0') { + dp[i] += dp[i - 1]; + } + if (s[i - 2] === '1' || s[i - 2] === '2' && s[i - 1] <= '6') { + dp[i] += dp[i - 2]; + } + } + + return dp[N]; +} \ No newline at end of file diff --git a/Week_05/G20200343030523/id_523/LeetCode_64_523.java b/Week_05/G20200343030523/id_523/LeetCode_64_523.java new file mode 100644 index 00000000..393ff496 --- /dev/null +++ b/Week_05/G20200343030523/id_523/LeetCode_64_523.java @@ -0,0 +1,42 @@ +package dynamic; + +/** + * https://leetcode-cn.com/problems/minimum-path-sum/ + */ +public class MinimumPathSum { + + public int minPathSum(int[][] grid) { + + if (grid == null || grid.length == 0 || grid[0].length == 0) { + return 0; + } + + int m = grid.length; + int n = grid[0].length; + int[][] dp = new int[m][n]; + + dp[0][0] = grid[0][0]; + + for (int i = 1; i < m; i++) { + dp[i][0] = grid[i][0] + dp[i - 1][0]; + } + + for (int j = 1; j < n; j++) { + dp[0][j] = grid[0][j] + dp[0][j - 1]; + } + + for (int i = 1; i < m; i++) { + for (int j = 1; j < n; j++) { + dp[i][j] = Math.min(dp[i - 1][j], dp[i][j - 1]) + grid[i][j]; + } + } + return dp[m - 1][n - 1]; + } + + public static void main(String[] args) { + int[][] grid = new int[][]{{1, 3, 1}, {1, 5, 1}, {4, 2, 1}}; + MinimumPathSum pathSum = new MinimumPathSum(); + System.out.println(pathSum.minPathSum(grid)); + } + +} diff --git a/Week_05/G20200343030523/id_523/LeetCode_72_523.java b/Week_05/G20200343030523/id_523/LeetCode_72_523.java new file mode 100644 index 00000000..112f98ab --- /dev/null +++ b/Week_05/G20200343030523/id_523/LeetCode_72_523.java @@ -0,0 +1,38 @@ +package dynamic; + +/** + * https://leetcode-cn.com/problems/edit-distance/ + */ +public class EditDistance { + + public int minDistance(String word1, String word2) { + + int m = word1.length(); + int n = word2.length(); + + int[][] dp = new int[m + 1][n + 1]; + for (int i = 0; i <= m; i++) { + dp[i][0] = i; + } + for (int j = 0; j <= n; j++) { + dp[0][j] = j; + } + + for (int i = 1; i <= m; i++) { + for (int j = 1; j <= n; j++) { + int value = word1.charAt(i - 1) == word2.charAt(j - 1) ? 0 : 1; + dp[i][j] = min(dp[i - 1][j] + 1, dp[i][j - 1] + 1, dp[i - 1][j - 1] + value); + } + } + return dp[m][n]; + } + + private int min(int v1, int v2, int v3) { + return v1 <= v2 ? (v1 <= v3 ? v1 : v3) : (v2 <= v3 ? v2 : v3); + } + + public static void main(String[] args) { + EditDistance distance = new EditDistance(); + System.out.println(distance.minDistance("zoologicoarchaeologist", "zoogeologist")); + } +} diff --git a/Week_05/G20200343030527/LeetCode_221_527.java b/Week_05/G20200343030527/LeetCode_221_527.java new file mode 100644 index 00000000..118752bd --- /dev/null +++ b/Week_05/G20200343030527/LeetCode_221_527.java @@ -0,0 +1,22 @@ +public class Solution { + public int maximalSquare(char[][] matrix) { + int rows = matrix.length; + int cols; + if (rows > 0) { + cols = matrix[0].length; + }else { + cols = 0; + } + int[][] dp = new int[rows + 1][cols + 1]; + int max = 0; + for (int i = 1; i <= rows; i++) { + for (int j = 1; j <= cols; j++) { + if (matrix[i-1][j-1] == '1'){ + dp[i][j] = Math.min(Math.min(dp[i][j - 1], dp[i - 1][j]), dp[i - 1][j - 1]) + 1; + max = Math.max(max, dp[i][j]); + } + } + } + return max * max; + } +} \ No newline at end of file diff --git a/Week_05/G20200343030527/LeetCode_64_527.java b/Week_05/G20200343030527/LeetCode_64_527.java new file mode 100644 index 00000000..fbe6cae6 --- /dev/null +++ b/Week_05/G20200343030527/LeetCode_64_527.java @@ -0,0 +1,24 @@ +class Solution { + public int minPathSum(int[][] grid) { + int[][] dp = new int[grid.length][grid[0].length]; + + int temp = 0; + for(int i = 0; i < grid.length; i++){ + dp[i][0] = grid[i][0] + temp; + temp = dp[i][0]; + } + + temp = 0; + for(int i = 0; i < grid[0].length; i++){ + dp[0][i] = grid[0][i] + temp; + temp = dp[0][i]; + } + + for(int i = 1;i < grid.length;i++){ + for(int j = 1; j < grid[0].length; j++){ + dp[i][j] = Math.min(dp[i-1][j],dp[i][j-1]) + grid[i][j]; + } + } + return dp[grid.length - 1][grid[0].length - 1]; + } +} \ No newline at end of file diff --git a/Week_05/G20200343030529/LeetCode_363_529.java b/Week_05/G20200343030529/LeetCode_363_529.java new file mode 100644 index 00000000..7f9c8788 --- /dev/null +++ b/Week_05/G20200343030529/LeetCode_363_529.java @@ -0,0 +1,34 @@ +class Solution { + public int maxSumSubmatrix(int[][] matrix, int k) { + if (matrix.length == 0) { + return 0; + } + int row = matrix.length; + int col = matrix[0].length; + int result = Integer.MIN_VALUE; + for (int left = 0; left < col; left++) { + int[] rowSum = new int[row]; + for (int right = left; right < col; right++) { + for (int i = 0; i < row; i++) { + rowSum[i] += matrix[i][right]; + } + result = Math.max(result, findBestSum(rowSum, k)); + } + } + return result; + } + + private int findBestSum(int[] rowSum, int k ) { + int result = Integer.MIN_VALUE; + int cum = 0; + TreeSet set = new TreeSet<>(); + set.add(0); + for (int sum : rowSum) { + cum += sum; + Integer num = set.ceiling(cum - k); + if (num != null) result = Math.max(result, cum - num); + set.add(cum); + } + return result; + } +} \ No newline at end of file diff --git a/Week_05/G20200343030529/LeetCode_64_529.java b/Week_05/G20200343030529/LeetCode_64_529.java new file mode 100644 index 00000000..86b525d5 --- /dev/null +++ b/Week_05/G20200343030529/LeetCode_64_529.java @@ -0,0 +1,17 @@ +class Solution { + public int minPathSum(int[][] grid) { + int[][] dp = new int[grid.length + 1][grid[0].length + 1]; + for (int k = 0; k < dp.length; k++) dp[k][dp[k].length - 1] = Integer.MAX_VALUE; + for (int m = 0; m < dp[0].length; m++) dp[dp.length - 1][m] = Integer.MAX_VALUE; + dp[grid.length][grid[0].length - 1] = 0; + dp[grid.length - 1][grid[0].length] = 0; + + + for (int i = dp.length - 2; i >= 0; i--) { + for (int j = dp[i].length - 2; j >= 0; j--) { + dp[i][j] = Math.min(dp[i][j + 1], dp[i + 1][j]) + grid[i][j]; + } + } + return dp[0][0]; + } +} \ No newline at end of file diff --git a/Week_05/G20200343030531/LeetCode_621_531.go b/Week_05/G20200343030531/LeetCode_621_531.go new file mode 100644 index 00000000..30cf6987 --- /dev/null +++ b/Week_05/G20200343030531/LeetCode_621_531.go @@ -0,0 +1,28 @@ +package main + +import "fmt" + +func main() { + s := "ABCAABBCDEF" + fmt.Println(leastInterval([]byte(s), len(s))) +} + +// 抄的leetcode golang题解,不是很熟练。 +func leastInterval(tasks []byte, n int) int { + s := [26]int{} + max := 0 + count := 0 + for i := 0; i < len(tasks); i++ { + s[tasks[i]-'A']++ + if max < s[tasks[i]-'A'] { + max = s[tasks[i]-'A'] + count = 1 + } else if s[tasks[i]-'A'] == max { + count++ + } + } + if n == 0 || (max-1)*(n+1)+count < len(tasks) { + return len(tasks) + } + return (max-1)*(n+1) + count +} diff --git a/Week_05/G20200343030531/LeetCode_91_531.go b/Week_05/G20200343030531/LeetCode_91_531.go new file mode 100644 index 00000000..851aaf70 --- /dev/null +++ b/Week_05/G20200343030531/LeetCode_91_531.go @@ -0,0 +1,34 @@ +package main + +import "fmt" + +func main() { + fmt.Println(numDecodings("1245221")) +} + +// 分析,这道题很有意思,看起来很复杂,只要理清边界条件,能取到的数组只有"0","1","2" +func numDecodings(s string) int { + if s[0] == '0' { + return 0 + } + + dp := make([]int, len(s)+1) + dp[0], dp[1] = 1, 1 + for i := 1; i < len(s); i++ { + index := i + 1 + if s[i] == '0' { + if s[i-1] != '1' && s[i-1] != '2' { + return 0 + } else { + dp[index] = dp[index-2] + } + } else { + if (s[i-1] == '1') || (s[i-1] == '2' && s[i] <= '6') { + dp[index] = dp[index-1] + dp[index-2] + } else { + dp[index] = dp[index-1] + } + } + } + return dp[len(s)] +} diff --git a/Week_05/G20200343030533/LeetCode_045_533.cpp b/Week_05/G20200343030533/LeetCode_045_533.cpp new file mode 100644 index 00000000..541852c4 --- /dev/null +++ b/Week_05/G20200343030533/LeetCode_045_533.cpp @@ -0,0 +1,78 @@ +#include +#include +#include +#include +using namespace std; + +/* +子问题: 抵达第i个位置的最少步数 = 0..i-1中的最小步数 + 1 +DP方程: DP[i] = min(DP[0..i-1], j + a[j] > i ) +*/ + +//代码没错,就是时间复杂度是O(n^2), 就有变态的数据不能AC +// 90 / 92 个通过测试用例 +class Solution1 { +public: + int jump(vector& nums) { + int dp[nums.size()]; + int MAX = nums.size() + 1; + for (int i = 0; i < nums.size(); i++) dp[i] = MAX; + dp[0] = 0; //初始化第一个位置 + for (int i = 1 ;i < nums.size() ; i++){ + for(int j = 0; j < i ; j++){ + if (nums[j] + j >= i){ + dp[i] = min(dp[i],dp[j]+1); + } + } + } + return dp[nums.size()-1]; + } +}; +//92 / 92 个通过测试用例 +class Solution2 { +public: + int jump(vector& nums) { + int dp[nums.size()]; + int num_len = nums.size() ; + for (int i = 0; i < nums.size(); i++) dp[i] = INT_MAX; + dp[0] = 0; //初始化第一个位置 + + for (int i = 0 ;i < nums.size() ; i++){ + for(int j = 1; j <= nums[i] ; j++){ + int next = min(i+j, num_len-1); //不能越界 + dp[next] = min(dp[next],dp[i]+1); + } + } + return dp[nums.size()-1]; + } +}; + +//剪枝 +class Solution { +public: + int jump(vector& nums) { + int num_len = nums.size() ; + if ( num_len <= 1) return 0; + int farthest = 0; + int dp[num_len]; + for (int i = 0; i < num_len ; i++) dp[i] = INT_MAX - 1; + dp[0] = 0; //初始化第一个位置 + + for (int i = 0 ;i < num_len ; i++){ + if ((i+nums[i]+1)>= num_len) return dp[i]+1; + for(int j = farthest-i; j <= nums[i] && nums[i] + i > farthest; j++){ + int next = i + j; //抵达的最后位置 + dp[next] = min(dp[next],dp[i]+1); + } + farthest = i + nums[i]; + } + return dp[num_len-1]; + } +}; + +int main(int argc, char *argv[]){ + vector vec{2,3,1,1,4}; + Solution sol; + cout << sol.jump(vec) << '\n'; + return 0; +} \ No newline at end of file diff --git a/Week_05/G20200343030533/LeetCode_053_533.cpp b/Week_05/G20200343030533/LeetCode_053_533.cpp new file mode 100644 index 00000000..890ee2f7 --- /dev/null +++ b/Week_05/G20200343030533/LeetCode_053_533.cpp @@ -0,0 +1,33 @@ +#include +#include +#include +using namespace std; + +/* +DP方程: dp[i] = max(dp[i-1], 0) + a[i] +如果前一个状态比较小,立刻止损,只用当前最大值 +*/ +class Solution { +public: + int maxSubArray(vector& nums) { + int m = nums.size(); + int dp[m]; + dp[0] = nums[0]; + for (int i = 1; i < m; i++){ + dp[i] = max(dp[i-1], 0) + nums[i]; + } + + int max_num = dp[0]; + for (int i = 1; i < m; i++){ + max_num = max(max_num, dp[i]); + } + return max_num; + } +}; + +int main(int argc, char *argv[]){ + Solution sol; + vector nums{-2,1,-3,4,-1,2,1,-5,4}; + cout << sol.maxSubArray(nums) << '\n'; + return 0; +} \ No newline at end of file diff --git a/Week_05/G20200343030533/LeetCode_055_533.cpp b/Week_05/G20200343030533/LeetCode_055_533.cpp new file mode 100644 index 00000000..1645a9cb --- /dev/null +++ b/Week_05/G20200343030533/LeetCode_055_533.cpp @@ -0,0 +1,75 @@ +#include +#include +#include +#include +#include +using namespace std; + +/* +a.子问题: 第i个位置可达 = 前0..i-1中有个位置可达 + 对应最大步数 > i +b.状态数组: DP[i], true/false +c.DP方程: DP[i] = 0..i-1 + a[i] > 0 +时间复杂度是O(n^2), 超时 +*/ +class Solution1 { +public: + bool canJump(vector& nums) { + vector valid(nums.size(), false); + valid[0] = true; + for ( int i = 1; i < nums.size(); i++){ + for (int j = 0; j < i; j++){ + if ( valid[j] && j + nums[j] >= i){ + valid[i] = true; + break; + } + } + } + return valid[nums.size()-1]; + + } +}; + +/* +尝试从后往前递归,但是时间复杂度还是O(n^2), 还是超时 +*/ +class Solution2 { +public: + int mymin(int i, int j ){ + return i < j ? i :j; + } + bool canJump(vector& nums) { + vector valid(nums.size(), false); + valid[valid.size()-1] = true; + for ( int i = nums.size() - 2; i >= 0; i--){ + int jump = mymin( i + nums[i], nums.size() - 1 ); + for (int j = i+1; j <= jump; j++){ + if ( valid[j] ){ + valid[i] = true; + break; + } + } + } + return valid[0]; + + } +}; + +/* +从后往前,不断更新last的位置 +last - i <= nums[i] , 上一个能抵达的位置和当前位置相比, 是否比现在位置能去的最远路程远 +*/ +class Solution { +public: + bool canJump(vector& nums) { + int last = nums.size() - 1; + for(int i = nums.size() - 2; i >= 0; i--) + if(last - i <= nums[i]) last = i; + return last == 0; + } +}; + + + +int main(int argc, char *argv[]){ + return 0; +} \ No newline at end of file diff --git a/Week_05/G20200343030533/LeetCode_062_533.cpp b/Week_05/G20200343030533/LeetCode_062_533.cpp new file mode 100644 index 00000000..f26e4de0 --- /dev/null +++ b/Week_05/G20200343030533/LeetCode_062_533.cpp @@ -0,0 +1,32 @@ +#include +#include +#include +#include +#include +using namespace std; + +/* +子问题/状态数组/转移方程, a[i,j] = a[i-1,j] + a[i,j-1] +*/ + +class Solution { +public: + int uniquePaths(int m, int n) { + int dp[m][n]; + for (int i = 0; i < m; i++) dp[i][0] = 1; + for (int j = 0; j < n; j++) dp[0][j] = 1; + + for (int i = 1; i < m; i++){ + for (int j = 1; j < n; j++){ + dp[i][j] = dp[i-1][j] + dp[i][j-1]; + } + } + return dp[m-1][n-1]; + } +}; + +int main(int argc, char *argv[]){ + Solution sol; + cout << sol.uniquePaths(3,2) << '\n'; + return 0; +} \ No newline at end of file diff --git a/Week_05/G20200343030533/LeetCode_063_533.cpp b/Week_05/G20200343030533/LeetCode_063_533.cpp new file mode 100644 index 00000000..c244b52c --- /dev/null +++ b/Week_05/G20200343030533/LeetCode_063_533.cpp @@ -0,0 +1,46 @@ +#include +#include +#include +#include +#include +using namespace std; + +/* 类似62题,只不过状态转移方程变了 +if grid[i][j] == 1: (不为空地) + DP[i][j] = 0; +else: + DP[i][j] = DP[i-1][j] + DP[i][j-1] +*/ + +class Solution { +public: + int uniquePathsWithObstacles(vector>& obstacleGrid) { + int m = obstacleGrid.size(); + int n = obstacleGrid[0].size(); + long int dp[m][n]; //居然有一个值很大,导致溢出 + if (obstacleGrid[0][0] == 1) return 0; + dp[0][0] = 1; + for (int i = 1; i < m; i++){ + dp[i][0] = obstacleGrid[i][0] == 0 ? dp[i-1][0] : 0; + } + for (int i = 1; i < n; i++){ + dp[0][i] = obstacleGrid[0][i] == 0 ? dp[0][i-1] : 0; + } + + for(int i = 1; i < m; i++){ + for(int j = 1; j < n; j++){ + if (obstacleGrid[i][j] == 1){ + dp[i][j] = 0; + } else{ + dp[i][j] = dp[i-1][j] + dp[i][j-1]; + } + } + } + return dp[m-1][n-1]; + } +}; + + +int main(int argc, char *argv[]){ + return 0; +} \ No newline at end of file diff --git a/Week_05/G20200343030533/LeetCode_064_533.cpp b/Week_05/G20200343030533/LeetCode_064_533.cpp new file mode 100644 index 00000000..0e7bba7a --- /dev/null +++ b/Week_05/G20200343030533/LeetCode_064_533.cpp @@ -0,0 +1,49 @@ +#include +#include +#include +#include + +using namespace std; +/* +a. 子问题: 到i,j 最短路径到i-1,j与到i,j-1路径的最小值加上当前路径 +b. +c. 状态函数: opt[i][j] = min(opt[i-1][j], opt[i][j]) + a[i][j] +*/ +class Solution { +public: +//解决方法1 + int minPathSum(vector>& grid) { + int m = grid.size(); + int n = grid[0].size(); + // m x n + vector> opt(m, vector(n,0)); + //初始化第一列 + opt[0][0] = grid[0][0]; + for (int i = 1; i < m; i++){ + opt[i][0] = opt[i-1][0] + grid[i][0]; + } + for (int j = 1; j < n; j++){ + opt[0][j] = opt[0][j-1] + grid[0][j]; + } + + for (int i = 1; i < m; i++){ + for (int j = 1; j < n; j++){ + opt[i][j] = min(opt[i-1][j], opt[i][j-1]) + grid[i][j]; + } + } + return opt[m-1][n-1]; + } +}; + +int main(int argc, char *argv[]){ + Solution sol; + + vector> grid{ + {1,3,1}, + {1,5,1}, + {4,2,1} + }; + cout << "minium path sum " << sol.minPathSum(grid) << '\n'; + + return 0; +} \ No newline at end of file diff --git a/Week_05/G20200343030533/LeetCode_1143_053.cpp b/Week_05/G20200343030533/LeetCode_1143_053.cpp new file mode 100644 index 00000000..a6e6f557 --- /dev/null +++ b/Week_05/G20200343030533/LeetCode_1143_053.cpp @@ -0,0 +1,35 @@ +#include +#include +#include +using namespace std; +// 最长公共子串 +class Solution { +public: + int longestCommonSubsequence(string text1, string text2) { + int m = text1.length(); + int n = text2.length(); + int opt[m+1][n+1]; + for (int i = 0; i < m+1; i++) opt[i][0] = 0; + for (int j = 0; j < n+1; j++) opt[0][j] = 0; + + for (int i = 1; i < m + 1; i++){ + for (int j = 1; j < n + 1; j++){ + if (text1[i-1] != text2[j-1]){ + opt[i][j] = max(opt[i-1][j], opt[i][j-1]); + } else{ + opt[i][j] = opt[i-1][j-1] + 1; + } + + } + } + return opt[m][n]; + + + } +}; + +int main(int argc, char *argv[]){ + Solution sol; + cout << sol.longestCommonSubsequence("abc", "acd") << '\n'; + return 0; +} \ No newline at end of file diff --git a/Week_05/G20200343030533/LeetCode_121_533.cpp b/Week_05/G20200343030533/LeetCode_121_533.cpp new file mode 100644 index 00000000..e020bdea --- /dev/null +++ b/Week_05/G20200343030533/LeetCode_121_533.cpp @@ -0,0 +1,58 @@ +#include +#include +#include +#include +#include +#include +using namespace std; + +/*子问题: +一次完整的操作 = 一次买入和一次卖出 +该问题就受到三个因素影响,时间和操作和次数,因变量是利润, + +因此需要用三个变量来定义定义问题 +DP[i][j][k] 表示 第i天状态为j(0持有,1不持有),且操作次数为k(k=0,1)的情况下最大利润 + +总计有i * j * k = i * 2 * 2 = 4i种 状态 + +DP[i][0][0] = DP[i-1][0][0] ; //之前没有操作 +DP[i][0][1] = max(DP[i-1][0][1] + DP[i-1][1][0] + a[i]); // 不操作, 或者之前持有后卖出构成一次完成操作 +DP[i][1][0] = max(DP[i-1][1][0] + DP[i-1][0][0] - a[i]); //不操作,或者之前不持有,现在持有,形成一半操作 +DP[i][1][1] ;// 不存在,因为一次完整的操作后,最终一定不持有。 + + +*/ + +class Solution { +public: + int maxProfit(vector& prices) { + if (prices.size() == 0 ) return 0; + int DP[prices.size()][2][2]; + for (int i = 0 ; i < prices.size(); i++ ){ + for (int j = 0; j < 2; j++){ + for (int k = 0; k < 2; k++ ) + DP[i][j][k] = 0; + } + } + DP[0][0][0] = 0; + DP[0][1][0] = -prices[0]; //买入 + + for (int i = 1 ; i < prices.size(); i++ ){ + DP[i][0][0] = DP[i-1][0][0]; + DP[i][1][0] = max(DP[i-1][1][0], DP[i-1][0][0] - prices[i]); + DP[i][0][1] = max(DP[i-1][0][1], DP[i-1][1][0] + prices[i]); + } + return DP[prices.size()-1][0][1]; + + } +}; + + + +int main(int argc, char *argv[]){ + + vector prices{7,1,5,3,6}; + Solution sol; + cout << sol.maxProfit(prices) << '\n'; + return 0; +} \ No newline at end of file diff --git a/Week_05/G20200343030533/LeetCode_122_533.cpp b/Week_05/G20200343030533/LeetCode_122_533.cpp new file mode 100644 index 00000000..1f655554 --- /dev/null +++ b/Week_05/G20200343030533/LeetCode_122_533.cpp @@ -0,0 +1,51 @@ +#include +#include +#include +#include +#include +#include +using namespace std; + +/*子问题: +因为交易次数不受限制, 所以该问题就受到两个因素影响,时间和操作,因变量是利润, +因此需要用两个变量来定义定义问题 +DP[i][j] 表示 第i天状态为j(0持有,1不持有)的情况下最大利润 + +DP[i][0] = max(DP[i-1][0], DP[i-1][1] + a[i]) +DP[i][1] = max(DP[i-1][1], DP[i-1][1] - a[i]) + +分别为表示: + 第i天不持有,是前一天不持有,当天保持不变,或者是前一天持有,卖出去 + 第i天持有,是前一天持有,当天保持不变,或者是前一天步持有,买进来 +*/ + +class Solution { +public: + int maxProfit(vector& prices) { + if (prices.size() == 0 ) return 0; + int DP[prices.size()][2]; + for (int i = 0 ; i < prices.size(); i++ ){ + for (int j = 0; j < 2; j++){ + DP[i][j] = 0; + } + } + DP[0][0] = 0; + DP[0][1] = -prices[0]; + + for (int i = 1 ; i < prices.size(); i++ ){ + DP[i][0] = max(DP[i-1][0], DP[i-1][1] + prices[i]); + DP[i][1] = max(DP[i-1][1], DP[i-1][0] - prices[i]); + printf("%d-%d\n", DP[i][0], DP[i][1]); + } + + } +}; + + +int main(int argc, char *argv[]){ + + vector prices{7,1,5,3,6}; + Solution sol; + cout << sol.maxProfit(prices) << '\n'; + return 0; +} \ No newline at end of file diff --git a/Week_05/G20200343030533/LeetCode_198_533.cpp b/Week_05/G20200343030533/LeetCode_198_533.cpp new file mode 100644 index 00000000..46ac1c51 --- /dev/null +++ b/Week_05/G20200343030533/LeetCode_198_533.cpp @@ -0,0 +1,38 @@ +#include +#include +#include +#include +#include +using namespace std; + +/* +受到两个因素影响, 房子位置和是否偷窃, +状态数组: DP[i][j], i房子, j是否偷窃 +DP[i][0] = max(DP[i-1][1], DP[i-1][0]) +DP[i][1] = DP[i-1][0] + a[i] +*/ + +class Solution { +public: + int rob(vector& nums) { + if (nums.size() == 0 ) return 0; + vector> DP(nums.size(), vector(2,0)); + + DP[0][0] = 0; + DP[0][1] = nums[0]; + + for (int i = 1; i < nums.size(); i++){ + DP[i][0] = max(DP[i-1][1], DP[i-1][0]); + DP[i][1] = DP[i-1][0] + nums[i]; + } + return max(DP[nums.size()-1][1], DP[nums.size()-1][0]); + + } +}; + +int main(int argc, char *argv[]){ + vector nums{1,2,3,1}; + Solution Sol; + cout << Sol.rob(nums) << '\n'; + return 0; +} \ No newline at end of file diff --git a/Week_05/G20200343030533/LeetCode_322_533.cpp b/Week_05/G20200343030533/LeetCode_322_533.cpp new file mode 100644 index 00000000..3717b7ee --- /dev/null +++ b/Week_05/G20200343030533/LeetCode_322_533.cpp @@ -0,0 +1,145 @@ +#include +#include +#include +#include +#include +#include +#include +using namespace std; +//零钱兑换 +//暴力求解,一定超时 +class Solution1 { +public: + int MIN_COMB = INT_MAX; + int coinChange(vector& coins, int amount) { + DFS(0, amount, coins); + return MIN_COMB; + } + + void DFS(int depth, int amount, vector& coins){ + if (amount == 0){ + MIN_COMB = min(depth, MIN_COMB); + return ; + } + for (auto coin : coins){ + if (amount - coin < 0 ) continue; //减枝 + DFS(depth+1, amount - coin, coins); + + } + return ; + } +}; +// BFS,, 依旧超时 +class Solution2 { +public: + int coinChange(vector& coins, int amount) { + + queue> q; //level and amount + q.push({0, amount}); + + while ( !q.empty()) { + + int level = q.front().first; + int surplus = q.front().second; + q.pop(); + + for (auto c : coins){ + if ( surplus - c < 0 ) continue; + if ( surplus - c == 0 ) return level + 1; + q.push({level+1, surplus-c}); + } + } + return -1; + + + } +}; + +//贪心算法,不一定能得到最优解 +class Solution3 { +public: + int coinChange(vector& coins, int amount) { + sort(coins.begin(), coins.end(), std::greater<>()); + return DFS(0, amount, coins); + } + + int DFS(int level, int amount, vector& coins){ + if (amount <= 0){ + return amount == 0 ? level : -1; + } + for (auto coin : coins){ + int res = DFS(level+1, amount - coin, coins); + if (res > 0 ) return res; + } + return -1; + } +}; + +// 递归+记忆化 +class Solution4 { +public: + unordered_map dict; + int coinChange(vector& coins, int amount) { + if (amount < 1) return 0; + return DFS(coins, amount); + } + int DFS(vector& coins, int amount){ + if (amount < 0 ) return -1; + if (amount == 0 ) return 0; + if (dict.find(amount) != dict.end()) return dict[amount]; + + int min = INT_MAX; //足够大的值 + for (int coin : coins){ + int res = DFS(coins, amount-coin); + if (res >= 0 && res < min){ + min = res + 1; + } + } + dict[amount] = (min == INT_MAX ? -1 : min); + return dict[amount]; + } +}; + +//最终答案,动态递推 +class Solution5 { +public: + int coinChange(vector& coins, int amount) { + int MAX = amount + 1;// 只要保证比amount大即可, 因为后续要和当前最小的选择比较。 + vector dp(amount+1, MAX); //DP数组 + dp[0] = 0; + for (int i = 1; i <= amount; i++){ + for (int j = 0; j < coins.size(); j++){ + if (coins[j] <= i){ //举例, i = 2, 只能考虑coin=1,2, 排除5 + dp[i] = min(dp[i], dp[i-coins[j]] + 1); + } + } + } + return dp[amount] > amount ? -1 : dp[amount]; + } +}; +//优化的DP, 交换内外层循环, 通过枚举硬币省了判断语句 +class Solution { +public: + int coinChange(vector& coins, int amount) { + int MAX = amount + 1;// 只要保证比amount大即可, 因为后续要和当前最小的选择比较。 + vector dp(amount+1, MAX); //DP数组 + dp[0] = 0; + for (int j = 0; j < coins.size(); j++){ + for (int i = coins[j]; j <= amount; i++){ + dp[i] = min(dp[i], dp[i-coins[j]] + 1); + } + } + return dp[amount] > amount ? -1 : dp[amount]; + } +}; + + +int main(int argc, char *argv[]){ + Solution4 sol; + Solution sol2; + vector vec1{186,419,83,408}; + vector vec2{1,2,5}; + cout << sol.coinChange(vec1, 11) << '\n'; + cout << sol2.coinChange(vec1, 6249) << '\n'; + return 0; +} \ No newline at end of file diff --git a/Week_05/G20200343030533/LeetCode_363_533.cpp b/Week_05/G20200343030533/LeetCode_363_533.cpp new file mode 100644 index 00000000..8057c379 --- /dev/null +++ b/Week_05/G20200343030533/LeetCode_363_533.cpp @@ -0,0 +1,179 @@ +#include +#include +#include +#include +#include +#include +#include +#include +using namespace std; + + +//暴力做法, 穷举所有情况 +class Solution1 { +public: + int maxSumSubmatrix(vector>& matrix, int k) { + + int rows = matrix.size(); + int cols = matrix[0].size(); + + int res = -INT_MAX; + + for (int i = 0 ; i < rows; i++){ + for (int j = i ; j < rows; j++){ + for (int m = 0; m < cols; m++){ + for (int n = m; n < cols; n++){ + int total = calcSums(matrix, i, j, m, n); + if ( total == k) return k; + if ( total < k) res = max(res, total); + + } + + } + } + } + return res; + + } + int calcSums(vector>& matrix, int i, int j, int m, int n){ + int total = 0; + for (int rs = i; rs <= j; rs++){ + for (int cs = m; cs <= n; cs++){ + total += matrix[rs][cs]; + } + } + return total; + + } +}; + +/* +每次都需要重复计算, 采用DP方法 +影响结果的有4个变量,行起始,行结束,列起始,列结束 +DP[i][j[m][n], 表示从i..j, m..n的和 +DP[0][2][0][2], 表示从0-2行,0-2列区域的合 + +状态转移 +if i == j && m == n: //即固定行固定列 + DP[i][j][m][n] = matrix[i][m] +else if i == j && m != n: //固定行, 向下移动列 + DP[i][j][m][n] = DP[i][j][m][n-1] + matrix[i][n] +else if i!=j && m == n: //固定列, 向右移动行 + DP[i][j][m][n] = DP[i][j-1][m][n] + matrix[j][m] +else: //沿对角线往下移动 + DP[i][j][m][n] = DP[i][j-1][m][n] + DP[i][j][m][n-1] - DP[i][j-1][m][n-1] + matrix[j][n]; + +*/ + +//还是超时 +class Solution2 { +public: + + int maxSumSubmatrix(vector>& matrix, int k) { + + int rows = matrix.size(); + if (rows == 0 ) return 0; + int cols = matrix[0].size(); + if (cols == 0 ) return 0; + + // 状态数组 + //int DP[rows][rows][cols][cols]; // stack-overflow, 爆栈了 + // 在heap上分配 + + vector < vector < vector> > > DP(rows, vector>>( rows, vector> (cols, vector(cols, 0) ) ) ); + + int res = INT_MIN; + for (int i = 0 ; i < rows; i++){ + for (int j = i ; j < rows; j++){ + for (int m = 0; m < cols; m++){ + for (int n = m; n < cols; n++){ + if (i == j && m == n){ + DP[i][j][m][n] = matrix[i][m]; + } else if ( i == j && m != n){ + DP[i][j][m][n] = DP[i][j][m][n-1] + matrix[i][n]; + } else if ( i != j && m == n){ + DP[i][j][m][n] = DP[i][j-1][m][n] + matrix[j][m]; + } else { + DP[i][j][m][n] = DP[i][j-1][m][n] + DP[i][j][m][n-1] - DP[i][j-1][m][n-1] + matrix[j][n]; + } + if (DP[i][j][m][n] == k) return k; + if (DP[i][j][m][n] < k) { + res = max(DP[i][j][m][n], res); + } + } + } + } + } + return res; + + } + +}; + +/* +为了降低维度, 我们重新定义状态 +DP[i][j]: 从0..i, 0..j的和 + +DP[i][j] = DP[i-1][j] + DP[i][j-1] - DP[i-1][j-1] + matrix[i][j] + +对于任意的 i1..i2, j1..j2的状态,我们都有 + +DP[i1..i2][j1..j2] = DP[i2][j2] - DP[i2][j1] - DP[i1][j2] + DP[i1][j1]; +*/ + +class Solution { +public: + + int maxSumSubmatrix(vector>& matrix, int k) { + + int rows = matrix.size(); + if (rows == 0 ) return 0; + int cols = matrix[0].size(); + if (cols == 0 ) return 0; + + int res = -INT_MAX; + int DP[rows+1][cols+1]; + for (int i = 0; i < rows + 1; i++){ + DP[i][0] = 0; + } + for (int j = 0; j < cols + 1; j++){ + DP[0][j] = 0; + } + for (int i = 1 ; i < rows + 1; i++){ + for (int j = 1 ; j < cols + 1; j++){ + DP[i][j] = DP[i-1][j] + DP[i][j-1] - DP[i-1][j-1] + matrix[i-1][j-1]; + //printf("%d-%d:%d\n", i, j, DP[i][j]); + } + } + for (int i1 = 0 ; i1 < rows; i1++){ + for (int i2 = i1+1 ; i2 <= rows; i2++){ + for (int j1 = 0; j1 < cols; j1++){ + for (int j2 = j1+1; j2 <= cols; j2++){ + int total = DP[i2][j2] - DP[i2][j1] - DP[i1][j2] + DP[i1][j1]; + //printf("%d.%d.%d.%d: %d\n",i1,i2,j1,j2,total); + if (total == k) return total; + if ( total > matrix{{2,2,-1},{2,1,3}}; + + Solution sol; + clock_t t; + t = clock(); + cout << sol.maxSumSubmatrix(matrix, 0) << endl ; + t = clock() - t; + cout << "time: " << ((float)t)/CLOCKS_PER_SEC << endl; + return 0; +} diff --git a/Week_05/G20200343030533/LeetCode_518_533.cpp b/Week_05/G20200343030533/LeetCode_518_533.cpp new file mode 100644 index 00000000..38f41c90 --- /dev/null +++ b/Week_05/G20200343030533/LeetCode_518_533.cpp @@ -0,0 +1,68 @@ +#include +#include +#include +#include +#include +#include +using namespace std; + +//本题是研究所有可能, 322题目是最小硬币组合 +//姊妹题: https://leetcode-cn.com/problems/coin-change/ + +/* +a. 子问题,状态数组, DP方程 +凑齐i的组合总数 = 凑齐i-k个硬币的方法的和 +DP[i]表示第总数为i的状态的硬币数 +DP[i] += DP[i-coin] for coin in coins +*/ + + +//外层循环是硬币,也就是先找到能被对应硬币填充的位置进行填充。 +class Solution { +public: + int change(int amount, vector& coins) { + int dp[amount+1]; + memset(dp, 0, sizeof(dp)); + dp[0] = 1; + for (int coin : coins){ + for (int j = 1; j <= amount; j++){ + if (j < coin) continue; //也就是2不能用5凑 + dp[j] += dp[j-coin]; + cout << "coin " << coin << " with amount " << j << "->" << dp[j] << '\n'; + } + } + return dp[amount]; + } +}; + +class Solution2 { +public: + int change(int amount, vector& coins) { + int dp[amount+1][coins.size()+1]; + for (int i = 0; i < amount + 1; i++ ){ + for (int j = 0; j < coins.size() + 1; j++){ + dp[i][j]= 0; + } + } + for (int i = 0 ; i < coins.size() + 1; i++){ + dp[0][i] = 1; + } + for (int i = 1; i < amount+1; i++){ + for(int j = 1; j < coins.size() + 1; j++){ + if ( i >= coins[j-1]){ + dp[i][j] = dp[i-coins[j-1]][j] + dp[i][j-1]; + } else{ + dp[i][j] = dp[i][j-1]; + } + } + } + return dp[amount][coins.size()]; + } +}; + +int main(int argc, char *argv[]){ + Solution sol; + vector vec{1,2}; + cout << sol.change(3, vec) << '\n'; + return 0; +} \ No newline at end of file diff --git a/Week_05/G20200343030533/NOTE.md b/Week_05/G20200343030533/NOTE.md index 50de3041..cbf0efb4 100644 --- a/Week_05/G20200343030533/NOTE.md +++ b/Week_05/G20200343030533/NOTE.md @@ -1 +1,304 @@ -学习笔记 \ No newline at end of file +# 学习笔记 + +不要对名字浮想联翩,过度扩充它的含义,我们更应该关注它的定义和它想表达的内容。 + +DP的关键就是求解子问题的时候,能够重复利用(reuse)已经求解的子问题结果,而不是从头计算,因此降低了计算的时间复杂度(但是提高了空间复杂度)。 + +> Simplifying a complicated problem by breaking it down into simpler sub-problems.(in a recrusive manner) + +DP两种形式 + +- 自顶向下(递归+记忆化) +- 自底向上(递推+状态表) + +两种方法都是DP,但是为了提高DP能力,尽量将递归都转成递推。 + +动态规划和递归或者分治没有根本上的区别(关键看有无最优的子结构) + +共性:找到重复子问题(计算机指令集) + +差异性:最优子结构,中途可以淘汰次优解 + +**做题的关键点** + +1. **子问题**,最优子结构 +2. **状态数组**,存储中间状态(状态表, 可以是一维,或者是多维) +3. **递推公式**(状态转移方程或DP方程) + +初学者/面试要关注于第二步,复杂题目关注第三步 + +复杂的递推无非两点: + +1. 维度增加(复杂题目,高维是常态) +2. 存在取舍(最大值,最小值,有障碍等) + +## 路径计数 + +题目 + +- [不同路径题目](https://leetcode-cn.com/problems/unique-paths/) +- [不同路径 2 题目](https://leetcode-cn.com/problems/unique-paths-ii/) + +子问题: 第i,j位置到end的走法=第i+1,j到end的走法 + 第i,j+1到终点的走法 + +状态定义:从当前点到end有多少走法 + +动态转移方程`opt[i][j] =opt[i+1][j]+opt[i][j+1]` + +![1583642420494](https://user-images.githubusercontent.com/19432485/76217801-0e977700-624e-11ea-98a7-3295d28b1119.png) + +或者子问题可以定义为: 从start到i,j的走法 = 从start到i-1,j的走法 + 从start 到i,j-1的走法 + +状态定义: 从start开始到当前点有多少中走法, + +DP方程`opt[i][j] = opt[i-1][j] + opt[i][j-1]` + +![1583643316830](https://user-images.githubusercontent.com/19432485/76217802-0f300d80-624e-11ea-9ad2-0c90434e22aa.png) + +实际写代码要注意状态表的初始化,例如斐波那契数列中的n=0,n=1情况。 + +```cpp +class Solution { +public: + int uniquePathsWithObstacles(vector>& obstacleGrid) { + + long int opt[100][100]; + int m = obstacleGrid.size(); + int n = obstacleGrid[0].size(); + // 初始化第一行第一列 + if (obstacleGrid[0][0] == 1 ){ //第一个位置就是障碍物,直接为0. + return 0; + } else{ + opt[0][0] = 1; + } + + for (int i = 1; i < m; i++){ + opt[i][0] = obstacleGrid[i][0] == 1 ? 0 : opt[i-1][0]; + } + for ( int j = 1; j < n; j++){ + opt[0][j] = obstacleGrid[0][j] == 1 ? 0 :opt[0][j-1]; + } + + for ( int i = 1; i < m; i++){ + for ( int j = 1; j > opt(m+1, vector(n+1, 0)); // m+1 x n+1 的容器 + for(int i = 1; i < m+1; i++){ + for (int j = 1; j < n + 1; j++){ + if (text1[i-1] == text2[j-1]){ + opt[i][j] = opt[i-1][j-1] + 1; + } else{ + opt[i][j] = max(opt[i-1][j], opt[i][j-1]); + } + } + } + return opt[m][n]; + + } +}; +``` + +代码注意点: + +- 数组的长/宽为字符串大小+1,所以初始化的第一行和第一列都是0 +- 是比较`(text1[i-1] == text2[j-1]`而不是比较`(text1[i] == text2[j]` +- 注意数组不要越界 + +![1583650714912](https://user-images.githubusercontent.com/19432485/76217806-0fc8a400-624e-11ea-884b-2b10976228c2.png) +**小结**: + +- 多练习,这类字符串题目是经验问题,只能多练习 +- 数组大小,初始化,下标不能越界。 + +**动态规划思维**的小结 + +1. 打破自己的思维惯性,形成机器思维(找重复性) +2. 理解复杂逻辑的关键(树形结构) +3. 也是职业进阶的要点要领(不需要亲力亲为,要放权,允许下属犯错) + +补充内容: , MIT算法课程 + +## 习题讲解 + +每次做DP题目之前,需要想到DP三个步骤: + +- 寻找子问题 +- 构建状态数组 +- 定义DP方程 + +### 爬楼梯问题 + + + +过于简单: F(n) = F(n-1) + F(n-2) + +思考题: + +- 每次可以有1,2,3(简单) +- 每次依旧有1,2,3选择,但是相邻两步不能相同(中等) + +### 三角形最小路径和 + +可能的方法,暴力递归(N层递归,每一层往左或者往右) 和 递归加记忆化 + +DP方法(O(mn )) + +a. 重复性(子问题): problem(i,j) = min(sub(i+1,j), sub(i+1,j+1)) + a[i,j] + +b. 定义状态数组 f[i,j] + +c. DP方程 F[i,j] = min(F[i+1,j], F[i+1,j+1]) + a[i,j] + +> 似乎只要定义成子问题,DP方程也就写出来了。 + +### 最大子序列和(高频) + +最开始的思维方式是纯凭感觉,数学上不严谨,难以找到**自相似性**,具有拓展性,基本上无法使用代码实现。 + +a. 子问题: + +定义子问题时候,根据经验,从后往前来看. + +`max_sum(i) = Max(max_sum(i-1) , 0) + a[i]` + +b. 状态数组定义 + +从一开始到第i个元素的累加后最大值。 + +c. DP方程 + + `F[i] = Max(F[i-1], 0 +a[i])` + +或者,最大子序列和 = 当前元素自身最大,或者包含之前后最大 + +### 硬币兑换 + +解题方法 + +1. 暴力递归 +2. BFS +3. DP + +这题,我把多种写法都写出来了, + +### 打家劫舍 + +> 参考之前斐波那契的思考题2 + +首先,我们定义数组 a[i] : 0..i ,第i天能偷到的最大金额 , 返回 a[n-1] + +于是DP方程为 a[i] = a[i-1] + nums[i] + +但是我们不确定第i-1的房子有没有被偷,缺少信息。 + +因此得到第一个**经验**,当你一维数组不够用的时候,就需要升维。比如说这里我们只用一维的话,永远不知道之前房子有没有被偷盗。 + +**优化**: 定义数组`a[i][0,1]` 1:不偷,0偷 + +- 如果不偷第i个房子,那么第i-1个房子可以偷,也可以不偷,选择其中的最大值 +- 如果偷第i个房子,那么之前的房子一定不偷,当前房子肯定偷 + +于是新的DP方程 + +- `a[i][0] = Max(a[i-1][0], a[i-1][1])` +- `a[i][1]= a[i-1][0] + nums[i]` + +高级DP必经之路,增加维度。 + +**继续优化**: 新的状态定义 a[i]: 0..i 天,第i天必偷的最大值,返回max(a) + +DP方程: `a[i] = Max(a[i-1] + 0, a[i-2] + nums[i])` + +这个定义下,就类似于斐波那契数组了。 + +继续强调,面试的时候定义状态最重要,竞赛则是定义DP方程最难。 + +对于初学者,建议从第二维开始,进阶到只用一个维度。初学者要从工整的DP开始,不要一步登天。 + +## 其他 + +Cpp的二维数组定义 + +容器: m行n列的0 + +```cpp +vector > vec( m, vector (n,0)); +``` + +数组 + +```cpp +//stack分配 +int arr[m][n]; +//heap分配 +int **arr = new int*[m];//声明m行 +for (int i = 0; i < m; i++){ + arr[i] = new int[n]; //每个有n个元素 +} +//删除 +for (int i = 0; i < m; i++){ + delete []arr[i]; +} +delete [] arr; +``` + +数组求最大值和最小值(`algorithm::max_element`) + +```cpp +*max_element(dp, dp+m); //返回的是指针 +``` + +在线的Cpp shell, + + + diff --git a/Week_05/G20200343030535/LeetCode_221_535.java b/Week_05/G20200343030535/LeetCode_221_535.java new file mode 100644 index 00000000..2897fe8c --- /dev/null +++ b/Week_05/G20200343030535/LeetCode_221_535.java @@ -0,0 +1,20 @@ +package leetcode.Week05; + +public class LeetCode_221_535 { + + public int maximalSquare(char[][] matrix) { + if(matrix.length == 0) return 0; + int m = matrix.length, n = matrix[0].length, result = 0; + int[][] b = new int[m+1][n+1]; + for (int i = 1 ; i <= m; i++) { + for (int j = 1; j <= n; j++) { + if(matrix[i-1][j-1] == '1') { + b[i][j] = Math.min(Math.min(b[i][j-1] , b[i-1][j-1]), b[i-1][j]) + 1; + result = Math.max(b[i][j], result); + } + } + } + + return result*result; + } +} diff --git a/Week_05/G20200343030535/LeetCode_64_535.java b/Week_05/G20200343030535/LeetCode_64_535.java new file mode 100644 index 00000000..6eec6882 --- /dev/null +++ b/Week_05/G20200343030535/LeetCode_64_535.java @@ -0,0 +1,20 @@ +package leetcode.Week05; + +public class LeetCode_64_535 { + + public int minPathSum(int[][] grid) { + int m = grid.length; + int n = grid[0].length; + int[][] dp = grid; + for(int i = 0; i < m; i++) { + for(int j = 0; j < n ; j++) { + if(i == 0 && j == 0) continue; + else if(i == 0) dp[i][j] = dp[i][j - 1] + dp[i][j]; + else if(j == 0) dp[i][j] = dp[i - 1][j] + dp[i][j]; + else dp[i][j] = Math.min(dp[i - 1][j], dp[i][j - 1]) + dp[i][j]; + } + } + return dp[m - 1][n - 1]; + } + +} diff --git a/Week_05/G20200343030537/LeetCode_32_537.py b/Week_05/G20200343030537/LeetCode_32_537.py new file mode 100644 index 00000000..341cb97f --- /dev/null +++ b/Week_05/G20200343030537/LeetCode_32_537.py @@ -0,0 +1,25 @@ +# +# @lc app=leetcode.cn id=32 lang=python3 +# +# [32] 最长有效括号 +# + +# @lc code=start +class Solution: + def longestValidParentheses(self, s: str) -> int: + if(not s): + return 0 + res=0 + n=len(s) + dp=[0]*n + for i in range(1,len(s)): + if(s[i]==")"): + if(s[i-1]=="("): + dp[i]=dp[i-2]+2 + if(s[i-1]==")" and i-dp[i-1]-1>=0 and s[i-dp[i-1]-1]=="("): + dp[i]=dp[i-1]+dp[i-dp[i-1]-2]+2 + res=max(res,dp[i]) + return res + +# @lc code=end + diff --git a/Week_05/G20200343030537/LeetCode_72_537.py b/Week_05/G20200343030537/LeetCode_72_537.py new file mode 100644 index 00000000..8457d59f --- /dev/null +++ b/Week_05/G20200343030537/LeetCode_72_537.py @@ -0,0 +1,40 @@ +# +# @lc app=leetcode.cn id=72 lang=python3 +# +# [72] 编辑距离 +# + +# @lc code=start +class Solution: + def minDistance(self, word1: str, word2: str) -> int: + n = len(word1) + m = len(word2) + + # if one of the strings is empty + if n * m == 0: + return n + m + + # array to store the convertion history + d = [ [0] * (m + 1) for _ in range(n + 1)] + + # init boundaries + for i in range(n + 1): + d[i][0] = i + for j in range(m + 1): + d[0][j] = j + + # DP compute + for i in range(1, n + 1): + for j in range(1, m + 1): + left = d[i - 1][j] + 1 + down = d[i][j - 1] + 1 + left_down = d[i - 1][j - 1] + if word1[i - 1] != word2[j - 1]: + left_down += 1 + d[i][j] = min(left, down, left_down) + + return d[n][m] + + +# @lc code=end + diff --git a/Week_05/G20200343030543/LeetCode_410_543.java b/Week_05/G20200343030543/LeetCode_410_543.java new file mode 100644 index 00000000..6772515c --- /dev/null +++ b/Week_05/G20200343030543/LeetCode_410_543.java @@ -0,0 +1,26 @@ +class Solution { + private int ans; + private int n, m; + private void dfs(int[] nums, int i, int cntSubarrays, int curSum, int curMax) { + if (i == n && cntSubarrays == m) { + ans = Math.min(ans, curMax); + return; + } + if (i == n) { + return; + } + if (i > 0) { + dfs(nums, i + 1, cntSubarrays, curSum + nums[i], Math.max(curMax, curSum + nums[i])); + } + if (cntSubarrays < m) { + dfs(nums, i + 1, cntSubarrays + 1, nums[i], Math.max(curMax, nums[i])); + } + } + public int splitArray(int[] nums, int M) { + ans = Integer.MAX_VALUE; + n = nums.length; + m = M; + dfs(nums, 0, 0, 0, 0); + return ans; + } +} \ No newline at end of file diff --git a/Week_05/G20200343030543/LeetCode_64_543.java b/Week_05/G20200343030543/LeetCode_64_543.java new file mode 100644 index 00000000..cb446c78 --- /dev/null +++ b/Week_05/G20200343030543/LeetCode_64_543.java @@ -0,0 +1,10 @@ +public class Solution { + public int calculate(int[][] grid, int i, int j) { + if (i == grid.length || j == grid[0].length) return Integer.MAX_VALUE; + if (i == grid.length - 1 && j == grid[0].length - 1) return grid[i][j]; + return grid[i][j] + Math.min(calculate(grid, i + 1, j), calculate(grid, i, j + 1)); + } + public int minPathSum(int[][] grid) { + return calculate(grid, 0, 0); + } +} \ No newline at end of file diff --git a/Week_05/G20200343030543/NOTE.md b/Week_05/G20200343030543/NOTE.md index 50de3041..86de6074 100644 --- a/Week_05/G20200343030543/NOTE.md +++ b/Week_05/G20200343030543/NOTE.md @@ -1 +1,2 @@ -学习笔记 \ No newline at end of file +学习笔记 +自己问题没坚持好计划 \ No newline at end of file diff --git a/Week_05/G20200343030545/LeetCode_1143_545.py b/Week_05/G20200343030545/LeetCode_1143_545.py new file mode 100644 index 00000000..8efdbaea --- /dev/null +++ b/Week_05/G20200343030545/LeetCode_1143_545.py @@ -0,0 +1,82 @@ +""" + 给定两个字符串 text1 和 text2,返回这两个字符串的最长公共子序列。 + + 一个字符串的 子序列 是指这样一个新的字符串:它是由原字符串在不改变字符的相对顺序的情况下删除某些字符(也可以不删除任何字符)后组成的新字符串。 + 例如,"ace" 是 "abcde" 的子序列,但 "aec" 不是 "abcde" 的子序列。两个字符串的「公共子序列」是这两个字符串所共同拥有的子序列。 + + 若这两个字符串没有公共子序列,则返回 0。 + + 示例 1: + 输入:text1 = ""abcde"", text2 = "ace" + 输出:3 + 解释:最长公共子序列是 "ace",它的长度为 3。 + + 示例 2: + 输入:text1 = "abc", text2 = "abc" + 输出:3 + 解释:最长公共子序列是 "abc",它的长度为 3。 + + 示例 3: + 输入:text1 = "abc", text2 = "def" + 输出:0 + 解释:两个字符串没有公共子序列,返回 0。 +  + 提示: + 1 <= text1.length <= 1000 + 1 <= text2.length <= 1000 + 输入的字符串只含有小写英文字符。 +""" +from functools import lru_cache + + +class Solution: + def longestCommonSubsequence(self, text1: str, text2: str) -> int: + return self.dp_1(text1, text2) + # return self.recursive(text1, text2, len(text1) - 1, len(text2) - 1) + + @classmethod + def dp_1(cls, text1: str, text2: str) -> int: + """ + 定义一个二维数组dp用来存储最长公共子序列的长度。 + 其中dp[i][j] 表示text1的前i个字符与text2的前j个字符的最长公共子序列的长度。 + + 从text1和text2的后面开始分析 + 1. 当text1[i] == text2[j]时,那么最长公共子序列的长度就应该是 + text1前i-1个字符与text2前j-1个字符最长公共子序列的长度+1。 即1+ dp[i-1][j-1] + + 2. 当text1[i] != text2[j]时,那么最长公共子序列的长度就应该是 + text1前i-1个字符的和text2前j个字符的最长公共子序列 和 text1中前i个字符和text2前j个字符的最长公共子序列中的最大值。 + 即 Max(dp[i-1][j], dp[i][j-1]) + 所以状态转移方程是: + dp[i][j] = dp[i-1][j-1] + 1 if text[i] == text[j] else max(dp[i-1][j], dp[i][j-1]) + + 时间复杂度:O(m*n) + 空间复杂度:O(m*n) + """ + res = 0 + + if text1 and text2: + m = len(text1) + 1 + n = len(text2) + 1 + + dp = [[0] * n for i in range(m)] + + for i in range(1, m): + for j in range(1, n): + dp[i][j] = dp[i - 1][j - 1] + 1 if text1[i - 1] == text2[j - 1] else max(dp[i - 1][j], dp[i][j - 1]) + res = dp[m - 1][n - 1] + return res + + @classmethod + @lru_cache(None) # None 表示 不限制 缓存本身的大小,如果不设置默认是128 + def recursive(cls, text1, text2, i, j): + """ + 时间复杂度:O(m*n) + 空间复杂度:O(m*n) + + """ + if i < 0 or j < 0: + return 0 + if text1[i] == text2[j]: + return cls.recursive(text1, text2, i - 1, j - 1) + return max(cls.recursive(text1, text2, i, j - 1), cls.recursive(text1, text2, i, j - 1)) diff --git a/Week_05/G20200343030545/LeetCode_120_545.py b/Week_05/G20200343030545/LeetCode_120_545.py new file mode 100644 index 00000000..4c031f1c --- /dev/null +++ b/Week_05/G20200343030545/LeetCode_120_545.py @@ -0,0 +1,82 @@ +""" + 给定一个三角形,找出自顶向下的最小路径和。每一步只能移动到下一行中相邻的结点上。 + 例如,给定三角形: + + [ + [2], + [3,4], + [6,5,7], + [4,1,8,3] + ] + 自顶向下的最小路径和为 11(即,2 + 3 + 5 + 1 = 11)。 + + + 说明: + 如果你可以只使用 O(n) 的额外空间(n 为三角形的总行数)来解决这个问题,那么你的算法会很加分。 +""" +from functools import lru_cache +from typing import List + + +class Solution: + def minimumTotal(self, triangle: List[List[int]]) -> int: + return self.recursive(triangle) + + @classmethod + def dp_1(cls, triangle: List[List[int]]) -> int: + """ + 动态规划 从下往上计算 + 状态转移方程: + problem(i,j)=min(sub_problem(i+1, j), sub_problem(i+1, j)) + triangle[i][j] + 时间复杂度:O(n*n) + 空间复杂度:O(1) + """ + dp = triangle + for row in range(len(dp) - 2, -1, -1): + for col in range(len(dp[row])): + dp[row][col] += min(dp[row + 1][col], dp[row + 1][col + 1]) + return dp[0][0] + + @classmethod + def dp_2(cls, triangle: List[List[int]]) -> int: + """ + 从上往下算, + 状态转移方程和上面类似,只不过要注意边界的处理,所以倾向于dp_1的解法。但是我觉得dp_2我更能想到。 + 时间复杂度:O(n*n) + 空间复杂度:O(1) + """ + dp = triangle + for row in range(1, len(dp)): + row_len = len(triangle[row]) + for col in range(row_len): + if col == 0: + dp[row][col] += dp[row - 1][col] + elif col == row_len - 1: + dp[row][col] += dp[row - 1][col - 1] + else: + dp[row][col] += min(dp[row - 1][col], dp[row - 1][col - 1]) + return min(dp[-1]) + + @classmethod + def recursive(cls, triangle: List[List[int]]): + """ + 递归 + 时间复杂度:O(n^2) + 空间复杂度:O(n^2) + """ + + @lru_cache(None) + def recursive_(level: int, col_index: int): + # terminator + if level == len(triangle) - 1: + return triangle[level][col_index] + # drill down + left = recursive_(level + 1, col_index) + right = recursive_(level + 1, col_index + 1) + return min(left, right) + triangle[level][col_index] + + return recursive_(0, 0) + + +if __name__ == '__main__': + print(Solution.recursive([[2], [3, 4], [6, 5, 7], [4, 1, 8, 3]])) diff --git a/Week_05/G20200343030545/LeetCode_121_545.py b/Week_05/G20200343030545/LeetCode_121_545.py new file mode 100644 index 00000000..924d45e1 --- /dev/null +++ b/Week_05/G20200343030545/LeetCode_121_545.py @@ -0,0 +1,56 @@ +""" + 给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。 + 如果你最多只允许完成一笔交易(即买入和卖出一支股票),设计一个算法来计算你所能获取的最大利润。 + 注意你不能在买入股票前卖出股票。 + + 示例 1: + 输入: [7,1,5,3,6,4] + 输出: 5 + 解释: 在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。 + 注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格。 + + 示例 2: + 输入: [7,6,4,3,1] + 输出: 0 + 解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。 +""" +from typing import List + + +class Solution: + def maxProfit(self, prices: List[int]) -> int: + return self.dp_2(prices) + + @classmethod + def dp_2(cls, prices: List[int]) -> int: + """ + 用两个变量来代替数组 + 时间复杂度:O(n) + 空间复杂度:O(1) + + """ + max_profit, min_price = 0, float("int") + for price in prices: + min_price = min(price, min_price) + max_profit = max(max_profit, price - min_price) + return max_profit + + @classmethod + def dp_1(cls, prices: List[int]) -> int: + """ + dp 数组 dp[i] 表示第i 天的最大收益 + dp[i] = max(dp[i-1], prices[i] - min_prices) + """ + max_profit = 0 + if prices: + min_prices = float("inf") + prices_len = len(prices) + dp = [0] * (prices_len + 1) # 浪费一个空间好去算最大收益 + max_profit = 0 + + for index in range(prices_len): + min_prices = min(min_prices, prices[index]) + + dp[index] = max(dp[index - 1], prices[index] - min_prices) + max_profit = max(max_profit, dp[index]) + return max_profit diff --git a/Week_05/G20200343030545/LeetCode_152_545.py b/Week_05/G20200343030545/LeetCode_152_545.py new file mode 100644 index 00000000..daedb563 --- /dev/null +++ b/Week_05/G20200343030545/LeetCode_152_545.py @@ -0,0 +1,62 @@ +""" + 给定一个整数数组 nums ,找出一个序列中乘积最大的连续子序列(该序列至少包含一个数)。 + + 示例 1: + 输入: [2,3,-2,4] + 输出: 6 + 解释: 子数组 [2,3] 有最大乘积 6。 + 示例 2: + 输入: [-2,0,-1] + 输出: 0 + 解释: 结果不能为 2, 因为 [-2,-1] 不是子数组。 +""" +from typing import List + + +class Solution: + def maxProduct(self, nums: List[int]) -> int: + return self.dp_2(nums) + + @classmethod + def dp_1(cls, nums: List[int]) -> int: + """ + 时间复杂度:O(n) + 空间负载度:O(1) + + """ + nums_len = len(nums) + min_dp = [0] * nums_len + max_dp = [0] * nums_len + + for index, row in enumerate(nums): + if index == 0: + min_dp[index] = row + max_dp[index] = row + else: + min_dp[index] = min(max_dp[index - 1] * row, row, min_dp[index - 1] * row) + max_dp[index] = max(max_dp[index - 1] * row, row, min_dp[index - 1] * row) + return max(max_dp) + + @classmethod + def dp_2(cls, nums: List[int]) -> int: + """ + 滚动变量优化,不需要dp数组 + 时间复杂度:O(n) + 空间复杂度:O(1) + + """ + assert nums + min_info = max_info = 1 + res = float("-inf") + + for num in nums: + if num < 0: + min_info, max_info = max_info, min_info + min_info = min(num, min_info * num) + max_info = max(num, max_info * num) + res = max(res, max_info) + return res + + +if __name__ == '__main__': + print(Solution.dp_1([2, 3, -2, 4])) diff --git a/Week_05/G20200343030545/LeetCode_198_545.py b/Week_05/G20200343030545/LeetCode_198_545.py new file mode 100644 index 00000000..759cdd78 --- /dev/null +++ b/Week_05/G20200343030545/LeetCode_198_545.py @@ -0,0 +1,114 @@ +""" + 你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金, + 影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。 + 给定一个代表每个房屋存放金额的非负整数数组,计算你在不触动警报装置的情况下,能够偷窃到的最高金额。 + + 示例 1: + 输入: [1,2,3,1] + 输出: 4 + 解释: 偷窃 1 号房屋 (金额 = 1) ,然后偷窃 3 号房屋 (金额 = 3)。 +   偷窃到的最高金额 = 1 + 3 = 4 。 + + 示例 2: + 输入: [2,7,9,3,1] + 输出: 12 + 解释: 偷窃 1 号房屋 (金额 = 2), 偷窃 3 号房屋 (金额 = 9),接着偷窃 5 号房屋 (金额 = 1)。 +   偷窃到的最高金额 = 2 + 9 + 1 = 12 。 +""" +from functools import lru_cache +from typing import List + + +class Solution: + def rob(self, nums: List[int]) -> int: + return self.recursive(nums) + + @classmethod + def recursive(cls, nums: List[int]) -> int: + """:argument + 递归的写法 + 加上了 缓存 + 时间复杂度:O(n) + 空间复杂度:O(n) + """ + nums_len = len(nums) + + @lru_cache(None) + def helper(index): + # terminator + if index < 0: + return 0 + if index == 0: + return nums[0] + + choose_i = helper(index - 2) + nums[index] + not_choose_i = helper(index - 1) + return max(choose_i, not_choose_i) + + return helper(nums_len - 1) + + @classmethod + def dp_1(cls, nums: List[int]) -> int: + """ + 状态转移方程: + dp[i][0] 表示下标为i的房子不偷时 能偷到的最大金额 + dp[i][1] 表示下表为i的房子偷时 能偷到的最大金额 + + 所以状态转移方程是: + dp[i][0] = max(dp[i-1][0], dp[i-1][1]) # 当下标为i的房子不偷,则取i-1房子偷和不偷的最大值 + dp[i][1] = dp[i-1][0] + nums[i] #当下标为i的房子偷时,i-1肯定不能偷了,但是可以加上nums[i] + 时间复杂度:O(n) + 空间复杂度:O(n) + """ + res = 0 + if nums: + nums_length = len(nums) + dp = [[0] * 2 for i in range(nums_length)] + dp[0][1] = nums[0] # 表示第一个房子偷时的能带来的最大金额¬ + + for index in range(1, nums_length): + dp[index][0] = max(dp[index - 1][0], dp[index - 1][1]) + dp[index][1] = dp[index - 1][0] + nums[index] + res = max(dp[len(nums) - 1][1], dp[len(nums) - 1][0]) + return res + + @classmethod + def dp_2(cls, nums: List[int]): + """ + a[i] 表示 偷下标为i的房子的最大收益 + 状态转移方程: + a[i] = max(a[i-1] , a[i-2]+nums[i]) + 时间复杂度:O(n) + 空间复杂度:O(n) + """ + res = 0 + if nums: + nums_len = len(nums) + if nums_len == 1: + return nums[0] + dp = [0] * nums_len + + for index in range(2, nums_len): + dp[index] = max(dp[index - 1], dp[index - 2] + nums[index]) + res = max(dp[index], res) + return res + + @classmethod + def dp_3(cls, nums: List[int]) -> int: + """ + 用两个变量来存当前的最大值 和 上一个的最大值 + 时间复杂度:O(n) + 空间复杂度:O(1) + """ + curr_max = 0 # 当前最大值 + prev_max = 0 # 上一个最大值 + + for num in nums: + tmp_max = curr_max + curr_max = max(prev_max + num, curr_max) + prev_max = tmp_max + return curr_max + + +if __name__ == '__main__': + print(Solution.recursive([1, 2, 3, 1])) diff --git a/Week_05/G20200343030545/LeetCode_213_545.py b/Week_05/G20200343030545/LeetCode_213_545.py new file mode 100644 index 00000000..e23da53b --- /dev/null +++ b/Week_05/G20200343030545/LeetCode_213_545.py @@ -0,0 +1,57 @@ +""" + 你是一个专业的小偷,计划偷窃沿街的房屋,每间房内都藏有一定的现金。 + 这个地方所有的房屋都围成一圈,这意味着第一个房屋和最后一个房屋是紧挨着的。同时,相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。 + 给定一个代表每个房屋存放金额的非负整数数组,计算你在不触动警报装置的情况下,能够偷窃到的最高金额。 + + 示例 1: + + 输入: [2,3,2] + 输出: 3 + 解释: 你不能先偷窃 1 号房屋(金额 = 2),然后偷窃 3 号房屋(金额 = 2), 因为他们是相邻的。 + + 示例 2: + 输入: [1,2,3,1] + 输出: 4 + 解释: 你可以先偷窃 1 号房屋(金额 = 1),然后偷窃 3 号房屋(金额 = 3)。 +   偷窃到的最高金额 = 1 + 3 = 4 。 +""" +from typing import List + + +class Solution: + def rob(self, nums: List[int]) -> int: + return self.dp_1(nums) + + @classmethod + def dp_1(cls, nums: List[int]) -> int: + """ + 由于第一个房子和最后一个房子是相邻的,所以能偷的最大值就是 + max( 开始偷第一个房子的最大金额nums[1:] , 开始偷最后一个房子的最大金额nums[:n-1]) + 状态转移方程 + dp[i] 表示第i个房子能偷的最大金额 + dp[i] = max(dp[i-1], dp[i-2] + num[i]) + """ + + def dp(params: List[int]) -> int: + params_len = len(params) + res = 0 + if params: + if params_len == 1: + return params[0] + + dp_ = [0] * params_len + dp_[0] = params[0] + + res = dp_[1] = max(params[0], params[1]) + + for index in range(2, params_len): + dp_[index] = max(dp_[index - 1], dp_[index - 2] + params[index]) + res = max(res, dp_[index]) + return res + + if not nums: + return 0 + if len(nums) == 1: + return nums[0] + + return max(dp(nums[1:]), dp(nums[:len(nums) - 1])) diff --git a/Week_05/G20200343030545/LeetCode_221_545.py b/Week_05/G20200343030545/LeetCode_221_545.py new file mode 100644 index 00000000..86a6094d --- /dev/null +++ b/Week_05/G20200343030545/LeetCode_221_545.py @@ -0,0 +1,43 @@ +""" + 在一个由 0 和 1 组成的二维矩阵内,找到只包含 1 的最大正方形,并返回其面积。 + + 示例: + + 输入: + + 1 0 1 0 0 + 1 0 1 1 1 + 1 1 1 1 1 + 1 0 0 1 0 + + 输出: 4 +""" +from typing import List + + +class Solution: + def maximalSquare(self, matrix: List[List[str]]) -> int: + return self.dp_1(matrix) + + @classmethod + def dp_1(cls, matrix: List[List[str]]) -> int: + """ + 状态转移方程: + dp[i][j] = min(dp[i-1][j-1], dp[i][j-1], dp[i-1][j]) + 1 + 时间复杂度:O(m*n) + 空间复杂度:O(m*n) + """ + + res = 0 + if matrix: + m = len(matrix) + n = len(matrix[0]) + + dp = [[0] * (n + 1) for i in range(m + 1)] + + for i in range(1, m + 1): + for j in range(1, n + 1): + if matrix[i - 1][j - 1] == "1": + dp[i][j] = min(dp[i - 1][j - 1], dp[i][j - 1], dp[i - 1][j]) + 1 + res = max(res, dp[i][j]) + return res * res diff --git a/Week_05/G20200343030545/LeetCode_322_545.py b/Week_05/G20200343030545/LeetCode_322_545.py new file mode 100644 index 00000000..2d92cec9 --- /dev/null +++ b/Week_05/G20200343030545/LeetCode_322_545.py @@ -0,0 +1,64 @@ +""" + 给定不同面额的硬币 coins 和一个总金额 amount。 + 编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1。 + + 示例 1: + 输入: coins = [1, 2, 5], amount = 11 + 输出: 3 + 解释: 11 = 5 + 5 + 1 + + 示例 2: + 输入: coins = [2], amount = 3 + 输出: -1 +""" +from functools import lru_cache +from typing import List + + +class Solution: + def coinChange(self, coins: List[int], amount: int) -> int: + return self.dp_1(coins, amount) + + @classmethod + def recursive(cls, coins: List[int], amount: int) -> int: + @lru_cache(None) + def helper(amt): + # terminator + if amt < 0: + return -1 + if amt == 0: + return 0 + + res = float("inf") + # process + for coin in coins: + sub_problem = helper(amt - coin) + if sub_problem == -1: + continue + res = min(res, sub_problem + 1) + return res if res != float("inf") else -1 + + return helper(amount) + + @classmethod + def dp_1(cls, coins: List[int], amount: int) -> int: + """ + 动态递归 + dp[i] 表示总金额为i时的最优解法 + 例如 当i=11 硬币分别为[1,2,5]时 dp[11] = min( dp[11-1] ,dp[11-2], dp[11-5])+1 + 所以状态转移方程为: + dp[i] = min([dp[i-coin] for coin in coins if coin<=i]) +1 + 状态转移方程加了一个i>=coin的条件,如果coin>i则没必要往下找了 + + 时间复杂度:O(an) a代表amount n代表硬币的个数 + 空间复杂度:O(a) + + """ + dp = [float("inf") if i else 0 for i in range(amount + 1)] + for i in range(1, amount + 1): + dp[i] = min([dp[i - coin] if i >= coin else float("inf") for coin in coins]) + 1 + return -1 if dp[amount] == float("inf") else dp[amount] + + @classmethod + def bfs(cls, coins: List[int], amount: int) -> int: + pass diff --git a/Week_05/G20200343030545/LeetCode_403_545.py b/Week_05/G20200343030545/LeetCode_403_545.py new file mode 100644 index 00000000..daf3ca3c --- /dev/null +++ b/Week_05/G20200343030545/LeetCode_403_545.py @@ -0,0 +1,61 @@ +""" + 一只青蛙想要过河。 假定河流被等分为 x 个单元格,并且在每一个单元格内都有可能放有一石子(也有可能没有)。 + 青蛙可以跳上石头,但是不可以跳入水中。 + 给定石子的位置列表(用单元格序号升序表示), 请判定青蛙能否成功过河(即能否在最后一步跳至最后一个石子上)。  + 开始时, 青蛙默认已站在第一个石子上,并可以假定它第一步只能跳跃一个单位(即只能从单元格1跳至单元格2)。 + 如果青蛙上一步跳跃了 k 个单位,那么它接下来的跳跃距离只能选择为 k - 1、k 或 k + 1个单位。  + 另请注意,青蛙只能向前方(终点的方向)跳跃。 + + 请注意: + 石子的数量 ≥ 2 且 < 1100; + 每一个石子的位置序号都是一个非负整数,且其 < 231; + 第一个石子的位置永远是0。 + + 示例 1: + [0,1,3,5,6,8,12,17] + + 总共有8个石子。 + 第一个石子处于序号为0的单元格的位置, 第二个石子处于序号为1的单元格的位置, + 第三个石子在序号为3的单元格的位置, 以此定义整个数组... + 最后一个石子处于序号为17的单元格的位置。 + + 返回 true。即青蛙可以成功过河,按照如下方案跳跃: + 跳1个单位到第2块石子, 然后跳2个单位到第3块石子, 接着 + 跳2个单位到第4块石子, 然后跳3个单位到第6块石子, + 跳4个单位到第7块石子, 最后,跳5个单位到第8个石子(即最后一块石子)。 + + 示例 2: + [0,1,2,3,4,8,9,11] + + 返回 false。青蛙没有办法过河。 + 这是因为第5和第6个石子之间的间距太大,没有可选的方案供青蛙跳跃过去。 +""" +from functools import lru_cache +from typing import List + + +class Solution: + def canCross(self, stones: List[int]) -> bool: + return self.recursive(stones) + + @classmethod + def recursive(cls, stones: List[int]) -> bool: + """ + 记忆化搜索 + """ + end = stones[-1] + set_ = set(stones) + + @lru_cache(None) + def helper(start, jump): + if start == end: + return True + + for i in (jump - 1, jump, jump + 1): + if i <= 0: + continue + if start + i in set_ and helper(start + i, i): + return True + return False + + return helper(0, 0) diff --git a/Week_05/G20200343030545/LeetCode_53_545.py b/Week_05/G20200343030545/LeetCode_53_545.py new file mode 100644 index 00000000..e7968705 --- /dev/null +++ b/Week_05/G20200343030545/LeetCode_53_545.py @@ -0,0 +1,70 @@ +""" + 给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。 + 示例: + + 输入: [-2,1,-3,4,-1,2,1,-5,4], + 输出: 6 + 解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。 + + 进阶: + 如果你已经实现复杂度为 O(n) 的解法,尝试使用更为精妙的分治法求解。 +""" +from typing import List + + +class Solution: + def maxSubArray(self, nums: List[int]) -> int: + return self.directly(nums) + + @classmethod + def directly(cls, nums: List[int]) -> int: + """ + 时间复杂度:O(n^2) + 空间复杂度:O(1) + 这个解法会超时😂 + """ + max_num = float("-inf") + len_num = len(nums) + + for index in range(len_num): + tmp_max_num = 0 + for tmp_index in range(index, len_num): + tmp_max_num += nums[tmp_index] + if tmp_max_num > max_num: + max_num = tmp_max_num + return max_num + + @classmethod + def dp_1(cls, nums: List[int]) -> int: + """ + 状态转移方程: + 最大子序列 = 当前元素自身最大 或者 包含之前的最大 + dp[i] = max(nums[i], nums[i]+dp[i-1]) + 时间复杂度:O(n) + 空间复杂度:O(n) + """ + dp = [0] * len(nums) + for index, num in enumerate(nums): + if index == 0: + dp[index] = num + else: + dp[index] = max(num, num + dp[index - 1]) + return max(dp) + + @classmethod + def dp_2(cls, nums: List[int]) -> int: + """ + 状态转移方程同上 + 只不过是复用nums(但是会改变nums本身的元素) + 时间复杂度:O(n) + 空间复杂度:O(1) + """ + for index, num in enumerate(nums): + if index == 0: + continue + nums[index] = max(num, nums[index - 1] + num) + return max(nums) + + +if __name__ == '__main__': + print(Solution().dp_1([-2, 1, -3, 4, -1, 2, 1, -5, 4])) diff --git a/Week_05/G20200343030545/LeetCode_55_545.py b/Week_05/G20200343030545/LeetCode_55_545.py new file mode 100644 index 00000000..60b47b77 --- /dev/null +++ b/Week_05/G20200343030545/LeetCode_55_545.py @@ -0,0 +1,87 @@ +""" + 给定一个非负整数数组,你最初位于数组的第一个位置。 + 数组中的每个元素代表你在该位置可以跳跃的最大长度。 + 判断你是否能够到达最后一个位置。 + + 示例 1: + 输入: [2,3,1,1,4] + 输出: true + 解释: 我们可以先跳 1 步,从位置 0 到达 位置 1, 然后再从位置 1 跳 3 步到达最后一个位置。 + + 示例 2: + 输入: [3,2,1,0,4] + 输出: false + 解释: 无论怎样,你总会到达索引为 3 的位置。但该位置的最大跳跃长度是 0 , 所以你永远不可能到达最后一个位置。 +""" +from functools import lru_cache +from typing import List + + +class Solution: + def canJump(self, nums: List[int]) -> bool: + return self.dp_1(nums) + + @classmethod + def greedy(cls, nums: List[int]) -> bool: + """ + 贪心算法 + 思路: + 1、定义一个最远能跳到的位置max_i 初始值为0 + 2、循环遍历数组,当max_i大于等于i时,说明i这个位置可以到达。 + 3、可以到达的情况下,判断i+num是否大于max_i,如果大于就更新max_i + 4、优化处理,每次循环可以判断i是否大于max_i,如果大于了,则后续的就不用走了,因为i这块已经中断了。 + 时间复杂度:O(n) + 空间复杂度:O(1) + """ + max_i = i = 0 # 表示当前能跳到的最远位置 + for i, num in enumerate(nums): + if i <= max_i < i + num: # 当前位置能到达, 并且 当前位置加上跳的步骤大于max_i, 就更新max_i + max_i = i + num + if max_i < i: + return False + return max_i >= i + + @classmethod + def dp_1(cls, nums: List[int]) -> bool: + """ + 动态规划: + 定义dp数组 dp[i]表示从下标为0 到i是否可达 + 状态转移方程: + dp[i] = dp[j] && nums[j]+j>=i i [1, nums_len] j [0,i] + """ + nums_len = len(nums) + dp = [False] * nums_len + dp[0] = True + + for i in range(1, nums_len): + for j in range(0, i): + if dp[j] and nums[j] + j >= i: + dp[i] = True + break + return dp[nums_len - 1] + + @classmethod + def recursive(cls, nums: List[int]) -> bool: + """ + 回溯 枚举第一个位置跳到最后一个位置的的方法,可以看出如果第一个可以到第二个,那么就可以简化成从第二个到达最后一个的,分解成子问题, + 使用lru_cache,来保存重复结果,避免重复计算。 + 时间复杂度:O(n^2) + 空间复杂度:O(2n) + """ + nums_len = len(nums) + + @lru_cache(None) + def helper(index): + # terminator + if index == nums_len - 1: + return True + + # process + furthest = min(nums[index] + index, nums_len - 1) + for i in range(index + 1, furthest + 1): + if helper(i): + return True + + return False + + return helper(0) diff --git a/Week_05/G20200343030545/LeetCode_621_545.py b/Week_05/G20200343030545/LeetCode_621_545.py new file mode 100644 index 00000000..5dba4e2f --- /dev/null +++ b/Week_05/G20200343030545/LeetCode_621_545.py @@ -0,0 +1,38 @@ +""" + 给定一个用字符数组表示的 CPU 需要执行的任务列表。 + 其中包含使用大写的 A - Z 字母表示的26 种不同种类的任务。 + 任务可以以任意顺序执行,并且每个任务都可以在 1 个单位时间内执行完。 + CPU 在任何一个单位时间内都可以执行一个任务,或者在待命状态。 + 然而,两个相同种类的任务之间必须有长度为 n 的冷却时间,因此至少有连续 n 个单位时间内 CPU 在执行不同的任务,或者在待命状态。 + + 你需要计算完成所有任务所需要的最短时间。 + + 示例 1: + 输入: tasks = ["A","A","A","B","B","B"], n = 2 + 输出: 8 + 执行顺序: A -> B -> (待命) -> A -> B -> (待命) -> A -> B. + + 注: + 任务的总个数为 [1, 10000]。 + n 的取值范围为 [0, 100]。 +""" +from typing import List + + +class Solution: + def leastInterval(self, tasks: List[str], n: int) -> int: + pass + + @classmethod + def use_sort(cls, tasks: List[str], n: int) -> int: + # 如果没有任务 或者 单位时间为0 ,则返回任务的个数 + if not tasks or not n: + return len(tasks) + + # 将任务按个数划分 得到task_counts key是task value是task的个数 + task_counts = dict() + for task in tasks: + task_counts[task] = task_counts.get(task, 0) + 1 + + # 这个返回的是一个列表 里面的元素是元祖格式 第一个元素是任务名称 第二个元素是任务出现的次数 + task_counts = sorted(task_counts.items(), key=lambda i: i[1], reverse=True) diff --git a/Week_05/G20200343030545/LeetCode_62_545.py b/Week_05/G20200343030545/LeetCode_62_545.py new file mode 100644 index 00000000..c9556e35 --- /dev/null +++ b/Week_05/G20200343030545/LeetCode_62_545.py @@ -0,0 +1,66 @@ +""" + 一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。 + 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。 + 问总共有多少条不同的路径? + + 示例 1: + 输入: m = 3, n = 2 + 输出: 3 + 解释: + 从左上角开始,总共有 3 条路径可以到达右下角。 + 1. 向右 -> 向右 -> 向下 + 2. 向右 -> 向下 -> 向右 + 3. 向下 -> 向右 -> 向右 + + 示例 2: + 输入: m = 7, n = 3 + 输出: 28 +  + 提示: + 1 <= m, n <= 100 + 题目数据保证答案小于等于 2 * 10 ^ 9 +""" + + +class Solution: + def uniquePaths(self, m: int, n: int) -> int: + return self.dp_2(m, n) + + @classmethod + def dp_1(cls, m: int, n: int) -> int: + """ + 时间复杂度:O(m*n) + 空间负载度:O(m*n) + """ + res = 0 + if m > 0 and n > 0: + # 初始化一个table + table = [[0] * n for i in range(m)] + # 给定第一行 和第一列初始值 + for i in range(m): + table[m][0] = 1 + for j in range(n): + table[0][n] = 1 + + for i in range(1, m): + for j in range(1, n): + table[i][j] = table[i - 1][j] + table[i][j - 1] + res = table[-1][-1] # 防止数组下标越界 + return res + + @classmethod + def dp_2(cls, m: int, n: int) -> int: + """ + 时间复杂度:O(m*n) + 空间复杂度:O(n) + 优化了空间复杂度,用一维数组表示每一列的值,计算新值是加上上一列的值就行 + """ + res = 0 + if m > 0 and n > 0: + table = [1] * n + + for i in range(1, m): + for j in range(1, n): + table[j] = table[j] + table[j - 1] + res = table[-1] + return res diff --git a/Week_05/G20200343030545/LeetCode_63_545.py b/Week_05/G20200343030545/LeetCode_63_545.py new file mode 100644 index 00000000..95344434 --- /dev/null +++ b/Week_05/G20200343030545/LeetCode_63_545.py @@ -0,0 +1,80 @@ +""" + 一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。 + 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。 + 现在考虑网格中有障碍物。那么从左上角到右下角将会有多少条不同的路径? + 网格中的障碍物和空位置分别用 1 和 0 来表示。 + + 说明:m 和 n 的值均不超过 100。 + + 示例 1: + 输入: + [ +   [0,0,0], +   [0,1,0], +   [0,0,0] + ] + 输出: 2 + 解释: + 3x3 网格的正中间有一个障碍物。 + 从左上角到右下角一共有 2 条不同的路径: + 1. 向右 -> 向右 -> 向下 -> 向下 + 2. 向下 -> 向下 -> 向右 -> 向右 +""" +from typing import List + + +class Solution: + def uniquePathsWithObstacles(self, obstacleGrid: List[List[int]]) -> int: + return self.dp_2(obstacleGrid) + + @classmethod + def dp_1(cls, obstacleGrid: List[List[int]]) -> int: + """ + 时间复杂度:O(m*n) + 空间复杂度:O(1) + """ + res = 0 + if obstacleGrid and obstacleGrid[0]: + m = len(obstacleGrid) + n = len(obstacleGrid[0]) + if obstacleGrid[0][0] == 1: + # 表示起始位置就有障碍物,所以直接返回0 + return res + + # 开始 初始化目标数组的第一行和第一列的值 + obstacleGrid[0][0] = 1 + for i in range(1, m): + obstacleGrid[i][0] = 0 if obstacleGrid[i][0] == 1 else obstacleGrid[i - 1][0] + + for j in range(1, n): + obstacleGrid[0][j] = 0 if obstacleGrid[0][j] == 1 else obstacleGrid[0][j - 1] + + for i in range(1, m): + for j in range(1, n): + if obstacleGrid[i][j] == 1: + # 说明有障碍物 + obstacleGrid[i][j] = 0 + else: + # 没有障碍物 + obstacleGrid[i][j] = obstacleGrid[i - 1][j] + obstacleGrid[i][j - 1] + res = obstacleGrid[-1][-1] + return res + + @classmethod + def dp_2(cls, obstacleGrid: List[List[int]]) -> int: + """ + 时间复杂度:O(n*m) + 空间复杂度:O(n) + + """ + res = 0 + if obstacleGrid and obstacleGrid[0]: + m = len(obstacleGrid) + n = len(obstacleGrid[0]) + table = [1] + n * [0] + + for i in range(m): + for j in range(n): + table[j] = 0 if obstacleGrid[i][j] == 1 else table[j - 1] + table[j] + res = table[-2] + return res diff --git a/Week_05/G20200343030545/LeetCode_64_545.py b/Week_05/G20200343030545/LeetCode_64_545.py new file mode 100644 index 00000000..59cd0ac1 --- /dev/null +++ b/Week_05/G20200343030545/LeetCode_64_545.py @@ -0,0 +1,95 @@ +""" + 给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。 + 说明:每次只能向下或者向右移动一步。 + 示例: + 输入: + [ +   [1,3,1], + [1,5,1], + [4,2,1] + ] + 输出: 7 + 解释: 因为路径 1→3→1→1→1 的总和最小。 +""" +from functools import lru_cache +from typing import List + + +class Solution: + def minPathSum(self, grid: List[List[int]]) -> int: + return self.dp_1(grid) + + @classmethod + def dp_1(cls, grid: List[List[int]]) -> int: + """ + 动态规划 + dp[i,j] 表示 第i 行和第j 列的最小路径和 + 状态转移方程 + dp[i,j] = grid[i, j] + min( dp[i+1][j], dp[i][j+1] ) + 时间复杂度:O(m*n) + 空间复杂度:O(m*n) + """ + row_len = len(grid) + col_len = len(grid[0]) + + dp = [[0] * col_len for i in range(row_len)] + + dp[0][0] = grid[0][0] + for i in range(row_len): + for j in range(col_len): + if i == 0 and j != 0: + dp[i][j] = grid[i][j] + dp[i][j - 1] + elif i != 0 and j == 0: + dp[i][j] = grid[i][j] + dp[i - 1][j] + elif i != 0 and j != 0: + dp[i][j] += grid[i][j] + min(dp[i - 1][j], dp[i][j - 1]) + return dp[row_len - 1][col_len - 1] + + @classmethod + def recursive_1(cls, grid: List[List[int]]) -> int: + """ + 递归 自顶向下走 这样好理解但是边界条件比较模糊,需要考虑清楚 + 左上角走到右下角开始走 + 每次有两种选择: + 1.向下走 grid[row_index+1][col_index] + 2.向右走 grid[row_index][col_index+1] + 取这两者中的最小值 加上自己的所在位置的值 + + 如果row_index或者col_index到到 最后一行 和者最后一列的下标时,返回grid[row_index][col_index] + 如果row_index或者col_index超出了最后一行或最后一列的下标时 返回无穷大 + """ + col_len = len(grid[0]) + row_len = len(grid) + + @lru_cache(None) + def helper(row_index, col_index): + if row_index == row_len or col_index == col_len: + return float("inf") + elif row_index == row_len - 1 and col_index == col_len - 1: + return grid[row_index][col_index] + else: + return grid[row_index][col_index] + min( + helper(row_index + 1, col_index), helper(row_index, col_index + 1) + ) + + return helper(0, 0) + + @classmethod + def recursive_2(cls, grid: List[List[int]]) -> int: + """ + 递归 自底向上 远离和1一样只不过时从下往上算 + """ + row_len = len(grid) + col_len = len(grid[0]) + + @lru_cache(None) + def helper(row_index, col_index): + if row_index == 0 and col_index == 0: + return grid[row_index][col_index] + if row_index < row_len - 1 or col_index < col_len - 1: + return float("inf") + return grid[row_index][col_index] + min( + helper(row_index - 1, col_index), helper(row_index, col_index - 1) + ) + + return helper(row_len - 1, col_len - 1) diff --git a/Week_05/G20200343030545/LeetCode_70_545.py b/Week_05/G20200343030545/LeetCode_70_545.py new file mode 100644 index 00000000..e26b0581 --- /dev/null +++ b/Week_05/G20200343030545/LeetCode_70_545.py @@ -0,0 +1,90 @@ +""" + 假设你正在爬楼梯。需要 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 阶 +""" +from functools import lru_cache + + +class Solution: + def climbStairs(self, n: int) -> int: + assert n > 0 + # return self.recursive(n) + return self.dp_1(n) + + @classmethod + @lru_cache(None) + def recursive(cls, n: int) -> int: + """ + 时间复杂度:O(n) + 空间负载度:O(n) #因为用了缓存,递归树的节点 只会被计算一次 + """ + if n < 3: + return n + + return cls.recursive(n - 2) + cls.recursive(n - 1) + + @classmethod + def dp_1(cls, n: int) -> int: + a, b = 1, 1 + for i in range(1, n): + a, b = b, a + b + return b + + +class SolutionWith3Cases: + """ + 每次可以上一个台阶或者两个台阶 或者三个台阶 + """ + + def climbStairs(self, n: int) -> int: + assert n > 0 + return self.dp_1(n) + + @classmethod + @lru_cache(None) + def recursive(cls, n) -> int: + if n < 3: + return n if n != 0 else 1 + return cls.recursive(n - 1) + cls.recursive(n - 2) + cls.recursive(n - 3) + + @classmethod + def dp_1(cls, n) -> int: + a, b, c = 1, 1, 2 + for i in range(2, n): + a, b, c = b, c, a + b + c + return b if n < 2 else c + + +class SolutionWith3CasesAndUnique: + """ + 每次可以上一个台阶或者两个台阶 或者三个台阶, 并且每次上的台阶不可以重复, + 比如第一层上1层台阶下一次就不能上一层了,但是下下一次可以上一层 + + """ + + def climbStairs(self, n: int) -> int: + assert n > 0 + pass + + @classmethod + @lru_cache(None) + def recursive(cls, n) -> int: + pass diff --git a/Week_05/G20200343030545/LeetCode_72_545.py b/Week_05/G20200343030545/LeetCode_72_545.py new file mode 100644 index 00000000..bb93d790 --- /dev/null +++ b/Week_05/G20200343030545/LeetCode_72_545.py @@ -0,0 +1,62 @@ +""" + 给定两个单词 word1 和 word2,计算出将 word1 转换成 word2 所使用的最少操作数 。 + 你可以对一个单词进行如下三种操作: + 插入一个字符 + 删除一个字符 + 替换一个字符 + 示例 1: + 输入: word1 = "horse", word2 = "ros" + 输出: 3 + 解释: + horse -> rorse (将 'h' 替换为 'r') + rorse -> rose (删除 'r') + rose -> ros (删除 'e') + 示例 2: + 输入: word1 = "intention", word2 = "execution" + 输出: 5 + 解释: + intention -> inention (删除 't') + inention -> enention (将 'i' 替换为 'e') + enention -> exention (将 'n' 替换为 'x') + exention -> exection (将 'n' 替换为 'c') + exection -> execution (插入 'u') +""" + + +class Solution: + def minDistance(self, word1: str, word2: str) -> int: + pass + + @classmethod + def dp_1(cls, word1: str, word2: str) -> int: + """ + 动态规划: + dp数组 dp[i][j] 表示word1 到i的位置 转换成word2到j的位置需要的最少步数 + + 状态转移方程: + dp[i][j] = { + min(dp[i-1][j]+1, dp[i][j-1]+1, dp[i-1][j-1]) word1[i-1] == word2[j-1] + min(dp[i-1][j]+1, dp[i][j-1]+1, dp[i-1][j-1]+1) word[i-1] != word2[j-1] + } + """ + m = len(word1) + n = len(word2) + + if m * n == 0: + return m + n + dp = [[0] * (n + 1) for i in range(m + 1)] + + for i in range(m + 1): + dp[i][0] = i + + for j in range(n + 1): + dp[0][j] = j + + for i in range(1, m + 1): + for j in range(1, n + 1): + dp[i][j] = min( + dp[i][j - 1] + 1, + dp[i - 1][j] + 1, + dp[i - 1][j - 1] if word1[i - 1] == word2[j - 1] else dp[i - 1][j - 1] + 1 + ) + return dp[m][n] diff --git a/Week_05/G20200343030545/LeetCode_91_545.py b/Week_05/G20200343030545/LeetCode_91_545.py new file mode 100644 index 00000000..c36292b9 --- /dev/null +++ b/Week_05/G20200343030545/LeetCode_91_545.py @@ -0,0 +1,91 @@ +""" + 一条包含字母 A-Z 的消息通过以下方式进行了编码: + 'A' -> 1 + 'B' -> 2 + ... + 'Z' -> 26 + 给定一个只包含数字的非空字符串,请计算解码方法的总数。 + + 示例 1: + + 输入: "12" + 输出: 2 + 解释: 它可以解码为 "AB"(1 2)或者 "L"(12)。 + + 示例 2: + 输入: "226" + 输出: 3 + 解释: 它可以解码为 "BZ" (2 26), "VF" (22 6), 或者 "BBF" (2 2 6) 。 +""" +from functools import lru_cache + + +class Solution: + def numDecodings(self, s: str) -> int: + return self.dp_1(s) + + @classmethod + def dp_1(cls, s: str) -> int: + """ + 动态规划dp[i] 为s[:i]解码的总方法数 + 分情况建立最优子结构 + 当s[i] == 0: + dp[i] = 0 if s[i-1] not in ('1', '2') else dp[i-2] + 当s[i-1] ==1: + dp[i] = dp[i-1] + dp[i-2] + 当s[i-1]==2 and '1'<=s[i]<='6': + dp[i] = dp[i-1] + dp[i-2] + + """ + if s == '0': + return 0 + s_len = len(s) + dp = [0] * (s_len + 1) + dp[0] = 1 + dp[1] = 1 + + for index in range(1, s_len): + if s[index] == "0": + if s[index - 1] in ("1", "2"): + dp[index + 1] = dp[index - 1] + else: + return 0 + else: + if s[index - 1] == "1": + dp[index + 1] = dp[index] + dp[index - 1] + elif s[index - 1] == "2" and s[index] <= "6": + dp[index + 1] = dp[index] + dp[index - 1] + else: + dp[index + 1] = dp[index] + return dp[s_len] + + @classmethod + def recursive(cls, s: str): + s_len = len(s) + + @lru_cache(None) + def helper(s_index): + # terminator + if s_len == s_index: + # 划分到了最后直接返回1 + return 1 + if s[s_index] == 0: + # 表示现在这个是以0开头的直接返回0 + return 0 + + ans1 = helper(s_index + 1) + ans2 = 0 + if s_index < s_len - 1: + # 判断s_index 和 s_index+1之和是否大于26 + first = s[s_index] + second = s[s_index + 1] + + if int(f"{first}{second}") <= 26: + ans2 = helper(s_index + 2) + return ans1 + ans2 + + return helper(0) if s == '0' else 1 + + +if __name__ == '__main__': + print(Solution().dp_1('01')) diff --git a/Week_05/G20200343030551/Leetcode-064_MinimumPathSum_551.cpp b/Week_05/G20200343030551/Leetcode-064_MinimumPathSum_551.cpp new file mode 100644 index 00000000..1d360be0 --- /dev/null +++ b/Week_05/G20200343030551/Leetcode-064_MinimumPathSum_551.cpp @@ -0,0 +1,26 @@ +#include +#include + +using namespace std; + +class Solution +{ +public: + int minPathSum(vector> &grid) + { + int m = grid.size(); + int n = grid[0].size(); + vector> dp(m, vector(n)); + for (int i = 0; i < m; i++) + dp[i][0] = (i == 0 ? 0 : dp[i - 1][0]) + grid[i][0]; + for (int i = 0; i < n; i++) + dp[0][i] = (i == 0 ? 0 : dp[0][i - 1]) + grid[0][i]; + + for (int i = 1; i < m; i++) + { + for (int j = 1; j < n; j++) + dp[i][j] = min(dp[i - 1][j], dp[i][j - 1]) + grid[i][j]; + } + return dp[m - 1][n - 1]; + } +}; \ No newline at end of file diff --git a/Week_05/G20200343030551/Leetcode-076_MinimumWindowSubstring_551.cpp b/Week_05/G20200343030551/Leetcode-076_MinimumWindowSubstring_551.cpp new file mode 100644 index 00000000..b10b426b --- /dev/null +++ b/Week_05/G20200343030551/Leetcode-076_MinimumWindowSubstring_551.cpp @@ -0,0 +1,36 @@ +#include +#include + +using namespace std; + +class Solution +{ +public: + string minWindow(string s, string t) + { + unordered_map map; + for (auto elem:t) map[elem]++; + int left = 0; + int cnt = 0; + int max_len = s.size() + 1; + int start = left; + + for (int i = 0; i < s.size(); i++) + { + if (--map[s[i]] >= 0) + cnt++; + while (cnt == t.size()) + { + if (max_len > (i - left + 1)) + { + max_len = i - left + 1; + start = left; + } + //出现 包含于t集合的重复字符 于旧窗口中 窗口可变 + if (++map[s[left]] > 0) cnt--; + left++; + } + } + return max_len == (s.size() + 1) ? "" : s.substr(start, max_len); + } +}; \ No newline at end of file diff --git a/Week_05/G20200343030551/Leetcode-091_DecodeWays_551.cpp b/Week_05/G20200343030551/Leetcode-091_DecodeWays_551.cpp new file mode 100644 index 00000000..467f975c --- /dev/null +++ b/Week_05/G20200343030551/Leetcode-091_DecodeWays_551.cpp @@ -0,0 +1,34 @@ +#include +#include +using namespace std; + +class Solution { +public: + int numDecodings(string s) { + if(s[0]=='0') + return 0; + vectordp(s.size()+1); + dp[0]=1; + dp[1]=1; + for(int i=1;i +#include +using namespace std; + +struct Node +{ + int row_nums; + int col_nums; + Node():row_nums(0),col_nums(0){} +}; + +class Solution { +public: + int maximalSquare(vector>& matrix) { + if(matrix.empty() || matrix[0].empty() ) + return 0; + int rows=matrix.size(); + int cols=matrix[0].size(); + vector> dp(rows+1,vector(cols+1)); + for(int i=1;i<=rows;i++) + { + for(int j=1;j<=cols;j++) + { + if(matrix[i-1][j-1]=='1') + { + dp[i][j].row_nums=min(dp[i-1][j].row_nums,dp[i-1][j-1].row_nums)+1; + dp[i][j].col_nums=min(dp[i][j-1].col_nums,dp[i-1][j-1].col_nums)+1; + } + } + } + + int max_size=0; + for(int i=1;i<=rows;i++) + { + for (int j = 1; j <= cols; j++) + { + int edge=min(dp[i][j].row_nums,dp[i][j].col_nums); + max_size=max(max_size,edge*edge); + } + } + return max_size; + } +}; + diff --git a/Week_05/G20200343030551/Leetcode-647_PalindromicSubstring_551.cpp b/Week_05/G20200343030551/Leetcode-647_PalindromicSubstring_551.cpp new file mode 100644 index 00000000..5dba01b3 --- /dev/null +++ b/Week_05/G20200343030551/Leetcode-647_PalindromicSubstring_551.cpp @@ -0,0 +1,25 @@ +#include +#include +using namespace std; + +class Solution { +public: + int countSubstrings(string s) { + if(s.empty()) + return 0; + int size=s.size(); + int res=0; + + vector> dp(size,vector(size)); + for(int i=size-1;i>=0;i--) + { + for(int j=i;j= 0; i --) { + for (int j = i + 2; j < len; j ++) { + int maxBetweenIAndJ = 0; + for (int k = i + 1; k <= j - 1; k ++) { + int lastShootK = dp[i][k] + dp[k][j] + _nums[i] * _nums[k] * _nums[j]; + maxBetweenIAndJ = Math.max(maxBetweenIAndJ, lastShootK); + } + dp[i][j] = maxBetweenIAndJ; + } + } + return dp[0][len - 1]; + } +} +// @lc code=end + diff --git a/Week_05/G20200343030561/Leetcode_32_561.java b/Week_05/G20200343030561/Leetcode_32_561.java new file mode 100644 index 00000000..13e6336a --- /dev/null +++ b/Week_05/G20200343030561/Leetcode_32_561.java @@ -0,0 +1,57 @@ +/* + * @lc app=leetcode.cn id=32 lang=java + * + * [32] 最长有效括号 + */ + +// s ( ( ( ) ( ) ) ) ( ) ) +// i 0 1 2 3 4 5 6 7 8 9 10 +// dp 0 0 0 2 0 4 6 7 0 10 0 +// @date Mar 12 2020 +// class Solution { +// public int longestValidParentheses(String s) { +// int l = s.length(), res = 0; +// if (l == 0) return 0; +// int[] dp = new int[l]; // close parenthesis +// for (int i = 1; i < l; i ++) { +// if (s.charAt(i) == ')') { +// if (s.charAt(i - 1) == '(') { +// dp[i]= 2; +// if (i - 2 >= 0) +// dp[i] += dp[i - 2]; +// } else if (i - 1 - dp[i - 1] >= 0 && s.charAt(i - 1 - dp[i - 1]) == '(') { +// dp[i] = dp[i - 1] + 2; +// if (i - 1 - dp[i - 1] - 1 >= 0) +// dp[i] += dp[i - 1 - dp[i - 1] - 1]; +// } +// } +// res = Math.max(res, dp[i]); +// } +// return res; +// } +// } + +// @lc code=start +// s ( ( ( ) ( ) ) ) ( ) ) +// i 0 1 2 3 4 5 6 7 8 9 10 11 +// dp 0 0 0 0 2 0 4 6 7 0 10 0 +class Solution { + public int longestValidParentheses(String s) { + int l = s.length(), res = 0; + if (l == 0) return 0; + int dp[] = new int[l + 1]; + for (int i = 2; i <= l; i ++) { + if (s.charAt(i - 1) == '(') continue; + int open1 = i - 2, open2 = i - 2 - dp[i - 1]; + if (s.charAt(open1) == '(') + dp[i] = dp[open1] + 2; + else if (open2 >= 0 && s.charAt(open2) == '(') + dp[i] = dp[i - 1] + dp[open2] + 2; + res = Math.max(res, dp[i]); + } + return res; + } +} + +// @lc code=end + diff --git a/Week_05/G20200343030561/Leetcode_363_561.java b/Week_05/G20200343030561/Leetcode_363_561.java new file mode 100644 index 00000000..6bc185b9 --- /dev/null +++ b/Week_05/G20200343030561/Leetcode_363_561.java @@ -0,0 +1,38 @@ +import java.util.TreeSet; + +/* + * @lc app=leetcode.cn id=363 lang=java + * + * [363] 矩形区域不超过 K 的最大数值和 + */ + +// similar as 1074 +// @lc code=start +class Solution { + public int maxSumSubmatrix(int[][] matrix, int k) { + int rl = matrix.length, cl = matrix[0].length, res = Integer.MIN_VALUE; + for (int r = 0; r < rl; r ++) + for (int c = 1; c < cl; c ++) + matrix[r][c] += matrix[r][c - 1]; + + for (int c = 0; c < cl; c ++) { + for (int _c = -1; _c < c; _c ++) { + int s = 0; + TreeSet s_in_r = new TreeSet<>(); + s_in_r.add(s); + for (int r = 0; r < rl; r ++) { + s += matrix[r][c] - (_c >= 0? matrix[r][_c] : 0); + Integer _s = s_in_r.ceiling(s - k); + if (_s != null) { + System.out.println(s - _s); + res = Math.max(res, s - _s); + } + s_in_r.add(s); + } + } + } + return res; + } +} +// @lc code=end + diff --git a/Week_05/G20200343030561/Leetcode_403_561.java b/Week_05/G20200343030561/Leetcode_403_561.java new file mode 100644 index 00000000..4f62075d --- /dev/null +++ b/Week_05/G20200343030561/Leetcode_403_561.java @@ -0,0 +1,25 @@ +import java.util.*; +/* + * @lc app=leetcode.cn id=403 lang=java + * + * [403] 青蛙过河 + */ + +// @lc code=start +class Solution { + public boolean canCross(int[] stones) { + Map> dp = new HashMap<>(); + for (int i = 0; i < stones.length; i ++) + dp.put(stones[i], new HashSet<>()); + dp.get(0).add(0); + for (int i = 0; i < stones.length; i ++) + for (int last : dp.get(stones[i])) + for (int next = last - 1; next <= last + 1; next ++) + if (next > 0 && dp.containsKey(stones[i] + next)) + dp.get(stones[i] + next).add(next); + int lastStone = stones[stones.length - 1]; + return !dp.get(lastStone).isEmpty(); + } +} +// @lc code=end + diff --git a/Week_05/G20200343030561/Leetcode_410_561.java b/Week_05/G20200343030561/Leetcode_410_561.java new file mode 100644 index 00000000..2652a150 --- /dev/null +++ b/Week_05/G20200343030561/Leetcode_410_561.java @@ -0,0 +1,33 @@ +/* + * @lc app=leetcode.cn id=410 lang=java + * + * [410] 分割数组的最大值 + */ + +// @lc code=start +// 无后向性 +class Solution { + public int splitArray(int[] nums, int m) { + int n = nums.length; + int[][] dp = new int[n + 1][m + 1]; + for (int i = 1; i <= n; i ++) + dp[i][0] = Integer.MAX_VALUE; + for (int j = 1; j <= m; j ++) + dp[0][j] = Integer.MAX_VALUE; + + int[] kadane = new int[n + 1]; + for (int i = 0; i < n; i ++) + kadane[i + 1] = kadane[i] + nums[i]; + + for (int i = 1; i <= n; i ++) { + for (int j = 1; j <= m; j ++) { + dp[i][j] = Integer.MAX_VALUE; + for (int k = 0; k < i; k ++) + dp[i][j] = Math.min(dp[i][j], Math.max(dp[k][j - 1], kadane[i] - kadane[k])); + } + } + return dp[n][m]; + } +} +// @lc code=end + diff --git a/Week_05/G20200343030561/Leetcode_552_561.java b/Week_05/G20200343030561/Leetcode_552_561.java new file mode 100644 index 00000000..3cfc5a85 --- /dev/null +++ b/Week_05/G20200343030561/Leetcode_552_561.java @@ -0,0 +1,41 @@ +/* + * @lc app=leetcode.cn id=552 lang=java + * + * [552] 学生出勤记录 II + */ + +// @lc code=start +class Solution { + public int checkRecord(int n) { + int MOD = 1000000007; + long a0l0 = 1; + long a0l1 = 0; + long a0l2 = 0; + long a1l0 = 0; + long a1l1 = 0; + long a1l2 = 0; + long _a0l0; + long _a0l1; + long _a0l2; + long _a1l0; + long _a1l1; + long _a1l2; + for (int i = 0; i < n + 1; i ++) { + _a0l0 = a0l0 + a0l1 + a0l2; + _a0l1 = a0l0; + _a0l2 = a0l1; + _a1l0 = a1l0 + a1l1 + a1l2 + _a0l0; + _a1l1 = a1l0; + _a1l2 = a1l1; + a0l0 = (_a0l0) % MOD; + a0l1 = _a0l1; + a0l2 = _a0l2; + a1l0 = (_a1l0) % MOD; + a1l1 = _a1l1; + a1l2 = _a1l2; + } + return (int)a1l0; + } +} +// @lc code=end + diff --git a/Week_05/G20200343030561/Leetcode_621_561.java b/Week_05/G20200343030561/Leetcode_621_561.java new file mode 100644 index 00000000..fcad975f --- /dev/null +++ b/Week_05/G20200343030561/Leetcode_621_561.java @@ -0,0 +1,22 @@ +/* + * @lc app=leetcode.cn id=621 lang=java + * + * [621] 任务调度器 + */ + +// @lc code=start +class Solution { + public int leastInterval(char[] tasks, int n) { + int[] rows = new int[26]; + for (char task: tasks) + rows[task - 'A'] ++; + Arrays.sort(rows); + int peak = rows[25] - 1; + int space = peak * n; + for (int i = 24; i >=0 && rows[i] > 0; i --) + space -= Math.min(rows[i], peak); + return space > 0 ? space + tasks.length : tasks.length; + } +} +// @lc code=end + diff --git a/Week_05/G20200343030561/Leetcode_647_561.java b/Week_05/G20200343030561/Leetcode_647_561.java new file mode 100644 index 00000000..c2ac232a --- /dev/null +++ b/Week_05/G20200343030561/Leetcode_647_561.java @@ -0,0 +1,47 @@ +/* + * @lc app=leetcode.cn id=647 lang=java + * + * [647] 回文子串 + */ + + +// class Solution { +// public int countSubstrings(String s) { +// int l = s.length(); +// boolean[][] dp = new boolean[l][l]; +// int res = 0; +// for (int i = l - 1; i >= 0; i --) { +// for (int j = i; j < l; j ++) { +// if ((j - i <= 2 || dp[i + 1][j - 1]) && s.charAt(i) == s.charAt(j)) { +// dp[i][j] = true; +// res ++; +// } +// } +// } +// return res; +// } +// } + +// @lc code=start +class Solution { + public int countSubstrings(String s) { + int l = s.length(); + boolean[] dp = new boolean[l]; + int res = 0; + for (int i = 0; i < l; i ++) { + dp[i] = true; // 对角线 + res ++; + for (int j = 0; j < i; j ++) { + // dp[j+1] 为右上角 + if (s.charAt(i) == s.charAt(j) && dp[j+1]) { + dp[j] = true; + res ++; + } else + dp[j] = false; + } + } + return res; + } +} +// @lc code=end + diff --git a/Week_05/G20200343030561/Leetcode_64_561.java b/Week_05/G20200343030561/Leetcode_64_561.java new file mode 100644 index 00000000..9f773832 --- /dev/null +++ b/Week_05/G20200343030561/Leetcode_64_561.java @@ -0,0 +1,28 @@ +/* + * @lc app=leetcode.cn id=64 lang=java + * + * [64] 最小路径和 + */ + +// @lc code=start +class Solution { + public int minPathSum(int[][] grid) { + int rl = grid.length, cl = grid[0].length; + int[][] dp = new int[rl][cl]; + dp[0][0] = grid[0][0]; + for (int c = 1; c < cl; c ++) { + dp[0][c] = dp[0][c - 1] + grid[0][c]; + } + for (int r = 1; r < rl; r ++) { + dp[r][0] = dp[r - 1][0] + grid[r][0]; + } + for (int r = 1; r < rl; r ++) { + for (int c = 1; c < cl; c ++) { + dp[r][c] = Math.min(dp[r - 1][c], dp[r][c - 1]) + grid[r][c]; + } + } + return dp[rl - 1][cl - 1]; + } +} +// @lc code=end + diff --git a/Week_05/G20200343030561/Leetcode_72_561.java b/Week_05/G20200343030561/Leetcode_72_561.java new file mode 100644 index 00000000..21990585 --- /dev/null +++ b/Week_05/G20200343030561/Leetcode_72_561.java @@ -0,0 +1,30 @@ +/* + * @lc app=leetcode.cn id=72 lang=java + * + * [72] 编辑距离 + */ + +// @lc code=start +class Solution { + public int minDistance(String word1, String word2) { + int rl = word1.length(), cl = word2.length(); + int[][] dp = new int[rl + 1][cl + 1]; + for (int r = 0; r <= rl; r ++) { + dp[r][0] = r; + } + for (int c = 0; c <= cl; c ++) { + dp[0][c] = c; + } + for (int r = 1; r <= rl; r ++) { + for (int c = 1; c <= cl; c ++) { + if (word1.charAt(r - 1) == word2.charAt(c - 1)) + dp[r][c] = dp[r - 1][c - 1]; + else + dp[r][c] = Math.min(dp[r - 1][c - 1], Math.min(dp[r][c - 1], dp[r - 1][c])) + 1; + } + } + return dp[rl][cl]; + } +} +// @lc code=end + diff --git a/Week_05/G20200343030561/Leetcode_76_561.java b/Week_05/G20200343030561/Leetcode_76_561.java new file mode 100644 index 00000000..c9aa53e9 --- /dev/null +++ b/Week_05/G20200343030561/Leetcode_76_561.java @@ -0,0 +1,65 @@ +import java.util.*; +/* + * @lc app=leetcode.cn id=76 lang=java + * + * [76] 最小覆盖子串 + */ + +// @date Mar 15 2020 +// class Solution { +// public String minWindow(String s, String t) { +// if (s.length() == 0 || t.length() == 0) return ""; +// Map mapT = new HashMap<>(); +// for (int i = 0; i < t.length(); i ++) +// mapT.put(t.charAt(i), mapT.getOrDefault(t.charAt(i), 0) + 1); + +// int sizeT = mapT.size(), left = 0, right = 0, formed = 0; +// Map window = new HashMap<>(); +// int[] ans = {-1, 0, 0}; + +// while (right < s.length()) { +// char c = s.charAt(right); +// window.put(c, window.getOrDefault(c, 0) + 1); +// if(mapT.containsKey(c) && window.get(c).intValue() == mapT.get(c).intValue()) +// formed ++; +// while (left <= right && formed == sizeT) { +// if (ans[0] == -1 || right - left + 1 < ans[0]) { +// ans[0] = right - left + 1; +// ans[1] = left; +// ans[2] = right; +// } +// c= s.charAt(left); +// window.put(c, window.get(c) - 1); +// if(mapT.containsKey(c) && window.get(c).intValue() < mapT.get(c).intValue()) +// formed -- ; +// left ++; +// } +// right ++; +// } +// return ans[0] == -1 ? "" : s.substring(ans[1], ans[2] + 1); +// } +// } + +// @lc code=start +class Solution { + public String minWindow(String s, String t) { + int[] count = new int[128]; + for (char c : t.toCharArray()) + count[c - '\0'] ++; + int len = 0, minLen = s.length(); // formed, ans[0] + String res = new String(); + for (int left = 0, right = 0; right < s.length(); right ++) { + if (-- count[s.charAt(right) - '\0'] >= 0) len ++; + while (len == t.length()) { + if (right - left + 1 <= minLen) { + minLen = right - left + 1; + res = s.substring(left, right + 1); + } + if (++ count[s.charAt(left++)] > 0) len --; + } + } + return res; + } +} +// @lc code=end + diff --git a/Week_05/G20200343030561/Leetcode_91_561.java b/Week_05/G20200343030561/Leetcode_91_561.java new file mode 100644 index 00000000..59208823 --- /dev/null +++ b/Week_05/G20200343030561/Leetcode_91_561.java @@ -0,0 +1,33 @@ +/* + * @lc app=leetcode.cn id=91 lang=java + * + * [91] 解码方法 + */ + +// @lc code=start +class Solution { + public int numDecodings(String s) { + int l = s.length(); + int[][] dp = new int[l + 1][3]; + dp[1][1] = singleDigit(s, 1) ? 1 : 0; + if (l == 1) return dp[1][1]; + dp[2][1] = singleDigit(s, 2) ? dp[1][1] : 0; + dp[2][2] = doubleDigit(s, 2) ? 1 : 0; + if (l == 2) return dp[2][1] + dp[2][2]; + for (int i = 3; i <= l; i ++) { + dp[i][1] = singleDigit(s, i) ? dp[i - 1][1] + dp[i - 1][2] : 0; + dp[i][2] = doubleDigit(s, i) ? dp[i - 2][1] + dp[i - 2][2] : 0; + } + return dp[l][1] + dp[l][2]; + } + boolean singleDigit (String s, int i) { + int n = Integer.parseInt(s.substring(i - 1, i)); + return n > 0; + } + boolean doubleDigit (String s, int i) { + int n = Integer.parseInt(s.substring(i - 2, i)); + return n <= 26 && n >= 10; + } +} +// @lc code=end + diff --git a/Week_05/G20200343030563/LeetCode_647_563.java b/Week_05/G20200343030563/LeetCode_647_563.java new file mode 100644 index 00000000..e4909a3f --- /dev/null +++ b/Week_05/G20200343030563/LeetCode_647_563.java @@ -0,0 +1,38 @@ +class Solution { + int n; + int m; + public int numIslands(char[][] grid) { + n = grid.length; + if (n == 0) return 0; + m = grid[0].length; + int count = 0; + + for (int i = 0; i < n; i++) + for (int j = 0; j < m; j++) { + if (grid[i][j] == '1') { + count++; + PutO(i, j, grid); + //õݹ + } + + } + + return count; + } + + private void PutO(int i, int j, char[][] grid) { + //ֹ ݹĵݿͣˣʼ + if (i >= n || j >= m || i < 0 || j < 0 || grid[i][j] == '0') return;; + + //ǰ㴦 + grid[i][j] = '0'; + + //һ + PutO(i+1, j, grid); + PutO(i-1, j, grid); + PutO(i, j+1, grid); + PutO(i, j-1, grid); + + //ݹһӰ + } +} \ No newline at end of file diff --git a/Week_05/G20200343030563/LeetCode_64_563.java b/Week_05/G20200343030563/LeetCode_64_563.java new file mode 100644 index 00000000..13d6f8c9 --- /dev/null +++ b/Week_05/G20200343030563/LeetCode_64_563.java @@ -0,0 +1,28 @@ +class Solution { + public int minPathSum(int[][] grid) { + int m = grid.length; + int n = grid[0].length; + if (grid == null || m == 0) return 0; + + int[][] dp = new int[m][n]; + + dp[m-1][n-1] = grid[m-1][n-1]; + + //ұһ j = n-1 + for (int i = m-2; i>= 0; i--) + dp[i][n-1] = dp[i+1][n-1] + grid[i][n-1]; + + //±һ i =m-1 + for (int j = n-2; j>= 0; j--) { + dp[m-1][j] = dp[m-1][j+1] + grid[m-1][j]; + } + for (int i = m-2; i>= 0; i--) + for (int j = n-2; j>= 0; j--) { + dp[i][j] = Math.min(dp[i+1][j], dp[i][j+1]) + grid[i][j]; + } + + + return dp[0][0]; + + } +} \ No newline at end of file diff --git a/Week_05/G20200343030569/LeetCode_221_569.java b/Week_05/G20200343030569/LeetCode_221_569.java new file mode 100644 index 00000000..2b62b6ac --- /dev/null +++ b/Week_05/G20200343030569/LeetCode_221_569.java @@ -0,0 +1,62 @@ + +/* + * 221. Maximal Square + * 最大正方形 + * + * 在一个由 0 和 1 组成的二维矩阵内,找到只包含 1 的最大正方形,并返回其面积。 + +示例: + +输入: + +1 0 1 0 0 +1 0 1 1 1 +1 1 1 1 1 +1 0 0 1 0 + +输出: 4 + + + */ +public class LeetCode_221_569 { + + public static void main(String[] args) { + // TODO Auto-generated method stub + char[][] matrix = { + { '1', '0', '1', '0', '0' }, + { '1', '0', '1', '1', '1' }, + { '1', '1', '1', '1', '1' }, + { '1', '0', '0', '1', '0' } + }; + + int result = new LeetCode_221_569().new Solution().maximalSquare(matrix); + System.out.println(result); + } + + /* + * 看来的别人的思路,关键在于状态方程 + * 状态数组dp[i][j],里面放的是最大长方形边长 + * 状态方程: dp(i, j)=min(dp(i−1, j), dp(i−1, j−1), dp(i, j−1))+1 + * if (grid(i, j) == 1) { + dp(i, j) = min(dp(i-1, j), dp(i, j-1), dp(i-1, j-1)) + 1; + } + */ + + class Solution { + public int maximalSquare(char[][] matrix) { + int rows = matrix.length; + int cols = matrix[0].length; + int[][] dp = new int[rows + 1][cols + 1]; + int maxsqlen = 0; + for (int i = 1; i <= rows; i++) { + for (int j = 1; j <= cols; j++) { + if (matrix[i-1][j-1] == '1'){ + dp[i][j] = Math.min(Math.min(dp[i][j - 1], dp[i - 1][j]), dp[i - 1][j - 1]) + 1; + maxsqlen = Math.max(maxsqlen, dp[i][j]); + } + } + } + return maxsqlen * maxsqlen; + } + } +} diff --git a/Week_05/G20200343030569/LeetCode_621_569.java b/Week_05/G20200343030569/LeetCode_621_569.java new file mode 100644 index 00000000..bd2c20d0 --- /dev/null +++ b/Week_05/G20200343030569/LeetCode_621_569.java @@ -0,0 +1,63 @@ +import java.util.Arrays; + +/* + * 621. Task Scheduler + * 任务调度器 + * + * 给定一个用字符数组表示的 CPU 需要执行的任务列表。其中包含使用大写的 A - Z 字母表示的26 种不同种类的任务。 + * 任务可以以任意顺序执行,并且每个任务都可以在 1 个单位时间内执行完。CPU 在任何一个单位时间内都可以执行一 + * 个任务,或者在待命状态。 + +然而,两个相同种类的任务之间必须有长度为 n 的冷却时间,因此至少有连续 n 个单位时间内 CPU 在执行不同的任务, +或者在待命状态。 + +你需要计算完成所有任务所需要的最短时间。 + +示例 1: + +输入: tasks = ["A","A","A","B","B","B"], n = 2 +输出: 8 +执行顺序: A -> B -> (待命) -> A -> B -> (待命) -> A -> B. +注: + +任务的总个数为 [1, 10000]。 +n 的取值范围为 [0, 100]。 + + */ +public class LeetCode_621_569 { + + public static void main(String[] args) { + char[] tasks = { 'A', 'A', 'A', 'B', 'B', 'B' }; + int n = 2; + int result = new LeetCode_621_569().new Solution().leastInterval(tasks, n); + System.out.println( result ); + } + + /* + * 解题思路: + * 1、将任务按类型分组,正好A-Z用一个int[26]保存任务类型个数 + * 2、对数组进行排序,优先排列个数(count)最大的任务, + * 如题得到的时间至少为 retCount =(count-1)* (n+1) + 1 ==> A->X->X->A->X->X->A(X为其他任务或者待命) + * 3、再排序下一个任务,如果下一个任务B个数和最大任务数一致, + * 则retCount++ ==> A->B->X->A->B->X->A->B + * 4、如果空位都插满之后还有任务,那就随便在这些间隔里面插入就可以,因为间隔长度肯定会大于n,在这种情况下就是任务的总数是最小所需时间 + * + */ + class Solution { + public int leastInterval(char[] tasks, int n) { + int[] taskCounts = new int[26]; + for(char task: tasks) { + taskCounts[task-'A']++; + } + Arrays.sort(taskCounts); + int lastCount = 0; //那最后一个桶大小如何求呢,很明显就是 拥有最多数任务的个数 + for (int i = 25; i >= 0; i--) { + if(taskCounts[i] != taskCounts[25]){ + break; + } + lastCount++; + } + return Math.max((taskCounts[25] - 1) * (n + 1) + lastCount, tasks.length); + } + } +} diff --git a/Week_05/G20200343030569/LeetCode_64_569.java b/Week_05/G20200343030569/LeetCode_64_569.java new file mode 100644 index 00000000..beb025af --- /dev/null +++ b/Week_05/G20200343030569/LeetCode_64_569.java @@ -0,0 +1,59 @@ +/* + * 64. Minimum Path Sum + * 最小路径和 + * + * + * 给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。 + +说明:每次只能向下或者向右移动一步。 + +示例: + +输入: +[ +  [1,3,1], + [1,5,1], + [4,2,1] +] +输出: 7 +解释: 因为路径 1→3→1→1→1 的总和最小。 + + */ +public class LeetCode_64_569 { + + public static void main(String[] args) { + // TODO Auto-generated method stub + int[][] grid = { + {1, 3, 1 }, + {1, 5, 1}, + {4, 2, 1} + }; + int result = new LeetCode_64_569().new Solution().minPathSum(grid); + System.out.println( result); + } + + /* + * 从终点到起点 + * 分治: problem[i,j] = min( subproblem[i+1,j], subproblem[i,j+1] ) + * 状态表: grid[i,j] + * dp方程: f[i,j] = min( f[i+1,j], f[i,j+1] ) + grid[i,j]; + * + */ + + class Solution { + public int minPathSum(int[][] grid) { + for(int i = grid.length -1; i>=0; i-- ) { + for( int j = grid[0].length-1; j>=0; j-- ) { + if( i == grid.length-1 && j != grid[0].length -1 ) { + grid[i][j] = grid[i][j] + grid[i][j+1]; + }else if( j == grid[0].length-1 && i != grid.length-1 ) { + grid[i][j] = grid[i][j] + grid[i+1][j]; + }else if( i != grid.length-1 && j != grid[0].length-1 ) { + grid[i][j] = Math.min(grid[i+1][j], grid[i][j+1]) + grid[i][j]; + } + } + } + return grid[0][0]; + } + } +} diff --git a/Week_05/G20200343030569/LeetCode_91_569.java b/Week_05/G20200343030569/LeetCode_91_569.java new file mode 100644 index 00000000..d2ff1521 --- /dev/null +++ b/Week_05/G20200343030569/LeetCode_91_569.java @@ -0,0 +1,67 @@ + +/* + * 91. Decode Ways + * 解码方法 + * 一条包含字母 A-Z 的消息通过以下方式进行了编码: + +'A' -> 1 +'B' -> 2 +... +'Z' -> 26 +给定一个只包含数字的非空字符串,请计算解码方法的总数。 + +示例 1: + +输入: "12" +输出: 2 +解释: 它可以解码为 "AB"(1 2)或者 "L"(12)。 +示例 2: + +输入: "226" +输出: 3 +解释: 它可以解码为 "BZ" (2 26), "VF" (22 6), 或者 "BBF" (2 2 6) 。 + + + */ +public class LeetCode_91_569 { + + public static void main(String[] args) { + // TODO Auto-generated method stub + String s = "12031"; + int result = new LeetCode_91_569().new Solution().numDecodings(s); + System.out.println( result ); + } + + /* + * 自底而上 + * 分治:problem[i] = subproblem[i+1] + subproblem[i+2](i+2如果该双字符不大于26,则i+2=0) + * 状态数组: dp[n+1] + * dp方程: + * 如果s[i]=0, dp[i]=0 + * 如果s[i]+s[i+1] <= 26, dp[i] = dp[i+1]+dp[i+2] + * 如果s[i]+s[i+1] > 26, dp[i] = dp[i+1] + * + */ + class Solution { + public int numDecodings(String s) { + int n = s.length(); + if( n <= 0) + return 0; + + int[] dp = new int[n+1]; + dp[n] = 1; + dp[n-1] = s.charAt(n-1) != '0' ? 1 : 0; + + for( int i = n-2; i >= 0; i-- ) { + if ( s.charAt(i) == '0') { + dp[i] = 0; + } else if (Integer.parseInt(s.substring(i,i+2)) <= 26 ) { + dp[i] = dp[i+1] + dp[i+2]; + } else { + dp[i] = dp[i+1]; + } + } + return dp[0]; + } + } +} diff --git a/Week_05/G20200343030571/LeetCode_1143_571.go b/Week_05/G20200343030571/LeetCode_1143_571.go new file mode 100644 index 00000000..31f78c67 --- /dev/null +++ b/Week_05/G20200343030571/LeetCode_1143_571.go @@ -0,0 +1,104 @@ +package main + +/* + * @lc app=leetcode.cn id=1143 lang=golang + * + * [1143] 最长公共子序列 + * + * https://leetcode-cn.com/problems/longest-common-subsequence/description/ + * + * algorithms + * Medium (58.57%) + * Likes: 70 + * Dislikes: 0 + * Total Accepted: 10.8K + * Total Submissions: 18.5K + * Testcase Example: '"abcde"\n"ace"' + * + * 给定两个字符串 text1 和 text2,返回这两个字符串的最长公共子序列。 + * + * 一个字符串的 子序列 是指这样一个新的字符串:它是由原字符串在不改变字符的相对顺序的情况下删除某些字符(也可以不删除任何字符)后组成的新字符串。 + * 例如,"ace" 是 "abcde" 的子序列,但 "aec" 不是 "abcde" + * 的子序列。两个字符串的「公共子序列」是这两个字符串所共同拥有的子序列。 + * + * 若这两个字符串没有公共子序列,则返回 0。 + * + * + * + * 示例 1: + * + * 输入:text1 = "abcde", text2 = "ace" + * 输出:3 + * 解释:最长公共子序列是 "ace",它的长度为 3。 + * + * + * 示例 2: + * + * 输入:text1 = "abc", text2 = "abc" + * 输出:3 + * 解释:最长公共子序列是 "abc",它的长度为 3。 + * + * + * 示例 3: + * + * 输入:text1 = "abc", text2 = "def" + * 输出:0 + * 解释:两个字符串没有公共子序列,返回 0。 + * + * + * + * + * 提示: + * + * + * 1 <= text1.length <= 1000 + * 1 <= text2.length <= 1000 + * 输入的字符串只含有小写英文字符。 + * + * + */ + +// @lc code=start + +/* + DP方程 + if s1[len-1] != s2[len-1] + LCS[s1,s2] = Max(LCS[s1-1, s2], LCS[s1, s2-1]) + if s1[len-1] == s2[len-1] + LCS[s1,s2] = LCS[s1-1, s2-1] + 1 +*/ +func longestCommonSubsequence(text1 string, text2 string) int { + m, n := len(text1), len(text2) + if m == 0 || n == 0 { + return 0 + } + dp := makeSlice(m+1, n+1) + + for i := 1; i <= m; i++ { + for j := 1; j <= n; j++ { + if text1[i-1] == text2[j-1] { + dp[i][j] = dp[i-1][j-1] + 1 + } else { + dp[i][j] = maxInt(dp[i-1][j], dp[i][j-1]) + } + } + } + return dp[m][n] +} + +func maxInt(a, b int) int { + if a > b { + return a + } + return b +} + +func makeSlice(m, n int) [][]int { + sl := make([][]int, m) + for i := range sl { + sl[i] = make([]int, n) + } + return sl +} + +// @lc code=end diff --git a/Week_05/G20200343030571/LeetCode_120_571.go b/Week_05/G20200343030571/LeetCode_120_571.go new file mode 100644 index 00000000..37558d43 --- /dev/null +++ b/Week_05/G20200343030571/LeetCode_120_571.go @@ -0,0 +1,84 @@ +package main + +/* + * @lc app=leetcode.cn id=120 lang=golang + * + * [120] 三角形最小路径和 + * + * https://leetcode-cn.com/problems/triangle/description/ + * + * algorithms + * Medium (63.78%) + * Likes: 333 + * Dislikes: 0 + * Total Accepted: 44.5K + * Total Submissions: 69.6K + * Testcase Example: '[[2],[3,4],[6,5,7],[4,1,8,3]]' + * + * 给定一个三角形,找出自顶向下的最小路径和。每一步只能移动到下一行中相邻的结点上。 + * + * 例如,给定三角形: + * + * [ + * ⁠ [2], + * ⁠ [3,4], + * ⁠ [6,5,7], + * ⁠ [4,1,8,3] + * ] + * + * + * 自顶向下的最小路径和为 11(即,2 + 3 + 5 + 1 = 11)。 + * + * 说明: + * + * 如果你可以只使用 O(n) 的额外空间(n 为三角形的总行数)来解决这个问题,那么你的算法会很加分。 + * + */ + +// @lc code=start + +/* + dp[i,j] = dp[i,j] + min(dp[i+1,j], dp[i+1,j+1]) +*/ +/* func minimumTotal(triangle [][]int) int { + row := len(triangle) + dp := make([][]int, row) + copy(dp, triangle) + + for i := row - 2; i >= 0; i-- { + for j := range dp[i] { + dp[i][j] = dp[i][j] + minInt(dp[i+1][j], dp[i+1][j+1]) + } + } + return dp[0][0] + +} */ + +/* 空间优化:将dp数组简化为一维 */ +func minimumTotal(triangle [][]int) int { + row := len(triangle) + maxCol := len(triangle[row-1]) + dp := make([]int, maxCol) + copy(dp, triangle[row-1]) + + for i := row - 2; i >= 0; i-- { + for j := 0; j < len(triangle[i]); j++ { + dp[j] = triangle[i][j] + minInt(dp[j], dp[j+1]) + } + } + return dp[0] +} + +func minInt(x, y int) int { + if x < y { + return x + } + return y +} + +/* func main() { + inPut := [][]int{{1}, {2, 3}} + println(minimumTotal(inPut)) +} +*/ +// @lc code=end diff --git a/Week_05/G20200343030571/LeetCode_63_571.go b/Week_05/G20200343030571/LeetCode_63_571.go new file mode 100644 index 00000000..a59902b8 --- /dev/null +++ b/Week_05/G20200343030571/LeetCode_63_571.go @@ -0,0 +1,212 @@ +package main + +/* + * @lc app=leetode.cn id=63 lang=golang + * + * [63] 不同路径 I + * + * https://letcoe-cn.com/problems/unique-paths-ii/description/ + * + * algorithms + * Medium (32.9%) + * Likes: 241 + *Dislikes: 0 + * Total Accepted: 45.4K + *otal Submissions: 139.4K + * Testcase Example: '[[0,0,0],[0,1,0],[0,0,0]' + * + * 一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为Start” )。 + * + *机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下中标记为“Finish”)。 + * + *现在考虑网格中有障碍物。那么从左上角到右下角将会有多条不同的路径? + * + * + * + * 网格中的障物和空位置分别用 1 和 0来表示。 + * + * 说明:  n 的值均不超过 100。 + * + * 示例 : + * + * 输入: + * [ + * [0,0,] + * [,10], + * [0,0,] + * ] + * 输出: 2 + * 解释: + *3x3 网格的正中间有一个障碍物。 + *从左上角到右下角一共有 2 条不同的路径: + *1 向右 -> 向右 -> 向下 -> 向下 +*2. 向下 -> 向下 -> 向右 -> 向右 + * + + * + +//@lc code=start + +/* + 思: +分治,将地图中一个点终点的路径这个总问题,不断的化解为【他所能一步到的点到终点的路径的和】的子问题 +*/ + +/* +1. 无效区域 0 +2 到了终点 1 +3. 否则 递归到下一层 +*/ + +func uniquePathsWithObstacles1(obstacleGrid [][]int) int { + if obstacleGrid == nil || + obstacleGrid[len(obstacleGrid)-1][len(obstacleGrid[0])-1] == 1 { + return 0 + } + + return countPaths1(obstacleGrid, 0, 0) +} + +func countPaths1(obstacleGrid [][]int, row int, col int) int { + if row >= len(obstacleGrid) || col >= len(obstacleGrid[0]) || obstacleGrid[row][col] == 1 { + return 0 + } + + if row == len(obstacleGrid)-1 && col == len(obstacleGrid[0])-1 { + return 1 + } + + return countPaths1(obstacleGrid, row+1, col) + countPaths1(obstacleGrid, row, col+1) +} + +/* +思路: + 记忆化搜索。在思路1的前提下,记录中间过程的结果。以达到减重复计算的优化目的 + + 注意golang的二维切片的初始化,这块没有办法,较繁琐 +*/ + +func uniquePathsWithObstacles2(obstacleGrid [][]int) int { + if obstacleGrid == nil || + obstacleGrid[len(obstacleGrid)-1][len(obstacleGrid[0])-1] == 1 { + return 0 + } + memo := make([][]int, len(obstacleGrid)) + + for i := range memo { + memo[i] = make([]int, len(obstacleGrid[0])) + } + + for i, tempSlice := range memo { + for j := range tempSlice { + memo[i][j] = -1 + } + } + + return countPaths2(obstacleGrid, memo, 0, 0) +} + +func countPaths2(ob, memo [][]int, row int, col int) int { + if row >= len(ob) || col >= len(ob[0]) || ob[row][col] == 1 { + return 0 + } + + if row == len(ob)-1 && col == len(ob[0])-1 { + return 1 + } + + if memo[row][col] != -1 { + return memo[row][col] + } + + memo[row][col] = countPaths2(ob, memo, row+1, col) + countPaths2(ob, memo, row, col+1) + return memo[row][col] +} + +/* + 思路3 + DP,自底向上 + 注意并尽量利用golang中以零值初始化的特性 +*/ + +func uniquePathsWithObstacles3(obstacleGrid [][]int) int { + if obstacleGrid == nil { + return 0 + } + row, col := len(obstacleGrid), len(obstacleGrid[0]) + if row == 0 || col == 0 || obstacleGrid[0] == nil { + return 0 + } + if obstacleGrid[0][0] == 1 || obstacleGrid[row-1][col-1] == 1 { + return 0 + } + dp := makeSlice(row, col) //二维数组,且元素全部初始化为0 + + for i := range dp[0] { + if obstacleGrid[0][i] == 1 { + break + } + dp[0][i] = 1 + } + for i := range dp { + if obstacleGrid[i][0] == 1 { + break + } + dp[i][0] = 1 + } + + for i := 1; i < row; i++ { + for j := 1; j < col; j++ { + if obstacleGrid[i][j] == 0 { + dp[i][j] = dp[i-1][j] + dp[i][j-1] + } + } + } + + return dp[row-1][col-1] +} + +/* func makeSlice(row, col int) [][]int { + slice := make([][]int, row) + for i := range slice { + slice[i] = make([]int, col) + } + return slice +} */ //刷题的时候在同一包内别处有声明,实现一致 + +/* + 思路4 + dp优化,将dp数组从二维简化为一维,优化依据是: + 每次迭代中计算路径之后,上一层的计算结果可以丢弃 +*/ + +func uniquePathsWithObstacles4(obstacleGrid [][]int) int { + if obstacleGrid == nil { + return 0 + } + row, col := len(obstacleGrid), len(obstacleGrid[0]) + if row == 0 || col == 0 || obstacleGrid[0] == nil { + return 0 + } + if obstacleGrid[0][0] == 1 || obstacleGrid[row-1][col-1] == 1 { + return 0 + } + + dp := make([]int, col) + dp[0] = 1 + + for i := 0; i < row; i++ { + for j := 0; j < col; j++ { + if obstacleGrid[i][j] == 0 { + if j > 0 { + dp[j] += dp[j-1] + } + } else { // 路障 + dp[j] = 0 + } + } + } + return dp[col-1] +} + +// @lc code=end diff --git a/Week_05/G20200343030573/LeetCode_64_573.py b/Week_05/G20200343030573/LeetCode_64_573.py new file mode 100644 index 00000000..08ccb477 --- /dev/null +++ b/Week_05/G20200343030573/LeetCode_64_573.py @@ -0,0 +1,32 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- + +import sys + +__author__ = "Onceabu" +__version__ = "v1.0" + +""" + Time + describe +""" + +reload(sys) +sys.setdefaultencoding('utf-8') + + +class Solution(object): + def minPathSum(self, grid): + """ + :type grid: List[List[int]] + :rtype: int + """ + # row行 + # col列 + row, col = len(grid), len(grid[0]) + dp = [0] + [sys.maxint] * (col - 1) + for r in range(row): + dp[0] = dp[0] + grid[r][0] + for c in range(1, col): + dp[c] = min(dp[c - 1], dp[c]) + grid[r][c] + return dp[-1] diff --git a/Week_05/G20200343030573/LeetCode_91_573.py b/Week_05/G20200343030573/LeetCode_91_573.py new file mode 100644 index 00000000..401af7e9 --- /dev/null +++ b/Week_05/G20200343030573/LeetCode_91_573.py @@ -0,0 +1,56 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- + +import sys + +__author__ = "Onceabu" +__version__ = "v1.0" + +""" + Time + describe +""" + +reload(sys) +sys.setdefaultencoding('utf-8') + + +class Solution(object): + def numDecodings(self, s): + """ + :type s: str + :rtype: int + """ + if s[0] == '0': + return 0 + a = b = 1 + for i in range(1, len(s)): + tmp = b + if s[i] == '0': + if s[i - 1] not in ['1', '2']: + return 0 + b = a + elif s[i - 1] == '1' or (s[i - 1] == '2' and '1' <= s[i] <= '6'): + b = a + b + a = tmp + return b + +# 复习斐波那契 +# def feb(n): +# if n <= 1: +# return n +# a, b = 0, 1 +# for i in range(1, n): +# a, b = b, a + b +# return b + + +# def feb(n): +# if n <= 1: +# return n +# return feb(n - 1) + feb(n - 2) +# +# +# if __name__ == '__main__': +# for i in range(10): +# print feb(i) diff --git a/Week_05/G20200343030575/LeetCode_64_575.swift b/Week_05/G20200343030575/LeetCode_64_575.swift new file mode 100644 index 00000000..171d5289 --- /dev/null +++ b/Week_05/G20200343030575/LeetCode_64_575.swift @@ -0,0 +1,31 @@ +/* + * @lc app=leetcode.cn id=64 lang=swift + * + * [64] 最小路径和 + */ + +// @lc code=start +class Solution { + func minPathSum(_ grid: [[Int]]) -> Int { + guard grid.count > 1 else { + return grid[0].reduce(0, +) + } + + var results = Array.init(repeating: 0, count: grid[0].count) + var sum = 0 + for i in 0.. Int { + guard let first = s.first, first != "0" else { + return 0 + } + + var results = Array.init(repeating: 0, count: s.count + 1) + results[0] = 1 + results[1] = 1 + for i in 1.. CombineResult{ + if second == "0" { + if first == "1" || first == "2" { + return .sameAsLastSecond + }else{ + return .notValid + } + }else{ + if first == "1" || (first == "2" && second >= "1" && second <= "6") { + return .sumOfPrevios + }else{ + return .sameAsLast + } + } + } +} +// @lc code=end + diff --git a/Week_05/G20200343030577/LeetCode_64_577.go b/Week_05/G20200343030577/LeetCode_64_577.go new file mode 100644 index 00000000..e6a1ab09 --- /dev/null +++ b/Week_05/G20200343030577/LeetCode_64_577.go @@ -0,0 +1,70 @@ +package leetcode + +/* + * @lc app=leetcode.cn id=64 lang=golang + * + * [64] 最小路径和 + * + * https://leetcode-cn.com/problems/minimum-path-sum/description/ + * + * algorithms + * Medium (64.44%) + * Likes: 403 + * Dislikes: 0 + * Total Accepted: 66.4K + * Total Submissions: 102.4K + * Testcase Example: '[[1,3,1],[1,5,1],[4,2,1]]' + * + * 给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。 + * + * 说明:每次只能向下或者向右移动一步。 + * + * 示例: + * + * 输入: + * [ + * [1,3,1], + * ⁠ [1,5,1], + * ⁠ [4,2,1] + * ] + * 输出: 7 + * 解释: 因为路径 1→3→1→1→1 的总和最小。 + * + * + */ +// create time: 2020-03-15 22:07 +// @lc code=start +func minPathSum(grid [][]int) int { + return minPathSumDP(grid) +} + +func minPathSumDP(grid [][]int) int { + // 处理边界 + if len(grid) == 0 || len(grid[0]) == 0 { + return 0 + } + min := func(a, b int) int { + if a < b { + return a + } + return b + } + // 构造dp空间 + m, n := len(grid), len(grid[0]) + dp := make([]int, n) + // 初始化dp + dp[0] = grid[0][0] + for i := 1; i < n; i++ { + dp[i] = dp[i-1] + grid[0][i] + } + // 递推 + for i := 1; i < m; i++ { + dp[0] += grid[i][0] + for j := 1; j < n; j++ { + dp[j] = grid[i][j] + min(dp[j], dp[j-1]) + } + } + return dp[n-1] +} + +// @lc code=end diff --git a/Week_05/G20200343030577/LeetCode_91_577.go b/Week_05/G20200343030577/LeetCode_91_577.go new file mode 100644 index 00000000..12cc8559 --- /dev/null +++ b/Week_05/G20200343030577/LeetCode_91_577.go @@ -0,0 +1,101 @@ +package leetcode + +/* + * @lc app=leetcode.cn id=91 lang=golang + * + * [91] 解码方法 + * + * https://leetcode-cn.com/problems/decode-ways/description/ + * + * algorithms + * Medium (22.96%) + * Likes: 311 + * Dislikes: 0 + * Total Accepted: 36.8K + * Total Submissions: 158.3K + * Testcase Example: '"12"' + * + * 一条包含字母 A-Z 的消息通过以下方式进行了编码: + * + * 'A' -> 1 + * 'B' -> 2 + * ... + * 'Z' -> 26 + * + * + * 给定一个只包含数字的非空字符串,请计算解码方法的总数。 + * + * 示例 1: + * + * 输入: "12" + * 输出: 2 + * 解释: 它可以解码为 "AB"(1 2)或者 "L"(12)。 + * + * + * 示例 2: + * + * 输入: "226" + * 输出: 3 + * 解释: 它可以解码为 "BZ" (2 26), "VF" (22 6), 或者 "BBF" (2 2 6) 。 + * + * + */ +// create time:2020-03-15 22:44 +// @lc code=start +func numDecodings(s string) int { + return numDecodingsDP(s) +} + +func numDecodingsDP(s string) int { + if len(s) == 0 { + return 0 + } + dp := make([]int, len(s)) + dp[0] = 1 + if s[0] == '0' { + dp[0] = 0 + } + for i := 1; i < len(s); i++ { + if !(s[i] >= '0' && s[i] <= '9') { + return 0 + } + if s[i] == '0' { + if s[i-1] == '1' || s[i-1] == '2' { + if i-2 >= 0 { + dp[i] = dp[i-2] + } else { + dp[i] = 1 + } + } else { + return 0 + } + continue + } + + if s[i-1] == '2' { + if s[i] >= '1' && s[i] <= '6' { + if i-2 >= 0 { + dp[i] = dp[i-1] + dp[i-2] + } else { + dp[i] = dp[i-1] + 1 + } + } else { + dp[i] = dp[i-1] + } + continue + } + + if s[i-1] == '1' { + if i-2 >= 0 { + dp[i] = dp[i-2] + dp[i-1] + } else { + dp[i] = dp[i-1] + 1 + } + continue + } + dp[i] = dp[i-1] + } + return dp[len(dp)-1] +} + +// @lc code=end diff --git a/Week_05/G20200343030577/NOTE.md b/Week_05/G20200343030577/NOTE.md index 50de3041..f4d00a97 100644 --- a/Week_05/G20200343030577/NOTE.md +++ b/Week_05/G20200343030577/NOTE.md @@ -1 +1,9 @@ -学习笔记 \ No newline at end of file +# 第5周学习心得 +### 创建时间:2020-03-15 23:37 + +## 动态递归一般步骤 +- 处理特殊情况 +- 构造dp空间 +- 初始化dp +- 递推 +- 返回最优解 \ No newline at end of file diff --git a/Week_05/G20200343030583/LeetCode_221_583.c b/Week_05/G20200343030583/LeetCode_221_583.c new file mode 100644 index 00000000..0966127b --- /dev/null +++ b/Week_05/G20200343030583/LeetCode_221_583.c @@ -0,0 +1,36 @@ +/* + * @lc app=leetcode id=221 lang=c + * + * [221] Maximal Square + */ +// transition dp[i][j] = min(dp[i-1][j],dp[i][j-1],dp[i-1][j-1]) +// note the the left-most column and top-most row can just form square with area 1. +// space complexity can be optimized according to the following link. +// https://leetcode.com/problems/maximal-square/discuss/61803/C%2B%2B-space-optimized-DP +// @lc code=start +#include +int maximalSquare(char** matrix, int matrixSize, int* matrixColSize){ + int dp[matrixSize][*matrixColSize]={0}; + int i,j,sz=0; + for(i = 0;i < matrixSize;i++){ + for(j = 0;j < *matrixColSize;j++){ + if(i != 0 || j != 0 || matrix[i][j] == '0'){ + dp[i][j] = matrix[i][j] - '0'; + } + else{ + dp[i][j] = min(dp[i-1][j],dp[i-1][j-1],dp[i][j-1]) + 1; + } + sz = dp[i][j] > sz ? dp[i][j] : sz; + } + } + return sz * sz; +} + +int min(int a, int b,int c){ + int min_num = a < b ? a : b; + return min_num < c ? min_num : c; +} + + +// @lc code=end + diff --git a/Week_05/G20200343030583/LeetCode_621_583.c b/Week_05/G20200343030583/LeetCode_621_583.c new file mode 100644 index 00000000..6e0191c7 --- /dev/null +++ b/Week_05/G20200343030583/LeetCode_621_583.c @@ -0,0 +1,62 @@ +/* + * @lc app=leetcode id=621 lang=c + * + * [621] Task Scheduler + * https://leetcode.com/problems/task-scheduler/discuss/104500/Java-O(n)-time-O(1)-space-1-pass-no-sorting-solution-with-detailed-explanation + * can also use priority queue to solve this problem, please refer to the solution, + * second one: https://leetcode.com/problems/task-scheduler/discuss/104496/concise-Java-Solution-O(N)-time-O(26)-space + */ + +// @lc code=start +#include + +int leastInterval(char* tasks, int tasksSize, int n){ + int counter[26] ={0}; + int i,max=0,maxCount; + for(i=0;i 0? emptySlot - avaiableTask:0; + + return tasksSize + idleSlot; + +} + +// devide into chunk and consider the number of tasks in each chunk +// insert less frequent tasks into the chunk +// Note that #most frequent tasks decides the #chunks, +// #chunks = #most frequent tasks - 1 +// n+1 is chunk size +// remember need to add #most frequent tasks in the end to finish them in cpu +int leastInterval(char* tasks, int tasksSize, int n){ + int counter[26] ={0}; + int i,max=0,maxCount; + for(i=0;i frameSize ? tasksSize : frameSize; + +} + +// @lc code=end + diff --git a/Week_05/G20200343030583/LeetCode_647_583.c b/Week_05/G20200343030583/LeetCode_647_583.c new file mode 100644 index 00000000..6e1ac3b1 --- /dev/null +++ b/Week_05/G20200343030583/LeetCode_647_583.c @@ -0,0 +1,37 @@ +/* + * @lc app=leetcode id=647 lang=c + * + * [647] Palindromic Substrings + */ + +// @lc code=start +#include + +int countSubstrings(char * s){ + int N = strlen(s); + if(N == 0){ + return 0; + } + int i,left,right,ans = 0; + // expand from center and there are 2*N -1 centers + for(i = 0;i < N;i++){ + ans += expand_palindromic(s,i,i); + ans += expand_palindromic(s,i,i+1); + } + return ans; +} + +int expand_palindromic(char* s,int left,int right){ + int count = 0; + int N = strlen(s); + while(left >= 0 && right < N && s[left] == s[right]){ + count++; + left--; + right++; + } + return count; +} + + +// @lc code=end + diff --git a/Week_05/G20200343030583/LeetCode_64_583.c b/Week_05/G20200343030583/LeetCode_64_583.c new file mode 100644 index 00000000..e93e3843 --- /dev/null +++ b/Week_05/G20200343030583/LeetCode_64_583.c @@ -0,0 +1,32 @@ +/* + * @lc app=leetcode id=64 lang=c + * + * [64] Minimum Path Sum + */ +// find the minimal sum of all numbers along its path => +// 路上的点到最后一个点的最小路径 = 从最下面的点走到最上面的最小路径 +// f[i,j] = min(f[i+1,j],f[i,j+1]) +// +// @lc code=start +#include +#include +int minPathSum(int** grid, int gridSize, int* gridColSize){ + int i, j; + for(i=1;i +// #include +// @lc code=start +int numDecodings(char * s){ + if(s == NULL) return 0; + int N = strlen(s); + if(N == 1){ + if(s[0]=='0'){ + return 0; + } + return 1; + } + // initilize the first two condition + int dp[N]; + if (s[0] != '0'){ + dp[0] = 1; + } + else{ + dp[0] = 0; + } + + int codeVal = 10 * (s[0] - '0') + (s[1] - '0'); + if(codeVal == 0 || (codeVal>26 && s[1]=='0')){ + dp[1] = 0; + } + else if(10 < codeVal && codeVal <= 26 && codeVal != 20){ + dp[1] = 2; + } + else dp[1] = dp[0]; + int i; + for(i = 2;i < N;i++){ + codeVal = 10 * (s[i-1] - '0') + (s[i] - '0'); + if((codeVal == 0) || (codeVal>26 && s[i]=='0')){ + dp[i] = 0; + } + else if(codeVal == 10 || codeVal == 20){ + dp[i] = dp[i-2]; + } + else if(10 < codeVal && codeVal <= 26){ + dp[i] = dp[i-1] + dp[i-2]; + } + else{ + // for 0 26 && s[i-1]!='0' + dp[i] = dp[i-1]; + } + + } + return dp[N-1]; +} + + + +// @lc code=end + diff --git a/Week_05/G20200343030583/NOTE.md b/Week_05/G20200343030583/NOTE.md index 50de3041..d63c8c26 100644 --- a/Week_05/G20200343030583/NOTE.md +++ b/Week_05/G20200343030583/NOTE.md @@ -1 +1,114 @@ -学习笔记 \ No newline at end of file +# Week 5 Dynamic Programming +1. **善用数学归纳法** +寻找重复性 => 找到最近最简方法,拆解成可重复解决的问题 +2. 避免人肉递归 => 画递归树 + +## DP: Divide & Conquer + optimal structure + +动态规划 和 递归或者分治 没有根本上的区别 (关键看有无最优子结构) +共性:找到重复子问题 +差异性:最优子结构、中途可以淘汰次优解 +three steps: +1. 化繁为简 => 各种子问题 +2. 定义好状态空间 +3. 状态转移方程 + +## Fibonacci +use **recursion** -> from top to bottom +```python +def fibonacci(n,memo): + if(n<=1): return n + if(memo[n] ==0): memo[n] = fibonacci(n-1) + fibonacci(n-2) + return memo[n] +``` + +Use **iteration** -> from bottom to top + +## Count the path +paths(start, end) = path(A,end) + path(B,end)
+path(A,end) = path(D,end) + path(C,end)
+path(B,end) = path(C,end) + path(E,end) + +状态转移方程 +```python +opt[i,j] = opt[i+1,j] + opt[i,j+1] +``` + +完整逻辑 +```python +if a[i.j] = ‘empty’: + opt[i,j] = opt[i+1,j] + opt[i,j+1] +else: opt[i,j] = 0 +``` + +Key points: +1. 最优子结构 opt[n] = best_of(opt[n-1],opt[n-2], ...) +2. 存储中间状态 +3. 状态转移方程 + +## `Largest common sequence` +Brute fore: list combination subsets of the string in text1 and compare each of them with text2 + +DP: 找重复子问题 +1. Text1 = “” text2 = 任意字符串 return “” +2. Text1 = “A” , text2 = 任意 return “A” if “A” in text2 else “” +3. Text1 = “.......A”, text2 = "...A” 从最后一个字符看起,因为最后一个字符是相同的,就是求”A”之前的最长子序列 + +Text1, text2 两个字符串排成一个矩阵的形式,比如 +| | A | B | A | Z | D | C | +|---|---|---|---|---|---|---| +| **B** | | | | | | | +| **A** | | | | | | | +| **C** | | | | | | | +| **B** | | | | | | | +| **A** | | | | | | | +| **D** | | | | | | | + +If text1[-1] != text2[-1]: LCS[text1,text2] = MAX(LCS[text1-1,text2], LCS[text1,text2-1])
+Note it actually is LCS[text1,text2] = MAX(LCS[text1-1,text2], LCS[text1,text2-1],LCS[text1-1,text2-1])
+But the case LCS[text1-1,text2-1] will be considered in LCS[text1-1,text2]
+ +If text1[-1] = text2[-1]: LCS[text1,text2] = LCS[text1-1,text2-1] + 1
+Note it actually is LCS[text1,text2] = MAX(LCS[text1-1,text2], LCS[text1,text2-1],LCS[text1-1,text2-1],LCS[text1-1,text2-1] + 1)
+But it can be proved that LCS[text1-1,text2-1] + 1 is always the max.
+ +## 爬楼梯问题 +如果相邻的两个步伐不能相同,思考如何去写状态方程 => 加多一个维度,参考后面的`house robber` + +## 三角形最小路径和 +1. brute force, 递归,n层:left or right: 2^n +2. DP + 从 2 走到下面的最小路径 即min(3走到下面的最小路径,4走到下面的最小路径),往下递推 + * 重复性(分治) problem(i,j) = min(sub(i+1,j),sub(I+1,j+1)) + a[i,j]) i is layer, j is left or right node + * 定义状态数组和状态转移方程 f[i,j]= min(f[i+1,j],f[i+1,j+1]) + a[i,j] + +## 最大子序列和 +1. Brute force: 列举起点和终点,n^2 +2. DP: + * 分治(子问题)从后面开始看,包括第i个index的数的最大和 max_sum(i) = MAX(max_sum(i-1),0) + a[i],max(max_sum(i-1),0) 指的是 subproblem 包括第i-1个index的数往前看的最大和,0即不包括第i-1个数=>最大子序和 = 当前元素自身最大,或者 包含之前后最大 + * 状态数组定义 f[i] + * DP方程:f[i] = max(f[i-1],0) + a[i] + +## Coin Change +有多少种不同的组合 = 上楼梯问题 +1. brute force 递归 11-1 or 11-2 or 11-5 再往下递推 广度优先遍历求解 +2. BFS +3. DP + * subproblems + * DP array f(n) = min(f(n-k) for k in [1,2,5]) + 1 + +## house robber +1 +```python +# a[i]: 0,...,i能偷到的max value: a[n-1] +# 要加上房子有没有被偷的信息:a[i][0,1]: 0: i偷, 1:不偷 +a[i][0] = max(a[i-1][0],a[i-1][1]) +a[i][1] = a[i-1][0] + nums[i] +``` + +2 +```python +# a[i]: 0,...,i能偷到的max value: max(a) +# a[i]:0,..,i天,且nums[i]必偷的最大值 +a[i] = max(a[i-1],a[i-2] + nums[i]) i-1天偷了第i天就不能偷了 +``` \ No newline at end of file diff --git a/Week_05/G20200343030585/LeetCode_120_585.py b/Week_05/G20200343030585/LeetCode_120_585.py new file mode 100644 index 00000000..4cccd1de --- /dev/null +++ b/Week_05/G20200343030585/LeetCode_120_585.py @@ -0,0 +1,58 @@ +# +# @lc app=leetcode.cn id=120 lang=python +# +# [120] 三角形最小路径和 +# +# 解题思路 +# 1.动态规划 +# 1.将塔型问题转化为从上面向下向右的问题 +# 2.重复子问题就是每次求当前值的最小路径,存在3中情况 +# 当前结点是最右边结点,只能从上面的路径来 dp[i][j] = dp[i-1][j] + dp[i][j] +# 当前结点是最左边结点,只能从上面的右边结点来, dp[i][j] = dp[i-1][j-1] + dp[i][j] +# 当前结点是中间节点,可以从两个结点过来,取最小值即可,因为取的是最小路径,不论从哪来到这个结点的后面的结果都一样, +# 只有前面的不同,所以只需要最小的结果就行 dp[i][j] = min(dp[i-1][j-1], dp[i-1][j]) + dp[i][j] +# 3.结果存在最后一行结果中,比大小就可以得到最小 +# 这里有一点需要理解就是每行的结点数是不一样的,不能用len(triangle[0])的结果 +# +# @lc code=start + +# bottom-up, O(n) space +# class Solution(object): +# def minimumTotal(self, triangle): +# if not triangle: +# return +# res = triangle[-1] +# # 从-2行开始到0行 +# for i in range(len(triangle)-2, -1, -1): +# # 循环每列结点 +# for j in range(len(triangle[i])): +# # 下一行的下一个值和下右边的值的最小值+当前结点的值 +# res[j] = min(res[j], res[j+1]) + triangle[i][j] +# return res[0] + + +# top-down +class Solution(object): + def minimumTotal(self, triangle): + """ + :type triangle: List[List[int]] + :rtype: int + """ + m = len(triangle) + + for i in range(1, m): + for j in range(len(triangle[i])): + if j == 0: + # 向下 + triangle[i][j] = triangle[i][j] + triangle[i-1][j] + elif j == len(triangle[i]) - 1: + triangle[i][j] = triangle[i][j] + triangle[i-1][j-1] + else: + # 向右 + triangle[i][j] = triangle[i][j] + min(triangle[i-1][j-1], triangle[i-1][j]) + + return min(triangle[-1]) + + +# @lc code=end + diff --git a/Week_05/G20200343030585/LeetCode_121_585.py b/Week_05/G20200343030585/LeetCode_121_585.py new file mode 100644 index 00000000..0c795e5c --- /dev/null +++ b/Week_05/G20200343030585/LeetCode_121_585.py @@ -0,0 +1,36 @@ +# +# @lc app=leetcode.cn id=121 lang=python +# +# [121] 买卖股票的最佳时机 +# +# 解题思路 +# 1.DP +# 1.subproblem 最大利润只会出现在最大利差之间,所以要找最大利差 +# 1.就是要找两个点,一个点是高点前的最低点,一个点是下一个低点前的最高点 +# 2.比较每次这样的利差,看那个最大 +# 2.dp数组 一个记录最小值,一个记录最大值 +# 3.dp方程 f(i) = f(max) - f(min) +# @lc code=start +class Solution(object): + def maxProfit(self, prices): + """ + :type prices: List[int] + :rtype: int + """ + + n = len(prices) + if n == 0: return 0 + + prev, cur, total = prices[0], 0, 0 + + for i in range(1, n): + cur = prices[i] + if prev > cur: + prev = cur + else: + total = max(total, cur - prev) + return total + + +# @lc code=end + diff --git a/Week_05/G20200343030585/LeetCode_122_585.py b/Week_05/G20200343030585/LeetCode_122_585.py new file mode 100644 index 00000000..c64902d2 --- /dev/null +++ b/Week_05/G20200343030585/LeetCode_122_585.py @@ -0,0 +1,53 @@ +# +# @lc app=leetcode.cn id=122 lang=python +# +# [122] 买卖股票的最佳时机 II +# +# 解题思路 +# 1.dp +# 1.subproblem 多次买卖的最大值,等于每次获利最大的和值 +# 2.dp数组 不需要,只需要知道前面的最小值和最大值就可以 +# 3.dp方程 f(n) = f(n-1) + f(n-2) +# 2.贪心 +# 1.只要每天有收益,就是总结果就是最好的,不用找最大的差值 + +# @lc code=start +class Solution(object): + def maxProfit(self, prices): + """ + :type prices: List[int] + :rtype: int + """ + + n = len(prices) + if n <= 1: + return 0 + + cur, prev,total = 0, prices[0], 0 + for i in range(1, n): + cur = prices[i] + total += max(0, cur - prev) + prev = cur + + return total + + +# class Solution(object): +# def maxProfit(self, prices): +# """ +# :type prices: List[int] +# :rtype: int +# """ +# if len(prices) == 0: +# return 0 +# length = len(prices) + +# total = 0 +# for i in range(length): +# if i - 1 >= 0 and prices[i] - prices[i-1] > 0: +# total += prices[i] - prices[i-1] + +# return total + +# @lc code=end + diff --git a/Week_05/G20200343030585/LeetCode_123_585.py b/Week_05/G20200343030585/LeetCode_123_585.py new file mode 100644 index 00000000..b4458e9f --- /dev/null +++ b/Week_05/G20200343030585/LeetCode_123_585.py @@ -0,0 +1,43 @@ +# +# @lc app=leetcode.cn id=123 lang=python +# +# [123] 买卖股票的最佳时机 III +# +# 解题思路 +# 1.DP +# 1.subproblem +# 1.只有一次买卖得到最大 +# 2.两次分两半产出最大 +# 3.f(n) = f(k) + f(n-k) +# 2.DP数组 dp[0][1] 0为小值,1为大值 +# 3.DP方程 f(n) = f(k) + f(n-k) +# 1. f(k) = max(f(i)) + +# @lc code=start +class Solution(object): + def maxProfit(self, prices): + """ + :type prices: List[int] + :rtype: int + """ + n = len(prices) + if n <= 1: + return 0 + + max_list = [] + cur, prev = 0, prices[0] + for i in range(1, n): + cur = prices[i] + if cur > prev : + max_list.append(cur - prev) + prev = cur + elif cur < prev: + prev = cur + + max_list.sort(reverse=True) + print(max_list) + return max_list[0] + max_list[1] + + +# @lc code=end + diff --git a/Week_05/G20200343030585/LeetCode_152_585.py b/Week_05/G20200343030585/LeetCode_152_585.py new file mode 100644 index 00000000..eca60545 --- /dev/null +++ b/Week_05/G20200343030585/LeetCode_152_585.py @@ -0,0 +1,38 @@ +# +# @lc app=leetcode.cn id=152 lang=python +# +# [152] 乘积最大子序列 +# +# 解题思路 +# 1.动态规划 +# 1.当前值肯定和上一个的值乘或不乘,乘或不乘产生一个最大值or最小值 +# 2.当当前值小于0时,为最小值,相反的情况为最大值 + +# @lc code=start +class Solution(object): + def maxProduct(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + + if not nums: + return 0 + + n = len(nums) + max_mul = nums[0] + imax = 1 + imin = 1 + for i in range(0, n): + if nums[i] < 0: + temp = imax + imax = imin + imin = temp + imax = max(imax * nums[i], nums[i]) + imin = min(imin * nums[i], nums[i]) + max_mul = max(max_mul, imax) + + return max_mul + +# @lc code=end + diff --git a/Week_05/G20200343030585/LeetCode_198_585.py b/Week_05/G20200343030585/LeetCode_198_585.py new file mode 100644 index 00000000..ca576927 --- /dev/null +++ b/Week_05/G20200343030585/LeetCode_198_585.py @@ -0,0 +1,88 @@ +# +# @lc app=leetcode.cn id=198 lang=python +# +# [198] 打家劫舍 +# +# 解题思路 +# 1.DP +# 1.subproblem 求更小数组里面的最大值 +# 2.状态数组定义 +# dp = [0][1] 0为不偷,1为偷两种情况 +# 2.DP方程 +# dp[i][0] = max(dp[i-1][0], dp[i-1][1]) +# dp[i][1] = dp[i-1][0] + nums[i] +# 2.DP +# 1.状态数组定义 +# dp = [0] 偷和不偷两种情况的最大值 +# 2.DP方程 +# dp[i] = max(dp[i-1], dp[i-2] + nums[i]) + +# @lc code=start +class Solution(object): + def rob(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + preMax = 0 + curMax = 0 + + for i in range(len(nums)): + temp = curMax + curMax = max(preMax + nums[i], curMax) + preMax = temp + + return curMax + + +# class Solution(object): +# def rob(self, nums): +# """ +# :type nums: List[int] +# :rtype: int +# """ +# n = len(nums) + +# if not nums: +# return 0 +# if n == 1: +# return nums[0] + +# dp = [0] * n +# dp[0] = nums[0] +# dp[1] = max(dp[0], nums[1]) +# for i in range(2, n): +# dp[i] = max(dp[i-1], dp[i-2] + nums[i]) + +# return dp[-1] + + + + +# class Solution(object): +# def rob(self, nums): +# """ +# :type nums: List[int] +# :rtype: int +# """ + +# if len(nums) == 0: +# return 0 + +# n = len(nums) +# # 0,1 0为不偷的列 1为偷的列 +# dp = [[0] * 2 for _ in range(n)] +# dp[0][0] = 0 +# dp[0][1] = nums[0] + +# for i in range(1,len(nums)): +# # 我这一次不偷就可以记录上一次偷的最大值 +# dp[i][0] = max(dp[i-1][0], dp[i-1][1]) +# dp[i][1] = dp[i-1][0] + nums[i] + +# return max(dp[n-1][0], dp[n-1][1]) + + + +# @lc code=end + diff --git a/Week_05/G20200343030585/LeetCode_213_585.py b/Week_05/G20200343030585/LeetCode_213_585.py new file mode 100644 index 00000000..9bc60543 --- /dev/null +++ b/Week_05/G20200343030585/LeetCode_213_585.py @@ -0,0 +1,75 @@ +# +# @lc app=leetcode.cn id=213 lang=python +# +# [213] 打家劫舍 II +# +# 解题思路 +# 1.DP +# 1.subproblem 类似I的情况,遇到每家都可以打劫和不打劫一家 +# 最大值是打劫和不打劫中的最大值 +# 2.DP数组 +# 1.这里只需要上一次的最大值,和前一次的最大值,就不需要数组 +# 2.特殊的地方是,这里最后一家和第一家只能选一个,那么就存在两次 +# 处理,第一次只取第一家的,第二次只取最后一家的 +# 3.DP方程 +# cur = max(cur, prev+num[i]) cur是上一次的最大值,prev为前一次的最大值 + +# @lc code=start +class Solution(object): + def rob(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + + # 0,1 0为不偷的列 1为偷的列 + def _rob(nums): + prev = 0 + cur = 0 + + for num in nums: + # 我这一次不偷就可以记录上一次偷的最大值 + cur, prev = max(cur, prev + num), cur + + return cur + + return max(_rob(nums[:-1]), _rob(nums[1:])) if len(nums) != 1 else nums[0] + + + + +# class Solution(object): +# def rob(self, nums): +# """ +# :type nums: List[int] +# :rtype: int +# """ +# if len(nums) == 0: +# return 0 +# if len(nums) == 1: +# return nums[0] + +# n = len(nums) +# # 0,1 0为不偷的列 1为偷的列 +# dp = [[0] * 2 for _ in range(n)] +# dp[0][0] = 0 +# dp[0][1] = nums[0] + +# for i in range(1,len(nums)): +# # 我这一次不偷就可以记录上一次偷的最大值 +# dp[i][0] = max(dp[i-1][0], dp[i-1][1]) +# if i != n - 1: +# dp[i][1] = dp[i-1][0] + nums[i] + +# dp1 = [[0] * 2 for _ in range(n)] +# dp1[n-1][0] = 0 +# dp1[n-1][1] = nums[n-1] +# for i in range(n-2, -1, -1): +# # 我这一次不偷就可以记录上一次偷的最大值 +# dp1[i][0] = max(dp1[i+1][0], dp1[i+1][1]) +# if i != 0: +# dp1[i][1] = dp1[i+1][0] + nums[i] + +# return max(dp[n-1][0], dp[n-1][1], dp1[0][0], dp1[0][1]) +# @lc code=end + diff --git a/Week_05/G20200343030585/LeetCode_221_585.py b/Week_05/G20200343030585/LeetCode_221_585.py new file mode 100644 index 00000000..3bc6ef45 --- /dev/null +++ b/Week_05/G20200343030585/LeetCode_221_585.py @@ -0,0 +1,44 @@ +# +# @lc app=leetcode.cn id=221 lang=python +# +# [221] 最大正方形 +# +# 解题思路 +# 1.动态规划 +# 1.subproblem 找正方形, +# 1、找到一个4个格子的正方形后在右下角标注+1 +# 2、找个4个相邻正方形后,格子里面就会是2,右下角+1=3 +# 2.DP数组 和matrix相同 +# 3.DP方程 +# dp[i][j] = min(dp[i-1][j], dp[i-1][j-1], dp[i][j-1]) + 1 +# +# +# @lc code=start +class Solution(object): + def maximalSquare(self, matrix): + """ + :type matrix: List[List[str]] + :rtype: int + """ + + if not matrix or len(matrix) == 0: + return 0 + + m, n = len(matrix), len(matrix[0]) + # +1 解决边界情况,就是只有一个元素不会循环问题 + dp = [[0]* (n + 1) for _ in range(m + 1)] + maxlen = 0 + + # +1 解决边界情况,就是只有一个元素不会循环问题 + for i in range(1, m + 1): + for j in range(1, n + 1): + # 判断角上是否是1,保证可以为正方形 + if matrix[i-1][j-1] == '1': + # matrix[i][j] = min(int(matrix[i-1][j]), int(matrix[i-1][j-1]), int(matrix[i][j-1])) + 1 + dp[i][j] = min(dp[i-1][j], dp[i-1][j-1], dp[i][j-1]) + 1 + maxlen = max(maxlen, dp[i][j]) + + return maxlen * maxlen + +# @lc code=end + diff --git a/Week_05/G20200343030585/LeetCode_32_585.py b/Week_05/G20200343030585/LeetCode_32_585.py new file mode 100644 index 00000000..6151aafd --- /dev/null +++ b/Week_05/G20200343030585/LeetCode_32_585.py @@ -0,0 +1,49 @@ +# +# @lc app=leetcode.cn id=32 lang=python +# +# [32] 最长有效括号 +# 官方题解 +# https://leetcode-cn.com/problems/longest-valid-parentheses/solution/zui-chang-you-xiao-gua-hao-by-leetcode/ +# 解题思路 +# 1.动态规划 +# 1.subproblem 循环匹配()括号 +# 2.DP数组 与字符串长度相同 +# 3.DP方程 +# dp[i] = sum(list) + + +# @lc code=start +class Solution(object): + def longestValidParentheses(self, s): + """ + :type s: str + :rtype: int + """ + + if not s: + return 0 + + n = len(s) + dp = [0] * n + dp[0] = 0 + maxans = 0 + + for i in range(1, n): + if s[i] == ')': + if s[i-1] == '(': + if i - 2 >= 0: + dp[i] = 2 + dp[i-2] + else: + dp[i] = 2 + elif i - dp[i-1] > 0 and s[i-dp[i-1] - 1] == '(': + if i-dp[i-1] >= 2: + dp[i] = dp[i-1] + 2 + dp[i - dp[i - 1] - 2] + else: + dp[i] = dp[i-1] + 2 + maxans = max(dp[i], maxans) + return maxans + + + +# @lc code=end + diff --git a/Week_05/G20200343030585/LeetCode_53_585.py b/Week_05/G20200343030585/LeetCode_53_585.py new file mode 100644 index 00000000..f5cc0f10 --- /dev/null +++ b/Week_05/G20200343030585/LeetCode_53_585.py @@ -0,0 +1,32 @@ +# +# @lc app=leetcode.cn id=53 lang=python +# +# [53] 最大子序和 +# 解题思路 +# 1.暴力求解 O(N^2) 遍历所有头和尾,头和尾都要是正数 +# 2.DP +# 1. 分治问题: max_sum(i) = max_sum(i-1) + nums[i] +# 2. 状态数组定义: f[i] +# 3.DP方程: f[i] = max(f[i-1], 0) + a[i] +# 求前面的最大值,如果小于0就不要前面的值 + +# @lc code=start +class Solution(object): + def maxSubArray(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + if not nums: + return 0 + + n = len(nums) + max_val = nums[0] + + for i in range(1, n): + if nums[i - 1] > 0: + nums[i] += nums[i-1] + max_val = max(max_val, nums[i]) + return max_val + +# @lc code=end diff --git a/Week_05/G20200343030585/LeetCode_621_585.py b/Week_05/G20200343030585/LeetCode_621_585.py new file mode 100644 index 00000000..d0b5312b --- /dev/null +++ b/Week_05/G20200343030585/LeetCode_621_585.py @@ -0,0 +1,35 @@ +# +# @lc app=leetcode.cn id=621 lang=python +# +# [621] 任务调度器 +# 官方解答 +# https://leetcode-cn.com/problems/task-scheduler/solution/ren-wu-diao-du-qi-by-leetcode/ + +# 1.动态规划 +# 直接看解答 +# +# @lc code=start +class Solution(object): + def leastInterval(self, tasks, n): + """ + :type tasks: List[str] + :type n: int + :rtype: int + """ + + map = [0] * 26 + for c in tasks: + map[ord(c) - ord('A')] += 1 + + map.sort() + max_val = map[25] - 1 # 间隔运行次数 + idle_slots = max_val * n # 总间隔时间 + for i in range(24, -1, -1): + if map[i] == 0: + continue + idle_slots -= min(map[i], max_val) + + return idle_slots + len(tasks) if idle_slots > 0 else len(tasks) + +# @lc code=end + diff --git a/Week_05/G20200343030585/LeetCode_62_585.py b/Week_05/G20200343030585/LeetCode_62_585.py new file mode 100644 index 00000000..33f3abf4 --- /dev/null +++ b/Week_05/G20200343030585/LeetCode_62_585.py @@ -0,0 +1,102 @@ +# +# @lc app=leetcode.cn id=62 lang=python +# +# [62] 不同路径 +# +# 解题思路 +# 1.动态规划 +# 1.重复子问题,每一次的path都来之上一阶段的路径结果 +# 2.无后效性,就是后面不会改变前面的结果 +# 3.最优子结构,这里不需要最优,需要所有解 +# 2.动态规划 +# 1、我们令 dp[i][j] 是到达 i, j 最多路径 +# 2、动态方程:dp[i][j] = dp[i-1][j] + dp[i][j-1] +# 3、注意,对于第一行 dp[0][j],或者第一列 dp[i][0],由于都是在边界,所以只能为 1 +# 每次从上面两种走法里面取和,下一步的走法等于上面走法 + 1,类似faboaral数列 +# 思路二 +# 优化一: +# 由于dp[i][j] = dp[i-1][j] + dp[i][j-1], +# 因此只需要保留当前行与上一行的数据 +# (在动态方程中,即pre[j] = dp[i-1][j]),两行,空间复杂度O(2n); +# 优化二: +# cur[j] += cur[j-1], 即cur[j] = cur[j] + cur[j-1] +# 等价于思路二-->> cur[j] = pre[j] + cur[j-1], +# 因此空间复杂度为O(n). + +# @lc code=start +class Solution(object): + def uniquePaths(self, m, n): + """ + cur为上一行的数据,然后直接在下一行里面使用,然后赋值 + """ + cur = [1] * n + for i in range(1, m): + for j in range(1, n): + cur[j] += cur[j-1] + return cur[-1] + +# class Solution(object): +# def uniquePaths(self, m, n): +# """ +# 计算每步的值,只需要当前节点前一个和上一个节点,等于只需要两行数据 +# pre为上一行数据,cur为当前行数据 +# """ +# pre = [1] * n +# cur = [1] * n +# for i in range(1, m): +# for j in range(1, n): +# cur[j] = pre[j] + cur[j-1] +# pre = cur[:] +# return pre[-1] + +# class Solution(object): +# def uniquePaths(self, m, n): +# """ +# :type m: int +# :type n: int +# :rtype: int +# """ +# # [1] * n 第一行,[1] + [0] * (n-1)构建matrix值, +# # 第一行和第一列的值为1 +# # m是行 n是列 +# dp = [[1]*n] + [[1]+[0] * (n-1) for _ in range(m-1)] +# # print(dp) + +# for i in range(1, m): +# for j in range(1, n): +# dp[i][j] = dp[i-1][j] + dp[i][j-1] + +# return dp[-1][-1] + + + + +# 超时 +# class Solution(object): +# def uniquePaths(self, m, n): +# """ +# :type m: int +# :type n: int +# :rtype: int +# """ +# if m == 0 or n == 0: +# return 0 +# def dp(down, right, path, res): +# if down == n - 1 and right == m - 1: +# res.append(path) +# return + +# if down + 1 < n: +# dp(down + 1, right, path + [(down + 1, right)], res) + +# if right + 1 < m: +# dp(down, right + 1, path + [(down, right + 1)], res) + +# res = [] +# dp(0, 0, [(0,0)], res) + +# return len(res) + + +# @lc code=end + diff --git a/Week_05/G20200343030585/LeetCode_63_585.py b/Week_05/G20200343030585/LeetCode_63_585.py new file mode 100644 index 00000000..3e684694 --- /dev/null +++ b/Week_05/G20200343030585/LeetCode_63_585.py @@ -0,0 +1,65 @@ +# -*- coding=utf-8 -*- +# +# @lc app=leetcode.cn id=63 lang=python +# +# [63] 不同路径 II +# +# 解题思路 +# 1.动态规划 +# 1.最优子结构 +# 2.重复子问题,不断左右找路径结果, +# 每次等于左边一步的次数+上面一步的次数 +# 3.无后效性 +# 复杂度分析 +# 时间复杂度 : O(M×N) 。长方形网格的大小是 M×N,而访问每个格点恰好一次。 +# 空间复杂度 : O(1)。我们利用 obstacleGrid 作为 DP 数组,因此不需要额外的空间。 + +# @lc code=start +class Solution(object): + def uniquePathsWithObstacles(self, obstacleGrid): + """ + :type obstacleGrid: List[List[int]] + :rtype: int + """ + if not obstacleGrid: + return 0 + + m = len(obstacleGrid) + n = len(obstacleGrid[0]) + + matrix = [[0] * n for _ in range(m)] + if obstacleGrid[0][0] == 1: + return 0 + else: + matrix[0][0] = 1 + + for i in range(1, n): + if obstacleGrid[0][i] == 1: + matrix[0][i] = 0 + else: + matrix[0][i] = matrix[0][i-1] + # print(matrix) + + # 第一列 + for j in range(1,m): + if obstacleGrid[j][0] == 1: + matrix[j][0] = 0 + else: + matrix[j][0] = matrix[j-1][0] + # print(matrix) + for i in range(1, m): + for j in range(1, n): + # print(matrix) + if obstacleGrid[i][j] == 1: + + matrix[i][j] = 0 + else: + matrix[i][j] = matrix[i-1][j] + matrix[i][j-1] + + return matrix[-1][-1] +# @lc code=end + +if __name__ == "__main__": + obj = Solution() + ret = obj.uniquePathsWithObstacles([[0,0],[1,1],[0,0]]) + print(ret) diff --git a/Week_05/G20200343030585/LeetCode_64_585.py b/Week_05/G20200343030585/LeetCode_64_585.py new file mode 100644 index 00000000..493bfd96 --- /dev/null +++ b/Week_05/G20200343030585/LeetCode_64_585.py @@ -0,0 +1,70 @@ +# +# @lc app=leetcode.cn id=64 lang=python +# +# [64] 最小路径和 +# +# 解题思路 +# 1.动态规划 +# 1. subproblem +# 每个结果值等于上一个元素和右一元素和当前元素的和最小 +# 所以为重复取最小值 +# 2.dp数组 记录每个的最小值,补充上一行和右一列 +# 3.dp方程 +# dp[i][j] = min(dp[i-1][j], dp[i][j-1]) + grid[i-1][j-1] + +# @lc code=start +# 性能略低 +# class Solution(object): +# def minPathSum(self, grid): +# """ +# :type grid: List[List[int]] +# :rtype: int +# """ +# if not grid: +# return 0 + +# m, n = len(grid), len(grid[0]) +# dp = [[float("inf")] * (n+1) for _ in range(m+1)] +# for i in range(1, m+1): +# for j in range(1, n+1): +# dp[i][j] = grid[i-1][j-1] +# if i==1 and j==1: +# continue +# dp[i][j] = min(dp[i-1][j], dp[i][j-1]) + grid[i-1][j-1] + + +# # print(dp) +# return dp[-1][-1] + + + +# class Solution(object): +# def minPathSum(self, grid): +# """ +# :type grid: List[List[int]] +# :rtype: int +# """ +# if not grid: +# return 0 + +# m, n = len(grid), len(grid[0]) +# # dp = [[float("inf")] * (n+1) for _ in range(m+1)] +# for i in range(0, m): +# for j in range(0, n): +# if i==0 and j==0: +# continue +# if i == 0: +# grid[i][j] = grid[i][j-1] + grid[i][j] +# elif j == 0 and i > 0: +# grid[i][j] = grid[i-1][j] + grid[i][j] +# else: +# grid[i][j] = min(grid[i-1][j], grid[i][j-1]) + grid[i][j] + + +# # print(grid) +# return grid[-1][-1] + + + +# @lc code=end + diff --git a/Week_05/G20200343030585/LeetCode_91_585.py b/Week_05/G20200343030585/LeetCode_91_585.py new file mode 100644 index 00000000..fa8e8cfc --- /dev/null +++ b/Week_05/G20200343030585/LeetCode_91_585.py @@ -0,0 +1,41 @@ +# +# @lc app=leetcode.cn id=91 lang=python +# +# [91] 解码方法 +# +# 解题思路 +# 1.动态规划 +# 1.subproblem +# dp[i] = dp[i-2] + dp[i-1] +# 1.任何字符为'0'返回0,不能解码 +# 2、前面两个数字存在于字典中,就是前面两种情况的和 dp[i] += dp[i-2] +# 3.如果前面两个不在字典中,就是dp[i] += dp[i-1] +# 2.dp数组 +# 3.dp方程 +# dp[i] = dp[i-2] + dp[i-1] + + +# @lc code=start +class Solution(object): + def numDecodings(self, s): + if not s: + return 0 + + dp = [0 for x in range(len(s) + 1)] + + # base case initialization + dp[0] = 1 + dp[1] = 0 if s[0] == "0" else 1 #(1) + + for i in range(2, len(s) + 1): + # One step jump + if 0 < int(s[i-1:i]) <= 9: #(2) + dp[i] += dp[i - 1] + # Two step jump + if 10 <= int(s[i-2:i]) <= 26: #(3) + dp[i] += dp[i - 2] + return dp[len(s)] + + +# @lc code=end + diff --git a/Week_05/G20200343030587/week05/src/main/java/com/jk/week05/LeetCode_64_587.java b/Week_05/G20200343030587/week05/src/main/java/com/jk/week05/LeetCode_64_587.java new file mode 100644 index 00000000..04c94e42 --- /dev/null +++ b/Week_05/G20200343030587/week05/src/main/java/com/jk/week05/LeetCode_64_587.java @@ -0,0 +1,21 @@ +package com.jk.week05; + +public class LeetCode_64_587 { + public int minPathSum(int[][] grid) { + int m = grid.length; + int n = grid[0].length; + + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + if (i == 0 && j > 0) { + grid[i][j] = grid[i][j - 1] + grid[i][j]; + }else if (j == 0 && i > 0) { + grid[i][j] = grid[i - 1][j] + grid[i][j]; + }else if (i != 0 && j != 0) { + grid[i][j] = Math.min(grid[i][j - 1], grid[i - 1][j]) + grid[i][j]; + } + } + } + return grid[m - 1][n - 1]; + } +} diff --git a/Week_05/G20200343030587/week05/src/main/java/com/jk/week05/LeetCode_91_587.java b/Week_05/G20200343030587/week05/src/main/java/com/jk/week05/LeetCode_91_587.java new file mode 100644 index 00000000..0d4f7c01 --- /dev/null +++ b/Week_05/G20200343030587/week05/src/main/java/com/jk/week05/LeetCode_91_587.java @@ -0,0 +1,20 @@ +package com.jk.week05; + +public class LeetCode_91_587 { + public int numDecodings(String s) { + + if (s.charAt(0) == '0') return 0; + int[] dp = new int[s.length() + 1]; + dp[0] = dp[1] = 1; + for (int i = 2; i <= s.length(); i++) { + if (s.charAt(i - 1) != '0') { + dp[i] += dp[i - 1]; + } + //后两位组合 在10~26中是合法的 + if (s.charAt(i - 2) == '1' || s.charAt(i - 2) == '2' && s.charAt(i - 1) <= '6') { + dp[i] += dp[i - 2]; + } + } + return dp[s.length()]; + } +} diff --git a/Week_05/G20200343030589/LeetCode_64_589.go b/Week_05/G20200343030589/LeetCode_64_589.go new file mode 100644 index 00000000..1e0503bc --- /dev/null +++ b/Week_05/G20200343030589/LeetCode_64_589.go @@ -0,0 +1,47 @@ +func minPathSum(grid [][]int) int { + // 取纵向 + m := len(grid) + // 取横向 + n := len(grid[0]) + + if m == 0 { + return 0 + } + + // 定义一个二维切片来存起点到该点的最小值 + dp := make([][]int,m) + + for i:=0;i= 3; + } + } + +} \ No newline at end of file diff --git a/Week_05/G20200343030591/LeetCode_1143_591.java b/Week_05/G20200343030591/LeetCode_1143_591.java new file mode 100644 index 00000000..20514583 --- /dev/null +++ b/Week_05/G20200343030591/LeetCode_1143_591.java @@ -0,0 +1,28 @@ +class Solution { + /** + * 最长公共子序列 + * 动态规划 + * 注意:如果 s1 为 ABCDE s2 为 EC 那么EC中的C 不属于公共子序列 + * 顺序必须 字符串的顺序也必须一样 才行 + * @param text1 + * @param text2 + * @return + */ + public int longestCommonSubsequence(String text1, String text2) { + int m = text1.length(); + int n = text2.length(); + int[][] dp = new int[m+1][n+1]; + for (int i=1; i < m + 1; i++) { + for (int j=1; j < n + 1; j++) { + // 如果两个字符的最后一位相等,则计算他们前面的字符的长度 同时加上 相同那串字符的长度 + if (text1.charAt(i - 1) == text2.charAt(j - 1)) { + dp[i][j] = dp[i - 1][j - 1] + 1; + // 否则如果 不相等的话 那个就 从 字符串1减一位 与 字符串2减一位中选择一个最大值 + } else { + dp[i][j] = Math.max(dp[i-1][j], dp[i][j-1]); + } + } + } + return dp[m][n]; + } +} \ No newline at end of file diff --git a/Week_05/G20200343030591/LeetCode_64_591.java b/Week_05/G20200343030591/LeetCode_64_591.java new file mode 100644 index 00000000..285ace26 --- /dev/null +++ b/Week_05/G20200343030591/LeetCode_64_591.java @@ -0,0 +1,18 @@ +class Solution { + /** + * 最小路径和 + * @param grid + * @return + */ + public int minPathSum(int[][] grid) { + for(int i = 0; i < grid.length; i++) { + for(int j = 0; j < grid[0].length; j++) { + if(i == 0 && j == 0) continue; + else if(i == 0) grid[i][j] = grid[i][j - 1] + grid[i][j]; + else if(j == 0) grid[i][j] = grid[i - 1][j] + grid[i][j]; + else grid[i][j] = Math.min(grid[i - 1][j], grid[i][j - 1]) + grid[i][j]; + } + } + return grid[grid.length - 1][grid[0].length - 1]; + } +} \ No newline at end of file diff --git a/Week_05/G20200343030593/Leet_code_64_593.java b/Week_05/G20200343030593/Leet_code_64_593.java new file mode 100644 index 00000000..87f58e59 --- /dev/null +++ b/Week_05/G20200343030593/Leet_code_64_593.java @@ -0,0 +1,18 @@ +class Solution { + public int minPathSum(int[][] grid) { + for(int i=0;i=0;i--){ + if(s.charAt(i)=='0'){ + continue; + } + int ans1=dp[i+1]; + int ans2=0; + int ten=(s.charAt(i)-'0')*10; + int one=(s.charAt(i+1)-'0'); + if((ten+one)<=26){ + ans2=dp[i+2]; + } + dp[i]=ans1+ans2; + } + return dp[0]; + } +} \ No newline at end of file diff --git a/Week_05/G20200343030595/LeetCode_221_595.go b/Week_05/G20200343030595/LeetCode_221_595.go new file mode 100644 index 00000000..1a5817f8 --- /dev/null +++ b/Week_05/G20200343030595/LeetCode_221_595.go @@ -0,0 +1,44 @@ +package main + +import "fmt" + +func maximalSquare(matrix [][]byte) int { + if len(matrix) < 1{ + return 0 + } + m, n := len(matrix), len(matrix[0]) + dp := make([][]int, m+1) + for i:=0; i<=m; i++ { + dp[i] = make([]int, n+1) + } + + maxLen := 0 + for i:=1; i b { + return a + } + return b +} + +func min(a, b, c int) int { + tmp := a + if tmp > b { + tmp = b + } + if tmp > c { + tmp = c + } + return tmp +} diff --git a/Week_05/G20200343030595/LeetCode_312_595.go b/Week_05/G20200343030595/LeetCode_312_595.go new file mode 100644 index 00000000..a44e2b9f --- /dev/null +++ b/Week_05/G20200343030595/LeetCode_312_595.go @@ -0,0 +1,24 @@ +package main + +func maxCoins(nums []int) int { + n := len(nums) + nums = append([]int{1}, append(nums, 1)...) + c := make([][]int, n+2) + for i := range c { + c[i] = make([]int, n+2) + } + for l := 1; l <= n; l++ { + for i := 1; i <= n-l+1; i++ { + j := i+l-1 + for k := i; k <= j; k++ { + c[i][j] = max(c[i][j], c[i][k-1] + nums[i-1]*nums[k]*nums[j+1] + c[k+1][j]) + } + } + } + return c[1][n] +} + +func max(a, b int) int { + if a > b { return a } + return b +} diff --git a/Week_05/G20200343030595/LeetCode_32_595.go b/Week_05/G20200343030595/LeetCode_32_595.go new file mode 100644 index 00000000..17385927 --- /dev/null +++ b/Week_05/G20200343030595/LeetCode_32_595.go @@ -0,0 +1,26 @@ +package main + +func longestValidParentheses(s string) int { + dp, res := make([]int,len(s)), 0 + for i,_ := range s{ + if i > 0 && s[i] == ')'{ + if s[i - 1] == '('{ + if i == 1{ + dp[i] = 2 + }else{ + dp [i] = dp[i - 2] + 2 + } + }else if s[i - 1] == ')' && i - dp[i - 1] - 1 >= 0 && s[i-dp[i-1]-1] == '(' { + if i - dp[i - 1] - 1 == 0{ + dp[i] = dp[i-1] + 2 + }else{ + dp[i] = dp[i-1] + 2 + dp[i-dp[i-1]-2] + } + } + if dp[i] > res{ + res = dp[i] + } + } + } + return res +} diff --git a/Week_05/G20200343030595/LeetCode_363_595.go b/Week_05/G20200343030595/LeetCode_363_595.go new file mode 100644 index 00000000..c70aaa9d --- /dev/null +++ b/Week_05/G20200343030595/LeetCode_363_595.go @@ -0,0 +1,62 @@ +package main + +import "math" + +func maxSumSubmatrix(matrix [][]int, k int) int { + if len(matrix) == 0 || len(matrix[0]) == 0 { + return 0 + } + + ans := math.MinInt32 + for l := 0; l < len(matrix[0]); l++ { + rowSum := make([]int, len(matrix)) + for r := l; r < len(matrix[0]); r++ { + for i := 0; i < len(matrix); i++ { + rowSum[i] += matrix[i][r] + } + + sum := []int{0} + tot := 0 + for i := 0; i < len(matrix); i++ { + tot += rowSum[i] + left, right := 0, len(sum)-1 + for left <= right { + mid := (left + right) / 2 + if tot-sum[mid] == k { + return k + } else if tot-sum[mid] > k { + left = mid + 1 + } else { + right = mid - 1 + if ans < tot-sum[mid] { + ans = tot - sum[mid] + } + } + } + + left, right = 0, len(sum)-1 + for left <= right { + mid := (left + right) / 2 + if tot <= sum[mid] { + right = mid - 1 + } else { + left = mid + 1 + } + } + + if left == len(sum) { + sum = append(sum, tot) + } else { + if sum[left] == tot { + continue + } + + cp := append([]int{}, sum[left:]...) + sum = append(sum[:left], tot) + sum = append(sum, cp...) + } + } + } + } + return ans +} diff --git a/Week_05/G20200343030595/LeetCode_403_595.go b/Week_05/G20200343030595/LeetCode_403_595.go new file mode 100644 index 00000000..d59ff066 --- /dev/null +++ b/Week_05/G20200343030595/LeetCode_403_595.go @@ -0,0 +1,42 @@ +package main + +import "math" + +func canCross(stones []int) bool { + if len(stones) == 0 { + return false + } + + if len(stones) == 1 { + return stones[0] == 0 + } + last := stones[len(stones)-1] + n := int(math.Sqrt(float64(2*last)+0.25)-0.5) + 5 + dp := make([][]bool, len(stones)) + for i := 0; i < len(stones); i++ { + dp[i] = make([]bool, n) + } + + m := make(map[int]int) + for i, stone := range stones { + m[stone] = i + } + + dp[0][0] = true + for i := 0; i < len(stones); i++ { + p := stones[i] + for j := 1; j+1 < n; j++ { + if (p-j == 0 && p == 1) || + (m[p-j] > 0 && (dp[m[p-j]][j+1] || dp[m[p-j]][j] || dp[m[p-j]][j-1])) { + dp[i][j] = true + } + } + } + + for i := 0; i < n; i++ { + if dp[len(stones)-1][i] { + return true + } + } + return false +} diff --git a/Week_05/G20200343030595/LeetCode_410_595.go b/Week_05/G20200343030595/LeetCode_410_595.go new file mode 100644 index 00000000..2f4c17bd --- /dev/null +++ b/Week_05/G20200343030595/LeetCode_410_595.go @@ -0,0 +1,35 @@ +package main + +func splitArray(nums []int, m int) int { + lBound, rBound := 0, 0 + for _, v := range nums { + rBound += v + if v > lBound { + lBound = v + } + } + + for lBound < rBound { + mid := (lBound + rBound) / 2 + cut := getCutSize(nums, mid) + if cut > m { + lBound = mid+1 + } else { + rBound = mid // can not be mid-1, one more cut doesn't mean less result + } + } + return lBound +} + +func getCutSize(nums []int, max int) int { + cutSize, curValue := 1, 0 // cutSize init value is 1, not 0 + for _, v := range nums { + if curValue + v <= max { + curValue += v + } else { + curValue = v + cutSize++ + } + } + return cutSize +} diff --git a/Week_05/G20200343030595/LeetCode_552_595.go b/Week_05/G20200343030595/LeetCode_552_595.go new file mode 100644 index 00000000..4a1196d4 --- /dev/null +++ b/Week_05/G20200343030595/LeetCode_552_595.go @@ -0,0 +1,28 @@ +package main + +func checkRecord(n int) int { + mod := int(1e9) + 7 + dp := [][]int{ + []int{1, 2, 4}, + []int{0, 1, 4}, + } + + for i := 3; i <= n; i++ { + dp[0] = append(dp[0], 0) + dp[0][i] += dp[0][i-1] + dp[0][i] += dp[0][i-2] + dp[0][i] += dp[0][i-3] + dp[0][i] %= mod + + dp[1] = append(dp[1], 0) + dp[1][i] += dp[0][i-1] + dp[1][i] += dp[0][i-2] + dp[1][i] += dp[0][i-3] + + dp[1][i] += dp[1][i-1] + dp[1][i] += dp[1][i-2] + dp[1][i] += dp[1][i-3] + dp[1][i] %= mod + } + return (dp[0][n] + dp[1][n]) % mod +} diff --git a/Week_05/G20200343030595/LeetCode_621_595.go b/Week_05/G20200343030595/LeetCode_621_595.go new file mode 100644 index 00000000..32eb2280 --- /dev/null +++ b/Week_05/G20200343030595/LeetCode_621_595.go @@ -0,0 +1,27 @@ +package main + +import "sort" + +func leastInterval(tasks []byte, n int) int { + data := make([]int, 26) + for _, v := range tasks { + data[v-'A']++ + } + sort.Ints(data) + duration := 0 + for data[25] > 0{ + i := 0 + for i<=n { + if data[25] == 0 { + break + } + if i<26 && data[25-i] > 0 { + data[25-i]-- + } + duration++ + i++ + } + sort.Ints(data) + } + return duration +} diff --git a/Week_05/G20200343030595/LeetCode_647_595.go b/Week_05/G20200343030595/LeetCode_647_595.go new file mode 100644 index 00000000..acda7b26 --- /dev/null +++ b/Week_05/G20200343030595/LeetCode_647_595.go @@ -0,0 +1,15 @@ +package main + +func countSubstrings(s string) int { + n, ans := len(s), 0 + for i:=0; i< 2*n-1; i++ { + left := i/2 + right := left + i%2 + for left>=0 && right i { + break + } + } + if c == count { + if res == "" || len(res) > i-j+1 { + res = s[j : i+1] + } + } + } + return res +} \ No newline at end of file diff --git a/Week_05/G20200343030595/LeetCode_91_595.go b/Week_05/G20200343030595/LeetCode_91_595.go new file mode 100644 index 00000000..deb607a5 --- /dev/null +++ b/Week_05/G20200343030595/LeetCode_91_595.go @@ -0,0 +1,55 @@ +package main + +import ( + "fmt" + "strconv" +) + +func numDecodings(s string) int { + if len(s) < 1 || s[0] == '0' { + return 0 + } + + dp := make([]int, len(s)) + dp[0] = 1 + for i := 1; i < len(s); i++ { + str := string(s[i-1 : i+1]) + switch { + case s[i] == '0': + if equal(str, 10) || equal(str, 20) { + if i < 2 { + dp[i] = 1 + } else { + dp[i] = dp[i-2] + } + } else { + return 0 + } + + case between(str, 11, 26): + if i > 2 { + dp[i] = dp[i-1] + dp[i-2] + } else { + dp[i] = dp[i-1] + 1 + } + + default: + dp[i] = dp[i-1] + } + } + return dp[len(s)-1] +} + +func equal(str string, num int) bool { + fmt.Printf("> num is %v\n", strconv.Itoa(num)) + return str == strconv.Itoa(num) +} + +func between(str string, start, end int) bool { + num, err := strconv.Atoi(str) + fmt.Printf("nums is %v\n", num) + if err != nil { + return false + } + return num >= start && num <= end +} diff --git a/Week_05/G20200343030597/Solution_64.java b/Week_05/G20200343030597/Solution_64.java new file mode 100644 index 00000000..6fd02b4f --- /dev/null +++ b/Week_05/G20200343030597/Solution_64.java @@ -0,0 +1,13 @@ +public class Solution_64 { + public int minPathSum(int[][] grid) { + for(int i = 0; i < grid.length; i++) { + for(int j = 0; j < grid[0].length; j++) { + if(i == 0 && j == 0) continue; + else if(i == 0) grid[i][j] = grid[i][j - 1] + grid[i][j]; + else if(j == 0) grid[i][j] = grid[i - 1][j] + grid[i][j]; + else grid[i][j] = Math.min(grid[i - 1][j], grid[i][j - 1]) + grid[i][j]; + } + } + return grid[grid.length - 1][grid[0].length - 1]; + } +} diff --git a/Week_05/G20200343030597/Solution_91.java b/Week_05/G20200343030597/Solution_91.java new file mode 100644 index 00000000..c1b602e7 --- /dev/null +++ b/Week_05/G20200343030597/Solution_91.java @@ -0,0 +1,27 @@ +public class Solution_91 { + public int numDecodings(String s) { + if (s == null || s.length() == 0) { + return 0; + } + int len = s.length(); + int[] dp = new int[len + 1]; + dp[len] = 1; + if (s.charAt(len - 1) == '0') { + dp[len - 1] = 0; + } else { + dp[len - 1] = 1; + } + for (int i = len - 2; i >= 0; i--) { + if (s.charAt(i) == '0') { + dp[i] = 0; + continue; + } + if ((s.charAt(i) - '0') * 10 + (s.charAt(i + 1) - '0') <= 26) { + dp[i] = dp[i + 1] + dp[i + 2]; + } else { + dp[i] = dp[i + 1]; + } + } + return dp[0]; + } +} diff --git "a/Week_05/G20200343030601/120.\344\270\211\350\247\222\345\275\242\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214.java" "b/Week_05/G20200343030601/120.\344\270\211\350\247\222\345\275\242\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214.java" new file mode 100644 index 00000000..9c794641 --- /dev/null +++ "b/Week_05/G20200343030601/120.\344\270\211\350\247\222\345\275\242\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214.java" @@ -0,0 +1,157 @@ +import java.util.Arrays; +import java.util.List; + +/* + * @lc app=leetcode.cn id=120 lang=java + * + * [120] 三角形最小路径和 + * + * https://leetcode-cn.com/problems/triangle/description/ + * + * algorithms + * Medium (63.77%) + * Likes: 328 + * Dislikes: 0 + * Total Accepted: 43.6K + * Total Submissions: 68.3K + * Testcase Example: '[[2],[3,4],[6,5,7],[4,1,8,3]]' + * + * 给定一个三角形,找出自顶向下的最小路径和。每一步只能移动到下一行中相邻的结点上。 + * + * 例如,给定三角形: + * + * [ + * ⁠ [2], + * ⁠ [3,4], + * ⁠ [6,5,7], + * ⁠ [4,1,8,3] + * ] + * + * + * 自顶向下的最小路径和为 11(即,2 + 3 + 5 + 1 = 11)。 + * + * 说明: + * + * 如果你可以只使用 O(n) 的额外空间(n 为三角形的总行数)来解决这个问题,那么你的算法会很加分。 + * + */ + +// @lc code=start +class Solution { + public int minimumTotal(List> triangle) { + // return MTRecursive(triangle, 0 , 0); + + // int[][] mem = new int[triangle.size()][triangle.size()]; + // Arrays.stream(mem).forEach(line -> Arrays.fill(line, Integer.MIN_VALUE)); // 没有想到更好的初始化方式 + // return MTRecursiveMem(triangle, 0, 0, mem); + + // return MTDP1(triangle); + + // return MTDP2(triangle); + + return MTDP3(triangle); + + // return MTDP4(triangle); + } + + // 递归:mininum(i, j) = Math.min(mininum(i + 1, j), mininum(i + 1, j + 1)) + v[i][j] + // 调用方式: mininum(v, 0, 0); + // 递归会有存在重复计算:如某子triangle会被其left父节点和right父节点重复计算; + private int MTRecursive(List> triangle, int i, int j) { + if (i == triangle.size() - 1 || j == triangle.size() - 1) + return triangle.get(i).get(j); + + int left = MTRecursive(triangle, i + 1, j); + int right = MTRecursive(triangle, i + 1, j + 1); + return Math.min(left, right) + triangle.get(i).get(j); + } + + // 递归 + 备忘录 + private int MTRecursiveMem(List> triangle, int i, int j, int[][] mem) { + if (i == triangle.size() - 1 || j == triangle.size() - 1) + return mem[i][j] = triangle.get(i).get(j); + + if (mem[i][j] != Integer.MIN_VALUE) + return mem[i][j]; + + int left = MTRecursiveMem(triangle, i + 1, j, mem); + int right = MTRecursiveMem(triangle, i + 1, j + 1, mem); + return mem[i][j] = Math.min(left, right) + triangle.get(i).get(j); + } + + // 动态规划:自底向上,n^2空间复杂度 + // 状态转移方程dp[i][j] = Math.min(dp[i - 1][j], dp[i - 1][j - 1]) + v[i][j] + private int MTDP1(List> triangle) { + int n = triangle.size(); + int[][] dp = new int[n][n]; + + // 处理边界值 + dp[0][0] = triangle.get(0).get(0); + for (int i = 1; i < n; i++) { + dp[i][0] = dp[i - 1][0] + triangle.get(i).get(0); + } + + for (int i = 1; i < n; i++) { + for (int j = 1; j < i; j++) { + dp[i][j] = Math.min(dp[i - 1][j], dp[i - 1][j - 1]) + triangle.get(i).get(j); + } + dp[i][i] = dp[i - 1][i - 1] + triangle.get(i).get(i); // 对角线位置的,不能从上部下来,只能从斜上部下来; + } + + // 遍历最底层,找出最短路径和 + int minTotal = Integer.MAX_VALUE; + for (int i = 0; i < n; i++) { + if (minTotal > dp[n - 1][i]) minTotal = dp[n - 1][i]; + } + return minTotal; + } + + // 动态规划:自顶向下,n^2空间复杂度 + // 状态转移方程:dp[i][j] = Math.min(dp[i + 1][j], dp[i + 1][j + 1]) + triangle.get(i).get(j); + private int MTDP2(List> triangle) { + int n = triangle.size(); + int dp[][] = new int[n][n]; + + // 处理边界 + for (int i = 0; i < n; i++) { + dp[n - 1][i] = triangle.get(n - 1).get(i); + } + + for (int i = n - 2; i >= 0; i--) { + for (int j = i; j >= 0; j--) { + dp[i][j] = Math.min(dp[i + 1][j], dp[i + 1][j + 1]) + triangle.get(i).get(j); + } + } + + return dp[0][0]; + } + + // 动态规划:自顶向下,n空间复杂度 + private int MTDP3(List> triangle) { + int n = triangle.size(); + int[] dp = new int[n + 1]; // 想想为什么不需要处理边界问题 + + for (int i = n - 1; i >= 0; i--) { + for (int j = 0; j <= i; j++) { + dp[j] = triangle.get(i).get(j) + Math.min(dp[j], dp[j + 1]); + } + } + + return dp[0]; + } + + // 动态规划:自顶向下 + // 直接在原二维数组上进行修改,不占用额外空间;(项目中不推荐使用) + private int MTDP4(List> triangle) { + for (int i = triangle.size() - 2; i >= 0; i--) { + for (int j = 0; j <= i; j++) { + int value = triangle.get(i).get(j) + Math.min(triangle.get(i + 1).get(j), triangle.get(i + 1).get(j + 1)); + triangle.get(i).set(j, value); + } + } + + return triangle.size() > 0 ? triangle.get(0).get(0) : 0; + } +} +// @lc code=end + diff --git "a/Week_05/G20200343030601/322.\351\233\266\351\222\261\345\205\221\346\215\242.java" "b/Week_05/G20200343030601/322.\351\233\266\351\222\261\345\205\221\346\215\242.java" new file mode 100644 index 00000000..d48c0a7b --- /dev/null +++ "b/Week_05/G20200343030601/322.\351\233\266\351\222\261\345\205\221\346\215\242.java" @@ -0,0 +1,110 @@ +/* + * @lc app=leetcode.cn id=322 lang=java + * + * [322] 零钱兑换 + * + * https://leetcode-cn.com/problems/coin-change/description/ + * + * algorithms + * Medium (37.83%) + * Likes: 379 + * Dislikes: 0 + * Total Accepted: 44.8K + * Total Submissions: 118.5K + * Testcase Example: '[1,2,5]\n11' + * + * 给定不同面额的硬币 coins 和一个总金额 + * amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1。 + * + * 示例 1: + * + * 输入: coins = [1, 2, 5], amount = 11 + * 输出: 3 + * 解释: 11 = 5 + 5 + 1 + * + * 示例 2: + * + * 输入: coins = [2], amount = 3 + * 输出: -1 + * + * 说明: + * 你可以认为每种硬币的数量是无限的。 + * + */ + +// @lc code=start +import java.util.Arrays; +class Solution { + + // f(amount) = 1 + min (f(amount - coin1) + // f(amount - coin2) + // ... + // f(amount - coinn)) + // 递归处理:超时 + public int coinChangeRecursive(int[] coins, int amount) { + if (amount <= 0) return amount; + int minCount = Integer.MAX_VALUE; + for (int i = 0; i < coins.length; i++) { + int remain = amount - coins[i]; + int remainCount = coinChangeRecursive(coins, remain); + if (remainCount >= 0 && remainCount < minCount) + minCount = remainCount; + } + return minCount == Integer.MAX_VALUE? -1 : minCount + 1; + } + + // 递归处理 + 备忘录: 还是超时了 + public int coinChangeRMem(int[] coins, int amount) { + int[] mem = new int[amount + 1]; + return coinChangeHelper(coins, amount, mem); + } + private int coinChangeHelper(int[] coins, int amount, int[] mem) { + if (amount <= 0) return amount; + + if (mem[amount] > 0) return mem[amount]; + + int minCount = Integer.MAX_VALUE; + for (int i = 0; i < coins.length; i++) { + int remain = amount - coins[i]; + int remainCount = coinChangeHelper(coins, remain, mem); + if (remainCount >= 0 && remainCount < minCount) + minCount = remainCount + 1; + } + mem[amount] = minCount == Integer.MAX_VALUE? -1 : minCount; + return mem[amount]; + } + + public int coinChange(int[] coins, int amount) { + int[] dp = new int[amount + 1]; + Arrays.fill(dp, amount + 1); + dp[0] = 0; + + for (int i = 1; i <= amount; i++) { + for (int coin : coins) { + if (i >= coin) { + dp[i] = Math.min(dp[i], dp[i - coin] + 1); + } + } + } + + return dp[amount] > amount ? -1 : dp[amount]; + + } + + // 自下而上的DP,计算每一个小于amount值时,需要的最小coin数 + public int coinChangeDP(int[] coins, int amount) { + int[] dp = new int[amount + 1]; + Arrays.fill(dp, amount + 1); + dp[0] = 0; + for (int i = 1; i <= amount; i++) { + for (int coin : coins) { + if (i >= coin) { + dp[i] = Math.min(dp[i], dp[i - coin] + 1); + } + } + } + return dp[amount] > amount ? -1 : dp[amount]; + } +} +// @lc code=end + diff --git "a/Week_05/G20200343030601/53.\346\234\200\345\244\247\345\255\220\345\272\217\345\222\214.java" "b/Week_05/G20200343030601/53.\346\234\200\345\244\247\345\255\220\345\272\217\345\222\214.java" new file mode 100644 index 00000000..56dd8a67 --- /dev/null +++ "b/Week_05/G20200343030601/53.\346\234\200\345\244\247\345\255\220\345\272\217\345\222\214.java" @@ -0,0 +1,65 @@ +/* + * @lc app=leetcode.cn id=53 lang=java + * + * [53] 最大子序和 + * + * https://leetcode-cn.com/problems/maximum-subarray/description/ + * + * algorithms + * Easy (49.53%) + * Likes: 1707 + * Dislikes: 0 + * Total Accepted: 178.2K + * Total Submissions: 358.7K + * Testcase Example: '[-2,1,-3,4,-1,2,1,-5,4]' + * + * 给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。 + * + * 示例: + * + * 输入: [-2,1,-3,4,-1,2,1,-5,4], + * 输出: 6 + * 解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。 + * + * + * 进阶: + * + * 如果你已经实现复杂度为 O(n) 的解法,尝试使用更为精妙的分治法求解。 + * + */ + +// @lc code=start +class Solution { + // 暴力:组合枚举 + public int maxSubArray1(int[] nums) { + int sumMax = Integer.MIN_VALUE; + for (int i = 0; i < nums.length; i++) { + int sum = 0; + for (int j = i; j < nums.length; j++) { + sum += nums[j]; + if (sum > sumMax) + sumMax = sum; + } + } + + return sumMax; + } + + // 如果当前subArray的和<=0了,则可以重新开始计数 + public int maxSubArray(int[] nums) { + int sumMax = Integer.MIN_VALUE; + int subArraySum = 0; + for (int num : nums) { + subArraySum += num; + if (subArraySum > sumMax) + sumMax = subArraySum; + if (subArraySum < 0) + subArraySum = 0; + + } + + return sumMax; + } +} +// @lc code=end + diff --git "a/Week_05/G20200343030601/64.\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214.java" "b/Week_05/G20200343030601/64.\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214.java" new file mode 100644 index 00000000..345fb443 --- /dev/null +++ "b/Week_05/G20200343030601/64.\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214.java" @@ -0,0 +1,107 @@ +/* + * @lc app=leetcode.cn id=64 lang=java + * + * [64] 最小路径和 + * + * https://leetcode-cn.com/problems/minimum-path-sum/description/ + * + * algorithms + * Medium (64.77%) + * Likes: 403 + * Dislikes: 0 + * Total Accepted: 66.3K + * Total Submissions: 102.3K + * Testcase Example: '[[1,3,1],[1,5,1],[4,2,1]]' + * + * 给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。 + * + * 说明:每次只能向下或者向右移动一步。 + * + * 示例: + * + * 输入: + * [ + * [1,3,1], + * ⁠ [1,5,1], + * ⁠ [4,2,1] + * ] + * 输出: 7 + * 解释: 因为路径 1→3→1→1→1 的总和最小。 + * + * + */ + +// @lc code=start +class Solution { + // 动态规划: + // f(i, j) = cell[i][j] + f(i - 1, j - 1) + // 空间复杂度:m * n + public int minPathSum1(int[][] grid) { + if (null == grid || 0 == grid.length) + return 0; + int rows = grid.length; + int cols = grid[0].length; + int[][] dp = new int[rows][cols]; + // 处理边界值 + dp[0][0] = grid[0][0]; + for (int i = 1; i < rows; i++) { + dp[i][0] = dp[i - 1][0] + grid[i][0]; + } + for (int i = 1; i < cols; i++) { + dp[0][i] = dp[0][i - 1] + grid[0][i]; + } + + for (int r = 1; r < rows; r++) { + for (int c = 1; c < cols; c++) { + dp[r][c] = grid[r][c] + Math.min(dp[r - 1][c], dp[r][c - 1]); + } + } + + return dp[rows - 1][cols - 1]; + } + + // 动态规划: + // f(i, j) = cell[i][j] + f(i - 1, j - 1) + // 空间复杂度:O(n) + public int minPathSum2(int[][] grid) { + if (null == grid || 0 == grid.length) return 0; + int rows = grid.length, cols = grid[0].length; + int[] dp = new int[cols]; + + // 处理边界值 + dp[0] = grid[0][0]; + for (int c = 1; c < cols; c++) + dp[c] = dp[c - 1] + grid[0][c]; + + for (int r = 1; r < rows; r++) { + dp[0] = grid[r][0] + dp[0]; + for (int c = 1; c < cols; c++) { + dp[c] = grid[r][c] + Math.min(dp[c - 1], dp[c]); + } + } + + return dp[cols - 1]; + } + + // 动态规划: + // f(i, j) = cell[i][j] + f(i - 1, j - 1) + // 空间复杂度:O(1) 直接借用了原二维数组 + public int minPathSum(int[][] grid) { + if (null == grid || 0 == grid.length) return 0; + int rows = grid.length, cols = grid[0].length; + + // 处理边界值 + for (int c = 1; c < cols; c++) + grid[0][c] += grid[0][c - 1]; + + for (int r = 1; r < rows; r++) { + grid[r][0] += grid[r - 1][0]; + for (int c = 1; c < cols; c++) + grid[r][c] += Math.min(grid[r - 1][c], grid[r][c - 1]); + } + + return grid[rows - 1][cols - 1]; + } +} +// @lc code=end + diff --git "a/Week_05/G20200343030601/91.\350\247\243\347\240\201\346\226\271\346\263\225.java" "b/Week_05/G20200343030601/91.\350\247\243\347\240\201\346\226\271\346\263\225.java" new file mode 100644 index 00000000..2e3d5c16 --- /dev/null +++ "b/Week_05/G20200343030601/91.\350\247\243\347\240\201\346\226\271\346\263\225.java" @@ -0,0 +1,123 @@ +/* + * @lc app=leetcode.cn id=91 lang=java + * + * [91] 解码方法 + * + * https://leetcode-cn.com/problems/decode-ways/description/ + * + * algorithms + * Medium (23.20%) + * Likes: 311 + * Dislikes: 0 + * Total Accepted: 36.7K + * Total Submissions: 158.1K + * Testcase Example: '"12"' + * + * 一条包含字母 A-Z 的消息通过以下方式进行了编码: + * + * 'A' -> 1 + * 'B' -> 2 + * ... + * 'Z' -> 26 + * + * + * 给定一个只包含数字的非空字符串,请计算解码方法的总数。 + * + * 示例 1: + * + * 输入: "12" + * 输出: 2 + * 解释: 它可以解码为 "AB"(1 2)或者 "L"(12)。 + * + * + * 示例 2: + * + * 输入: "226" + * 输出: 3 + * 解释: 它可以解码为 "BZ" (2 26), "VF" (22 6), 或者 "BBF" (2 2 6) 。 + * + * + */ + +// @lc code=start +class Solution { + // if 第1位是1~9,则合法,继续解码后面的 + // if 前2位是10~26,也合法,继续解码后面的 + // 递归方式解决此问题,明显存在重复计算问题 + public int numDecodings1(String s) { + if (null == s || 0 == s.length()) return 0; + int result = 0; + + // 解码第一位 + int value = s.charAt(0) - '0'; + if (value > 0 && value < 10) + result += (s.length() > 1 ? numDecodings(s.substring(1)) : 1); + + // 解码前两位 + if (s.length() > 1) { + value = 10 * (s.charAt(0) - '0') + (s.charAt(1) - '0'); + if (value >= 10 && value <= 26) + result += (s.length() > 2? numDecodings(s.substring(2)) : 1); + } + + return result; + } + + // 动态规划 + // if 第1位是1~9,则合法,记后序解法为count1 + // if 前2位是10~26,也合法,记后序解法为count2 + // 总解法count = count1 + count2 + // 空间复杂度:O(n) + public int numDecodings2(String s) { + if (null == s || s.length() == 0) return 0; + + int[] dp = new int[s.length() + 1]; + dp[s.length()] = 1; + dp[s.length() - 1] = s.charAt(s.length() - 1) != '0'? 1 : 0; + + for (int i = s.length() - 2; i >= 0; i--) { + if (s.charAt(i) == '0') // 此时一位、两位都无效 + continue; + else + { + dp[i] += dp[i + 1]; // 一位有效 + int value = 10 * (s.charAt(i) - '0') + (s.charAt(i + 1) - '0'); + if (value >= 10 && value <= 26) + dp[i] += dp[i + 2]; // 两位有效 + } + } + + return dp[0]; + } + + // 动态规划 + // if 第1位是1~9,则合法,记后序解法为count1 + // if 前2位是10~26,也合法,记后序解法为count2 + // 总解法count = count1 + count2 + // 空间复杂度:O(1) + public int numDecodings(String s) { + if (null == s || s.length() == 0) return 0; + + int count = 0, count1 = 0, count2 = 1; + if (s.charAt(s.length() - 1) != '0') { + count = 1; + count1 = 1; + } + + for (int i = s.length() - 2; i >= 0; i--) { + count = 0; + if (s.charAt(i) != '0') + { + count = count1; // 一位有效 + count += (10 * (s.charAt(i) - '0') + (s.charAt(i + 1) - '0') <= 26)? count2 : 0; // 两位有效 + } + + count2 = count1; + count1 = count; + } + + return count; + } +} +// @lc code=end + diff --git a/Week_05/G20200343030601/NOTE.md b/Week_05/G20200343030601/NOTE.md index 50de3041..9e7dada3 100644 --- a/Week_05/G20200343030601/NOTE.md +++ b/Week_05/G20200343030601/NOTE.md @@ -1 +1,17 @@ -学习笔记 \ No newline at end of file +# 学习笔记(第五周) + +**学号:** G20200343030601 + +**姓名:** 冯学智 + +**微信:** SDMrFeng + +## 本周学习总结 + +本周做题过程中按照以下思路处理本周的实战题目和作业题目: + +从纯递归 -> 递归+备忘录 -> 动态规划 -> 优化动态规划的空间复杂度 -> Review高手代码,学习、做精简; + +使用O(n*m)的复杂度 -> O(n)的空间复杂度 -> O(1)的空间复杂度,整个过程是思维模式的进化; + +在学校时期,动态规划掌握并不扎实,通过本周的练习和复习,有超越。 diff --git a/Week_05/G20200343030603/LeetCode_1_603.java b/Week_05/G20200343030603/LeetCode_1_603.java new file mode 100644 index 00000000..a714dc08 --- /dev/null +++ b/Week_05/G20200343030603/LeetCode_1_603.java @@ -0,0 +1,40 @@ + //方法一:二维DP 时间复杂度O(mn) 空间复杂度O(mn) + // a.子问题 f[i,j] = grid[i,j] + min(f[i - 1,j],f[i,j - 1]) + // b.定义状态数组 f[i,j] + // c.DP方程: + // dp[i,j] = grid[i,j] + min(dp[i - 1,j],dp[i,j-1]) + + //方法二:一维DP 时间复杂度O(mn) 空间复杂度O(n)   + // a.子问题 f[j] = grid[j] + min(f[j],f[j - 1]) + // b.定义状态数组 f[j] + // c.DP方程: + // dp[j] = grid[i,j] + min(dp[j],dp[j-1]) +class Solution { + public int minPathSum(int[][] grid) { + if (grid == null || grid.length == 0 || (grid.length == 1 && grid[0].length == 0)) { + return 0; + } + + int m = grid.length;//行数 + int n = grid[0].length;//列数 + + //二维DP + int[][] dp = new int[m][n]; + dp[0][0] = grid[0][0]; + for (int i = 1; i < m; i++){ + dp[i][0] = dp[i - 1][0] + grid[i][0]; + } + + for (int j = 1; j < n; j++){ + dp[0][j] = dp[0][j - 1] + grid[0][j]; + } + + for (int i = 1; i < m; i++) { + for (int j = 1; j < n; j++) { + dp[i][j] = grid[i][j] + Math.min(dp[i - 1][j], dp[i][j - 1]); + } + } + return dp[m - 1][n - 1]; + + } +} \ No newline at end of file diff --git a/Week_05/G20200343030603/LeetCode_2_603.java b/Week_05/G20200343030603/LeetCode_2_603.java new file mode 100644 index 00000000..06f0ec9f --- /dev/null +++ b/Week_05/G20200343030603/LeetCode_2_603.java @@ -0,0 +1,24 @@ +//动态规划: +// DP方程:一个字母可能是由一位数也可能是两位数 +//if nums[i] + nums[i - 1] <= 26 +// dp[i] = dp[i - 1] + dp[i - 2] +//else +// dp[i] = dp[i - 1] + +class Solution { + public int numDecodings(String s) { + if (s == null || s.length() == 0) return 0; + + if (s.charAt(0) == '0') return 0; + + int[] dp = new int[s.length() + 1]; + dp[0] = 1; + for (int i = 0; i < s.length(); i++) { + dp[i + 1] = s.charAt(i) == '0' ? 0 : dp[i]; + if (i > 0 && (s.charAt(i - 1) == '1' || (s.charAt(i - 1) == '2' && s.charAt(i) <= '6'))) { + dp[i + 1] += dp[i - 1]; + } + } + return dp[s.length()]; + } +} \ No newline at end of file diff --git a/Week_05/G20200343030603/LeetCode_3_603.java b/Week_05/G20200343030603/LeetCode_3_603.java new file mode 100644 index 00000000..2643b19b --- /dev/null +++ b/Week_05/G20200343030603/LeetCode_3_603.java @@ -0,0 +1,23 @@ +//DP方程:dp[i][j] = min(dp[i][j-1], dp[i-1][j], dp[i-1][j-1]) + 1; +class Solution { + public int maximalSquare(char[][] matrix) { + if (matrix == null || matrix.length == 0 || (matrix.length == 1 && matrix[0].length == 0)) { + return 0; + } + + int row = matrix.length; // 行数 + int col = matrix[0].length; // 列数 + + int[][] dp = new int[row + 1][col + 1]; + int max = 0; + for (int i = 1; i <= row; i++) { + for (int j = 1; j<= col; j++) { + if (matrix[i - 1][j - 1] == '1') { + dp[i][j] = Math.min(Math.min(dp[i][j - 1], dp[i - 1][j]), dp[i - 1][j - 1]) + 1; + max = Math.max(max, dp[i][j]); + } + } + } + return max * max; + } +} \ No newline at end of file diff --git a/Week_05/G20200343030603/LeetCode_4_603.java b/Week_05/G20200343030603/LeetCode_4_603.java new file mode 100644 index 00000000..0d630b5e --- /dev/null +++ b/Week_05/G20200343030603/LeetCode_4_603.java @@ -0,0 +1,33 @@ +class Solution { + /** + * 思路: + * 1、将任务按类型分组,正好A-Z用一个int[26]保存任务类型个数 + * 2、对数组进行排序,优先排列个数(count)最大的任务, + * 如题得到的时间至少为 retCount = (count-1) * (n+1) + 1 ==> A->X->X->A->X->X->A(X 为其他任务或者待命) + * 3、再排序下一个任务,如果下一个任务B个数和最大任务数一致, + * 则retCount++ ==> A->B->X->A->B->X->A->B + * 4、如果空位都插满之后还有任务,那就随便在这些间隔里面插入就可以,因为间隔长度肯定会大于n,在这种情况下就是任务的总数是最小所需时间 + */ + public int leastInterval(char[] tasks, int n) { + if (tasks.length <= 1 || n < 1) { + return tasks.length; + } + //步骤1 + int[] counts = new int[26]; + for (int i = 0; i < tasks.length; i++) { + counts[tasks[i] - 'A']++; + } + //步骤2 + Arrays.sort(counts); + int maxCount = counts[25]; + int retCount = (maxCount - 1) * (n + 1) + 1; + int i = 24; + //步骤3 + while (i >= 0 && counts[i] == maxCount) { + retCount++; + i--; + } + //步骤4 + return Math.max(retCount,tasks.length); + } +} \ No newline at end of file diff --git a/Week_05/G20200343030603/LeetCode_5_603.java b/Week_05/G20200343030603/LeetCode_5_603.java new file mode 100644 index 00000000..f12907ce --- /dev/null +++ b/Week_05/G20200343030603/LeetCode_5_603.java @@ -0,0 +1,20 @@ +//DP方程:dp[i][j] = dp[i+1][j-1] && str[i]==str[j] +class Solution { + public int countSubstrings(String s) { + if (s == null || s.length() == 0){ + return 0; + } + int res = 0; + int size = s.length(); + boolean dp[][] = new boolean[size][size]; + for (int j = 0; j < size; j++) { + for (int i = j; i >= 0; i--) { + if (s.charAt(i) == s.charAt(j) && ((j - i < 2) || dp[i + 1][j - 1])) { + dp[i][j] = true; + res++; + } + } + } + return res; + } +} \ No newline at end of file diff --git a/Week_05/G20200343030603/LeetCode_6_603.java b/Week_05/G20200343030603/LeetCode_6_603.java new file mode 100644 index 00000000..8ba230c2 --- /dev/null +++ b/Week_05/G20200343030603/LeetCode_6_603.java @@ -0,0 +1,26 @@ +//DP方程: +//if s[i] = ')' && s[i - 1] = '(' +// dp[i] = dp[i - 1] + dp[i - dp[i - 1] - 2] + 2 +//else if s[i] = ')' && s[i - 1] = ')' +// dp[i] = dp[i - 1] + dp[i - dp[i - 1] - 2] + 2 +class Solution { + public int longestValidParentheses(String s) { + if (s == null || s.length() == 0){ + return 0; + } + + int maxans = 0; + int[] dp = new int[s.length()]; + for (int i = 1; i < s.length(); i++) { + if (s.charAt(i) == ')') { + if (s.charAt(i - 1) == '(') { + dp[i] = (i >= 2 ? dp[i - 2] : 0) + 2; + } else if (i - dp[i - 1] > 0 && s.charAt(i - dp[i - 1] - 1) == '(') { + dp[i] = dp[i - 1] + ((i - dp[i - 1]) >= 2 ? dp[i - dp[i - 1] - 2] : 0) + 2; + } + maxans = Math.max(maxans, dp[i]); + } + } + return maxans; + } +} \ No newline at end of file diff --git a/Week_05/G20200343030605/MiniPathSumSolution.php b/Week_05/G20200343030605/MiniPathSumSolution.php new file mode 100644 index 00000000..297a629a --- /dev/null +++ b/Week_05/G20200343030605/MiniPathSumSolution.php @@ -0,0 +1,40 @@ +miniPathSum($grid); \ No newline at end of file diff --git a/Week_05/G20200343030611/LeetCode_1143_611.java b/Week_05/G20200343030611/LeetCode_1143_611.java new file mode 100644 index 00000000..19b55f4a --- /dev/null +++ b/Week_05/G20200343030611/LeetCode_1143_611.java @@ -0,0 +1,22 @@ +package datast.dp; + +public class LeetCode_1143_611 { + + class Solution { + public int longestCommonSubsequence(String text1, String text2) { + int m = text1.length(); + int n = text2.length(); + int[][] dp = new int[m + 1][n + 1]; + for (int i = 1; i <= m; i++){ + for (int j = 1; j <=n; j++){ + if (text1.charAt(i - 1) == text2.charAt(j - 1)){ + dp[i][j] = dp[i - 1][j - 1] + 1; + } else { + dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]); + } + } + } + return dp[m][n]; + } + } +} diff --git a/Week_05/G20200343030611/LeetCode_120_611.java b/Week_05/G20200343030611/LeetCode_120_611.java new file mode 100644 index 00000000..b7bceadb --- /dev/null +++ b/Week_05/G20200343030611/LeetCode_120_611.java @@ -0,0 +1,19 @@ +package datast.dp; + +import java.util.List; + +public class LeetCode_120_611 { + + class Solution { + public int minimumTotal(List> triangle) { + + int[] dp = new int[triangle.size() + 1]; + for (int i = triangle.size() - 1; i >= 0; i--){ + for (int j = 0; j < triangle.get(i).size(); j++){ + dp[j] = Math.min(dp[j], dp[j + 1]) + triangle.get(i).get(j); + } + } + return dp[0]; + } + } +} diff --git a/Week_05/G20200343030611/LeetCode_198_611.java b/Week_05/G20200343030611/LeetCode_198_611.java new file mode 100644 index 00000000..99855fa3 --- /dev/null +++ b/Week_05/G20200343030611/LeetCode_198_611.java @@ -0,0 +1,19 @@ +package datast.dp; + +public class LeetCode_198_611 { + + class Solution { + public int rob(int[] nums) { + if (nums.length == 0) return 0; + int[] dp = new int[nums.length]; + dp[0] = nums[0]; + dp[1] = Math.max(nums[0], nums[1]); + int max = dp[1]; + for (int i = 2; i < nums.length; i++){ + dp[i] = Math.max(dp[i - 1], dp[i - 2] + nums[i]); + max = Math.max(dp[i], max); + } + return max; + } + } +} diff --git a/Week_05/G20200343030611/LeetCode_322_611.java b/Week_05/G20200343030611/LeetCode_322_611.java new file mode 100644 index 00000000..3ba5c28e --- /dev/null +++ b/Week_05/G20200343030611/LeetCode_322_611.java @@ -0,0 +1,22 @@ +package datast.dp; + +public class LeetCode_322_611 { + + class Solution { + public int coinChange(int[] coins, int amount) { + if (amount == 0) return 0; + if (coins.length == 0) return -1; + int[] dp = new int[amount + 1]; + for (int i = 1; i <= amount; i++){ + int min = Integer.MAX_VALUE; + for (int coin : coins){ + if (i - coin >= 0 && dp[i - coin] < min){ + min = dp[i - coin] + 1; + } + } + dp[i] = min; + } + return dp[amount] == Integer.MAX_VALUE ? -1 : dp[amount]; + } + } +} diff --git a/Week_05/G20200343030611/LeetCode_509_611.java b/Week_05/G20200343030611/LeetCode_509_611.java new file mode 100644 index 00000000..f2476d21 --- /dev/null +++ b/Week_05/G20200343030611/LeetCode_509_611.java @@ -0,0 +1,17 @@ +package datast.dp; + +public class LeetCode_509_611 { + + class Solution { + public int fib(int N) { + if ( N < 2) return N; + int f1 = 0, f2 = 1, f3 = 1; + for (int i = 2; i <= N; i++){ + f3 = f1 + f2; + f1 = f2; + f2 = f3; + } + return f3; + } + } +} diff --git a/Week_05/G20200343030611/LeetCode_53_611.java b/Week_05/G20200343030611/LeetCode_53_611.java new file mode 100644 index 00000000..9d12f153 --- /dev/null +++ b/Week_05/G20200343030611/LeetCode_53_611.java @@ -0,0 +1,18 @@ +package datast.dp; + +public class LeetCode_53_611 { + + class Solution { + public int maxSubArray(int[] nums) { + if (nums.length == 1) return nums[0]; + int[] dp = new int[nums.length]; + dp[0] = nums[0]; + int max = dp[0]; + for (int i = 1; i < nums.length; i ++){ + dp[i] = Math.max(dp[ i - 1], 0) + nums[i]; + max = Math.max(dp[i], max); + } + return max; + } + } +} diff --git a/Week_05/G20200343030611/LeetCode_62_611.java b/Week_05/G20200343030611/LeetCode_62_611.java new file mode 100644 index 00000000..cf22b565 --- /dev/null +++ b/Week_05/G20200343030611/LeetCode_62_611.java @@ -0,0 +1,18 @@ +package datast.dp; + +public class LeetCode_62_611 { + + class Solution { + public int uniquePaths(int m, int n) { + int[][] dp = new int[m][n]; + for (int i = 0; i < m; i++) dp[i][0] = 1; + for (int i = 0; i < n; i++) dp[0][i] = 1; + for (int i = 1; i < m; i++){ + for (int j = 1; j < n; j++){ + dp[i][j] = dp[i - 1][j] + dp[i][j - 1]; + } + } + return dp[m - 1][n - 1]; + } + } +} diff --git a/Week_05/G20200343030611/LeetCode_63_611.java b/Week_05/G20200343030611/LeetCode_63_611.java new file mode 100644 index 00000000..9d0ea8ae --- /dev/null +++ b/Week_05/G20200343030611/LeetCode_63_611.java @@ -0,0 +1,31 @@ +package datast.dp; + +public class LeetCode_63_611 { + + class Solution { + public int uniquePathsWithObstacles(int[][] obstacleGrid) { + if (obstacleGrid[0][0] == 1) return 0; + int m = obstacleGrid.length; + int n = obstacleGrid[0].length; + int[][] dp = new int[m][n]; + for (int i = 0; i < m; i++){ + if (obstacleGrid[i][0] == 1) break; + dp[i][0] = 1; + } + for (int i = 0; i < n; i++){ + if (obstacleGrid[0][i] == 1) break; + dp[0][i] = 1; + } + for (int i = 1;i < m; i++){ + for (int j = 1; j < n; j++){ + if (obstacleGrid[i][j] == 1){ + dp[i][j] = 0; + } else { + dp[i][j] = dp[i - 1][j] + dp[i][j - 1]; + } + } + } + return dp[m - 1][n - 1]; + } + } +} diff --git a/Week_05/G20200343030627/LeetCode_1_627.js b/Week_05/G20200343030627/LeetCode_1_627.js new file mode 100644 index 00000000..425cfab8 --- /dev/null +++ b/Week_05/G20200343030627/LeetCode_1_627.js @@ -0,0 +1,24 @@ +// minimum-path-sum + +var minPathSum = function(grid) { + if (grid.length == 0) { + return 0 + } + + var record = []; + var i,j; + for (i=0; i2 && s[1]==0) return 0; + + if (s.length == 2) { + if (s > 26 || s==10 || s==20) { + return 1; + } else { + return 2 + } + } + + var first = 1; + var second; + if (s.slice(0,2) > 26 || s[1]==0) { + second = 1; + } else { + second = 2; + } + var result; + for(var i=2; i2 || s[i-1]==0) && s[i]==0) return 0; + if (s[i] == 0) { + result = first; + first = 0; + second = result; + } else if (s.slice(i-1,i+1) >26 || s[i-1]==0){ + result = second; + first = second; + second = result; + } else{ + result = first + second; + first = second; + second = result; + } + } + + return result; +}; \ No newline at end of file diff --git a/Week_05/G20200343030631/Leetcode_221_631.java b/Week_05/G20200343030631/Leetcode_221_631.java new file mode 100644 index 00000000..7196134c --- /dev/null +++ b/Week_05/G20200343030631/Leetcode_221_631.java @@ -0,0 +1,43 @@ + +/** + * 解题思路: 动态规划方式查找边长,根据正方形特性,假想一个以当前点作为右下角的正方形,每次计算当前范围内边长 + * 时间复杂度: O(mn) + * 空间复杂度: O(mn) + * 执行用时: 9 ms, 在所有 Java 提交中击败了24.33%的用户 + * 内存消耗: 43.6 MB, 在所有 Java 提交中击败了8.69%的用户 + */ +public class Solution { + public static void main(String[] args) { + char[][] matrix = new char[][]{ + {'1', '0', '1', '0', '0'}, + {'1', '0', '1', '1', '1'}, + {'1', '1', '1', '1', '1'}, + {'1', '0', '0', '1', '0'} + }; + System.out.println(maximalSquare(matrix)); + } + + public static int maximalSquare(char[][] matrix) { + // 边界条件 + if (null == matrix || matrix.length == 0 || matrix[0].length == 0) { + return 0; + } + // 记录二维数组的行列 + int rowCount = matrix.length; + int colCount = matrix[0].length; + // 记录中间状态,行列各多增加一,作为初始状态 + int[][] dp = new int[rowCount + 1][colCount + 1]; + // 记录最大边长 + int maxSquareLength = 0; + for (int i = 0; i < rowCount; i++) { + for (int j = 0; j < colCount; j++) { + if ('1' == matrix[i][j]) { + // 因为中间状态扩展了行列,故计算matrix中的行列中间状态对应的dp时,需要偏移+1 + dp[i + 1][j + 1] = Math.min(Math.min(dp[i][j + 1], dp[i][j]), dp[i + 1][j]) + 1; + maxSquareLength = Math.max(maxSquareLength, dp[i + 1][j + 1]); + } + } + } + return maxSquareLength * maxSquareLength; + } +} diff --git a/Week_05/G20200343030631/Leetcode_647_631.java b/Week_05/G20200343030631/Leetcode_647_631.java new file mode 100644 index 00000000..2a210823 --- /dev/null +++ b/Week_05/G20200343030631/Leetcode_647_631.java @@ -0,0 +1,36 @@ +/** + * 解题思路: 动态规划思路,s[i]-s[j]之间是否为回文取决于s[i+1]-s[j-1]是否为回文及i j位置元素是否相同 + * dp数组定义:dp[i][j]代表i-j之间字符串是否为回文 + * 转移方程:dp[i][j] = dp[i+1][j-1] && s[i]==s[j] + * 时间复杂度: O(n^2) + * 空间复杂度: O(n) + * 执行用时: 13 ms, 在所有 Java 提交中击败了28.93%的用户 + * 内存消耗: 42.2 MB, 在所有 Java 提交中击败了5.13%的用户 + */ +class Solution { + public static void main(String[] args) { + System.out.println(countSubstrings("aaa")); + System.out.println(countSubstrings("abc")); + System.out.println(countSubstrings("aabaa")); + System.out.println(countSubstrings("fdsklf")); + System.out.println(countSubstrings("a")); + } + + public static int countSubstrings(String s) { + int result = 0; + // 边界条件 + if (null == s || s.length() == 0) { + return result; + } + boolean[][] dp = new boolean[s.length()][s.length()]; + for (int i = 0; i < s.length(); i++) { + for (int j = i; j >= 0; j--) { + if (s.charAt(i) == s.charAt(j) && ((i - j) < 2 || dp[i - 1][j + 1])) { + dp[i][j] = true; + result++; + } + } + } + return result; + } +} \ No newline at end of file diff --git a/Week_05/G20200343030631/Leetcode_64_631.java b/Week_05/G20200343030631/Leetcode_64_631.java new file mode 100644 index 00000000..383986e3 --- /dev/null +++ b/Week_05/G20200343030631/Leetcode_64_631.java @@ -0,0 +1,36 @@ +/** + * 解题思路: 自底向上动态规划,碰到边界直接取上方或者左侧元素,未达到边界,取左侧、上方元素中的最小值 + * 时间复杂度: O(mn) + * 空间复杂度: O(1) + * 执行用时: 5 ms, 在所有 Java 提交中击败了11.00%的用户 + * 内存消耗: 42.4 MB, 在所有 Java 提交中击败了23.13%的用户 + */ +public class Solution { + public static void main(String[] args) { + int[][] grid = new int[][]{{1,3,1},{1,5,1},{4,2,1}}; + System.out.println(minPathSum(grid)); + } + + public static int minPathSum(int[][] grid) { + // 边界条件 + if (null == grid || grid.length == 0){ + return 0; + } + // 二维数组的行列数 + int rowCount = grid.length; + int colCount = grid[0].length; + // 自底向上逐步计算 + for (int i = rowCount - 1; i >= 0; i--) { + for (int j = colCount - 1; j >= 0; j--) { + if (j == colCount - 1 && i != rowCount - 1){ // 达到列边界,不许判断最小值,直接取值 + grid[i][j] = grid[i][j] + grid[i+1][j]; + }else if (j != colCount - 1 && i == rowCount - 1){ // 达到行边界,直接取值 + grid[i][j] = grid[i][j] + grid[i][j+1]; + }else if (j != colCount - 1 && i != rowCount - 1){ // 行列都未达到边界,取左侧、上方元素中的最小值 + grid[i][j] = grid[i][j] + Math.min(grid[i+1][j], grid[i][j+1]); + } + } + } + return grid[0][0]; + } +} diff --git a/Week_05/G20200343030631/Leetcode_91_631.java b/Week_05/G20200343030631/Leetcode_91_631.java new file mode 100644 index 00000000..052d8075 --- /dev/null +++ b/Week_05/G20200343030631/Leetcode_91_631.java @@ -0,0 +1,83 @@ +import java.util.HashMap; +import java.util.Map; + +/** + * 解题思路: 分情况讨论,如果当前字符为0,前一字符为1或者2,则dp[i] = dp[i-2];如果当前字符不为0,只有取1位数字和两位数字两种情况,取1位时,到下一个字符需要考虑与前一位相连后是否存在于编码表,取两位时不需要考虑再取前一个字符 + * 时间复杂度: O(n) + * 空间复杂度: O(n) + * 执行用时: 4 ms, 在所有 Java 提交中击败了28.70%的用户 + * 内存消耗: 38.9 MB, 在所有 Java 提交中击败了5.01%的用户 + */ +public class Solution { + // 存放数字与字符的映射 + private static Map codecDic = new HashMap<>(); + + public static void main(String[] args) { + Version2 version1 = new Version2(); + System.out.println(version1.numDecodings("1")); + System.out.println(version1.numDecodings("12")); + System.out.println(version1.numDecodings("226")); + System.out.println(version1.numDecodings("262")); + System.out.println(version1.numDecodings("0")); + System.out.println(version1.numDecodings("10")); + System.out.println(version1.numDecodings("101")); + System.out.println(version1.numDecodings("00")); + System.out.println(version1.numDecodings("100")); + System.out.println(version1.numDecodings("110")); + System.out.println(version1.numDecodings("301")); + System.out.println(version1.numDecodings("27")); + } + + private void prepareCodecDic() { + // 按照ascii码生成 + for (int i = 65; i < 91; i++) { + codecDic.put(String.valueOf(i - 64), (char) i); + } + } + + public int numDecodings(String s) { + // 边界条件,需要考虑0开头特殊情况,0无映射关系 + if (null == s || s.length() == 0 || s.startsWith("0") || s.contains("00")) { + return 0; + } + if (s.length() == 1) { + return 1; + } + // 生成映射关系 + prepareCodecDic(); + // dp数组 + int[] dp = new int[s.length()]; + dp[0] = 1; + if (!s.substring(0, 2).contains("0")) { + if (codecDic.containsKey(s.substring(0, 2))) { + dp[1] = 2; + }else { + dp[1] = 1; + } + }else { + if (codecDic.containsKey(s.substring(0, 2))) { + dp[1] = 1; + }else { + dp[1] = 0; + } + } + + for (int i = 2; i < s.length(); i++) { + String prevTmpStr = s.substring(i - 1, i + 1); + String currentTmpStr = s.substring(i, i + 1); + if ("0".equals(currentTmpStr)) { + if (codecDic.containsKey(prevTmpStr)) { + dp[i] = dp[i - 2]; + } else { + return 0; + } + } else if (codecDic.containsKey(prevTmpStr)) { + dp[i] = dp[i - 1] + dp[i - 2]; + } else { + dp[i] = dp[i - 1]; + } + } + return dp[s.length() - 1]; + } + +} diff --git a/Week_05/G20200343030631/NOTE.md b/Week_05/G20200343030631/NOTE.md index 50de3041..28cbaea7 100644 --- a/Week_05/G20200343030631/NOTE.md +++ b/Week_05/G20200343030631/NOTE.md @@ -1 +1,45 @@ -学习笔记 \ No newline at end of file +# 学习笔记 +## 第十二课 动态规划 + +### 关键点 + +- 动态规划和 递归、分治 没有根本上的区别,关键看有无最优子结构 +- 共性:找到重复子问题 +- 差异性:最优子结构、中途可以淘汰次优解 + +### 解决问题的关键 + +- 1. 最优子结构 opt[n] = best_of(opt[n-1], opt[n-2], ···) +- 2. 储存中间状态:opt[i] +- 3. 递推公式,也叫状态转移方程或者DP方程 + +### 分析问题的思维 + +- 1. 分析问题,找到共性重复点,分解为子问题 +- 2. 找到初始状态、边界 +- 3. 不断重复练习 +- 4. 先定义出状态方程,再优化 + +### 小结 + +- 1. 打破思维惯性,形成机器思维 + + - 机器思维的特点 + + - 重复 + - 简单逻辑 + +- 2. 理解复杂逻辑的关键 +- 3. 也是职业进阶的要点要领 + + - 类推到管理思维上 + +### 练习感悟 + +- 找到重复子问题是关键 + + - 子问题可以是对最终答案的条件,不一定指定就是最终答案 + + - 221-求出边长 + + - 子问题定义不好会在写状态方程时,出现多种异常情况判断条件,此时需要考虑重新定义子问题 diff --git a/Week_05/G20200343030633/leetcode-198-house-robber.py b/Week_05/G20200343030633/leetcode-198-house-robber.py new file mode 100644 index 00000000..b7a8c9a7 --- /dev/null +++ b/Week_05/G20200343030633/leetcode-198-house-robber.py @@ -0,0 +1,15 @@ +# f(n) = max(f(n-2)+V(n),f(n-1)) + +def rob(nums): + def f(n, ns): + if n == 0: + return ns[0] + if n == 1: + return max(ns[0], ns[1]) + return max(f(n - 2, ns) + ns[n], f(n - 1, ns)) + + return f(len(nums) - 1, nums) + + +print(rob([1, 2, 3, 1])) +print(rob([2, 7, 9, 3, 1])) diff --git a/Week_05/G20200343030633/leetcode-322-coin-change.py b/Week_05/G20200343030633/leetcode-322-coin-change.py new file mode 100644 index 00000000..bea744a6 --- /dev/null +++ b/Week_05/G20200343030633/leetcode-322-coin-change.py @@ -0,0 +1,48 @@ +# 寻找最优子结构:S的最少硬币数,是由S减去最后一枚币值大小的最少硬币数+1 +# 定义状态:F(S) = F(S-C)+1 +# DP方程:F(S) = min(F(S-C) C IN [1,2,5]) + 1 +import functools + +#自顶向下 +def coinChange(coins, amount): + def dp(rem, coinsx): + if rem < 0: + return -1 + if rem == 0: + return 0 + mini = int(1e9) + for coin in coinsx: + res = dp(rem - coin, coinsx) + if 0 <= res < mini: + mini = res + 1 + return mini if mini < int(1e9) else -1 + + if amount < 1: + return 0 + return dp(amount, coins) + +# 自下而上 +def coinChange1(coins, amount): + MAX = float('inf') + dp = [0] + [MAX] * amount + + for i in range(1, amount + 1): + dp[i] = min([dp[i - c] if i - c >= 0 else MAX for c in coins]) + 1 + + print(dp) + return [dp[amount], -1][dp[amount] == MAX] + +#拼不出来的不用算,change1的内外循环对调 +def coinChange2(coins, amount): + dp = [float('inf')] * (amount + 1) + dp[0] = 0 + + for coin in coins: + for x in range(coin, amount + 1): + dp[x] = min(dp[x], dp[x - coin] + 1) + print(dp) + return dp[amount] if dp[amount] != float('inf') else -1 + + + +print(coinChange2([6, 8, 9], 8)) diff --git a/Week_05/G20200343030633/leetcode-72-edit-distance.py b/Week_05/G20200343030633/leetcode-72-edit-distance.py new file mode 100644 index 00000000..7b0a8fb6 --- /dev/null +++ b/Week_05/G20200343030633/leetcode-72-edit-distance.py @@ -0,0 +1,51 @@ +class Solution: + #自下而上--循环迭代 + def minDistance(self, word1, word2): + """ + :type word1: str + :type word2: str + :rtype: int + """ + n = len(word1) + m = len(word2) + + # if one of the strings is empty + if n * m == 0: + return n + m + + # array to store the convertion history + d = [[0] * (m + 1) for _ in range(n + 1)] + + # init boundaries + for i in range(n + 1): + d[i][0] = i + for j in range(m + 1): + d[0][j] = j + + # DP compute + for i in range(1, n + 1): + for j in range(1, m + 1): + left = d[i - 1][j] + 1 + down = d[i][j - 1] + 1 + left_down = d[i - 1][j - 1] + if word1[i - 1] != word2[j - 1]: + left_down += 1 + d[i][j] = min(left, down, left_down) + + return d[n][m] + + #自顶向下--递归 + def minDistance2(self, word1: str, word2: str) -> int: + if not word1 or not word2: + return len(word1) + len(word2) + if word1[0] == word2[0]: + return self.minDistance(word1[1:], word2[1:]) + else: + inserted = 1 + self.minDistance(word1, word2[1:]) + deleted = 1 + self.minDistance(word1[1:], word2) + replace = 1 + self.minDistance(word1[1:], word2[1:]) + return min(inserted, deleted, replace) + +s = Solution() +print(s.minDistance("exit","eerr")) +print(s.minDistance2("horse","ros")) \ No newline at end of file diff --git a/Week_05/G20200343030635/id_635/62.py b/Week_05/G20200343030635/id_635/62.py new file mode 100644 index 00000000..bededeeb --- /dev/null +++ b/Week_05/G20200343030635/id_635/62.py @@ -0,0 +1,18 @@ +class Solution: + def minPathSum(self, grid: List[List[int]]) -> int: + if not grid: return 0 + row = len(grid) + col = len(grid[0]) + dp = [[0]*col for _ in range(row)] + dp[0][0] = grid[0][0] + # 第一行 + for j in range(1, col): + dp[0][j] = dp[0][j-1] + grid[0][j] + # 第一列 + for i in range(1, row): + dp[i][0] = dp[i-1][0] + grid[i][0] + + for i in range(1, row): + for j in range(1, col): + dp[i][j] = min(dp[i-1][j], dp[i][j-1]) + grid[i][j] + return dp[-1][-1] diff --git a/Week_05/G20200343030635/id_635/91.py b/Week_05/G20200343030635/id_635/91.py new file mode 100644 index 00000000..610f39c3 --- /dev/null +++ b/Week_05/G20200343030635/id_635/91.py @@ -0,0 +1,7 @@ +class Solution: + def numDecodings(self, s: str) -> int: + pp, p = 1, int(s[0] != '0') + for i in range(1, len(s)): + pp, p = p, pp * (9 < int(s[i-1:i+1]) <= 26) + p * (int(s[i]) > 0) + return p + diff --git a/Week_06/G20190282010007/NOTE.md b/Week_06/G20190282010007/NOTE.md index 50de3041..04665946 100644 --- a/Week_06/G20190282010007/NOTE.md +++ b/Week_06/G20190282010007/NOTE.md @@ -1 +1,46 @@ -学习笔记 \ No newline at end of file +学习笔记 + +并查集 +1、 适用场景 +组团、配对问题 +group or not? +2、 基本操作 +makeSet(s): 建立一个新的并查集,其中包含s个单元素集合 +unionSet(x, y): 把元素x和元素y所在的集合合并,要求x和y所在的集合不相交,如果相交则不合并 +find(x): 找到元素x所在的集合的代表,该操作也可以用于判断两个元素是否位于同一个集合,只要将他们各自的代表比较一下就可以了 + +并查集的js代码模板 + let makeSet = (x) => { parent[x] = x} + let find = (x) => { + while (parent[x] != x) { + parent[x] = parent[parent[x]] + x = parent[x] + } + return x + } + let union = (x, y) => { + let rootX = find(x), rootY = find(y) + if (rootX == rootY) return + parent[rootX] = rootY + } + +字典树 +1、 字典树的数据结构 +即Trie树,又称单词查找树或键树,是一种属性结构,典型应用是用于统计和排序大量的字符串(但不仅限于字符串),所以经常被搜索引擎用于文本词频统计 +优点是:最大限度的减少无谓的字符串比较,查询效率比哈希表高 +2、 字典树的核心思想 +空间换时间 +利用字符串的公共前缀来降低查询时间的开销以达到提高效率的目的 +3、 字典树的基本性质 +a、节点本身不存完整单词; +b、从根节点到某一节点,路径上经过的字符链接起来,为该节点对应的字符串 +c、每个节点的所有子节点路径代表的字符都不相同 + + +关于单词搜索2的时间复杂度分析,构造字典的时候,需要循环words,words中的每个单词也要将字母抽取出来 +所以第一步构造字典树已有O(n*n) +然后dfs中,4向查找,每个board的元素查找4次,这里又有,O(4*n) = O(n) +循环遍历board中的没个元素拿去dfs,由于题目中的board是二维数组,那么两层循环下来,是O(n*n) +所以单词搜索2的总时间复杂度为:O(n*n) + O(n) + O(n*n) = O(n*n) + +高级搜索很懵逼,AVL树(自平衡树)和红黑树(自平衡二叉搜索树)也是很懵逼,多方面查资料与反复过遍数中 \ No newline at end of file diff --git a/Week_06/G20190282010007/leetcode_212_007.js b/Week_06/G20190282010007/leetcode_212_007.js new file mode 100644 index 00000000..eb89ce89 --- /dev/null +++ b/Week_06/G20190282010007/leetcode_212_007.js @@ -0,0 +1,68 @@ +// 题目: 单词搜索2 +/** + * 题目描述: +给定一个二维网格 board 和一个字典中的单词列表 words,找出所有同时在二维网格和字典中出现的单词。 + +单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母在一个单词中不允许被重复使用。 + + + */ + + // 解题语言: javaScript + + // 解题 + + /** + * @param {character[][]} board + * @param {string[]} words + * @return {string[]} + */ + var findWords = function (board, words) { + // 定好4向 + let direction = [[-1, 0], [1, 0], [0, -1], [0,1]] + // 创建字典树trie + const trie = {} + for (const word of words) { + node = trie + for (const char of word) { + if (!node[char]) {node[char] = {}} + // node[char] = node[char] || {} + node = node[char] + } + node._end = true + } + // dfs + function dfs(board, node, i, j, word) { + // 将单词放入Set数组中 + if (node._end) { + res.add(word) + } + // 当前逻辑 + const tmp = board[i][j] + board[i][j] = '@' + for (const arr of direction) { + let _i = i + arr[0] + let _j = j + arr[1] + if (_i >= 0 && _i < m && _j >= 0 && _j < n && node[board[_i,_j]] && board[_i][_j] !== '@' && board[_i]) { + // 根据条件判断是否下探 + dfs(board, node[board[_i][_j]], _i, _j, word + board[_i][_j]) + } + } + // 还原 + board[i][j] = tmp + } + + // 使用dfs + const res = new Set() + const m = board.length + const n = board[0].length + + for (let i = 0; i < m; i++) { + for (let j = 0; j < n; j++) { + if (trie[board[i][j]]) { + dfs(board, trie[board[i][j]], i, j, board[i][j]) + } + } + } + return Array.from(res) + } \ No newline at end of file diff --git a/Week_06/G20190282010007/leetcode_547_007.js b/Week_06/G20190282010007/leetcode_547_007.js new file mode 100644 index 00000000..5a9a2902 --- /dev/null +++ b/Week_06/G20190282010007/leetcode_547_007.js @@ -0,0 +1,52 @@ +// 题目: 朋友圈 +/** + * 题目描述: +班上有 N 名学生。其中有些人是朋友,有些则不是。他们的友谊具有是传递性。如果已知 A 是 B 的朋友,B 是 C 的朋友, +那么我们可以认为 A 也是 C 的朋友。所谓的朋友圈,是指所有朋友的集合。 + +给定一个 N * N 的矩阵 M,表示班级中学生之间的朋友关系。如果M[i][j] = 1,表示已知第 i 个和 j 个学生互为朋友关系, +否则为不知道。你必须输出所有学生中的已知的朋友圈总数。 + + */ + + // 解题语言: javaScript + + // 解题 + +/** + * + * @param {number[][]} M + * @return {number} + */ +var findCircleNum = function (M) { + let n = M.length + if (n == 0) return 0 + let count = n + + // 声明单集 + let parent = new Array(n) + for (let i = 0; i < n; i++) parent[i] = i + + let findParent = (p) => { + while (parent[p] != p) { + parent[p] = parent[parent[p]] + p = parent[p] + } + return p + } + + let union = (p, q) => { + let rootP = findParent(p), rootQ = findParent(q) + if (rootP === rootQ) return + parent[rootP] = rootQ + count-- + } + + for (let i = 0; i < n; i++ ) { + for (let j = 0; j < n; j++) { + if (M[i][j] === 1) union(i, j) + } + } + return count +} + diff --git a/Week_06/G20190379010083/LeetCode_200_083.swift b/Week_06/G20190379010083/LeetCode_200_083.swift new file mode 100644 index 00000000..a9d6a897 --- /dev/null +++ b/Week_06/G20190379010083/LeetCode_200_083.swift @@ -0,0 +1,67 @@ +// +// 0200_NumberOfIslands.swift +// AlgorithmPractice +// +// https://leetcode-cn.com/problems/number-of-islands/ +// 第一遍总结: +// 1、经典DFS操作,没有什么好说的 +// 2、BFS,相关题目:94 RottingOranges(腐烂的橘子) +// Created by Ryeagler on 2020/3/16. +// Copyright © 2020 Ryeagle. All rights reserved. +// + +import Foundation + +class NumberOfIslands { + //MARK: DFS(递归) + func numIslands(_ grid: [[Character]]) -> Int { + var grid = grid, count = 0 + for i in 0..= 0 && i < grid.count && j >= 0 && j < grid[0].count && grid[i][j] == "1" { + grid[i][j] = "0" + dfs(&grid, i, i + 1) + dfs(&grid, i, j - 1) + dfs(&grid, i - 1, j) + dfs(&grid, i + 1, j) + } + } + + //MARK: BFS + func numIslands_BFS(_ grid: [[Character]]) -> Int { + var grid = grid, count = 0 + var queue = Queue<(Int, Int)>() + let directions = [[1, 0], [-1, 0], [0, 1], [0, -1]] + for i in 0..= 0 && row < grid.count && column >= 0 && column < grid[0].count && grid[row][column] == "1" { + grid[row][column] = "0" + queue.enqueue((row, column)) + } + } + } + } + } + } + return count + } + +} diff --git a/Week_06/G20190379010083/LeetCode_22_083.swift b/Week_06/G20190379010083/LeetCode_22_083.swift new file mode 100644 index 00000000..6afdd2fd --- /dev/null +++ b/Week_06/G20190379010083/LeetCode_22_083.swift @@ -0,0 +1,69 @@ +// +// 0022_GenerateParentheses.swift +// AlgorithmPractice +// +// https://leetcode-cn.com/problems/generate-parentheses/ +// Created by Ryeagler on 2020/2/26. +// Copyright © 2020 Ryeagle. All rights reserved. +// + +import Foundation + +class GenerateParentheses { + //MARK: Backtrace + func generateParentheses(_ n: Int) -> [String] { + var combinations = [String]() + backtrace(&combinations, String(), 0, 0, n) + return combinations + } + + private func backtrace(_ result: inout [String], _ current: String, _ open: Int, _ close: Int, _ max: Int) { + if current.count == 2 * max { + result.append(current) + return + } + if open < max { + backtrace(&result, current + "(", open + 1, close, max) + } + if close < open { + backtrace(&result, current + ")", open, close + 1, max) + } + } + + //MARK: Brute Force + func generate(_ n: Int) -> [String] { + var combinations = [String]() + var current = [Character](repeating: " ", count: 2 * n) + generateAll(¤t, 0, &combinations) + return combinations + } + + private func generateAll(_ current: inout [Character], _ position: Int, _ result: inout [String]) { + if position == current.count { + if valid(current) { + result.append(String(current)) + } + } else { + current[position] = "(" + generateAll(¤t, position + 1, &result) + current[position] = ")" + generateAll(¤t, position + 1, &result) + } + } + + func valid(_ current: [Character]) -> Bool { + var balance = 0 + for c in current { + if c == "(" { + balance += 1 + } else { + balance -= 1 + } + if balance < 0 { + return false + } + } + return balance == 0 + } +} + diff --git a/Week_06/G20200343030001/Leetcode_022_001.java b/Week_06/G20200343030001/Leetcode_022_001.java new file mode 100644 index 00000000..efa3e4be --- /dev/null +++ b/Week_06/G20200343030001/Leetcode_022_001.java @@ -0,0 +1,36 @@ +package Week_06; + +import java.util.ArrayList; +import java.util.List; + +public class Leetcode_022_001 { + private List ans; + + public List generateParenthesis(int n) { + ans = new ArrayList<>(); + + dfs(0, 0, n, ""); + + return ans; + } + + private void dfs(int left, int right, int n, String str) { + if (left == n && left == right) { + ans.add(str); + + return; + } + + if (left < n) { + dfs(left + 1, right, n, str + "("); + } + + if (right < left) { + dfs(left, right + 1, n,str + ")"); + } + } + + public static void main(String[] args) { + System.out.println(new Leetcode_022_001().generateParenthesis(3)); + } +} diff --git a/Week_06/G20200343030001/Leetcode_070_001.java b/Week_06/G20200343030001/Leetcode_070_001.java new file mode 100644 index 00000000..ab13085b --- /dev/null +++ b/Week_06/G20200343030001/Leetcode_070_001.java @@ -0,0 +1,51 @@ +package Week_06; + +/** + * 爬楼梯,类似题目解法基本一致 + */ +public class Leetcode_070_001 { + /** + * 斐波那契数列法 + * + * @param n + * @return + */ + public int climbStairs(int n) { + if (n < 4) { + return n; + } + + int f1 = 1, f2 = 2, f3 = 3; + + for (int i = 3; i < n + 1; i++) { + f3 = f2 + f1; + f1 = f2; + f2 = f3; + } + + return f3; + } + + /** + * 动态规划法 + * + * @param n + * @return + */ + public int climbStairs(int n) { + if (n < 4) { + return n; + } + + int[] dp = new int[n + 1]; + + dp[1] = 1; + dp[2] = 2; + + for (int i = 3; i < n + 1; i++) { + dp[i] = dp[i - 1] + dp[i - 2]; + } + + return dp[n]; + } +} diff --git a/Week_06/G20200343030001/Leetcode_206_001.java b/Week_06/G20200343030001/Leetcode_206_001.java new file mode 100644 index 00000000..9752e2bd --- /dev/null +++ b/Week_06/G20200343030001/Leetcode_206_001.java @@ -0,0 +1,72 @@ +package Week_06; + +class Leetcode_026_001 { + private class TrieNode { + private boolean isEnd; + private TrieNode[] next; + + public TrieNode() { + isEnd = false; + next = new TrieNode[26]; + } + + } + + private TrieNode root; + + /** Initialize your data structure here. */ + public Leetcode_026_001() { + root = new TrieNode(); + } + + /** Inserts a word into the trie. */ + public void insert(String word) { + TrieNode cur = root; + for (int i = 0, len = word.length(), ch; i < len; i++) { + ch = word.charAt(i) - 'a'; + + if (cur.next[ch] == null) { + cur.next[ch] = new TrieNode(); + } + + cur = cur.next[ch]; + } + + cur.isEnd = true; + } + + /** Returns if the word is in the trie. */ + public boolean search(String word) { + TrieNode cur = root; + for (int i = 0, len = word.length(), ch; i < len; i++) { + ch = word.charAt(i) - 'a'; + + if (cur.next[ch] == null) { + return false; + } + + cur = cur.next[ch]; + } + + return cur.isEnd; + } + + /** + * Returns if there is any word in the trie that starts with the given prefix. + */ + public boolean startsWith(String prefix) { + TrieNode cur = root; + + for (int i = 0, len = prefix.length(), ch; i < len; i++) { + ch = prefix.charAt(i) - 'a'; + + if (cur.next[ch] == null) { + return false; + } + + cur = cur.next[ch]; + } + + return true; + } +} diff --git a/Week_06/G20200343030001/Leetcode_547_001.java b/Week_06/G20200343030001/Leetcode_547_001.java new file mode 100644 index 00000000..ad4b8084 --- /dev/null +++ b/Week_06/G20200343030001/Leetcode_547_001.java @@ -0,0 +1,27 @@ +package Week_06; + +public class Leetcode_547_001 { + public int findCircleNum(int[][] M) { + boolean[] visited = new boolean[M.length]; + int ret = 0; + + for(int i = 0; i < M.length; ++i) { + if(!visited[i]) { + dfs(M, visited, i); + ret++; + } + } + + return ret; + } + + private void dfs(int[][] m, boolean[] visited, int i) { + for(int j = 0; j < m.length; ++j) { + if(m[i][j] == 1 && !visited[j]) { + visited[j] = true; + + dfs(m, visited, j); + } + } + } +} diff --git a/Week_06/G20200343030005/Leetcode_208_001.js b/Week_06/G20200343030005/Leetcode_208_001.js new file mode 100644 index 00000000..e456af99 --- /dev/null +++ b/Week_06/G20200343030005/Leetcode_208_001.js @@ -0,0 +1,70 @@ +// 208. 实现 Trie (前缀树) https://leetcode-cn.com/problems/implement-trie-prefix-tree/ + +var TrieNode = function() { + this.next = {}; + this.isEnd = false; +}; + +/** + * Initialize your data structure here. + */ +var Trie = function() { + this.root = new TrieNode(); +}; + +/** + * Inserts a word into the trie. + * @param {string} word + * @return {void} + */ +Trie.prototype.insert = function(word) { + if (!word) return false; + + let node = this.root; + for (let i = 0; i < word.length; ++i) { + if (!node.next[word[i]]) { + node.next[word[i]] = new TrieNode(); + } + node = node.next[word[i]]; + } + node.isEnd = true; + return true; +}; + +/** + * Returns if the word is in the trie. + * @param {string} word + * @return {boolean} + */ +Trie.prototype.search = function(word) { + if (!word) return false; + + let node = this.root; + for (let i = 0; i < word.length; ++i) { + if (node.next[word[i]]) { + node = node.next[word[i]]; + } else { + return false; + } + } + return node.isEnd; +}; + +/** + * Returns if there is any word in the trie that starts with the given prefix. + * @param {string} prefix + * @return {boolean} + */ +Trie.prototype.startsWith = function(prefix) { + if (!prefix) return true; + + let node = this.root; + for (let i = 0; i < prefix.length; ++i) { + if (node.next[prefix[i]]) { + node = node.next[prefix[i]]; + } else { + return false; + } + } + return true; +}; diff --git a/Week_06/G20200343030005/Leetcode_22_001.js b/Week_06/G20200343030005/Leetcode_22_001.js new file mode 100644 index 00000000..748fa595 --- /dev/null +++ b/Week_06/G20200343030005/Leetcode_22_001.js @@ -0,0 +1,25 @@ +// 22. 括号生成 https://leetcode-cn.com/problems/generate-parentheses/ + +var generateParenthesis = function(n) { + let res = []; + // cur :当前字符 left:当前字符左括号 right:当前字符右括号 + const help = (cur, left, right) => { + if (cur.length === 2 * n) { + res.push(cur); + return; + } + if (left < n) { + help(cur + "(", left + 1, right); + } + if (right < left) { + help(cur + ")", left, right + 1); + } + }; + help("", 0, 0); + return res; +}; + +// n = 3 +var n = 3; + +console.log(generateParenthesis(n)); diff --git a/Week_06/G20200343030005/Leetcode_433_001.js b/Week_06/G20200343030005/Leetcode_433_001.js new file mode 100644 index 00000000..45018bf0 --- /dev/null +++ b/Week_06/G20200343030005/Leetcode_433_001.js @@ -0,0 +1,32 @@ +// 433. 最小基因变化 https://leetcode-cn.com/problems/minimum-genetic-mutation/ + +/** + * @param {string} start + * @param {string} end + * @param {string[]} bank + * @return {number} + */ +var minMutation = function(start, end, bank) { + let bankSet = new Set(bank); + if (!bankSet.has(end)) return -1; + let queue = [[start, 0]]; + let dna = ["A", "C", "G", "T"]; + while (queue.length) { + let [node, count] = queue.shift(); + if (node === end) return count; + for (let i = 0; i < node.length; i++) { + for (let j = 0; j < dna.length; j++) { + let d = node.slice(0, i) + dna[j] + node.slice(i + 1); + if (bankSet.has(d)) { + queue.push([d, count + 1]); + bankSet.delete(d); + } + } + } + } + return -1; +}; +var start = "AACCGGTT"; +var end = "AACCGGTA"; +var bank = ["AACCGGTA"]; +console.log(minMutation(start, end, bank)); diff --git a/Week_06/G20200343030005/Leetcode_70_001.js b/Week_06/G20200343030005/Leetcode_70_001.js new file mode 100644 index 00000000..695a81f5 --- /dev/null +++ b/Week_06/G20200343030005/Leetcode_70_001.js @@ -0,0 +1,41 @@ +// 70. 爬楼梯 https://leetcode-cn.com/problems/climbing-stairs/ + +/** + * @param {number} n + * @return {number} + */ +// 方法一:暴力法 +var climbStairs = function(n) { + return climb_Stairs(0, n); +}; +function climb_Stairs(i, n) { + if (i > n) { + return 0; + } + if (i == n) { + return 1; + } + return climb_Stairs(i + 1, n) + climb_Stairs(i + 2, n); +} +// 方法三:动态规划 +/* var climbStairs = function(n) { + if (n == 1) { + return 1; + } + var dp = new Array(n + 1); + dp[1] = 1; + dp[2] = 2; + for (var i = 3; i <= n; i++) { + dp[i] = dp[i - 1] + dp[i - 2]; + } + return dp[n]; +}; */ + +// 方法六:斐波那契公式 +/* var climbStairs = function(n) { + const sqrt5 = Math.sqrt(5); + const fibn = + Math.pow((1 + sqrt5) / 2, n + 1) - Math.pow((1 - sqrt5) / 2, n + 1); + return Math.round(fibn / sqrt5); +}; */ +console.log(climbStairs(7)); diff --git a/Week_06/G20200343030007/Leetcode_007_22.java b/Week_06/G20200343030007/Leetcode_007_22.java new file mode 100644 index 00000000..0c4c17b0 --- /dev/null +++ b/Week_06/G20200343030007/Leetcode_007_22.java @@ -0,0 +1,47 @@ +public class Solution { + + class Node { + /** + * 当前得到的字符串 + */ + private String res; + /** + * 剩余左括号数量 + */ + private int left; + /** + * 剩余右括号数量 + */ + private int right; + + public Node(String str, int left, int right) { + this.res = str; + this.left = left; + this.right = right; + } + } + + public List generateParenthesis(int n) { + List res = new ArrayList<>(); + if (n == 0) { + return res; + } + Queue queue = new LinkedList<>(); + queue.offer(new Node("", n, n)); + + while (!queue.isEmpty()) { + + Node curNode = queue.poll(); + if (curNode.left == 0 && curNode.right == 0) { + res.add(curNode.res); + } + if (curNode.left > 0) { + queue.offer(new Node(curNode.res + "(", curNode.left - 1, curNode.right)); + } + if (curNode.right > 0 && curNode.left < curNode.right) { + queue.offer(new Node(curNode.res + ")", curNode.left, curNode.right - 1)); + } + } + return res; + } +} diff --git a/Week_06/G20200343030007/Leetcode_007_36.java b/Week_06/G20200343030007/Leetcode_007_36.java new file mode 100644 index 00000000..789d4bb2 --- /dev/null +++ b/Week_06/G20200343030007/Leetcode_007_36.java @@ -0,0 +1,35 @@ +class Solution { + public boolean isValidSudoku(char[][] board) { + // init data + HashMap [] rows = new HashMap[9]; + HashMap [] columns = new HashMap[9]; + HashMap [] boxes = new HashMap[9]; + for (int i = 0; i < 9; i++) { + rows[i] = new HashMap(); + columns[i] = new HashMap(); + boxes[i] = new HashMap(); + } + + // validate a board + for (int i = 0; i < 9; i++) { + for (int j = 0; j < 9; j++) { + char num = board[i][j]; + if (num != '.') { + int n = (int)num; + int box_index = (i / 3 ) * 3 + j / 3; + + // keep the current cell value + rows[i].put(n, rows[i].getOrDefault(n, 0) + 1); + columns[j].put(n, columns[j].getOrDefault(n, 0) + 1); + boxes[box_index].put(n, boxes[box_index].getOrDefault(n, 0) + 1); + + // check if this value has been already seen before + if (rows[i].get(n) > 1 || columns[j].get(n) > 1 || boxes[box_index].get(n) > 1) + return false; + } + } + } + + return true; + } +} diff --git a/Week_06/G20200343030009/LeetCode_208_009.js b/Week_06/G20200343030009/LeetCode_208_009.js new file mode 100644 index 00000000..7a84f466 --- /dev/null +++ b/Week_06/G20200343030009/LeetCode_208_009.js @@ -0,0 +1,45 @@ +/* + 208. 实现 Trie (前缀树) + 实现一个 Trie (前缀树),包含 insert, search, 和 startsWith 这三个操作。 + + 示例: + Trie trie = new Trie(); + + trie.insert("apple"); + trie.search("apple"); // 返回 true + trie.search("app"); // 返回 false + trie.startsWith("app"); // 返回 true + trie.insert("app"); + trie.search("app"); // 返回 true + 说明: + 你可以假设所有的输入都是由小写字母 a-z 构成的。 + 保证所有输入均为非空字符串。 +*/ +var Trie = function() { + this.root = {} + this.end_of_word = '#' +}; +Trie.prototype.insert = function(word) { + let node = this.root + for (let char of word) { + if (!node.hasOwnProperty(char)) node[char] = {} + node = node[char] + } + node.end_of_word = this.end_of_word +}; +Trie.prototype.search = function(word) { + let node = this.root + for (let char of word) { + if (!node.hasOwnProperty(char)) return false + node = node[char] + } + return node.hasOwnProperty('end_of_word') +}; +Trie.prototype.startsWith = function(prefix) { + let node = this.root + for (let char of prefix) { + if (!node.hasOwnProperty(char)) return false + node = node[char] + } + return true +}; \ No newline at end of file diff --git a/Week_06/G20200343030009/LeetCode_547_009.js b/Week_06/G20200343030009/LeetCode_547_009.js new file mode 100644 index 00000000..89bd2161 --- /dev/null +++ b/Week_06/G20200343030009/LeetCode_547_009.js @@ -0,0 +1,78 @@ +/* + 547. 朋友圈 + 班上有 N 名学生。其中有些人是朋友,有些则不是。他们的友谊具有是传递性。如果已知 A 是 B 的朋友,B 是 C 的朋友,那么我们可以认为 A 也是 C 的朋友。所谓的朋友圈,是指所有朋友的集合。 + 给定一个 N * N 的矩阵 M,表示班级中学生之间的朋友关系。如果M[i][j] = 1,表示已知第 i 个和 j 个学生互为朋友关系,否则为不知道。你必须输出所有学生中的已知的朋友圈总数。 + + 示例 1: + 输入: + [[1,1,0], + [1,1,0], + [0,0,1]] + 输出: 2 + 说明:已知学生0和学生1互为朋友,他们在一个朋友圈。 + 第2个学生自己在一个朋友圈。所以返回2。 + + 示例 2: + 输入: + [[1,1,0], + [1,1,1], + [0,1,1]] + 输出: 1 + + 说明:已知学生0和学生1互为朋友,学生1和学生2互为朋友,所以学生0和学生2也是朋友,所以他们三个在一个朋友圈,返回1。 + 注意: + N 在[1,200]的范围内。 + 对于所有学生,有M[i][i] = 1。 + 如果有M[i][j] = 1,则有M[j][i] = 1。 +*/ +/** + * @param {number[][]} M + * @return {number} + */ +var findCircleNum = function(M) { + if (!M || !M.length) return 0 + + let n = M.length + let p = [] + for (let i = 0; i < n; i++) { + p[i] = i + } + + for (let i = 0; i < n; i++) { + for (let j = 0; j < n; j++) { + // 并查集:合并 + if (M[i][j] === 1) union(p, i, j) + } + } + + // 使用set保存数据,最后统计数量 + let set = new Set() + for (let i = 0; i < n; i++) { + set.add(parent(p, i)) + } + let num = 0 + set.forEach((item) => { + num++ + }) + return num + +}; + +// 并查集api +function union (p, i, j) { + p1 = parent(p, i) + p2 = parent(p, j) + p[p2] = p1 +} +function parent (p, i) { + let root = i + while (p[root] !== root) { + root = p[root] + } + while (p[i] !== i) { + let x = i + i = p[i] + p[x] = root + } + return root +} \ No newline at end of file diff --git a/Week_06/G20200343030015/LeetCode_127_015.java b/Week_06/G20200343030015/LeetCode_127_015.java new file mode 100644 index 00000000..3c599f48 --- /dev/null +++ b/Week_06/G20200343030015/LeetCode_127_015.java @@ -0,0 +1,71 @@ +package G20200343030015.week_06; + +import javafx.util.Pair; + +import java.util.*; + +/** + * Created by majiancheng on 2020/3/22. + */ + +/** + * 127. 单词接龙 + * 给定两个单词(beginWord 和 endWord)和一个字典,找到从 beginWord 到 endWord 的最短转换序列的长度。转换需遵循如下规则: + *

+ * 每次转换只能改变一个字母。 + * 转换过程中的中间单词必须是字典中的单词。 + *

+ * 来源:力扣(LeetCode) + * 链接:https://leetcode-cn.com/problems/word-ladder + * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + */ +public class LeetCode_127_015 { + + //将wordList中的词统一变为 *bc, a*c, ab* + //采用广度搜索 遍历每个值 + public int ladderLength(String beginWord, String endWord, List wordList) { + if (!wordList.contains(endWord)) { + return 0; + } + + int length = beginWord.length(); + Map> wordMap = new HashMap>(); + for (String word : wordList) { + for (int i = 0; i < length; i++) { + String tmpWord = word.substring(0, i) + "*" + word.substring(i + 1, length); + List tmpList = wordMap.getOrDefault(tmpWord, new ArrayList()); + tmpList.add(word); + wordMap.put(tmpWord, tmpList); + } + } + + Queue> queue = new LinkedList>(); + queue.add(new Pair(beginWord, 1)); + Set visited = new HashSet(); + visited.add(beginWord); + + while (!queue.isEmpty()) { + Pair tmpPair = queue.remove(); + String word = (String) tmpPair.getKey(); + int level = (Integer) tmpPair.getValue(); + for (int i = 0; i < length; i++) { + List tmpWordList = wordMap + .getOrDefault(word.substring(0, i) + "*" + word.substring(i + 1, length), + new ArrayList(0)); + for (String tmpWord : tmpWordList) { + + if (tmpWord.equals(endWord)) { + return level + 1; + } + if (!visited.contains(tmpWord)) { + visited.add(tmpWord); + queue.add(new Pair(tmpWord, level + 1)); + } + } + } + + } + + return 0; + } +} diff --git a/Week_06/G20200343030015/LeetCode_200_015.java b/Week_06/G20200343030015/LeetCode_200_015.java new file mode 100644 index 00000000..f0f9c5f5 --- /dev/null +++ b/Week_06/G20200343030015/LeetCode_200_015.java @@ -0,0 +1,49 @@ +package G20200343030015.week_06; + +/** + * Created by majiancheng on 2020/3/22. + */ + +/** + * 200. 岛屿数量 + *

+ * 给定一个由 '1'(陆地)和 '0'(水)组成的的二维网格,计算岛屿的数量。一个岛被水包围,并且它是通过水平方向或垂直方向上相邻的陆地连接而成的。你可以假设网格的四个边均被水包围。 + *

+ * 来源:力扣(LeetCode) + * 链接:https://leetcode-cn.com/problems/number-of-islands + * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + */ +public class LeetCode_200_015 { + + //使用深度优先遍历 + public int numIslands(char[][] grid) { + if (grid.length == 0) return 0; + int rl = grid.length; + int cl = grid[0].length; + int numIslands = 0; + for (int i = 0; i < grid.length; i++) { + for (int j = 0; j < grid[i].length; j++) { + if (grid[i][j] == '1') { + dfs(grid, i, j); + numIslands++; + } + } + } + return numIslands; + } + + //深度优先遍历 + public void dfs(char[][] grid, int i, int j) { + int rl = grid.length; + int cl = grid[0].length; + if (i < 0 || j < 0 || i >= rl || j >= cl || grid[i][j] == '0') { + return; + } + + grid[i][j] = '0'; + dfs(grid, i - 1, j); + dfs(grid, i + 1, j); + dfs(grid, i, j - 1); + dfs(grid, i, j + 1); + } +} diff --git a/Week_06/G20200343030015/LeetCode_208_015.java b/Week_06/G20200343030015/LeetCode_208_015.java new file mode 100644 index 00000000..bdf3a71b --- /dev/null +++ b/Week_06/G20200343030015/LeetCode_208_015.java @@ -0,0 +1,96 @@ +package G20200343030015.week_06; + +/** + * Created by majiancheng on 2020/3/22. + */ + +/** + * 208. 实现 Trie (前缀树) + * 实现一个 Trie (前缀树),包含 insert, search, 和 startsWith 这三个操作。 + * + */ +public class LeetCode_208_015 { + private TrieNode root; + + /** Initialize your data structure here. */ + public LeetCode_208_015() { + root = new TrieNode(); + } + + /** Inserts a word into the trie. */ + public void insert(String word) { + TrieNode node = root; + for(int i = 0; i < word.length(); i++) { + char c = word.charAt(i); + if(!node.containsKey(c)) { + node.put(c, new TrieNode()); + } + + node = node.get(c); + } + + node.setEnd(true); + } + + /** Returns if the word is in the trie. */ + public boolean search(String word) { + TrieNode endNode = this.searchPrefix(word); + + return endNode != null && endNode.isEnd(); + } + + /** Returns if there is any word in the trie that starts with the given prefix. */ + public boolean startsWith(String prefix) { + TrieNode endNode = this.searchPrefix(prefix); + + return endNode != null; + } + + + private TrieNode searchPrefix(String word) { + TrieNode node = root; + for(int i = 0; i < word.length(); i++) { + char c = word.charAt(i); + if(!node.containsKey(c)) { + return null; + } + + node = node.get(c); + } + + return node; + } +} + +class TrieNode { + + private TrieNode[] links; + + private final int R = 26; + + private boolean end; + + public TrieNode() { + links = new TrieNode[R]; + } + + public boolean containsKey(char ch) { + return links[ch - 'a'] != null; + } + + public TrieNode get(char ch) { + return links[ch - 'a']; + } + + public void put(char ch, TrieNode node) { + links[ch - 'a'] = node; + } + + public void setEnd(boolean end) { + this.end = end; + } + + public boolean isEnd() { + return this.end; + } +} diff --git a/Week_06/G20200343030015/LeetCode_22_015.java b/Week_06/G20200343030015/LeetCode_22_015.java new file mode 100644 index 00000000..2f26ce4f --- /dev/null +++ b/Week_06/G20200343030015/LeetCode_22_015.java @@ -0,0 +1,36 @@ +package G20200343030015.week_06; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by majiancheng on 2020/3/22. + */ + +/** + * 22. 括号生成 + * 给出 n 代表生成括号的对数,请你写出一个函数,使其能够生成所有可能的并且有效的括号组合。 + */ +public class LeetCode_22_015 { + + public List generateParenthesis(int n) { + List strs = new ArrayList(); + helper(strs, "", 0, 0, n); + return strs; + } + + public void helper(List strs, String curr, int open, int close, int n) { + if(curr.length() == n * 2) { + strs.add(curr); + return; + } + + if(open < n) { + helper(strs, curr + "(", open + 1, close, n); + } + if(close < open) { + helper(strs, curr + ")", open, close + 1, n); + } + } + +} diff --git a/Week_06/G20200343030015/LeetCode_70_015.java b/Week_06/G20200343030015/LeetCode_70_015.java new file mode 100644 index 00000000..4e59c7ec --- /dev/null +++ b/Week_06/G20200343030015/LeetCode_70_015.java @@ -0,0 +1,42 @@ +package G20200343030015.week_06; + +/** + * Created by majiancheng on 2020/3/22. + */ + +/** + * 70. 爬楼梯 + * 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 + *

+ * 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢? + *

+ * 注意:给定 n 是一个正整数。 + *

+ * 示例 1: + *

+ * 输入: 2 + * 输出: 2 + * 解释: 有两种方法可以爬到楼顶。 + * 1. 1 阶 + 1 阶 + * 2. 2 阶 + *

+ * 来源:力扣(LeetCode) + * 链接:https://leetcode-cn.com/problems/climbing-stairs + * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + */ +public class LeetCode_70_015 { + + public int climbStairs(int n) { + if (n >= 0 && n <= 2) { + return n; + } + int[] dp = new int[n]; + dp[1] = 1; + dp[2] = 2; + for (int i = 3; i < n; i++) { + dp[i] = dp[i - 1] + dp[i - 2]; + } + + return dp[n - 1] + dp[n - 2]; + } +} diff --git a/Week_06/G20200343030015/NOTE.md b/Week_06/G20200343030015/NOTE.md index 50de3041..85876bfd 100644 --- a/Week_06/G20200343030015/NOTE.md +++ b/Week_06/G20200343030015/NOTE.md @@ -1 +1,19 @@ -学习笔记 \ No newline at end of file +学习笔记 + +红黑树与AVL树,各自的优缺点总结 + +RB-Tree和AVL树作为BBST,其实现的算法时间复杂度相同,AVL作为最先提出的BBST,貌似RB-tree实现的功能都可以用AVL树是代替,那么为什么还需要引入RB-Tree呢? + +红黑树不追求"完全平衡",即不像AVL那样要求节点的 |balFact| <= 1,它只要求部分达到平衡,但是提出了为节点增加颜色,红黑是用非严格的平衡来换取增删节点时候旋转次数的降低,任何不平衡都会在三次旋转之内解决,而AVL是严格平衡树,因此在增加或者删除节点的时候,根据不同情况,旋转的次数比红黑树要多。 +就插入节点导致树失衡的情况,AVL和RB-Tree都是最多两次树旋转来实现复衡rebalance,旋转的量级是O(1) +删除节点导致失衡,AVL需要维护从被删除节点到根节点root这条路径上所有节点的平衡,旋转的量级为O(logN),而RB-Tree最多只需要旋转3次实现复衡,只需O(1),所以说RB-Tree删除节点的rebalance的效率更高,开销更小! +AVL的结构相较于RB-Tree更为平衡,插入和删除引起失衡,如2所述,RB-Tree复衡效率更高;当然,由于AVL高度平衡,因此AVL的Search效率更高啦。 +针对插入和删除节点导致失衡后的rebalance操作,红黑树能够提供一个比较"便宜"的解决方案,降低开销,是对search,insert ,以及delete效率的折衷,总体来说,RB-Tree的统计性能高于AVL. +故引入RB-Tree是功能、性能、空间开销的折中结果。 +5.1 AVL更平衡,结构上更加直观,时间效能针对读取而言更高;维护稍慢,空间开销较大。 +5.2 红黑树,读取略逊于AVL,维护强于AVL,空间开销与AVL类似,内容极多时略优于AVL,维护优于AVL。 +基本上主要的几种平衡树看来,红黑树有着良好的稳定性和完整的功能,性能表现也很不错,综合实力强,在诸如STL的场景中需要稳定表现。 +红黑树的查询性能略微逊色于AVL树,因为其比AVL树会稍微不平衡最多一层,也就是说红黑树的查询性能只比相同内容的AVL树最多多一次比较,但是,红黑树在插入和删除上优于AVL树,AVL树每次插入删除会进行大量的平衡度计算,而红黑树为了维持红黑性质所做的红黑变换和旋转的开销,相较于AVL树为了维持平衡的开销要小得多 + +总结:实际应用中,若搜索的次数远远大于插入和删除,那么选择AVL,如果搜索,插入删除次数几乎差不多,应该选择RB。 + diff --git a/Week_06/G20200343030017/climbing_stairs/Solution.java b/Week_06/G20200343030017/climbing_stairs/Solution.java new file mode 100644 index 00000000..88f72bee --- /dev/null +++ b/Week_06/G20200343030017/climbing_stairs/Solution.java @@ -0,0 +1,22 @@ +package week6.climbing_stairs; + +public class Solution { + // f(n)=f(n-1)+f(n-2); + public int climbStairs(int n) { + if (n<3) return n; + int[] sum = new int[n+1]; + sum[0]=0; + sum[1]=1; + sum[2]=2; + for (int t=3;t<=n;t++){ + sum[t] = sum[t-1]+sum[t-2]; + } + return sum[n]; + } + + public static void main(String[] args) { + int n =11; + Solution s = new Solution(); + System.out.println(s.climbStairs(n)); + } +} diff --git a/Week_06/G20200343030017/friend_circles/Solution.java b/Week_06/G20200343030017/friend_circles/Solution.java new file mode 100644 index 00000000..2e578867 --- /dev/null +++ b/Week_06/G20200343030017/friend_circles/Solution.java @@ -0,0 +1,64 @@ +package week6.friend_circles; + +public class Solution { + int[] disjoint; + public int findCircleNum(int[][] M) { + disjoint = new int[M.length]; + for (int n=0;n generateParenthesis(int n) { + List list = new ArrayList<>(); + recursion(n,n,"",list); + return list; + } + public void recursion(int left,int right,String temp,List list){ + if (left==0 && right==0){ + list.add(temp); + return; + } + if (left>0){ + recursion(left-1,right,temp+"(",list); + } + if (right>0 && right>left){ + recursion(left,right-1,temp+")",list); + } + } + + public static void main(String[] args) { + int n = 3; + Solution s = new Solution(); + System.out.println(s.generateParenthesis(n)); + } +} diff --git a/Week_06/G20200343030017/implement_trie_prefix_tree/App.java b/Week_06/G20200343030017/implement_trie_prefix_tree/App.java new file mode 100644 index 00000000..88612635 --- /dev/null +++ b/Week_06/G20200343030017/implement_trie_prefix_tree/App.java @@ -0,0 +1,13 @@ +package week6.implement_trie_prefix_tree; + +public class App { + public static void main(String[] args) { + String word = "apple"; + Trie obj = new Trie(); + obj.insert(word); + boolean param_2 = obj.search(word); + boolean param_3 = obj.search("app"); + System.out.println(param_2); + System.out.println(param_3); + } +} diff --git a/Week_06/G20200343030017/implement_trie_prefix_tree/Trie.java b/Week_06/G20200343030017/implement_trie_prefix_tree/Trie.java new file mode 100644 index 00000000..7aa00c48 --- /dev/null +++ b/Week_06/G20200343030017/implement_trie_prefix_tree/Trie.java @@ -0,0 +1,47 @@ +package week6.implement_trie_prefix_tree; + +public class Trie { + TrieNode trieNode; + /** Initialize your data structure here. */ + public Trie() { + trieNode = new TrieNode(); + } + + /** Inserts a word into the trie. */ + public void insert(String word) { + TrieNode node = trieNode; + for (int n=0;n bqueue = new LinkedList<>(); + Queue equeue = new LinkedList<>(); + HashSet bvisit = new HashSet<>(); + bvisit.add(start); + HashSet evisit = new HashSet<>(); + evisit.add(end); + String target; + int count = 0; + bqueue.add(start); + equeue.add(end); + while (!bqueue.isEmpty()&&!equeue.isEmpty()){ + int bsize = bqueue.size(); + int esize = equeue.size(); + if (bsize<=esize){ + target = bqueue.poll(); + for (String word:bank){ + if (!bvisit.contains(word) && !word.equals(target) &&vaild(target,word) ){ + bvisit.add(word); + if (equeue.contains(word)){ + return count+1; + }else{ + bqueue.add(word); + } + } + } + count++; + }else{ + target = equeue.poll(); + for (String word:bank){ + if (!evisit.contains(word) && !word.equals(target) &&vaild(target,word)){ + evisit.add(word); + if (bqueue.contains(word)){ + return count+1; + }else{ + equeue.add(word); + } + } + } + count++; + } + } + return -1; + } + + public boolean vaild(String target,String compare){ + int a = 0; + for (int n=0;n=target.length()-1){ + return true; + }else{ + return false; + } + } + + public static void main(String[] args) { + String[] words = {"AACCGGTA"}; + String beginword = "AACCGGTT"; + String endword = "AACCGGTA"; + /*String[] words = {"miss","dusk","kiss","musk","tusk","diss","disk","sang","ties","muss"}; + String beginword = "kiss"; + String endword = "tusk";*/ + /*String[] words = {"a","b","c"}; + String beginword = "a"; + String endword = "c";*/ + Solution s = new Solution(); + System.out.println(s.minMutation(beginword,endword,words)); + } +} diff --git a/Week_06/G20200343030017/n_queens/Solution.java b/Week_06/G20200343030017/n_queens/Solution.java new file mode 100644 index 00000000..5033a093 --- /dev/null +++ b/Week_06/G20200343030017/n_queens/Solution.java @@ -0,0 +1,66 @@ +package week6.n_queens; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class Solution { + public List> solveNQueens(int n) { + List> last = new ArrayList<>(); + int[][] queens = new int[n][n]; + for (int j=0;j> last){ + if (y==queens.length){ + last.add(create(queens)); + } + for (int x=0;x create(int[][] queens){ + List list = new ArrayList<>(); + for (int n=0;nrank[ys]){ + parent[ys]=xs; + }else if(rank[xs] wordList) { + if (!wordList.contains(endWord)) { + return 0; + } + Queue bqueue = new LinkedList<>(); + Queue equeue = new LinkedList<>(); + HashSet bvisit = new HashSet<>(); + bvisit.add(beginWord); + HashSet evisit = new HashSet<>(); + evisit.add(endWord); + String target; + int count = 0; + bqueue.add(beginWord); + equeue.add(endWord); + while (!bqueue.isEmpty()&&!equeue.isEmpty()){ + int bsize = bqueue.size(); + int esize = equeue.size(); + count++; + if (bsize<=esize){ + for (int n=0;n=target.length()-1){ + return true; + }else{ + return false; + } + } + + public static void main(String[] args) { + String[] words = {"lest","leet","lose","code","lode","robe","lost"}; + String beginword = "leet"; + String endword = "code"; + /*String[] words = {"miss","dusk","kiss","musk","tusk","diss","disk","sang","ties","muss"}; + String beginword = "kiss"; + String endword = "tusk";*/ + /*String[] words = {"a","b","c"}; + String beginword = "a"; + String endword = "c";*/ + List wordList = Arrays.asList(words); + Solution s = new Solution(); + System.out.println(s.ladderLength(beginword,endword,wordList)); + } +} diff --git "a/Week_06/G20200343030017/\346\200\273\347\273\223.txt" "b/Week_06/G20200343030017/\346\200\273\347\273\223.txt" new file mode 100644 index 00000000..d17d051b --- /dev/null +++ "b/Week_06/G20200343030017/\346\200\273\347\273\223.txt" @@ -0,0 +1,5 @@ +这周作业确实很难,但是如果认真听课还是很容易完成的 +内容比较多,作业涉及了字典树并查集和高级搜索,认真听课字典树完成起来很容易,几乎不需要看题解,不过应用不多 +并查集概念还算简单,应用我只会最简单的朋友圈,岛屿,我看了好几遍,勉强懂了,不过尝试还是一团懵,后面那道被环绕的区域根本没赶尝试 +高级搜索是重点,花在这上面的时间比较多,虽然有些题目以前做过,这次用双向BFS重写了一遍,发现代码更整洁了,而且效率10倍提升。剪枝一直在使用,我习惯先全局遍历,然后通过修改参数及条件实现剪枝,n皇后问题很有名上次没做,这次尝试了下,比想象的简单。 +那些AVL树面试概念必考的,之前看书旋转一片模糊,这次听课总算懂了,这部分内容概率比较多。 \ No newline at end of file diff --git a/Week_06/G20200343030019/LeetCode_200_019.java b/Week_06/G20200343030019/LeetCode_200_019.java new file mode 100644 index 00000000..f8c41d08 --- /dev/null +++ b/Week_06/G20200343030019/LeetCode_200_019.java @@ -0,0 +1,64 @@ +class Solution { + class Union { + int[] elements; + + public Union(int capacity) { + elements = new int[capacity]; + for (int i = 1; i < capacity; i ++) { + elements[i] = i; + } + } + + public int findRoot(int i) { + while(elements[i] != i) { + elements[i] = elements[elements[i]]; + i = elements[i]; + } + return i; + } + + public void union(int i, int j) { + i = findRoot(i); + j = findRoot(j); + elements[j] = i; + } + + public int groupSum() { + int sum = 0; + for (int i = 0; i < elements.length; i ++) { + if (elements[i] == i) sum ++; + } + return sum; + } + } + + public int numIslands(char[][] grid) { + if (grid == null || grid.length == 0) return 0; + Union union = new Union(grid.length * grid[0].length); + int h = grid.length; + int l = grid[0].length; + int seaSum = 0; + for (int i = 0; i < h; i ++) { + for (int j = 0; j < l; j ++) { + if(grid[i][j] == '1') { + for (int x = 0; x < 4; x ++) { + int index = findLand(grid, i, j, x); + if (index > -1) union.union(index, i * l + j); + } + } else seaSum ++; + } + } + return union.groupSum() - seaSum; + } + + int[] xOffset = new int[]{-1, 0, 1, 0}; + int[] yOffset = new int[]{0, 1, 0, -1}; + private int findLand(char[][] grid, int i, int j, int f) { + i = i + xOffset[f]; + j = j + yOffset[f]; + if (i >= 0 && j >= 0 && j < grid[0].length && i < grid.length && grid[i][j] == '1') { + return i * grid[0].length + j; + } + return -1; + } +} \ No newline at end of file diff --git a/Week_06/G20200343030019/LeetCode_208_019.java b/Week_06/G20200343030019/LeetCode_208_019.java new file mode 100644 index 00000000..816ea774 --- /dev/null +++ b/Week_06/G20200343030019/LeetCode_208_019.java @@ -0,0 +1,83 @@ +class Trie { + + private TrieNode trieNode; + + private class TrieNode { + private TrieNode[] trieNode; + private int capacity = 26; + private boolean end; + public TrieNode() { + trieNode = new TrieNode[26]; + } + + public TrieNode get(char c) { + return trieNode[c - 'a']; + } + + public TrieNode put(char c) { + int i = c - 'a'; + if (!containsKey(i)) { + trieNode[i] = new TrieNode(); + } + return trieNode[i]; + } + + public boolean containsKey(int i) { + return trieNode[i] != null; + } + + public boolean containsKey(char c) { + return trieNode[c - 'a'] != null; + } + + public boolean isEnd() { + return end; + } + + public void setEnd(boolean flag) { + end = flag; + } + } + + /** Initialize your data structure here. */ + public Trie() { + trieNode = new TrieNode(); + } + + /** Inserts a word into the trie. */ + public void insert(String word) { + TrieNode node = trieNode; + for (char c: word.toCharArray()){ + node = node.put(c); + } + node.setEnd(true); + } + + /** Returns if the word is in the trie. */ + public boolean search(String word) { + TrieNode node = trieNode; + for (char c: word.toCharArray()){ + node = node.get(c); + if (node == null) return false; + } + return node.isEnd(); + } + + /** Returns if there is any word in the trie that starts with the given prefix. */ + public boolean startsWith(String prefix) { + TrieNode node = trieNode; + for (char c: prefix.toCharArray()){ + node = node.get(c); + if (node == null) return false; + } + return true; + } +} + +/** + * Your Trie object will be instantiated and called as such: + * Trie obj = new Trie(); + * obj.insert(word); + * boolean param_2 = obj.search(word); + * boolean param_3 = obj.startsWith(prefix); + */ \ No newline at end of file diff --git a/Week_06/G20200343030019/LeetCode_547_019.java b/Week_06/G20200343030019/LeetCode_547_019.java new file mode 100644 index 00000000..3c4eee6c --- /dev/null +++ b/Week_06/G20200343030019/LeetCode_547_019.java @@ -0,0 +1,49 @@ +class Solution { + public int findCircleNum(int[][] M) { + if (M == null || M.length == 0) return 0; + Union person = new Union(M.length); + for (int i = 1; i < M.length; i ++) { + for (int j = 0; j < i; j ++) { + if (M[i][j] == 1) { + person.union(i, j); + } + } + } + + return person.groupSum(); + } + + class Union { + int[] elements; + + public Union(int capacity) { + elements = new int[capacity]; + for (int i = 1; i < capacity; i ++) { + elements[i] = i; + } + } + + public int findRoot(int i) { + while (elements[i] != i) { + elements[i] = elements[elements[i]]; + i = elements[i]; + } + return i; + } + + public void union(int i, int j) { + i = findRoot(i); + j = findRoot(j); + elements[j] = i; + } + + public int groupSum() { + int sum = 0; + for (int i = 0; i < elements.length; i ++) { + if (elements[i] == i) sum ++; + } + return sum; + } + } + +} \ No newline at end of file diff --git a/Week_06/G20200343030021/LeetCode_208_021.java b/Week_06/G20200343030021/LeetCode_208_021.java new file mode 100644 index 00000000..eea21061 --- /dev/null +++ b/Week_06/G20200343030021/LeetCode_208_021.java @@ -0,0 +1,83 @@ +package trie; + +/** + * #### [208. 实现 Trie (前缀树)](https://leetcode-cn.com/problems/implement-trie-prefix-tree/) + */ +public class ImplementTriePrefixTree { + class Trie { + + class TrieNode { + public char data; + public TrieNode[] children = new TrieNode[26]; + public boolean isEndingChar = false; + + public TrieNode(char data) { + this.data = data; + } + } + + private TrieNode root; + + /** + * Initialize your data structure here. + */ + public Trie() { + root = new TrieNode('/');//存储无意义字符 + } + + /** + * Inserts a word into the trie. + * 往 Trie 树中插入一个字符串 + */ + public void insert(String word) { + TrieNode p = this.root; + for (char i : word.toCharArray()) { + if (p.children[i - 'a'] == null) { + TrieNode newNode = new TrieNode(i); + p.children[i - 'a'] = newNode; + } + p = p.children[i - 'a']; + } + p.isEndingChar = true; + } + + + /** + * Returns if the word is in the trie. + * 在Trie树中查找一个字符串 + */ + public boolean search(String word) { + TrieNode p = this.root; + for (char i : word.toCharArray()) { + if (p.children[i - 'a'] == null) { + return false; //不存在 + } + p = p.children[i - 'a']; + } + return p.isEndingChar;//为 false : 不能完全匹配,只是前缀 + } + + /** + * Returns if there is any word in the trie that starts with the given prefix. + * 在Trie树中查找一个字符串前缀 + */ + public boolean startsWith(String prefix) { + TrieNode p = this.root; + for (char i : prefix.toCharArray()) { + if (p.children[i - 'a'] == null) { + return false; //不存在 + } + p = p.children[i - 'a']; + } + return true; + } + } + +/** + * Your Trie object will be instantiated and called as such: + * Trie obj = new Trie(); + * obj.insert(word); + * boolean param_2 = obj.search(word); + * boolean param_3 = obj.startsWith(prefix); + */ +} diff --git a/Week_06/G20200343030021/LeetCode_22_021.java b/Week_06/G20200343030021/LeetCode_22_021.java new file mode 100644 index 00000000..336f40f1 --- /dev/null +++ b/Week_06/G20200343030021/LeetCode_22_021.java @@ -0,0 +1,40 @@ +package recursion; + +import java.util.ArrayList; +import java.util.List; + +/** + * #### [22. 括号生成](https://leetcode-cn.com/problems/generate-parentheses/) + * 递归 + */ +public class GenerateParentheses { + public static List generateParenthesis(int n) { + ArrayList list = new ArrayList<>(); + generate(0, 0, n, "", list); + return list; + } + + + private static void generate(int left, int right, int n, String s, ArrayList list) { + // 递归终结条件 + if (left == n && right == n) { + list.add(s); + } + // 当前层逻辑 + String s1 = s + "("; + String s2 = s + ")"; + // 进入下一层 + if (left < n) { + generate(left + 1, right, n, s1, list); + } + if (right < left) { + generate(left, right + 1, n, s2, list); + } + // 清理当前层 + } + + + public static void main(String[] args) { + System.out.println(generateParenthesis(3)); + } +} diff --git a/Week_06/G20200343030025/LeetCode_1_025.java b/Week_06/G20200343030025/LeetCode_1_025.java new file mode 100644 index 00000000..8934bfa2 --- /dev/null +++ b/Week_06/G20200343030025/LeetCode_1_025.java @@ -0,0 +1,107 @@ +/** + * 208. 实现 Trie (前缀树) + * 难度 + * 中等 + *

+ * 225 + *

+ * 收藏 + *

+ * 分享 + * 切换为英文 + * 关注 + * 反馈 + * 实现一个 Trie (前缀树),包含 insert, search, 和 startsWith 这三个操作。 + *

+ * 示例: + *

+ * Trie trie = new Trie(); + *

+ * trie.insert("apple"); + * trie.search("apple"); // 返回 true + * trie.search("app"); // 返回 false + * trie.startsWith("app"); // 返回 true + * trie.insert("app"); + * trie.search("app"); // 返回 true + * 说明: + *

+ * 你可以假设所有的输入都是由小写字母 a-z 构成的。 + * 保证所有输入均为非空字符串。 + */ +public class Trie { + + /** + * 标识是否到此是一个完整的单词 + */ + private boolean endOfWord; + + /** + * 直接儿子结点 + */ + private Trie[] children; + + /** + * 代表的字符 + */ + private Character letter; + + public Trie() { + this(null); + } + + public Trie(Character letter) { + this.letter = letter; + this.endOfWord = false; + // 26 个英文单词 + this.children = new Trie[26]; + } + + /** + * 向字典树插入单词 + */ + public void insert(String word) { + Trie p = this; + for (int i = 0; i < word.length(); i++) { + char letter = word.charAt(i); + int index = letter - 'a'; + if (p.children[index] == null) { + p.children[index] = new Trie(letter); + } + p = p.children[index]; + } + + p.endOfWord = true; + } + + /** + * 查看单词是否在字典树中存在 + */ + public boolean search(String word) { + Trie p = this; + for (int i = 0; i < word.length(); i++) { + char letter = word.charAt(i); + int index = letter - 'a'; + if (p.children[index] == null) { + return false; + } + p = p.children[index]; + } + return p.endOfWord; + } + + /** + * 查看字典树中是否存在 word 开头的单词 + */ + public boolean startsWith(String word) { + Trie p = this; + for (int i = 0; i < word.length(); i++) { + char letter = word.charAt(i); + int index = letter - 'a'; + if (p.children[index] == null) { + return false; + } + p = p.children[index]; + } + return true; + } +} diff --git a/Week_06/G20200343030025/LeetCode_2_025.java b/Week_06/G20200343030025/LeetCode_2_025.java new file mode 100644 index 00000000..7e551d4d --- /dev/null +++ b/Week_06/G20200343030025/LeetCode_2_025.java @@ -0,0 +1,109 @@ +/** + *547. 朋友圈 + * 难度 + * 中等 + * + * 198 + * + * 收藏 + * + * 分享 + * 切换为英文 + * 关注 + * 反馈 + * 班上有 N 名学生。其中有些人是朋友,有些则不是。他们的友谊具有是传递性。如果已知 A 是 B 的朋友,B 是 C 的朋友,那么我们可以认为 A 也是 C 的朋友。所谓的朋友圈,是指所有朋友的集合。 + * + * 给定一个 N * N 的矩阵 M,表示班级中学生之间的朋友关系。如果M[i][j] = 1,表示已知第 i 个和 j 个学生互为朋友关系,否则为不知道。你必须输出所有学生中的已知的朋友圈总数。 + * + * 示例 1: + * + * 输入: + * [[1,1,0], + * [1,1,0], + * [0,0,1]] + * 输出: 2 + * 说明:已知学生0和学生1互为朋友,他们在一个朋友圈。 + * 第2个学生自己在一个朋友圈。所以返回2。 + * 示例 2: + * + * 输入: + * [[1,1,0], + * [1,1,1], + * [0,1,1]] + * 输出: 1 + * 说明:已知学生0和学生1互为朋友,学生1和学生2互为朋友,所以学生0和学生2也是朋友,所以他们三个在一个朋友圈,返回1。 + * 注意: + * + * N 在[1,200]的范围内。 + * 对于所有学生,有M[i][i] = 1。 + * 如果有M[i][j] = 1,则有M[j][i] = 1。 + */ +public class LeetCode_2_025 { + class UF { + // 连通分量个数 + private int count; + // 存储一棵树 + private int[] parent; + // 记录树的“重量” + private int[] size; + + public UF(int n) { + this.count = n; + parent = new int[n]; + size = new int[n]; + for (int i = 0; i < n; i++) { + parent[i] = i; + size[i] = 1; + } + } + + public void union(int p, int q) { + int rootP = find(p); + int rootQ = find(q); + if (rootP == rootQ) + return; + + // 小树接到大树下面,较平衡 + if (size[rootP] > size[rootQ]) { + parent[rootQ] = rootP; + size[rootP] += size[rootQ]; + } else { + parent[rootP] = rootQ; + size[rootQ] += size[rootP]; + } + count--; + } + + public boolean connected(int p, int q) { + int rootP = find(p); + int rootQ = find(q); + return rootP == rootQ; + } + + private int find(int x) { + while (parent[x] != x) { + // 进行路径压缩 + parent[x] = parent[parent[x]]; + x = parent[x]; + } + return x; + } + + public int count() { + return count; + } + } + + public int findCircleNum(int[][] M) { + int n = M.length; + UF uf = new UF(n); + for (int i = 0; i < n; i++) { + for (int j = 0; j < i; j++) { + if (M[i][j] == 1) + uf.union(i, j); + } + } + return uf.count(); + } + +} \ No newline at end of file diff --git a/Week_06/G20200343030029/LeetCode_4_029.java b/Week_06/G20200343030029/LeetCode_4_029.java new file mode 100644 index 00000000..e69de29b diff --git a/Week_06/G20200343030029/LeetCode_5_029.java b/Week_06/G20200343030029/LeetCode_5_029.java new file mode 100644 index 00000000..e69de29b diff --git a/Week_06/G20200343030035/LeetCode_200_035.py b/Week_06/G20200343030035/LeetCode_200_035.py new file mode 100644 index 00000000..64f9537f --- /dev/null +++ b/Week_06/G20200343030035/LeetCode_200_035.py @@ -0,0 +1,35 @@ +''' +200. 岛屿数量 + +给定一个由 '1'(陆地)和 '0'(水)组成的的二维网格,计算岛屿的数量。一个岛被水包围, +并且它是通过水平方向或垂直方向上相邻的陆地连接而成的。你可以假设网格的四个边均被水包围。 + +示例: + 输入: + 11110 + 11010 + 11000 + 00000 + + 输出: 1 + +示例: + 输入: + 11000 + 11000 + 00100 + 00011 + + 输出: 3 + +''' +class Solution: + def numIslands(self, grid) -> int: + def sink(i, j): + if 0 <= i < len(grid) and 0 <= j < len(grid[i]) and grid[i][j] == '1': + grid[i][j] = '0' + for x,y in zip([i+1, i-1, i, i], [j, j, j+1, j-1]): + sink(x,y) + return 1 + return 0 + return sum(sink(i, j) for i in range(len(grid)) for j in range(len(grid[i]))) \ No newline at end of file diff --git a/Week_06/G20200343030035/LeetCode_208_035.py b/Week_06/G20200343030035/LeetCode_208_035.py new file mode 100644 index 00000000..91a3b64f --- /dev/null +++ b/Week_06/G20200343030035/LeetCode_208_035.py @@ -0,0 +1,81 @@ +''' +208. 实现 Trie (前缀树) + +实现一个 Trie (前缀树),包含 insert, search, 和 startsWith 这三个操作。 + +示例: +Trie trie = new Trie(); + +trie.insert("apple"); +trie.search("apple"); // 返回 true +trie.search("app"); // 返回 false +trie.startsWith("app"); // 返回 true +trie.insert("app"); +trie.search("app"); // 返回 true + +说明: +你可以假设所有的输入都是由小写字母 a-z 构成的。 +保证所有输入均为非空字符串。 + +''' +class TrieNode: + def __init__(self): + self.children = [0]*26 + self.is_word = False + + +class Trie: + + def __init__(self): + """ + Initialize your data structure here. + """ + self.root = TrieNode() + + def _char_to_index(self,char): + return ord(char) - ord("a") + + def insert(self, word: str) -> None: + """ + Inserts a word into the trie. + """ + start = self.root + for char in word: + index = self._char_to_index(char) + if not start.children[index]: + start.children[index] = TrieNode() + start = start.children[index] + start.is_word = True + + def search(self, word: str) -> bool: + """ + Returns if the word is in the trie. + """ + start = self.root + for char in word: + index = self._char_to_index(char) + if not start.children[index]: + return False + start = start.children[index] + if start.is_word: return True + return False + + def startsWith(self, prefix: str) -> bool: + """ + Returns if there is any word in the trie that starts with the given prefix. + """ + start = self.root + for char in prefix: + index = self._char_to_index(char) + if not start.children[index]: + return False + start = start.children[index] + return True + + + +# Your Trie object will be instantiated and called as such: +# obj = Trie() +# obj.insert(word) +# param_2 = obj.search(word) +# param_3 = obj.startsWith(prefix) \ No newline at end of file diff --git a/Week_06/G20200343030363/LeetCode_130_363.java b/Week_06/G20200343030363/LeetCode_130_363.java new file mode 100644 index 00000000..7993059d --- /dev/null +++ b/Week_06/G20200343030363/LeetCode_130_363.java @@ -0,0 +1,58 @@ +package cn.geek.week6; + +/** + * @author lemon + * @version 1.0.0 + * @Description TODO + * @createTime 2020年03月20日 21:58:00 + */ +public class LeetCode_130_363 { + boolean[][] flag; + int[] vi = {-1, 0, 1, 0}; + int[] vj = {0, 1, 0, -1}; + + public void solve(char[][] board) { + int n = board.length; + if (n < 3) { + return; + } + int m = board[0].length; + if (m < 3) { + return; + } + flag = new boolean[n][m]; + int i = 0, j = 0, a = 0, b = 0, d = 1; + + int total = 2 * (m + n) - 4; + for (int k = 1; k <= total; k++) { + if (board[i][j] == 'O') { + dfs(i, j, n, m, board); + } + a = i + vi[d]; + b = j + vj[d]; + if (a >= n || a < 0 || b >= m || b < 0) { + d = (d + 1) % 4; + a = i + vi[d]; + b = j + vj[d]; + } + i = a; + j = b; + } + for (int p = 0; p < n; p++) + for (int q = 0; q < m; q++) { + if (!flag[p][q]) { + board[p][q] = 'X'; + } + } + } + + public void dfs(int i, int j, int n, int m, char[][] board) { + flag[i][j] = true; + for (int k = 0; k < 4; k++) { + int a = i + vi[k], b = j + vj[k]; + if (a >= 0 && a < n && b >= 0 && b < m && board[a][b] == 'O' && flag[a][b] == false) { + dfs(a, b, n, m, board); + } + } + } +} diff --git a/Week_06/G20200343030363/LeetCode_433_363.java b/Week_06/G20200343030363/LeetCode_433_363.java new file mode 100644 index 00000000..cf084327 --- /dev/null +++ b/Week_06/G20200343030363/LeetCode_433_363.java @@ -0,0 +1,66 @@ +package cn.geek.week6; + +import java.util.Arrays; +import java.util.HashSet; + +/** + * @author lemon + * @version 1.0.0 + * @Description TODO + * @createTime 2020年03月21日 22:53:00 + */ +public class LeetCode_433_363 { + + /** + * Min mutation int. + * + * @param start + * the start + * @param end + * the end + * @param bank + * the bank + * @return the int + */ + public int minMutation(String start, String end, String[] bank) { + HashSet set = new HashSet<>(Arrays.asList(bank)); + if (!set.contains(end)) { + return -1; + } + char[] four = {'A', 'C', 'G', 'T'}; + HashSet positive = new HashSet<>(); + positive.add(start); + HashSet negative = new HashSet<>(); + negative.add(end); + HashSet tempNewSet = new HashSet<>(); + int step = 0; + while (positive.size() > 0 && negative.size() > 0) { + step++; + if (positive.size() > negative.size()) { + HashSet temp = new HashSet<>(positive); + positive = negative; + negative = temp; + } + for (String item : positive) { + char[] tempStringChars = item.toCharArray(); + for (int i = tempStringChars.length - 1; i >= 0; --i) { + char oldChar = tempStringChars[i]; + for (int j = 0; j < 4; ++j) { + tempStringChars[i] = four[j]; + String newString = new String(tempStringChars); + if (negative.contains(newString)) { + return step; + } else if (set.contains(newString)) { + set.remove(newString); + tempNewSet.add(newString); + } + } + tempStringChars[i] = oldChar; + } + } + positive = new HashSet<>(tempNewSet); + tempNewSet.clear(); + } + return -1; + } +} diff --git "a/Week_06/G20200343030369/36.\346\234\211\346\225\210\347\232\204\346\225\260\347\213\254.swift" "b/Week_06/G20200343030369/36.\346\234\211\346\225\210\347\232\204\346\225\260\347\213\254.swift" new file mode 100644 index 00000000..74543c43 --- /dev/null +++ "b/Week_06/G20200343030369/36.\346\234\211\346\225\210\347\232\204\346\225\260\347\213\254.swift" @@ -0,0 +1,139 @@ +/* + * @lc app=leetcode.cn id=36 lang=swift + * + * [36] 有效的数独 + * + * https://leetcode-cn.com/problems/valid-sudoku/description/ + * + * algorithms + * Medium (58.24%) + * Likes: 291 + * Dislikes: 0 + * Total Accepted: 62.7K + * Total Submissions: 106.6K + * Testcase Example: '[["5","3",".",".","7",".",".",".","."],["6",".",".","1","9","5",".",".","."],[".","9","8",".",".",".",".","6","."],["8",".",".",".","6",".",".",".","3"],["4",".",".","8",".","3",".",".","1"],["7",".",".",".","2",".",".",".","6"],[".","6",".",".",".",".","2","8","."],[".",".",".","4","1","9",".",".","5"],[".",".",".",".","8",".",".","7","9"]]' + * + * 判断一个 9x9 的数独是否有效。只需要根据以下规则,验证已经填入的数字是否有效即可。 + * + * + * 数字 1-9 在每一行只能出现一次。 + * 数字 1-9 在每一列只能出现一次。 + * 数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。 + * + * + * + * + * 上图是一个部分填充的有效的数独。 + * + * 数独部分空格内已填入了数字,空白格用 '.' 表示。 + * + * 示例 1: + * + * 输入: + * [ + * ⁠ ["5","3",".",".","7",".",".",".","."], + * ⁠ ["6",".",".","1","9","5",".",".","."], + * ⁠ [".","9","8",".",".",".",".","6","."], + * ⁠ ["8",".",".",".","6",".",".",".","3"], + * ⁠ ["4",".",".","8",".","3",".",".","1"], + * ⁠ ["7",".",".",".","2",".",".",".","6"], + * ⁠ [".","6",".",".",".",".","2","8","."], + * ⁠ [".",".",".","4","1","9",".",".","5"], + * ⁠ [".",".",".",".","8",".",".","7","9"] + * ] + * 输出: true + * + * + * 示例 2: + * + * 输入: + * [ + * ["8","3",".",".","7",".",".",".","."], + * ["6",".",".","1","9","5",".",".","."], + * [".","9","8",".",".",".",".","6","."], + * ["8",".",".",".","6",".",".",".","3"], + * ["4",".",".","8",".","3",".",".","1"], + * ["7",".",".",".","2",".",".",".","6"], + * [".","6",".",".",".",".","2","8","."], + * [".",".",".","4","1","9",".",".","5"], + * [".",".",".",".","8",".",".","7","9"] + * ] + * 输出: false + * 解释: 除了第一行的第一个数字从 5 改为 8 以外,空格内其他数字均与 示例1 相同。 + * ⁠ 但由于位于左上角的 3x3 宫内有两个 8 存在, 因此这个数独是无效的。 + * + * 说明: + * + * + * 一个有效的数独(部分已被填充)不一定是可解的。 + * 只需要根据以上规则,验证已经填入的数字是否有效即可。 + * 给定数独序列只包含数字 1-9 和字符 '.' 。 + * 给定数独永远是 9x9 形式的。 + * + * + */ + +// @lc code=start +class Solution { + func isValidSudoku(_ board: [[Character]]) -> Bool { + + } + + func isValidSudokuIteration(_ board: [[Character]]) -> Bool { + let rows = Array(repeating: [Character: Int](), count: 9) + let columns = Array(repeating: [Character: Int](), count: 9) + let indexBox = Array(repeating: [Character: Int](), count: 9) + for i in 0..<9 { + for j in 0..<9 where board[i][j] != "." { + let c = board[i][j] + var row = rows[i] + if let _ = row[c] { + return false + } else { + row[c] = 1 + // rows[i] = row + } + + var column = columns[j] + if let _ = column[c] { + return false + } else { + column[c] = 1 + // columns[j] = column + } + + let index = (i / 3) * 3 + j / 3 + var box = indexBox[index] + if let _ = box[c] { + return false + } else { + box[c] = 1 + // indexBox[index] = box + } + } + } + return true + } + + func isValidSudokuOptimal(_ board: [[Character]]) -> Bool { + var rows = Array(repeating: Set(), count: 9) + var columns = Array(repeating: Set(), count: 9) + var boxes = Array(repeating: Set(), count: 9) + for i in 0..<9 { + for j in 0..<9 { + let v = board[i][j] + guard v != "." else {continue} + let index = (i / 3) * 3 + j / 3 + guard !rows[i].contains(v) && !columns[j].contains(v) && !boxes[index].contains(v) else { + return false + } + + rows[i].insert(v) + columns[j].insert(v) + boxes[index].insert(v) + } + } + } +} +// @lc code=end + diff --git "a/Week_06/G20200343030369/547.\346\234\213\345\217\213\345\234\210.swift" "b/Week_06/G20200343030369/547.\346\234\213\345\217\213\345\234\210.swift" new file mode 100644 index 00000000..d6686762 --- /dev/null +++ "b/Week_06/G20200343030369/547.\346\234\213\345\217\213\345\234\210.swift" @@ -0,0 +1,107 @@ +/* + * @lc app=leetcode.cn id=547 lang=swift + * + * [547] 朋友圈 + * + * https://leetcode-cn.com/problems/friend-circles/description/ + * + * algorithms + * Medium (54.73%) + * Likes: 198 + * Dislikes: 0 + * Total Accepted: 30K + * Total Submissions: 54K + * Testcase Example: '[[1,1,0],[1,1,0],[0,0,1]]' + * + * 班上有 N 名学生。其中有些人是朋友,有些则不是。他们的友谊具有是传递性。如果已知 A 是 B 的朋友,B 是 C 的朋友,那么我们可以认为 A 也是 + * C 的朋友。所谓的朋友圈,是指所有朋友的集合。 + * + * 给定一个 N * N 的矩阵 M,表示班级中学生之间的朋友关系。如果M[i][j] = 1,表示已知第 i 个和 j + * 个学生互为朋友关系,否则为不知道。你必须输出所有学生中的已知的朋友圈总数。 + * + * 示例 1: + * + * + * 输入: + * [[1,1,0], + * ⁠[1,1,0], + * ⁠[0,0,1]] + * 输出: 2 + * 说明:已知学生0和学生1互为朋友,他们在一个朋友圈。 + * 第2个学生自己在一个朋友圈。所以返回2。 + * + * + * 示例 2: + * + * + * 输入: + * [[1,1,0], + * ⁠[1,1,1], + * ⁠[0,1,1]] + * 输出: 1 + * 说明:已知学生0和学生1互为朋友,学生1和学生2互为朋友,所以学生0和学生2也是朋友,所以他们三个在一个朋友圈,返回1。 + * + * + * 注意: + * + * + * N 在[1,200]的范围内。 + * 对于所有学生,有M[i][i] = 1。 + * 如果有M[i][j] = 1,则有M[j][i] = 1。 + * + * + */ + +// @lc code=start +class Solution { + func findCircleNum(_ M: [[Int]]) -> Int { + let unionFind = UnionFind(n: M.count) + for i in 0.. Int { + var root = i + while root != p[root] { + root = p[root] + } + // 路径压缩 + var i = i + while i != p[i] { + let x = i + p[x] = root + i = p[i] + } + return root + } +} + +// @lc code=end + diff --git a/Week_06/G20200343030373/LeetCode_208_373/LeetCode_208_373_test.go b/Week_06/G20200343030373/LeetCode_208_373/LeetCode_208_373_test.go new file mode 100644 index 00000000..3cb1eee3 --- /dev/null +++ b/Week_06/G20200343030373/LeetCode_208_373/LeetCode_208_373_test.go @@ -0,0 +1,63 @@ +//https://leetcode-cn.com/problems/implement-trie-prefix-tree/ +package implement_trie_array_test + +import ( + "github.com/stretchr/testify/assert" + "testing" +) + +func TestTrie(t *testing.T) { + obj := Constructor() + obj.Insert("apple") + assert.Equal(t, true, obj.Search("apple")) + assert.Equal(t, false, obj.Search("app")) + assert.Equal(t, true, obj.StartsWith("app")) + obj.Insert("app") + assert.Equal(t, true, obj.Search("app")) +} + +type Trie struct { + isEnd bool + children [26]*Trie +} + +func Constructor() Trie { + return Trie{} +} + +func (this *Trie) Insert(word string) { + node := this + for _, char := range word { + index := char - 'a' + if node.children[index] == nil { + trie := Constructor() + node.children[index] = &trie + } + node = node.children[index] + } + node.isEnd = true +} + +func (this *Trie) Search(word string) bool { + node := this + for _, char := range word { + index := char - 'a' + node = node.children[index] + if node == nil { + return false + } + } + return node.isEnd +} + +func (this *Trie) StartsWith(prefix string) bool { + node := this + for _, char := range prefix { + index := char - 'a' + node = node.children[index] + if node == nil { + return false + } + } + return true +} diff --git a/Week_06/G20200343030373/LeetCode_212_373/LeetCode_212_373_test.go b/Week_06/G20200343030373/LeetCode_212_373/LeetCode_212_373_test.go new file mode 100644 index 00000000..9774d58c --- /dev/null +++ b/Week_06/G20200343030373/LeetCode_212_373/LeetCode_212_373_test.go @@ -0,0 +1,123 @@ +//https://leetcode-cn.com/problems/word-search-ii/ +package word_search_test + +import ( + "github.com/stretchr/testify/assert" + "testing" +) + +func TestWordSearch(t *testing.T) { + t.Log("Word Search II: Trie") + words := []string{"oath", "pea", "eat", "rain"} + board := [][]byte{ + {'o', 'a', 'a', 'n'}, + {'e', 't', 'a', 'e'}, + {'i', 'h', 'k', 'r'}, + {'i', 'f', 'l', 'v'}, + } + expect := []string{"oath", "eat"} + assert.Equal(t, expect, findWords(board, words)) +} + +func findWords(board [][]byte, words []string) []string { + var res []string + + resMap := make(map[string]bool) + + trie := Trie{} + for _, word := range words { + trie.Insert(word) + } + + m := len(board) + n := len(board[0]) + visited := make([][]bool, m) + for i := 0; i < m; i++ { + visited[i] = make([]bool, n) + } + + for i := 0; i < m; i++ { + for j := 0; j < n; j++ { + dfs(board, visited, "", i, j, trie, &resMap) + } + } + + for key := range resMap { + res = append(res, key) + } + + return res +} + +func dfs(board [][]byte, visited [][]bool, str string, x int, y int, trie Trie, resMap *map[string]bool) { + if x < 0 || x >= len(board) || y < 0 || y >= len(board[0]) { + return + } + + if visited[x][y] { + return + } + + str += string(board[x][y]) + if !trie.StartsWith(str) { + return + } + + if trie.Search(str) { + (*resMap)[str] = true + } + + visited[x][y] = true + dfs(board, visited, str, x-1, y, trie, resMap) + dfs(board, visited, str, x+1, y, trie, resMap) + dfs(board, visited, str, x, y-1, trie, resMap) + dfs(board, visited, str, x, y+1, trie, resMap) + visited[x][y] = false +} + +//Trie +type Trie struct { + isEnd bool + children [26]*Trie +} + +func Constructor() Trie { + return Trie{} +} + +func (this *Trie) Insert(word string) { + node := this + for _, char := range word { + index := char - 'a' + if node.children[index] == nil { + trie := Constructor() + node.children[index] = &trie + } + node = node.children[index] + } + node.isEnd = true +} + +func (this *Trie) Search(word string) bool { + node := this + for _, char := range word { + index := char - 'a' + node = node.children[index] + if node == nil { + return false + } + } + return node.isEnd +} + +func (this *Trie) StartsWith(prefix string) bool { + node := this + for _, char := range prefix { + index := char - 'a' + node = node.children[index] + if node == nil { + return false + } + } + return true +} diff --git a/Week_06/G20200343030375/LeetCode_36_375.java b/Week_06/G20200343030375/LeetCode_36_375.java new file mode 100644 index 00000000..123b44e9 --- /dev/null +++ b/Week_06/G20200343030375/LeetCode_36_375.java @@ -0,0 +1,62 @@ +package G20200343030375; + +import java.util.HashSet; +import java.util.Set; + + + + +/** + * 模仿 StefanPochmann(斯蒂芬)的,看着挺漂亮的,可是效率惨不忍睹 + */ +public class LeetCode_36_375 { + public static void main(String args[]){ + + char[][] array =new char[][]{ + {'5', '3', '.', '.', '7', '.', '.', '.', '.'}, + {'6', '.', '.', '1', '9', '5', '.', '.', '.'}, + {'.', '9', '8', '.', '.', '.', '.', '6', '.'}, + {'8', '.', '.', '.', '6', '.', '.', '.', '3'}, + {'4', '.', '.', '8', '.', '3', '.', '.', '1'}, + {'7', '.', '.', '.', '2', '.', '.', '.', '6'}, + {'.', '6', '.', '.', '.', '.', '2', '8', '.'}, + {'.', '.', '.', '4', '1', '9', '.', '.', '5'}, + {'.', '.', '.', '.', '8', '.', '.', '7', '9'} + }; + + + + char[][] array2 =new char[][]{ + {'8', '3', '.', '.', '7', '.', '.', '.', '.'}, + {'6', '.', '.', '1', '9', '5', '.', '.', '.'}, + {'.', '9', '8', '.', '.', '.', '.', '6', '.'}, + {'8', '.', '.', '.', '6', '.', '.', '.', '3'}, + {'4', '.', '.', '8', '.', '3', '.', '.', '1'}, + {'7', '.', '.', '.', '2', '.', '.', '.', '6'}, + {'.', '6', '.', '.', '.', '.', '2', '8', '.'}, + {'.', '.', '.', '4', '1', '9', '.', '.', '5'}, + {'.', '.', '.', '.', '8', '.', '.', '7', '9'} + }; + + + System.out.println( LeetCode_36_375.isValidSudoku(array)); + System.out.println( LeetCode_36_375.isValidSudoku(array2)); + } + + public static boolean isValidSudoku(char[][] board) { + + Set set = new HashSet<>(); + + for(int i =0 ;i< 9 ;++i){ + for(int j = 0; j<9 ; ++j){ + if (board[i][j] != '.') + if( !set.add(board[i][j]+ " r " +i) + ||!set.add(board[i][j] + " c " + j) + ||!set.add(board[i][j]+" "+ i/3+"-" + j/3) + ) + return false; + } + } + return true; + } +} diff --git a/Week_06/G20200343030375/LeetCode_433_375.java b/Week_06/G20200343030375/LeetCode_433_375.java new file mode 100644 index 00000000..94a39bf5 --- /dev/null +++ b/Week_06/G20200343030375/LeetCode_433_375.java @@ -0,0 +1,44 @@ +package G20200343030375; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.Queue; + +/** + * 广度优先 + */ +public class LeetCode_433_375 { + public int minMutation(String start, String end, String[] bank) { + HashSet set = new HashSet<>(Arrays.asList(bank)); + if (!set.contains(end)) { + return -1; + } + char[] four = {'A', 'C', 'G', 'T'}; + Queue queue = new LinkedList<>(); + queue.offer(start); + set.remove(start); + int step = 0; + while (queue.size() > 0) { + step++; + for (int count = queue.size(); count > 0; --count) { + char[] temStringChars = queue.poll().toCharArray(); + for (int i = 0, len = temStringChars.length; i < len; ++i) { + char oldChar = temStringChars[i]; + for (int j = 0; j < 4; ++j) { + temStringChars[i] = four[j]; + String newGenetic = new String(temStringChars); + if (end.equals(newGenetic)) { + return step; + } else if (set.contains(newGenetic)) { + set.remove(newGenetic); + queue.offer(newGenetic); + } + } + temStringChars[i] = oldChar; + } + } + } + return -1; + } +} diff --git a/Week_06/G20200343030377/LeetCode_200_377.java b/Week_06/G20200343030377/LeetCode_200_377.java new file mode 100644 index 00000000..37cfb478 --- /dev/null +++ b/Week_06/G20200343030377/LeetCode_200_377.java @@ -0,0 +1,34 @@ +class Solution { + int m; + int n; + public int numIslands(char[][] grid) { + m = grid.length; + if(m==0){ + return 0; + } + n = grid[0].length; + if(n==0){ + return 0; + } + int count = 0; + for(int i=0; i=m || j>=n || grid[i][j] == '0'){ + return; + } + grid[i][j]='0'; + dfsMark(grid, i-1, j); + dfsMark(grid, i+1, j); + dfsMark(grid, i, j-1); + dfsMark(grid, i, j+1); + } +} diff --git a/Week_06/G20200343030377/LeetCode_22_377.java b/Week_06/G20200343030377/LeetCode_22_377.java new file mode 100644 index 00000000..e51ebda8 --- /dev/null +++ b/Week_06/G20200343030377/LeetCode_22_377.java @@ -0,0 +1,18 @@ +class Solution { + List list = new ArrayList<>(); + public List generateParenthesis(int n) { + generate("", 0, 0, n); + return list; + } + private void generate(String res, int left, int right, int n){ + if(res.length()==n*2){ + list.add(res); + } + if(leftsize[rootQ]){ + parent[rootQ]=parent[rootP]; + size[rootP]+=size[rootQ]; + + }else{ + parent[rootP]=parent[rootQ]; + size[rootQ]+=size[rootP]; + } + //ʱ count--; + } + } + + //ѯڵ + public int find(int x){ + while (x!=parent[x]){ + parent[x]=parent[parent[x]]; + x=parent[x]; + } + return x; + } + + //ڵǷͬһ + public boolean isConnected(int p,int q){ + return find(p)==find(q); + } + } + + /*** + * 鼯 + * + * ⣺ + * ֽⷨ鼯https://leetcode-cn.com/problems/surrounded-regions/solution/bfsdi-gui-dfsfei-di-gui-dfsbing-cha-ji-by-ac_pipe/ + * ִʱ : 14 ms , Java ύл 10.36% û + * ڴ : 41.9 MB , Java ύл 37.60% û + * @param board + */ + public void solve(char[][] board) { + if(board.length==0) return; + + int n = board.length; + int m = board[0].length; + int endBorad=n*m-1; + UF uf=new UF(n,m); + + //λ + int[][] distances={{-1,0},{1,0},{0,-1},{0,1}}; + + for (int i = 0; i < n; i++) { + for (int j = 0; j < m; j++) { + if(board[i][j]=='O'){ + + int p=i*m+j; + //System.out.println(i+" "+j); + //ѱ߽'0'½λ ϲ + if(i==0 || i==n-1 || j==0 || j==m-1){ + //System.out.println(i+"=="+j); + uf.union(p,endBorad); + }else{ + //ѱ߽ڵ'0'ϲ + + for (int[] d : distances) { + int px = i+d[0]; + int qy = j+d[1]; + + //ע⣺ҲҪٽڵǷǡOѡ1ǰͬһ + if(board[px][qy]!='O') continue; + + //ע⣺Ҫ==0һжҲDZֵ߽ + if(px>=0 && px=0 && qysize[rootQ]){ + //QĸڵָPĸ + parent[rootQ] = parent[rootP]; + size[rootQ] += size[rootP]; + }else{ + parent[rootP] = parent[rootQ]; + size[rootP] += size[rootQ]; + } + + count--; + } + + + } + + public int find(int x){ + while (parent[x]!=x){ + parent[x]=parent[parent[x]]; + x=parent[x]; + } + + return x; + } + + public int getCount() { + return count; + } + } + + /** + * λд + * ȣʱЧʿ1 + * + * ο⣺https://leetcode.com/problems/number-of-islands/discuss/56354/1D-Union-Find-Java-solution-easily-generalized-to-other-problems + * + * ִʱ : 6 ms , Java ύл 25.47% û + * ڴ : 42.2 MB , Java ύл 5.02% û + */ + int[][] distance = {{-1,0},{1,0},{0,1},{0,-1}}; + public int numIslands(char[][] grid) { + if(grid.length==0) return 0; + UF uf=new UF(grid); + int n = grid.length; + int m = grid[0].length; + for (int i = 0; i < grid.length; i++) { + for (int j = 0; j < grid[i].length; j++) { + if(grid[i][j]=='1'){ + grid[i][j]='0'; + for (int[] d : distance) { + int p= i+d[0]; + int q= j+d[1]; + if(p>=0 && p=0 && q0 && grid[i-1][j]=='1'){ + uf.union(p, (i-1)*m+j); + } + if(i+10 && grid[i][j-1]=='1'){ + uf.union(p, i*m+(j-1)); + } + if(j+1 findWords(char[][] board, String[] words) { + List res=new ArrayList<>(); + int n = board.length; + if(n==0) return res; + + int m = board[0].length; + + + + // + TreeNode treeNode = buildTree(words); + + //鵥Ƿǰ׺ʺϷ + for (int i = 0; i < n; i++) { + for (int j = 0; j < m; j++) { + dfs(treeNode,i,j,board,res); + } + } + return res; + + } + + //λ + int[][] distances={{-1,0},{1,0},{0,1},{0,-1}}; + //йĽ + private void dfs(TreeNode root, int i ,int j , char[][] board, List res) { + char c = board[i][j]; + //Ƿһ + + if(board[i][j]=='#' || root.next[c - 'a']==null){ + return; + } + + TreeNode nextNode = root.next[c - 'a']; + //ҵһ + if(nextNode.word!=null){ + res.add(nextNode.word); + nextNode.word=null; + //˳Ҫж + } + + board[i][j]='#'; + for (int[] d : distances) { + int xd=i+d[0]; + int yd=j+d[1]; + + if(xd>=0 && yd>=0 && xdrank[rootP]){ + parent[rootP]=rootQ; + }else{ + parent[rootQ]=rootP; + if(rank[rootP]==rank[rootQ]){ + rank[rootP]++; + } + } + count--; + } + + public int count(){ + return count; + } + } + + public int findCircleNum2(int[][] M) { + int n=M.length; + UnionFind uf=new UnionFind(n); + for (int i = 0; i < n-1; i++) { + for (int j = i+1; j < n; j++) { + if(M[i][j]==1) uf.union(i,j); + } + } + return uf.count(); + } + + public static void main(String[] args) { + char a='1'; + System.out.println(a); + } + +} diff --git a/Week_06/G20200343030379/LeetCode_547_379_2.java b/Week_06/G20200343030379/LeetCode_547_379_2.java new file mode 100644 index 00000000..f8d966ee --- /dev/null +++ b/Week_06/G20200343030379/LeetCode_547_379_2.java @@ -0,0 +1,115 @@ +package G20200343030379; + +import java.util.Arrays; + +/** + * 547. Ȧ + * N ѧЩѣЩǡǵǴԡ֪ A B ѣB C ѣôǿΪ A Ҳ C ѡνȦָѵļϡ + * + * һ N * N ľ Mʾ༶ѧ֮ѹϵM[i][j] = 1ʾ֪ i j ѧΪѹϵΪ֪ѧе֪Ȧ + * + * ʾ 1: + * + * : + * [[1,1,0], + * [1,1,0], + * [0,0,1]] + * : 2 + * ˵֪ѧ0ѧ1ΪѣһȦ + * 2ѧԼһȦԷ2 + * ʾ 2: + * + * : + * [[1,1,0], + * [1,1,1], + * [0,1,1]] + * : 1 + * ˵֪ѧ0ѧ1Ϊѣѧ1ѧ2Ϊѣѧ0ѧ2ҲѣһȦ1 + * ע⣺ + * + * N [1,200]ķΧڡ + * ѧM[i][i] = 1 + * M[i][j] = 1M[j][i] = 1 + * + * + * ⣺https://leetcode-cn.com/problems/friend-circles/ + */ + + + +public class LeetCode_547_379_2 { + + /** + * ⣺https://leetcode-cn.com/problems/friend-circles/solution/union-find-suan-fa-xiang-jie-by-labuladong/ + * 1ƽ + * 2·ѹ + * + * ִʱ : 1 ms , Java ύл 99.93% û + * ڴ : 41.5 MB , Java ύл 78.93% û + * @return + */ + class UF{ + private int count; + private int[] size; + private int[] parent; + + public UF(int n) { + count=n; + size=new int[n]; + parent=new int[n]; + for (int i = 0; i < n; i++) { + //todo + parent[i] = i; + size[i] = 1; + } + } + + public void union(int p,int q){ + int rootP = find(p); + int rootQ = find(q); + + if(rootP!=rootQ){ + + if(size[rootP]>size[rootQ]){ + //QĸڵָPĸ + parent[rootQ] = parent[rootP]; + size[rootQ] += size[rootP]; + }else{ + parent[rootP] = parent[rootQ]; + size[rootP] += size[rootQ]; + } + + count--; + } + + + } + + public int find(int x){ + while (parent[x]!=x){ + parent[x]=parent[parent[x]]; + x=parent[x]; + } + + return x; + } + + public int getCount() { + return count; + } + } + + public int findCircleNum(int[][] M){ + UF uf=new UF(M.length); + int n = M.length; + for (int i = 0; i < n; i++) { + for (int j = 0; j < i; j++) { + if(M[i][j]==1){ + uf.union(i,j); + } + } + } + return uf.getCount(); + } + +} diff --git a/Week_06/G20200343030379/NOTE.md b/Week_06/G20200343030379/NOTE.md index 50de3041..65973b8d 100644 --- a/Week_06/G20200343030379/NOTE.md +++ b/Week_06/G20200343030379/NOTE.md @@ -1 +1,13 @@ -学习笔记 \ No newline at end of file +学习笔记 + +这周收获蛮多的, + +学会了 1、字典树的用法:优化搜索算法,而且可以套用模版;并查集:算法本身理解度高,而且可以套用模版 + 2、又学了一次剪枝+DFS+回溯算法,很赞。 + 3、学会了DFS 4个方位操作时的一个代码好技巧,就是利用方向数组,进行迭代,而不是手动计算方向,太容易写错了。 + 4、学会了DFS 递归剪枝的时候,像数独的题目,要尽可能的把存在的数字收集起来,而不是每次加一个数字都行、列、块遍历一次; + 应该在加数字前,把行、列、块出现数字收集一次,一次校验即可。算法时间提升是N^N的效率。 + + +总结:视频的话,最好不要花太多时间在上面,最好两天内完成,留出最后4天的时间思考题解和做题,留一天用来处理自己的事情, + 而且预留可能出现的临时事情。视频时间上有时候只要知道大概意思就好,剩下在题目的题解和代码中去思考,效果更佳。 \ No newline at end of file diff --git a/Week_06/G20200343030383/LeetCode_208_383.go b/Week_06/G20200343030383/LeetCode_208_383.go new file mode 100644 index 00000000..644bbfe6 --- /dev/null +++ b/Week_06/G20200343030383/LeetCode_208_383.go @@ -0,0 +1,61 @@ +// https://leetcode-cn.com/problems/implement-trie-prefix-tree/ +package leetcode + +type Trie struct { + children [26]*Trie + isLeaf bool +} + +/** Initialize your data structure here. */ +func Constructor() Trie { + return Trie{} +} + +/** Inserts a word into the trie. */ +func (this *Trie) Insert(word string) { + chars := []byte(word) + for cur, i := this, 0; i < len(chars); i++ { + k := chars[i] - 'a' + if cur.children[k] == nil { + cur.children[k] = &Trie{} + } + + cur = cur.children[k] + if i == len(chars)-1 { + cur.isLeaf = true + } + } +} + +/** Returns if the word is in the trie. */ +func (this *Trie) Search(word string) bool { + chars := []byte(word) + cur := this + for i := 0; i < len(chars); i++ { + cur = cur.children[chars[i]-'a'] + if cur == nil { + return false + } + } + return cur.isLeaf +} + +/** Returns if there is any word in the trie that starts with the given prefix. */ +func (this *Trie) StartsWith(prefix string) bool { + chars := []byte(prefix) + for cur, i := this, 0; i < len(chars); i++ { + if cur.children[chars[i]-'a'] == nil { + return false + } + cur = cur.children[chars[i]-'a'] + } + return true +} + +/** + * Your Trie object will be instantiated and called as such: + * obj := Constructor(); + * obj.Insert(word); + * param_2 := obj.Search(word); + * param_3 := obj.StartsWith(prefix); + */ diff --git a/Week_06/G20200343030383/LeetCode_547_383.go b/Week_06/G20200343030383/LeetCode_547_383.go new file mode 100644 index 00000000..0d09057f --- /dev/null +++ b/Week_06/G20200343030383/LeetCode_547_383.go @@ -0,0 +1,44 @@ +//https://leetcode-cn.com/problems/friend-circles/ +package leetcode + +func findCircleNum(M [][]int) int { + count := len(M) + ds := makeDisjointSet(count) + for i := 0; i < len(M); i++ { + for j := 0; j < i; j++ { + if M[i][j] == 1 { + if union(ds, i, j) { + count-- + } + } + } + } + return count + +} + +func makeDisjointSet(size int) []int { + s := make([]int, size) + for i := 0; i < size; i++ { + s[i] = i + } + return s +} + +func find(ds []int, v int) int { + for ds[v] != v { + ds[v] = ds[ds[ds[v]]] + v = ds[v] + } + return v +} + +func union(ds []int, p, q int) bool { + proot := find(ds, p) + qroot := find(ds, q) + if proot == qroot { + return false + } + ds[proot] = qroot + return true +} diff --git a/Week_06/G20200343030387/LeetCode_127_387.js b/Week_06/G20200343030387/LeetCode_127_387.js new file mode 100644 index 00000000..d7a97284 --- /dev/null +++ b/Week_06/G20200343030387/LeetCode_127_387.js @@ -0,0 +1,114 @@ +/** + * @param {string} beginWord + * @param {string} endWord + * @param {string[]} wordList + * @return {number} + */ +// 求最短距离,一般用广度优先比较合适,深度优先需要将所有可能情况都遍历到,然后比较最优; +// 从bgeinWord开始,每一层尝试转换成wordList里的单词,走到转换成enwWord,当前层就是最短距离; +// 中间需要存储访问过的单词,防止出来环路; +// 如果最终wordList里的都访问过了,还是没能转成endWord,则说明无法转换,返回0; +// 为加快找到能转换的单词,这里将wordList的单词用hash表存储对应的转换规则中,如'd*g' => ['dog', 'dug'] +var ladderLength1 = function (beginWord, endWord, wordList) { + const wordHash = new Map() + const wordLength = beginWord.length + const buildWordHash = function () { + let key = '' + let val = [] + wordList.forEach(word => { + for (let i = 0; i < wordLength; i++) { + key = replaceCharByIndex(word, i) + val = wordHash.get(key) || [] + val.push(word) + wordHash.set(key, val) + } + }) + } + const bfs = function () { + const queues = [{node: beginWord, level: 1}] + const visited = new Set() + let current = '' + let level = 0 + let childNodes = [] + visited.add(beginWord) + while (queues.length) { + current = queues.shift() + level = current.level + for (let wi = 0; wi < wordLength; wi++) { + childNodes = wordHash.get(replaceCharByIndex(current.node, wi)) + if (!childNodes) continue + for (let i = 0; i < childNodes.length; i++) { + if (childNodes[i] === endWord) { + return current.level + 1 + } + if (!visited.has(childNodes[i])) { + visited.add(childNodes[i]) + queues.push({node: childNodes[i], level: level + 1}) + } + } + } + } + return 0 + } + buildWordHash() + return bfs() +}; + +// 双向bfs +// 从beginWord和endWord逐渐向中间遍历; +// 每次遍历取节点最小的层,减少遍历次数; +// 用hashMap来获取当前字词可能变换的单词列表,比遍历26个字母逐个替换要快很多; +// 遍历的次数+1则为所求长度; +var ladderLength = function (beginWord, endWord, wordList) { + if (!wordList.includes(endWord)) return 0 + + const wordHash = new Map() + let key = '' + let val = [] + wordList.forEach(word => { + for (let i = 0; i < word.length; i++) { + key = replaceCharByIndex(word, i) + val = wordHash.get(key) || [] + val.push(word) + wordHash.set(key, val) + } + }) + + let front = new Set() + front.add(beginWord) + let back = new Set() + back.add(endWord) + const visited = new Set() + let len = 1 + let newWords = [] + while (front.size) { + const tmpSet = new Set() + for (let word of front) { + for (let wi = 0; wi < word.length; wi++) { + newWords = wordHash.get(replaceCharByIndex(word, wi)) + if (!newWords) continue + for (let newWord of newWords) { + if (back.has(newWord)) { + return len + 1 + } + if (wordList.includes(newWord) && !visited.has(newWord)) { + tmpSet.add(newWord) + visited.add(newWord) + } + } + } + } + len++ + front = tmpSet + if (front.size > back.size) { + const tmp = front + front = back + back = tmp + } + } + return 0 +} + +function replaceCharByIndex(str, index) { + return `${str.substring(0, index)}*${str.substring(index + 1)}` +} \ No newline at end of file diff --git a/Week_06/G20200343030387/LeetCode_208_387.js b/Week_06/G20200343030387/LeetCode_208_387.js new file mode 100644 index 00000000..25f3cde2 --- /dev/null +++ b/Week_06/G20200343030387/LeetCode_208_387.js @@ -0,0 +1,86 @@ +const TrieNode = function () { + this.links = new Map() + this._isEnd = false +} +TrieNode.prototype.setEnd = function () { + this._isEnd = true +} +TrieNode.prototype.isEnd = function () { + return this._isEnd +} +TrieNode.prototype.put = function (word, node) { + this.links.set(word, node) +} +TrieNode.prototype.containsKey = function (word) { + return this.links.has(word) +} +TrieNode.prototype.get = function (word) { + return this.links.get(word) +} + +/** + * Initialize your data structure here. + */ +var Trie = function () { + this.root = new TrieNode() +}; + +/** + * Inserts a word into the trie. + * @param {string} word + * @return {void} + */ +Trie.prototype.insert = function (word) { + let node = this.root + let char = '' + for (let i = 0; i < word.length; i++) { + char = word[i] + if (!node.containsKey(char)) { + node.put(char, new TrieNode()) + } + node = node.get(char) + } + node.setEnd() +}; + +/** + * Returns if the word is in the trie. + * @param {string} word + * @return {boolean} + */ +Trie.prototype.search = function (word) { + const node = this._searchPrefix(word) + return !!node && node.isEnd() +}; + +/** + * Returns if there is any word in the trie that starts with the given prefix. + * @param {string} prefix + * @return {boolean} + */ +Trie.prototype.startsWith = function (prefix) { + const node = this._searchPrefix(prefix) + return !!node +}; + +Trie.prototype._searchPrefix = function (prefix) { + let node = this.root + let char = '' + for (let i = 0; i < prefix.length; i++) { + char = prefix[i] + if (node.containsKey(char)) { + node = node.get(char) + } else { + return null + } + } + return node +} + +/** + * Your Trie object will be instantiated and called as such: + * var obj = new Trie() + * obj.insert(word) + * var param_2 = obj.search(word) + * var param_3 = obj.startsWith(prefix) + */ \ No newline at end of file diff --git a/Week_06/G20200343030387/LeetCode_212_387.js b/Week_06/G20200343030387/LeetCode_212_387.js new file mode 100644 index 00000000..38ddae69 --- /dev/null +++ b/Week_06/G20200343030387/LeetCode_212_387.js @@ -0,0 +1,55 @@ +/** +1. 对words构建字典树; +2. 对board的每个字符进行四联通的深度优先遍历(dfs); +3. dfs剪枝:每个新字符加入前,判断是否在当前字典树的下个节点,是则继续遍历,否则不再遍历; +4. 注意对已访问过的字符进行标记,这里将其替换为"@",待遍历完成后恢复数据; +**/ + +/** + * @param {character[][]} board + * @param {string[]} words + * @return {string[]} + */ +var findWords = function (board, words) { + // build trie + const trie = {} + for (const word of words) { + node = trie + for (const char of word) { + node[char] = node[char] || {} + node = node[char] + } + node._end = true + } + + // dfs fn + function dfs(board, node, i, j, word) { + if (node._end) { + res.add(word) + } + const tmp = board[i][j] + board[i][j] = '@' + for (const arr of [[-1, 0], [1, 0], [0, -1], [0, 1]]) { + let _i = i + arr[0] + let _j = j + arr[1] + if (_i >= 0 && _i < m && _j >= 0 && _j < n && node[board[_i][_j]] && board[_i][_j] !== '@') { + dfs(board.map(a => a.slice(0)), node[board[_i][_j]], _i, _j, word + board[_i][_j]) + } + } + board[i][j] = tmp + } + + // search board by dfs with each word + const res = new Set() + const m = board.length + const n = board[0].length + for (let i = 0; i < m; i++) { + for (let j = 0; j < n; j++) { + if (trie[board[i][j]]) { + dfs(board, trie[board[i][j]], i, j, board[i][j]) + } + } + } + + return Array.from(res) +}; diff --git a/Week_06/G20200343030387/LeetCode_36_387.js b/Week_06/G20200343030387/LeetCode_36_387.js new file mode 100644 index 00000000..b2494bce --- /dev/null +++ b/Week_06/G20200343030387/LeetCode_36_387.js @@ -0,0 +1,28 @@ +/** + * @param {character[][]} board + * @return {boolean} + */ +// 判断: +// 行中没有重复的数字。 +// 列中没有重复的数字。 +// 3 x 3 子数独内没有重复的数字 +var isValidSudoku = function (board) { + const rows = Array(9).fill(0).map(() => new Set()) + const cols = Array(9).fill(0).map(() => new Set()) + const boxes = Array(9).fill(0).map(() => new Set()) + for (let i = 0; i < 9; i++) { + for (let j = 0; j < 9; j++) { + let char = board[i][j] + if (char !== '.') { + let boxIndex = parseInt(parseInt(i / 3) * 3 + j / 3) + if (rows[i].has(char) || cols[j].has(char) || boxes[boxIndex].has(char)) { + return false + } + rows[i].add(char) + cols[j].add(char) + boxes[boxIndex].add(char) + } + } + } + return true +}; \ No newline at end of file diff --git a/Week_06/G20200343030387/LeetCode_547_387.js b/Week_06/G20200343030387/LeetCode_547_387.js new file mode 100644 index 00000000..f46d121b --- /dev/null +++ b/Week_06/G20200343030387/LeetCode_547_387.js @@ -0,0 +1,62 @@ +/** + * @param {number[][]} M + * @return {number} + */ +var findCircleNum = function (M) { + const n = M.length + const unionFind = new UnionFind(n) + for (let i = 0; i < n; i++) { + for (let j = 0; j < n; j++) { + if (M[i][j]) { + unionFind.union(i, j) + } + } + } + return unionFind.count +}; + +class UnionFind { + constructor(n) { + // 初始化并查集 + this.count = n + this.parent = [] + this.size = [] + for (let i = 0; i < n; i++) { + this.parent[i] = i + this.size[i] = 1 + } + } + + // 找到节点的中心节点,并进行路径压缩 + find(i) { + root = i + // 不断往上找,直到找到中心节点 + while (this.parent[root] !== root) { + root = this.parent[root] + } + // 路径压缩 + let x + while (this.parent[i] !== i) { + x = i + i = this.parent[i] + this.parent[x] = root + } + return root + } + + // 合并节点集 + union(i, j) { + const pi = this.find(i) + const pj = this.find(j) + if (pi === pj) return + // 小树合并到大树上,尽量让合并后树的高度较小 + if (this.size[pi] > this.size[pj]) { + this.parent[pi] = pj + this.size[pi] += this.size[pj] + } else { + this.parent[pj] = pi + this.size[pj] += this.size[pi] + } + this.count-- + } +} \ No newline at end of file diff --git a/Week_06/G20200343030387/NOTE.md b/Week_06/G20200343030387/NOTE.md index 50de3041..f59ec8d0 100644 --- a/Week_06/G20200343030387/NOTE.md +++ b/Week_06/G20200343030387/NOTE.md @@ -1 +1,110 @@ -学习笔记 \ No newline at end of file +学习笔记 +## 知识点 +1. 字典树 + a. 单词拆成字母节点存储 + b. 空间换时间的思想 + c. 适用前缀匹配场景,例如搜索栏的autocomplete; +2. 并查集 + a. 记住代码模板 + b. 应用场景:组团、配对问题,如朋友圈 +2. 高级搜索 + a. 剪枝:递归时提前中断一些不必要的遍历; + b. 双向搜索:前后同时向中间进行BFS; + c. 启发式搜索(A*):BFS + 优先队列 + 优先权重计算 + d. 深度学习,思想也是状态树的搜索,不过是中间的剪枝评估更高级了 +3. 红黑树、AVL + a. 了解AVL的四种旋转操作 + b. 两者的应用场景:红黑树适用插入、删除较多,AVL更适合读操作较多 + +## 并查集代码模板 +* java + +```java +class UnionFind { + private int count = 0; + private int[] parent; + public UnionFind(int n) { + count = n; + parent = new int[n]; + for (int i = 0; i < n; i++) { + parent[i] = i; + } + } + public int find(int p) { + while (p != parent[p]) { + parent[p] = parent[parent[p]]; + p = parent[p]; + } + return p; + } + public void union(int p, int q) { + int rootP = find(p); + int rootQ = find(q); + if (rootP == rootQ) return; + parent[rootP] = rootQ; + count--; + } +} +``` + +* python +```python +def init(p): + # for i = 0 .. n: p[i] = i; + p = [i for i in range(n)] + +def union(self, p, i, j): + p1 = self.parent(p, i) + p2 = self.parent(p, j) + p[p1] = p2 + +def parent(self, p, i): + root = i + while p[root] != root: + root = p[root] + while p[i] != i: # 路径压缩 ? + x = i; i = p[i]; p[x] = root + return root +``` + +## 双向BFS代码模板 +``` +def BFS(graph, start, end): + visited = set() + front = set() + back = set() + front.add([start]) + back.add([end]) + + while front: + visited.add(node) + + for node in front: + process(node) + + nodes = generate_related_nodes(node) + front = set(nodes) + if len(front) > len(back): + swap(front, back) + + # other processing work + ... +``` + +## A*代码模板 +``` +def AstarSearch(graph, start, end): + + pq = collections.priority_queue() # 优先级 —> 估价函数 + pq.append([start]) + visited.add(start) + + while pq: + node = pq.pop() # can we add more intelligence here ? + visited.add(node) + + process(node) + nodes = generate_related_nodes(node) + unvisited = [node for node in nodes if node not in visited] + pq.push(unvisited) +``` \ No newline at end of file diff --git a/Week_06/G20200343030391/LeetCode_1091_391.java b/Week_06/G20200343030391/LeetCode_1091_391.java new file mode 100644 index 00000000..dfa5a595 --- /dev/null +++ b/Week_06/G20200343030391/LeetCode_1091_391.java @@ -0,0 +1,77 @@ +package G20200343030391; + + +import java.util.LinkedList; +import java.util.Queue; + +public class LeetCode_1091_391 { + + public static void main(String[] args) { + int[][] grid = {{0, 0, 1, 0, 0, 0, 0}, {0, 1, 0, 0, 0, 0, 1}, {0, 0, 1, 0, 1, 0, 0}, {0, 0, 0, 1, 1, 1, 0}, {1, 0, 0, 1, 1, 0, 0}, {1, 1, 1, 1, 1, 0, 1}, {0, 0, 1, 0, 0, 0, 0}}; + int i = new LeetCode_1091_391().shortestPathBinaryMatrix_1(grid); + System.out.println(i); + + } + + /** + * BFS + * + * @param grid + * @return + */ + public int shortestPathBinaryMatrix_1(int[][] grid) { + if (grid[0][0] == 1 || grid[grid.length - 1][grid[0].length - 1] == 1) { + return -1; + } + int[][] direction = {{-1, -1}, {-1, 0}, {-1, 1}, {0, -1}, {0, 1}, {-1, 1}, {1, 0}, {1, 1}}; + int row = grid.length; + int clo = grid[0].length; + boolean[][] visited = new boolean[row][clo]; + Queue queue = new LinkedList<>(); + visited[0][0] = true; + queue.add(new int[]{0, 0, 1}); + while (!queue.isEmpty()) { + for (int j = 0; j < queue.size(); j++) { + int[] poll = queue.poll(); + int path = poll[2]; + int x = poll[0]; + int y = poll[1]; + if (x == row - 1 && y == clo - 1) { + return path; + } + for (int i = 0; i < direction.length; i++) { + int newX = x + direction[i][0]; + int newY = y + direction[i][1]; + if (newX >= 0 & newX < row && newY >= 0 && newY < clo && !visited[newX][newY] && grid[newX][newY] == 0) { + queue.add(new int[]{newX, newY, path + 1}); + visited[newX][newY] = true; + } + } + } + } + return -1; + } + + + /** + * DP + * + * @param grid + * @return + */ + public int shortestPathBinaryMatrix_2(int[][] grid) { + return -1; + } + + /** + * A* + * + * @param grid + * @return + */ + public int shortestPathBinaryMatrix_3(int[][] grid) { + return -1; + } + + +} diff --git a/Week_06/G20200343030391/LeetCode_130_391.java b/Week_06/G20200343030391/LeetCode_130_391.java new file mode 100644 index 00000000..3f922303 --- /dev/null +++ b/Week_06/G20200343030391/LeetCode_130_391.java @@ -0,0 +1,116 @@ +package G20200343030391; + +import java.util.Arrays; + +public class LeetCode_130_391 { + public static void main(String[] args) { + char[][] M = { + {'O','X','X','O','X'}, + {'X','O','O','X','O'}, + {'X','O','X','O','X'}, + {'O','X','O','O','O'}, + {'X','X','O','X','O'} + }; + + + + + + new LeetCode_130_391().solve_2(M); + System.out.println(Arrays.deepToString(M)); + + } + + /** + * 并查集 + * + * @param board + */ + public void solve_2(char[][] board) { + if (board.length <= 1 || board[0].length <= 1) { + return; + } + int row = board.length; + int clo = board[0].length; + int[][] directions = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}}; + int X = row * clo; + UnionFind unionFind = new UnionFind(X + 2); + for (int i = 0; i < row; i++) { + for (int j = 0; j < clo; j++) { + if (board[i][j] == 'O') { + if (i == 0 || j == 0 || i == row - 1 || j == clo - 1) { + unionFind.union(i * clo + j, X); + } else { + for (int k = 0; k < 4; k++) { + int newX = i + directions[k][0]; + int newY = j + directions[k][1]; + if (board[newX][newY] == 'O') { + unionFind.union(newX * clo + newY, i * clo + j); + } + } + } + } + } + } + for (int i = 0; i < row; i++) { + for (int j = 0; j < clo; j++) { + if (unionFind.connected(i * clo + j, X)) { + board[i][j] = 'O'; + } else { + board[i][j] = 'X'; + } + } + } + } + + + class UnionFind { + //存储树 + private int[] parent; + //子树大小 + private int[] size; + //联通分量 + private int count; + + public UnionFind(int count) { + parent = new int[count]; + size = new int[count]; + for (int i = 0; i < count; i++) { + parent[i] = i; + size[i] = 1; + } + this.count = count; + } + + public int find(int target) { + while (target != parent[target]) { + target = parent[target]; + parent[target] = parent[parent[target]]; + } + return target; + } + + public boolean connected(int p, int q) { + int rootP = find(p); + int rootQ = find(q); + return rootP == rootQ; + } + + public void union(int p, int q) { + int rootP = find(p); + int rootQ = find(q); + if (rootP == rootQ) { + return; + } + if (size[rootP] >= size[rootQ]) { + parent[rootQ] = rootP; + size[rootP] += size[rootQ]; + } else { + parent[rootP] = parent[rootQ]; + size[rootQ] += size[rootP]; + } + count--; + } + + } +} diff --git a/Week_06/G20200343030391/LeetCode_208_391.java b/Week_06/G20200343030391/LeetCode_208_391.java new file mode 100644 index 00000000..9d56196b --- /dev/null +++ b/Week_06/G20200343030391/LeetCode_208_391.java @@ -0,0 +1,109 @@ +package G20200343030391; + + +public class LeetCode_208_391 { + + public static void main(String[] args) { + Trie trie = new Trie(); + + trie.insert("a"); + boolean apple = trie.search("a");// 返回 true + System.out.println(apple); +// boolean app = trie.search("app");// 返回 false +// System.out.println(app); + boolean app1 = trie.startsWith("a");// 返回 true + System.out.println(app1); +// trie.insert("app"); +// boolean app2 = trie.search("app");// 返回 true +// System.out.println(app2); + } + + + public static class Trie { + + private TrieNode trieNode; + + /** Initialize your data structure here. */ + public Trie() { + this.trieNode = new TrieNode(); + } + + /** + * Inserts a word into the trie. + */ + public void insert(String word) { + TrieNode node = this.trieNode; + for (int i = 0; i < word.length(); i++) { + if (!node.containKey(word.charAt(i))) { + node.put(word.charAt(i), new TrieNode()); + } + node = node.get(word.charAt(i)); + } + node.setEnd(); + } + + /** + * Returns if the word is in the trie. + */ + public boolean search(String word) { + TrieNode node = this.trieNode; + for (int i = 0; i < word.length(); i++) { + if (!node.containKey(word.charAt(i))) { + return false; + } + node = node.get(word.charAt(i)); + } + return node.isEnd(); + } + + /** Returns if there is any word in the trie that starts with the given prefix. */ + public boolean startsWith(String prefix) { + TrieNode node = this.trieNode; + for (int i = 0; i < prefix.length(); i++) { + if (!node.containKey(prefix.charAt(i))) { + return false; + } + node = node.get(prefix.charAt(i)); + } + return true; + } + + } + public static class TrieNode{ + TrieNode[] links; + boolean isEnd; + + public TrieNode() { + this.links = new TrieNode[26]; + } + + public boolean containKey(char c) { + return this.links[c - 'a'] != null; + } + + public TrieNode get(char c) { + return this.links[c - 'a']; + } + + public void put(char c, TrieNode node) { + links[c - 'a'] = node; + } + + public void setEnd(){ + this.isEnd = true; + } + + public boolean isEnd(){ + return this.isEnd; + } + + } + +/** + * Your Trie object will be instantiated and called as such: + * Trie obj = new Trie(); + * obj.insert(word); + * boolean param_2 = obj.search(word); + * boolean param_3 = obj.startsWith(prefix); + */ +} diff --git a/Week_06/G20200343030391/LeetCode_212_391.java b/Week_06/G20200343030391/LeetCode_212_391.java new file mode 100644 index 00000000..24027cf9 --- /dev/null +++ b/Week_06/G20200343030391/LeetCode_212_391.java @@ -0,0 +1,94 @@ +package G20200343030391; + + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; + +public class LeetCode_212_391 { + + public static void main(String[] args) { + String[] words = {"oath", "pea", "eat", "rain"}; + char[][] board = + { + {'o', 'a', 'a', 'n'}, + {'e', 't', 'a', 'e'}, + {'i', 'h', 'k', 'r'}, + {'i', 'f', 'l', 'v'} + }; + List list = new LeetCode_212_391().findWords(board, words); + System.out.println(list); + + } + + /** + * Trie + * 时间复杂度 O(N * M * 4^k) + * + * @param board + * @param words + * @return + */ + public List findWords(char[][] board, String[] words) { + TrieNode root = new TrieNode(); + TrieNode node = root; + for (int i = 0; i < words.length; i++) { + String word = words[i]; + for (int j = 0; j < word.length(); j++) { + TrieNode trieNode = node.nodes[word.charAt(j) - 'a']; + if (trieNode == null) { + node.nodes[word.charAt(j) - 'a'] = new TrieNode(); + node = node.nodes[word.charAt(j) - 'a']; + } else { + node = node.nodes[word.charAt(j) - 'a']; + } + } + node.isEnd = true; + node.val = word; + node = root; + } + + int row = board.length; + int clo = board[0].length; + int[][] direction = {{0, -1}, {0, 1}, {-1, 0}, {1, 0}}; + boolean[][] visited = new boolean[row][clo]; + HashSet result = new HashSet<>(); + for (int i = 0; i < row; i++) { + for (int j = 0; j < clo; j++) { + dfs(i, j, row, clo, board, visited, direction, result, root); + } + } + + return new ArrayList<>(result); + } + + private void dfs(int i, int j, int row, int clo, char[][] board, boolean[][] visited, int[][] direction, HashSet result, TrieNode node) { + if (i < 0 || i >= row || j < 0 || j >= clo || visited[i][j]) { + return; + } + TrieNode trieNode = node.nodes[board[i][j] - 'a']; + if (trieNode == null) { + return; + } + visited[i][j] = true; + if (trieNode.isEnd) { + result.add(trieNode.val); + } + + for (int k = 0; k < 4; k++) { + dfs(i + direction[k][0], j + direction[k][1], row, clo, board, visited, direction, result, trieNode); + } + visited[i][j] = false; + + } + + public static class TrieNode { + TrieNode[] nodes; + String val; + boolean isEnd; + + public TrieNode() { + nodes = new TrieNode[26]; + } + } +} diff --git a/Week_06/G20200343030391/LeetCode_31_391.java b/Week_06/G20200343030391/LeetCode_31_391.java new file mode 100644 index 00000000..ca0bad84 --- /dev/null +++ b/Week_06/G20200343030391/LeetCode_31_391.java @@ -0,0 +1,40 @@ +package G20200343030391; + + +public class LeetCode_31_391 { + + public static void main(String[] args) { + char[][] board = { + {'5', '3', '.', '.', '7', '.', '.', '.', '.'}, + {'6', '.', '.', '1', '9', '5', '.', '.', '.'}, + {'.', '9', '8', '.', '.', '.', '.', '6', '.'}, + {'8', '.', '.', '.', '6', '.', '.', '.', '3'}, + {'4', '.', '.', '8', '.', '3', '.', '.', '1'}, + {'7', '.', '.', '.', '2', '.', '.', '.', '6'}, + {'.', '6', '.', '.', '.', '.', '2', '8', '.'}, + {'.', '.', '.', '4', '1', '9', '.', '.', '5'}, + {'.', '.', '.', '.', '8', '.', '.', '7', '9'} + }; + boolean validSudoku = new LeetCode_31_391().isValidSudoku(board); + System.out.println(validSudoku); + + } + + public boolean isValidSudoku(char[][] board) { + for (int i = 0; i < board.length; i++) { + for (int j = 0; j < board[0].length; j++) { + char c = board[i][j]; + for (int k = 0; k < 9; k++) { + if (k != j && board[i][k] != '.' && board[i][k] == c) return false; + if (k != i && board[k][j] != '.' && board[k][j] == c) return false; + int blockX = 3 * (i / 3) + k / 3; + int blockY = 3 * (j / 3) + k % 3; + if (blockX != i && blockY != j && board[blockX][blockY] != '.' && board[blockX][blockY] == c) { + return false; + } + } + } + } + return true; + } +} diff --git a/Week_06/G20200343030391/LeetCode_37_391.java b/Week_06/G20200343030391/LeetCode_37_391.java new file mode 100644 index 00000000..96d5dcf5 --- /dev/null +++ b/Week_06/G20200343030391/LeetCode_37_391.java @@ -0,0 +1,70 @@ +package G20200343030391; + + +public class LeetCode_37_391 { + + public static void main(String[] args) { + char[][] board = { + {'5', '3', '.', '.', '7', '.', '.', '.', '.'}, + {'6', '.', '.', '1', '9', '5', '.', '.', '.'}, + {'.', '9', '8', '.', '.', '.', '.', '6', '.'}, + {'8', '.', '.', '.', '6', '.', '.', '.', '3'}, + {'4', '.', '.', '8', '.', '3', '.', '.', '1'}, + {'7', '.', '.', '.', '2', '.', '.', '.', '6'}, + {'.', '6', '.', '.', '.', '.', '2', '8', '.'}, + {'.', '.', '.', '4', '1', '9', '.', '.', '5'}, + {'.', '.', '.', '.', '8', '.', '.', '7', '9'} + }; + new LeetCode_37_391().solveSudoku(board); + for (int i = 0; i < 9; i++) { + for (int j = 0; j < 9; j++) { + System.out.print(board[i][j] + " "); + + } + System.out.println(); + } + + } + + public void solveSudoku(char[][] board) { + solve(board); + } + + /** + * DFS + * @param board + * @return + */ + private boolean solve(char[][] board) { + for (int i = 0; i < board.length; i++) { + for (int j = 0; j < board[0].length; j++) { + if (board[i][j] == '.') { + for (char c = '1'; c <= '9'; c++) { + if (isValidSudoku(board, i, j, c)) { + board[i][j] = c; + if (solve(board)) { + return true; + } + board[i][j] = '.'; + } + } + return false; + } + } + } + return true; + } + + public boolean isValidSudoku(char[][] board, int i, int j, char c) { + for (int k = 0; k < 9; k++) { + if (k != j && board[i][k] != '.' && board[i][k] == c) return false; + if (k != i && board[k][j] != '.' && board[k][j] == c) return false; + int blockX = 3 * (i / 3) + k / 3; + int blockY = 3 * (j / 3) + k % 3; + if (blockX != i && blockY != j && board[blockX][blockY] != '.' && board[blockX][blockY] == c) { + return false; + } + } + return true; + } +} diff --git a/Week_06/G20200343030391/LeetCode_547_391.java b/Week_06/G20200343030391/LeetCode_547_391.java new file mode 100644 index 00000000..082332d3 --- /dev/null +++ b/Week_06/G20200343030391/LeetCode_547_391.java @@ -0,0 +1,112 @@ +package G20200343030391; + +public class LeetCode_547_391 { + public static void main(String[] args) { + int[][] M = { + {1, 1, 1}, + {1, 1, 1}, + {1, 1, 1}}; + int circleNum = new LeetCode_547_391().findCircleNum(M); + System.out.println(circleNum); + + } + + public int findCircleNum(int[][] M) { + int count = M.length; + UnionFind unionFind = new UnionFind(count); + for (int i = 0; i < count; i++) { + for (int j = 0; j < i; j++) { + if (M[i][j] == 1) { + unionFind.union(i, j); + } + } + } + return unionFind.count; + } + + class UnionFind { + private int count; + private int[] parent; + + public UnionFind(int n) { + this.count = n; + parent = new int[n]; + for (int i = 0; i < n; i++) { + parent[i] = i; + } + } + + public int find(int p) { + while (p != parent[p]) { + parent[p] = parent[parent[p]]; + p = parent[p]; + } + return p; + } + + public void union(int p, int q) { + int pRoot = find(p); + int qRoot = find(q); + if (pRoot == qRoot) { + return; + } + parent[pRoot] = qRoot; + count--; + } + } + + class UF { + // 连通分量个数 + private int count; + // 存储一棵树 + private int[] parent; + // 记录树的“重量” + private int[] size; + + public UF(int n) { + this.count = n; + parent = new int[n]; + size = new int[n]; + for (int i = 0; i < n; i++) { + parent[i] = i; + size[i] = 1; + } + } + + public void union(int p, int q) { + int rootP = find(p); + int rootQ = find(q); + if (rootP == rootQ) + return; + + // 小树接到大树下面,较平衡 + if (size[rootP] > size[rootQ]) { + parent[rootQ] = rootP; + size[rootP] += size[rootQ]; + } else { + parent[rootP] = rootQ; + size[rootQ] += size[rootP]; + } + count--; + } + + public boolean connected(int p, int q) { + int rootP = find(p); + int rootQ = find(q); + return rootP == rootQ; + } + + private int find(int x) { + while (parent[x] != x) { + // 进行路径压缩 + parent[x] = parent[parent[x]]; + x = parent[x]; + } + return x; + } + + public int count() { + return count; + } + } +} diff --git a/Week_06/G20200343030391/LeetCode_79_391.java b/Week_06/G20200343030391/LeetCode_79_391.java new file mode 100644 index 00000000..a8967ace --- /dev/null +++ b/Week_06/G20200343030391/LeetCode_79_391.java @@ -0,0 +1,62 @@ +package G20200343030391; + + +public class LeetCode_79_391 { + + public static void main(String[] args) { + char[][] board = { + {'a'} + }; + boolean abcced = new LeetCode_79_391().exist(board, "b"); + System.out.println(abcced); + } + + /** + * DFS + * + * @param board + * @param word + * @return + */ + public boolean exist(char[][] board, String word) { + + int[][] direction = {{0, -1}, {0, 1}, {-1, 0}, {1, 0}}; + int row = board.length; + int clo = board[0].length; + for (int i = 0; i < row; i++) { + for (int j = 0; j < clo; j++) { + if (board[i][j] == word.charAt(0)) { + dfs(i, j, row, clo, 0, board, direction, word); + } + if (find) { + return true; + } + } + } + return find; + } + + boolean find; + + private void dfs(int i, int j, int row, int clo, int index, char[][] board, int[][] direction, String word) { + if (index == word.length() - 1) { + find = true; + return; + } + if (board[i][j] == word.charAt(index)) { + char orign = board[i][j]; + board[i][j] = '#'; + for (int k = 0; k < 4; k++) { + int newX = i + direction[k][0]; + int newY = j + direction[k][1]; + if ((newX >= 0 && newX < row && newY >= 0 && newY < clo) && board[newX][newY] != '#' && board[newX][newY] == word.charAt(index + 1)) { + dfs(newX, newY, row, clo, index + 1, board, direction, word); + } + if (find) { + return; + } + } + board[i][j] = orign; + } + } +} diff --git a/Week_06/G20200343030391/NOTE.md b/Week_06/G20200343030391/NOTE.md index 50de3041..40c013d7 100644 --- a/Week_06/G20200343030391/NOTE.md +++ b/Week_06/G20200343030391/NOTE.md @@ -1 +1,99 @@ -学习笔记 \ No newline at end of file +# 学习笔记 +## 字典树 +### 基本结构 + - 字典树,即 Trie 树,又称单词查找树或键树,是一种树形结构。典型应用是用于统计和排序大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。 它的优点是:最大限度地减少无谓的字符串比较,查询效率比哈希表高。 +### 基本性质 + - 1. 结点本身不存完整单词; + - 2. 从根结点到某一结点,路径上经过的字符连接起来,为该结点对应的字符串; + - 3. 每个结点的所有子结点路径代表的字符都不相同。 + +### 核心思想 + - Trie 树的核心思想是空间换时间。利用字符串的公共前缀来降低查询时间的开销以达到提高效率的目的。 +## 并查集 + +### 适用场景 + - 组团、配对问题 + - Group or not ? +### 基本操作 + - makeSet(s):建立一个新的并查集,其中包含 s 个单元素集合。 + - unionSet(x, y):把元素 x 和元素 y 所在的集合合并,要求 x 和 y 所在 + 的集合不相交,如果相交则不合并。 + - ind(x):找到元素 x 所在的集合的代表,该操作也可以用于判断两个元 + 素是否位于同一个集合,只要将它们各自的代表比较一下就可以了。 +### 代码模板 + ```java + class UF { + // 连通分量个数 + private int count; + // 存储一棵树 + private int[] parent; + // 记录树的“重量” + private int[] size; + + public UF(int n) { + this.count = n; + parent = new int[n]; + size = new int[n]; + for (int i = 0; i < n; i++) { + parent[i] = i; + size[i] = 1; + } + } + + public void union(int p, int q) { + int rootP = find(p); + int rootQ = find(q); + if (rootP == rootQ) + return; + + // 小树接到大树下面,较平衡 + if (size[rootP] > size[rootQ]) { + parent[rootQ] = rootP; + size[rootP] += size[rootQ]; + } else { + parent[rootP] = rootQ; + size[rootQ] += size[rootP]; + } + count--; + } + + public boolean connected(int p, int q) { + int rootP = find(p); + int rootQ = find(q); + return rootP == rootQ; + } + + private int find(int x) { + while (parent[x] != x) { + // 进行路径压缩 + parent[x] = parent[parent[x]]; + x = parent[x]; + } + return x; + } + + public int count() { + return count; + } + } + ``` +## A* +### 估价函数 + +### 代码模板 + ```java + def AstarSearch(graph, start, end): + + pq = collections.priority_queue() # 优先级 —> 估价函数 + pq.append([start]) + visited.add(start) + + while pq: + node = pq.pop() # can we add more intelligence here ? + visited.add(node) + + process(node) + nodes = generate_related_nodes(node) + unvisited = [node for node in nodes if node not in visited] + pq.push(unvisited) + ``` \ No newline at end of file diff --git a/Week_06/G20200343030393/LeetCode_127_393.py b/Week_06/G20200343030393/LeetCode_127_393.py new file mode 100644 index 00000000..01ab7ab6 --- /dev/null +++ b/Week_06/G20200343030393/LeetCode_127_393.py @@ -0,0 +1,50 @@ +import string +import collections + +class Solution(object): + def ladderLength(self, beginWord, endWord, wordList): + """ + :type beginWord: str + :type endWord: str + :type wordList: List[str] + :rtype: int + """ + if endWord not in wordList: + return 0 + + wordSet = set(wordList) + + def nextWords(word, visited): + for i in range(len(word)): + for c in string.ascii_lowercase: + nextWord = word[:i] + c + word[i + 1:] + if nextWord in wordSet and nextWord not in visited: + yield nextWord + + beginQueue = collections.deque([(beginWord)]) + endQueue = collections.deque([(endWord)]) + + beginVisited, endVisited = set([beginWord]), set([endWord]) + step = 1 + while beginQueue and endQueue: + newQueue = beginQueue + beginQueue = collections.deque() + while newQueue: + word = newQueue.popleft() + for nextWord in nextWords(word, beginVisited): + if nextWord in endQueue: + return step + 1 + beginQueue.append(nextWord) + beginVisited.add(nextWord) + step += 1 + beginQueue, endQueue = endQueue, beginQueue + beginVisited, endVisited = endVisited, beginVisited + return 0 + + +beginWord = "hit" +endWord = "cog" +wordList = ["hot", "dot", "dog", "lot", "log", "cog"] + +aa = Solution() +print(aa.ladderLength(beginWord, endWord, wordList)) diff --git a/Week_06/G20200343030393/LeetCode_36_393.py b/Week_06/G20200343030393/LeetCode_36_393.py new file mode 100644 index 00000000..7acd0920 --- /dev/null +++ b/Week_06/G20200343030393/LeetCode_36_393.py @@ -0,0 +1,33 @@ +class Solution(object): + def isValidSudoku(self, board): + """ + :type board: List[List[str]] + :rtype: bool + """ + big = set() + for i in range(0, 9): + for j in range(0, 9): + if board[i][j] != '.': + cur = board[i][j] + if (i, cur) in big or (cur, j) in big or (i / 3, j / 3, cur) in big: + return False + big.add((i, cur)) + big.add((cur, j)) + big.add((i / 3, j / 3, cur)) + return True + + +board = [ + ["5","3",".",".","7",".",".",".","."], + ["6",".",".","1","9","5",".",".","."], + [".","9","8",".",".",".",".","6","."], + ["8",".",".",".","6",".",".",".","3"], + ["4",".",".","8",".","3",".",".","1"], + ["7",".",".",".","2",".",".",".","6"], + [".","6",".",".",".",".","2","8","."], + [".",".",".","4","1","9",".",".","5"], + [".",".",".",".","8",".",".","7","9"] +] + +aa = Solution() +print(aa.isValidSudoku(board)) diff --git a/Week_06/G20200343030395/LeetCode_10_395.java b/Week_06/G20200343030395/LeetCode_10_395.java new file mode 100644 index 00000000..47263bdc --- /dev/null +++ b/Week_06/G20200343030395/LeetCode_10_395.java @@ -0,0 +1,5 @@ +package Week_06.G20200343030395; + +public class LeetCode_10_395 { + +} diff --git a/Week_06/G20200343030395/LeetCode_1_395.java b/Week_06/G20200343030395/LeetCode_1_395.java new file mode 100644 index 00000000..a19cfec2 --- /dev/null +++ b/Week_06/G20200343030395/LeetCode_1_395.java @@ -0,0 +1,42 @@ +package Week_06.G20200343030395; + +public class LeetCode_1_395 { + public int climbStairs(int n) { + int memo[] = new int[n+1]; + return cs(0, n, memo); + } + + public int cs(int i, int n, int memo[]) + { + if(i > n) { + return 0; + } + + if(i == n) { + return 1; + } + + if(memo[i] > 0) { + return memo[i]; + } + + memo[i] = cs(i+1, n, memo) + cs(i+2, n, memo); + return memo[i]; + } + + public int dp(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]; + } +} diff --git a/Week_06/G20200343030395/LeetCode_2_395.java b/Week_06/G20200343030395/LeetCode_2_395.java new file mode 100644 index 00000000..52eb0087 --- /dev/null +++ b/Week_06/G20200343030395/LeetCode_2_395.java @@ -0,0 +1,95 @@ +package Week_06.G20200343030395; + +public class LeetCode_2_395 { + class Trie { + + private TrieNode root; + + /** Initialize your data structure here. */ + public Trie() { + root = new TrieNode(); + } + + /** Inserts a word into the trie. */ + public void insert(String word) { + TrieNode node = root; + + for (int i = 0; i < word.length(); i++) { + char currentChar = word.charAt(i); + + if(!node.containsKey(currentChar)) { + node.put(currentChar, new TrieNode()); + } + + node = node.get(currentChar); + } + + node.setEnd(); + } + + private TrieNode searchPrefix(String word) { + TrieNode node = root; + + for (int i =0; i< word.length(); i++) { + char curLetter = word.charAt(i); + if(node.containsKey(curLetter)) { + node = node.get(curLetter); + } else { + return null; + } + } + + return node; + } + + /** Returns if the word is in the trie. */ + public boolean search(String word) { + TrieNode node = searchPrefix(word); + return node!=null && node.isEnd(); + } + + + /** Returns if there is any word in the trie that starts with the given prefix. */ + public boolean startsWith(String prefix) { + TrieNode node = searchPrefix(prefix); + + return node!=null; + } + } + + class TrieNode { + + private TrieNode[] links; + + private final int R = 26; + + private boolean isEnd; + + public TrieNode() { + links = new TrieNode[R]; + } + + public boolean containsKey(char ch) { + return links[ch - 'a'] != null; + } + + public TrieNode get(char ch) { + return links[ch - 'a']; + } + + public void put(char ch, TrieNode node) { + links[ch - 'a'] = node; + } + + public void setEnd() { + isEnd = true; + } + + public boolean isEnd() { + return isEnd; + } + + } +} + + diff --git a/Week_06/G20200343030395/LeetCode_3_395.java b/Week_06/G20200343030395/LeetCode_3_395.java new file mode 100644 index 00000000..9e75c2c6 --- /dev/null +++ b/Week_06/G20200343030395/LeetCode_3_395.java @@ -0,0 +1,72 @@ +package Week_06.G20200343030395; + +import java.util.Arrays; +import java.util.LinkedList; +import java.util.Queue; + +public class LeetCode_3_395 { + public int bfsfindCircleNum(int[][] M) { + int[] visited = new int[M.length]; + int count = 0; + + Queue queue = new LinkedList<>(); + for (int i = 0; i < M.length; i++) { + if (visited[i] == 0) { + queue.add(i); + while (!queue.isEmpty()) { + int s = queue.remove(); + + visited[s] = 1; + for (int j = 0; j < M.length; j++) { + if (M[s][j] == 1 && visited[j] == 0) { + queue.add(j); + } + } + } + + count++; + } + } + + return count; + } + + int find(int parent[], int i) { + if (parent[i] == -1) { + return i; + } + + return find(parent, parent[i]); + } + + void union(int parent[], int x, int y) { + int xset = find(parent, x); + int yset = find(parent, y); + + if (xset != yset) { + parent[xset] = yset; + } + } + + public int findCircleNum(int[][] M) { + int[] parent = new int[M.length]; + + Arrays.fill(parent, -1); + for (int i=0; i generateParenthesis(int n) { + List ans = new ArrayList<>(); + + backtrack(ans, "", 0, 0, n); + + return ans; + } + + public void backtrack(List ans, String cur, int left, int right, int max){ + if(cur.length() == max*2) { + ans.add(cur); + return; + } + + //左括号少于长度的时候,可以加左括号 + if(left < max) { + backtrack(ans, cur+"(", left+1, right, max); + } + //右括号少于长度的时候,可以加右括号 + if(right < left) { + backtrack(ans, cur+")", left, right+1, max); + } + } +} diff --git a/Week_06/G20200343030395/NOTE.md b/Week_06/G20200343030395/NOTE.md index 50de3041..9b56d2b0 100644 --- a/Week_06/G20200343030395/NOTE.md +++ b/Week_06/G20200343030395/NOTE.md @@ -1 +1,46 @@ -学习笔记 \ No newline at end of file +学习笔记 + +## 2020/3/17 +* 搜索树 +1. 节点不存储整个单词,只存储一个字母。全路径连一起才是词 +2. 同一节点的所有子节点表示的字母都不同 +3. 节点可以存储出现的频次(额外信息) + + +* A* +``` +def AStarSearch(graph, start, end): + pq = collections.priority_queue() #优先级->估价函数 + pq.append([start]) + visited.add(start) + + while pq: + node = pq.pop() + visited.add(node) + + process(node) + nodes = generate_related_nodes(node) + unvisited = [node for node in nodes if node not in visited] + pq.push(unvisited) +``` + +1. 启发式函数(估价函数) + * h(n)用来评估哪些节点是我们要找的最有希望的节点,会返回非负实数,可以认为是从节点n的目标节点路径的估计成本 + * 启发式函数是一种告知搜索方向的方法 + +* AVL树 +1. 平衡二叉搜索树 +2. 每个节点存平衡因子(-1,0,1) 左右子树高度差 +3. 四种旋转(右旋,左旋,右左旋,左右旋) +4. 调整次数频繁 + +* 红黑树 O(logN) +1. 近似平衡二叉树,确保左右子树高度差小于两倍(减少旋转频率) +2. 每个节点要么是黑的,要么是红的 +3. 根节点一定是黑的 +4. 叶子结点,空节点一定是黑的 +5. 不能有两个相邻的红节点 +6. 从任一节点到其每个叶子节点的所有路径都包含相同数目的黑节点 + +读多用AVL,读一半写一半用红黑 + diff --git a/Week_06/G20200343030401/LeetCode_37_401.java b/Week_06/G20200343030401/LeetCode_37_401.java new file mode 100644 index 00000000..fdbb3ab4 --- /dev/null +++ b/Week_06/G20200343030401/LeetCode_37_401.java @@ -0,0 +1,103 @@ +//题目链接:https://leetcode-cn.com/problems/sudoku-solver/#/description +class Solution { + // box size + int n = 3; + // row size + int N = n * n; + + int [][] rows = new int[N][N + 1]; + int [][] columns = new int[N][N + 1]; + int [][] boxes = new int[N][N + 1]; + + char[][] board; + + boolean sudokuSolved = false; + + public boolean couldPlace(int d, int row, int col) { + /* + Check if one could place a number d in (row, col) cell + */ + int idx = (row / n ) * n + col / n; + return rows[row][d] + columns[col][d] + boxes[idx][d] == 0; + } + + public void placeNumber(int d, int row, int col) { + /* + Place a number d in (row, col) cell + */ + int idx = (row / n ) * n + col / n; + + rows[row][d]++; + columns[col][d]++; + boxes[idx][d]++; + board[row][col] = (char)(d + '0'); + } + + public void removeNumber(int d, int row, int col) { + /* + Remove a number which didn't lead to a solution + */ + int idx = (row / n ) * n + col / n; + rows[row][d]--; + columns[col][d]--; + boxes[idx][d]--; + board[row][col] = '.'; + } + + public void placeNextNumbers(int row, int col) { + /* + Call backtrack function in recursion + to continue to place numbers + till the moment we have a solution + */ + // if we're in the last cell + // that means we have the solution + if ((col == N - 1) && (row == N - 1)) { + sudokuSolved = true; + } + // if not yet + else { + // if we're in the end of the row + // go to the next row + if (col == N - 1) backtrack(row + 1, 0); + // go to the next column + else backtrack(row, col + 1); + } + } + + public void backtrack(int row, int col) { + /* + Backtracking + */ + // if the cell is empty + if (board[row][col] == '.') { + // iterate over all numbers from 1 to 9 + for (int d = 1; d < 10; d++) { + if (couldPlace(d, row, col)) { + placeNumber(d, row, col); + placeNextNumbers(row, col); + // if sudoku is solved, there is no need to backtrack + // since the single unique solution is promised + if (!sudokuSolved) removeNumber(d, row, col); + } + } + } + else placeNextNumbers(row, col); + } + + public void solveSudoku(char[][] board) { + this.board = board; + + // init rows, columns and boxes + for (int i = 0; i < N; i++) { + for (int j = 0; j < N; j++) { + char num = board[i][j]; + if (num != '.') { + int d = Character.getNumericValue(num); + placeNumber(d, i, j); + } + } + } + backtrack(0, 0); + } +} \ No newline at end of file diff --git a/Week_06/G20200343030401/LeetCode_547_401.java b/Week_06/G20200343030401/LeetCode_547_401.java new file mode 100644 index 00000000..35ceb671 --- /dev/null +++ b/Week_06/G20200343030401/LeetCode_547_401.java @@ -0,0 +1,32 @@ +//题目链接:https://leetcode-cn.com/problems/friend-circles/ +class Solution { + int find(int parent[], int i) { + if (parent[i] == -1) + return i; + return find(parent, parent[i]); + } + + void union(int parent[], int x, int y) { + int xset = find(parent, x); + int yset = find(parent, y); + if (xset != yset) + parent[xset] = yset; + } + public int findCircleNum(int[][] M) { + int[] parent = new int[M.length]; + Arrays.fill(parent, -1); + for (int i = 0; i < M.length; i++) { + for (int j = 0; j < M.length; j++) { + if (M[i][j] == 1 && i != j) { + union(parent, i, j); + } + } + } + int count = 0; + for (int i = 0; i < parent.length; i++) { + if (parent[i] == -1) + count++; + } + return count; + } +} \ No newline at end of file diff --git a/Week_06/G20200343030403/leetcode208.java b/Week_06/G20200343030403/leetcode208.java new file mode 100644 index 00000000..e21785eb --- /dev/null +++ b/Week_06/G20200343030403/leetcode208.java @@ -0,0 +1,84 @@ +class Trie { + class TrieNode { + private TrieNode[] links; + + private final int R = 26; + + private boolean isEnd; + + public TrieNode() { + links = new TrieNode[R]; + } + + public boolean containsKey(char ch) { + return links[ch - 'a'] != null; + } + + public TrieNode get(char ch) { + return links[ch - 'a']; + } + + public void put(char ch, TrieNode node) { + links[ch - 'a'] = node; + } + + public void setEnd() { + isEnd = true; + } + + public boolean isEnd() { + return isEnd; + } + } + + private TrieNode root; + + /** + * Initialize your data structure here. + */ + public Trie() { + root = new TrieNode(); + } + + /** + * Inserts a word into the trie. + */ + public void insert(String word) { + TrieNode node = root; + for (int i = 0; i < word.length(); i++) { + char curChar = word.charAt(i); + if (!node.containsKey(curChar)) { + node.put(curChar, new TrieNode()); + } + node = node.get(curChar); + } + node.setEnd(); + } + + /** + * Returns if the word is in the trie. + */ + public boolean search(String word) { + TrieNode node = searchPrefix(word); + return node != null && node.isEnd(); + } + + /** + * Returns if there is any word in the trie that starts with the given prefix. + */ + public boolean startsWith(String prefix) { + return searchPrefix(prefix) != null; + } + + private TrieNode searchPrefix(String word) { + TrieNode node = root; + for (int i = 0; i < word.length(); i++) { + char curLetter = word.charAt(i); + if (!node.containsKey(curLetter)) { + return null; + } + node = node.get(curLetter); + } + return node; + } +} \ No newline at end of file diff --git a/Week_06/G20200343030403/leetcode212 .java b/Week_06/G20200343030403/leetcode212 .java new file mode 100644 index 00000000..514ca88e --- /dev/null +++ b/Week_06/G20200343030403/leetcode212 .java @@ -0,0 +1,119 @@ +// leetcode212 单词搜索II +// trie前缀树 + DFS +// 1. 改造TrieNode,增加存储字符串的val,减少字符串拼接的开销 +// 2. 增加布尔型visited的辅助数组,判断该字符是否已经被使用,减少字符串比较的开销 +// 时间复杂度O(N + m*n*4^k) +class Solution { + + int[] dx = {-1, 1, 0, 0}; + int[] dy = {0, 0, -1, 1}; + + boolean[][] visited; + Set res = new HashSet<>(); + + public List findWords(char[][] board, String[] words) { + if (board == null || board[0] == null) return new ArrayList<>(); + + Trie trie = new Trie(); + for (String word : words) { + trie.insert(word); + } + + // DFS + int m = board.length; + int n = board[0].length; + visited = new boolean[m][n]; + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + dfs(board, i, j, trie.root); + } + } + + return new LinkedList<>(res); + } + + private void dfs(char[][] board, int i, int j, TrieNode root) { + char ch = board[i][j]; + TrieNode node = root.get(ch); + if (node == null) return; + + if (node.isEnd()) { + res.add(node.val); + } + + // used +// board[i][j] = '@'; + visited[i][j] = true; + for (int k = 0; k < 4; k++) { + int x = i + dx[k]; + int y = j + dy[k]; + if (x < 0 || x == board.length || y < 0 || y == board[0].length || visited[x][y]) + continue; + dfs(board, x, y, node); + } + // reset +// board[i][j] = ch; + visited[i][j] = false; + } +} + +class TrieNode { + private TrieNode[] links; + + private final int R = 26; + + private boolean isEnd; + + public String val; + + public TrieNode() { + links = new TrieNode[R]; + } + + public TrieNode get(char ch) { + return links[ch - 'a']; + } + + public boolean containsKey(char ch) { + return links[ch - 'a'] != null; + } + + public void put(char ch, TrieNode node) { + links[ch - 'a'] = node; + } + + public void setEnd() { + isEnd = true; + } + + public boolean isEnd() { + return isEnd; + } +} + +class Trie { + public TrieNode root; + + /** + * Initialize your data structure here. + */ + public Trie() { + root = new TrieNode(); + } + + /** + * Inserts a word into the trie. + */ + public void insert(String word) { + TrieNode node = root; + for (int i = 0; i < word.length(); i++) { + char curChar = word.charAt(i); + if (!node.containsKey(curChar)) { + node.put(curChar, new TrieNode()); + } + node = node.get(curChar); + } + node.setEnd(); + node.val = word; + } +} \ No newline at end of file diff --git "a/Week_06/G20200343030407/[208]\345\256\236\347\216\260 Trie (\345\211\215\347\274\200\346\240\221).py" "b/Week_06/G20200343030407/[208]\345\256\236\347\216\260 Trie (\345\211\215\347\274\200\346\240\221).py" new file mode 100644 index 00000000..dea8b452 --- /dev/null +++ "b/Week_06/G20200343030407/[208]\345\256\236\347\216\260 Trie (\345\211\215\347\274\200\346\240\221).py" @@ -0,0 +1,76 @@ +# 实现一个 Trie (前缀树),包含 insert, search, 和 startsWith 这三个操作。 +# +# 示例: +# +# Trie trie = new Trie(); +# +# trie.insert("apple"); +# trie.search("apple"); // 返回 true +# trie.search("app"); // 返回 false +# trie.startsWith("app"); // 返回 true +# trie.insert("app"); +# trie.search("app"); // 返回 true +# +# 说明: +# +# +# 你可以假设所有的输入都是由小写字母 a-z 构成的。 +# 保证所有输入均为非空字符串。 +# +# Related Topics 设计 字典树 + + +# leetcode submit region begin(Prohibit modification and deletion) +class Trie: + + def __init__(self): + """ + Initialize your data structure here. + """ + self.root = {} + + def insert(self, word: str) -> None: + """ + Inserts a word into the trie. + """ + tree = self.root + for char in word: + if char not in tree: + tree[char] = {} + tree = tree[char] + tree['#'] = '#' + return True + + + def search(self, word: str) -> bool: + """ + Returns if the word is in the trie. + """ + tree = self.root + for char in word: + if char in tree: + tree = tree[char] + else: + return False + return True if '#' in tree else False + + + def startsWith(self, prefix: str) -> bool: + """ + Returns if there is any word in the trie that starts with the given prefix. + """ + tree = self.root + for char in prefix: + if char in tree: + tree = tree[char] + else: + return False + return True + + +# Your Trie object will be instantiated and called as such: +obj = Trie() +print(obj.insert('apple')) +print(obj.search('ap')) +print(obj.startsWith('ap')) +# leetcode submit region end(Prohibit modification and deletion) diff --git "a/Week_06/G20200343030407/[70]\347\210\254\346\245\274\346\242\257.py" "b/Week_06/G20200343030407/[70]\347\210\254\346\245\274\346\242\257.py" new file mode 100644 index 00000000..fbc57b1c --- /dev/null +++ "b/Week_06/G20200343030407/[70]\347\210\254\346\245\274\346\242\257.py" @@ -0,0 +1,39 @@ +# 假设你正在爬楼梯。需要 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 动态规划 + + +# leetcode submit region begin(Prohibit modification and deletion) +class Solution: + def climbStairs(self, n: int) -> int: + if n == 0 or n == 1 or n == 2: + return n + pp = 1 + p = 2 + for i in range(3, n + 1): + tmp = pp + p + pp = p + p = tmp + return p +# leetcode submit region end(Prohibit modification and deletion) diff --git a/Week_06/G20200343030409/LeetCode_36_409.java b/Week_06/G20200343030409/LeetCode_36_409.java new file mode 100644 index 00000000..1ff32459 --- /dev/null +++ b/Week_06/G20200343030409/LeetCode_36_409.java @@ -0,0 +1,94 @@ +/* + time complexity: O(1), space complexity: O(1) + + Method 1 - use string + + use string, to store + row, col, box's used value in set + simple way, but it's so slow... 12ms + + */ +class Solution { + public boolean isValidSudoku(char[][] board) { + Set used = new HashSet<>(); + + for (int i = 0; i < 9; i++) { + for (int j = 0; j < 9; j++) { + char num = board[i][j]; + if (num != '.') { + if (!used.add(num + "row" + i) || + !used.add(num + "col" + j) || + !used.add(num + "box" + i/3 + "-" + j/3)) { + return false; + } + } + } + } + return true; + } +} +/* + Method 2 - use 3 set + 2ms + + + the key is + char boxVal = board[(i/3)*3 + j/3][(i%3)*3 + j%3]; +*/ +class Solution2 { + */ + public boolean isValidSudoku(char[][] board) { + + for (int i = 0; i < 9; i++) { + Set row = new HashSet<>(); + Set col = new HashSet<>(); + Set box = new HashSet<>(); + + for (int j = 0; j < 9; j++) { + char rowVal = board[i][j]; + if (rowVal != '.' && !row.add(rowVal)) return false; + + char colVal = board[j][i]; + if (colVal != '.' && !col.add(colVal)) return false; + + char boxVal = board[(i/3)*3 + j/3][(i%3)*3 + j%3]; + if (boxVal != '.' && !box.add(boxVal)) return false; + + } + } + return true; + } +} +/* + Method 3 - use bitwise operator +*/ +class Solution3 { + */ + public boolean isValidSudoku(char[][] board) { + int[] row = new int[9]; + int[] col = new int[9]; + int[] box = new int[9]; + int idx = 0; + for (int i = 0; i < 9; i++) { + for (int j = 0; j < 9; j++) { + char num = board[i][j]; + int boxIndex = (i/3)*3 + j/3; + + if (num != '.') { + idx = 1 << (num - '0'); // 左移(1~9)意思就是用9個位元去存 + + if ((row[i] & idx) > 0 || + (col[j] & idx) > 0 || + (box[boxIndex] & idx) > 0) { //用&去判斷是否存在 + return false; + } + row[i] |= idx; // 紀錄值 + col[j] |= idx; + box[boxIndex] |= idx; + } + + } + } + return true; + } +} \ No newline at end of file diff --git a/Week_06/G20200343030409/LeetCode_37_409.java b/Week_06/G20200343030409/LeetCode_37_409.java new file mode 100644 index 00000000..9be0e6d2 --- /dev/null +++ b/Week_06/G20200343030409/LeetCode_37_409.java @@ -0,0 +1,50 @@ +/* + + time complexity: O(9^m), m represents the number of blanks to be filled in + space complexity: O(1) + +*/ +class Solution { + public void solveSudoku(char[][] board) { + if (board == null || board.length == 0) return; + solve(board); + } + + private boolean solve(char[][] board) { + for (int i = 0; i < board.length; i++) { + for (int j = 0; j < board[0].length; j++) { + + if (board[i][j] == '.') { + for (char c = '1'; c <= '9'; c++) { //每個位置一一放入去try + if (isValid(board, i, j, c)) { + board[i][j] = c; //set value + + if (solve(board)) return true; // resursive + + board[i][j] = '.'; // backtrack + } + + } + return false; + } + } + } + return true; + } + + + private boolean isValid(char[][] board, int row, int col, char c) { + for (int i = 0; i < 9; i++) { //判斷9個格子 + char rowVal = board[row][i]; + if (rowVal != '.' && rowVal == c) return false; + + char colVal = board[i][col]; + if (colVal != '.' && colVal == c) return false; + + // 因為沒有用set, 所以判斷式是這樣, 這裡再針對(i,j) 去判斷9宮格內是否有c了 + char boxVal = board[3*(row/3) + i/3][3*(col/3) + i%3]; + if (boxVal != '.' && boxVal == c) return false; + } + return true; + } +} \ No newline at end of file diff --git a/Week_06/G20200343030415/LeetCode-208-415.java b/Week_06/G20200343030415/LeetCode-208-415.java new file mode 100644 index 00000000..5c840231 --- /dev/null +++ b/Week_06/G20200343030415/LeetCode-208-415.java @@ -0,0 +1,75 @@ +class Trie { + + class TrieNode{ + private TrieNode[] links; + private final int R = 26; + private boolean isEnd; + public TrieNode(){ + links = new TrieNode[R]; + } + public boolean containsKey(char ch){ + return links[ch - 'a'] != null; + } + + public TrieNode get(char ch){ + return links[ch - 'a']; + } + + public void put(char ch,TrieNode node){ + links[ch - 'a'] = node; + } + + public void setEnd(){ + isEnd = true; + } + + public boolean isEnd(){ + return isEnd; + } + } + + private TrieNode root; + + /** Initialize your data structure here. */ + public Trie() { + root = new TrieNode(); + } + + /** Inserts a word into the trie. */ + public void insert(String word) { + TrieNode node = root; + for (int i = 0; i < word.length(); i++) { + char currentChar = word.charAt(i); + if(!node.containsKey(currentChar)){ + node.put(currentChar,new TrieNode()); + } + node = node.get(currentChar); + } + node.setEnd(); + } + + + private TrieNode searchPrefix(String word){ + TrieNode node = root; + for (int i = 0; i < word.length(); i++) { + char curLetter = word.charAt(i); + if(node.containsKey(curLetter)){ + node = node.get(curLetter); + }else { + return null; + } + } + return node; + } + /** Returns if the word is in the trie. */ + public boolean search(String word) { + TrieNode node = searchPrefix(word); + return node != null && node.isEnd(); + } + + /** Returns if there is any word in the trie that starts with the given prefix. */ + public boolean startsWith(String prefix) { + TrieNode node = searchPrefix(prefix); + return node != null; + } +} \ No newline at end of file diff --git a/Week_06/G20200343030415/LeetCode-22-415.java b/Week_06/G20200343030415/LeetCode-22-415.java new file mode 100644 index 00000000..100e7065 --- /dev/null +++ b/Week_06/G20200343030415/LeetCode-22-415.java @@ -0,0 +1,29 @@ +import java.util.ArrayList; + +//leetcode submit region begin(Prohibit modification and deletion) +class Solution { + + List res = new ArrayList<>(); + + public List generateParenthesis(int n) { + generate(0,0,n,""); + return res; + } + + public void generate(int left,int right,int n, String s){ + if(left == n && right == n){ + res.add(s); + return; + } + //当前逻辑 + String s1 = s + "("; + String s2 = s + ")"; + //下探下一层 + if(left < n){ + generate(left + 1,right,n,s1); + } + if(right < left){ + generate(left,right+1,n,s2); + } + } +} \ No newline at end of file diff --git a/Week_06/G20200343030415/LeetCode-547-415.java b/Week_06/G20200343030415/LeetCode-547-415.java new file mode 100644 index 00000000..a14f543b --- /dev/null +++ b/Week_06/G20200343030415/LeetCode-547-415.java @@ -0,0 +1,39 @@ +import java.util.Arrays; + +//leetcode submit region begin(Prohibit modification and deletion) +class Solution { + + int find(int parent[], int i){ + if(parent[i] == -1){ + return i; + } + return find(parent,parent[i]); + } + void union(int parent[],int x, int y){ + int xset = find(parent,x); + int yset = find(parent,y); + if(xset != yset){ + parent[xset] = yset; + } + } + + + public int findCircleNum(int[][] M) { + int[] parent = new int[M.length]; + Arrays.fill(parent,-1); + for (int i = 0; i < M.length; i++) { + for (int j = 0; j < M.length; j++) { + if(M[i][j] == 1 && i != j){ + union(parent,i,j); + } + } + } + int count = 0; + for (int i = 0; i < parent.length; i++) { + if(parent[i] == -1){ + count++; + } + } + return count; + } +} \ No newline at end of file diff --git a/Week_06/G20200343030417/NQueens.py b/Week_06/G20200343030417/NQueens.py new file mode 100644 index 00000000..83173206 --- /dev/null +++ b/Week_06/G20200343030417/NQueens.py @@ -0,0 +1,18 @@ +# N皇后问题, +class Solution(object): + def solveNQueens(self,n): + res = [] + if n == 0: return res + + def dfs(row,col,na,pie,cur_res): + if row == n: + res.append(["."*cur + "Q"+"."*(n-cur-1) for cur in cur_res]) + return + + for i in range(n): + if i not in col and i+row not in pie and i-row not in na: + dfs(row+1,col|{i}, na|{i-row},pie|{i+row},cur_res+[i]) + + dfs(0,set(),set(),set(),[]) + + return res \ No newline at end of file diff --git a/Week_06/G20200343030417/nums_of_islands.py b/Week_06/G20200343030417/nums_of_islands.py new file mode 100644 index 00000000..ed95290c --- /dev/null +++ b/Week_06/G20200343030417/nums_of_islands.py @@ -0,0 +1,89 @@ + +# DFS算法 +class Solution(object): + def numIslands(self, grid:List[List[str]]) -> int: + if not grid or not grid[0]: return 0 + + self.row,self.col = len(grid),len(grid[0]) + num = 0 + + for i in range(self.row): + for j in range(self.col): + if grid[i][j] == '1': + self.dfs(grid,i,j) + num += 1 + return num + + def dfs(self,grid,i,j): + grid[i][j] = '0' + for x,y in [(-1,0),(1,0),(0,-1),(0,1)]: + _i = i + x + _j = j + y + if 0 <= _i < self.row and 0 <= _j < self.col and grid[_i][_j] == '1': + self.dfs(grid,_i,_j) + + +# BFS算法 +class Solution(object): + def numIslands(self, grid:List[List[str]]) -> int: + from collections import deque + if not grid or not grid[0]: return 0 + self.row,self.col = len(grid),len(grid[0]) + num = 0 + + for i in range(self.row): + for j in range(self.col): + if grid[i][j] == '1': + self.bfs(deque,grid,i,j) + num += 1 + return num + + def bfs(self,deque,grid,i,j): + queue = deque() + queue.appendleft((i,j)) + grid[i][j] = '0' + + while queue: + i,j = queue.pop() + for x,y in [(1,0),(-1,0),(0,1),(0,-1)]: + _i = i + x + _j = j + y + if 0 <= _i < self.row and 0 <= _j < self.col and grid[_i][_j] == '1': + grid[_i][_j] = '0' + queue.appendleft((_i,_j)) + + +# 并查集 +class Solution(object): + def numIslands(self, grid:List[List[str]]) -> int: + f = {} + + def find(x): + f.setdefault(x,x) + if f[x] != x: + f[x] = find(f[x]) + return f[x] + + def union(x,y): + f[find(x)] = find(y) + + if not grid or not grid[0]: return 0 + row = len(grid) + col = len(grid[0]) + + for i in range(row): + for j in range(col): + if grid[i][j] == '1': + for x,y in [(-1,0),(0,-1)]: + _i = i + x + _j = j + y + if 0 <= _i < row and 0 <= _j < col and grid[_i][_j] == '1': + union(_i*col+_j,i*col+j) + + res = set() + for i in range(row): + for j in range(col): + if grid[i][j] == '1': + res.add(find((i*col+j))) + + return len(res) \ No newline at end of file diff --git a/Week_06/G20200343030423/LeetCode_200_423.java b/Week_06/G20200343030423/LeetCode_200_423.java new file mode 100644 index 00000000..76481527 --- /dev/null +++ b/Week_06/G20200343030423/LeetCode_200_423.java @@ -0,0 +1,24 @@ +public class LeetCode_200_423 { +} +class Solution423 { + public int numIslands(char[][] grid) { + int count = 0; + for(int i = 0; i < grid.length; i++) { + for(int j = 0; j < grid[0].length; j++) { + if(grid[i][j] == '1'){ + dfs(grid, i, j); + count++; + } + } + } + return count; + } + private void dfs(char[][] grid, int i, int j){ + if(i < 0 || j < 0 || i >= grid.length || j >= grid[0].length || grid[i][j] == '0') return; + grid[i][j] = '0'; + dfs(grid, i + 1, j); + dfs(grid, i, j + 1); + dfs(grid, i - 1, j); + dfs(grid, i, j - 1); + } +} diff --git a/Week_06/G20200343030423/LeetCode_547_423.java b/Week_06/G20200343030423/LeetCode_547_423.java new file mode 100644 index 00000000..99ad8dd2 --- /dev/null +++ b/Week_06/G20200343030423/LeetCode_547_423.java @@ -0,0 +1,25 @@ +public class LeetCode_547_423 { +} + +class Solution547 { + public int findCircleNum(int[][] M) { + boolean[] visited = new boolean[M.length]; + int ans = 0; + for(int i = 0; i < M.length; i++) { + if(!visited[i]) { + ans++; + dfs(M, i, visited); + } + } + return ans; + } + + private void dfs(int[][] M, int i, boolean[] visited) { + visited[i] = true; + for(int j = 0; j < M.length; j++) { + if(!visited[j] && M[i][j] == 1) { + dfs(M, j, visited); + } + } + } +} diff --git a/Week_06/G20200343030425/LeetCode_36_425/LeetCode_36_425.js b/Week_06/G20200343030425/LeetCode_36_425/LeetCode_36_425.js new file mode 100644 index 00000000..c5f47452 --- /dev/null +++ b/Week_06/G20200343030425/LeetCode_36_425/LeetCode_36_425.js @@ -0,0 +1,24 @@ +/* +* address:https://leetcode-cn.com/problems/valid-sudoku/submissions/ +* */ + +const isValidSudoku = function(board) { + let res = [] + for (let i = 0; i < 9; i++) { + for (let j = 0; j < 9; j++) { + let val = board[i][j]-1; + if (val>=0 && val<=8) { + let cur = 1 << j | 1 << i+9 | 1 << Math.floor(i/3)*3+Math.floor(j/3) + 18; + let old = res[val]; + if ((old & cur) === 0) { + res[val] = old | cur + } else { + return false + + } + } + + } + } + return true +}; diff --git a/Week_06/G20200343030425/LeetCode_70_425/LeetCode_70_425.js b/Week_06/G20200343030425/LeetCode_70_425/LeetCode_70_425.js new file mode 100644 index 00000000..b45bc8d9 --- /dev/null +++ b/Week_06/G20200343030425/LeetCode_70_425/LeetCode_70_425.js @@ -0,0 +1,14 @@ +/* +* address: https://leetcode-cn.com/problems/climbing-stairs/ +* */ + +const climbStairs = function(n) { + if(n<=2) return n; + [f1,f2,f3]=[1,2,3]; + for (let i = 3; i queue = new LinkedList<>(); + for (int i = 0; i < M.length; i++) { + if (visited[i] == 0) { + queue.add(i); + } + + while (!queue.isEmpty()) { + int s = queue.remove(); + visited[s] = 1; + + for (int j = 0; j < M.length; j++) { + if (M[i][j] == 1 && visited[j] == 0) { + queue.add(j); + } + } + } + + count++; + } + + return count; + } + +} diff --git a/Week_06/G20200343030429/NOTE.md b/Week_06/G20200343030429/NOTE.md index 50de3041..7ff06efb 100644 --- a/Week_06/G20200343030429/NOTE.md +++ b/Week_06/G20200343030429/NOTE.md @@ -1 +1,12 @@ -学习笔记 \ No newline at end of file +#学习笔记 +### Trie 相对于哈希的优点 + 尽管哈希表可以在 O(1)O(1) 时间内寻找键值,却无法高效的完成以下操作: + - 找到具有同一前缀的全部键值。 + - 按词典序枚举字符串的数据集。 + + Trie 树优于哈希表的另一个理由是,随着哈希表大小增加,会出现大量的冲突,时间复杂度可能增加到 O(n)O(n),其中 nn 是插入的键的数量。与哈希表相比,Trie 树在存储多个具有相同前缀的键时可以使用较少的空间。此时 Trie 树只需要 O(m)O(m) 的时间复杂度,其中 mm 为键长。而在平衡树中查找键值需要 O(m \log n)O(mlogn) 时间复杂度。 + +### Trie 树的结点结构 +Trie 树是一个有根的树 +- 最多 RR 个指向子结点的链接,其中每个链接对应字母表数据集中的一个字母。 +- 布尔字段,以指定节点是对应键的结尾还是只是键前缀。 diff --git a/Week_06/G20200343030431/LeetCode_22_ 431.java b/Week_06/G20200343030431/LeetCode_22_ 431.java new file mode 100644 index 00000000..12035bd3 --- /dev/null +++ b/Week_06/G20200343030431/LeetCode_22_ 431.java @@ -0,0 +1,33 @@ +package thread; + +import org.omg.PortableServer.LIFESPAN_POLICY_ID; + +import java.util.ArrayList; +import java.util.List; + +public class SolutionX { + public List generateParentthesis(int n) { + if (n == 0) { + return new ArrayList<>(); + } + List> dp = new ArrayList<>(n); + List dp0 = new ArrayList<>(); + dp0.add(""); + dp.add(dp0); + + for (int i = 1; i <= n; i++) { + List cur = new ArrayList<>(); + for (int j = 0; j < i; j++) { + List strl = dp.get(j); + List str2 = dp.get(i - 1 - j); + for (String sl : strl) { + for (String s2 : str2) { + cur.add("(" + sl + ")" + s2); + } + } + } + dp.add(cur); + } + return dp.get(n); + } +} diff --git a/Week_06/G20200343030431/LeetCode_547_431.java b/Week_06/G20200343030431/LeetCode_547_431.java new file mode 100644 index 00000000..8610fd58 --- /dev/null +++ b/Week_06/G20200343030431/LeetCode_547_431.java @@ -0,0 +1,25 @@ +package thread; +//547 +public class Solution { + public int findCircleNum(int[][] M) { + boolean[] visited = new boolean[M.length]; + int ans = 0; + for (int i = 0; i < M.length; i++) { + if (!visited[i]) { + ans++; + dfs(M, i, visited); + } + } + return ans; + } + + private void dfs(int[][] M, int i, boolean[] visited) { + visited[i] = true; + for (int j = 0; j < M.length; j++) { + if (!visited[j] && M[i][j] == 1) { + dfs(M, j, visited); + } + } + + } +} diff --git a/Week_06/G20200343030431/R-B Tree.md b/Week_06/G20200343030431/R-B Tree.md new file mode 100644 index 00000000..206bcd0e --- /dev/null +++ b/Week_06/G20200343030431/R-B Tree.md @@ -0,0 +1,27 @@ +一、红黑树的介绍 +先来看下算法导论对R-B Tree的介绍: +红黑树,一种二叉查找树,但在每个结点上增加一个存储位表示结点的颜色,可以是Red或Black。 +通过对任何一条从根到叶子的路径上各个结点着色方式的限制,红黑树确保没有一条路径会比其他路径长出俩倍,因而是接近平衡的。 + +  + +红黑树,作为一棵二叉查找树,满足二叉查找树的一般性质。下面,来了解下 二叉查找树的一般性质。 + +二叉查找树 +二叉查找树,也称有序二叉树(ordered binary tree),或已排序二叉树(sorted binary tree),是指一棵空树或者具有下列性质的二叉树: + +若任意节点的左子树不空,则左子树上所有结点的值均小于它的根结点的值; +若任意节点的右子树不空,则右子树上所有结点的值均大于它的根结点的值; +任意节点的左、右子树也分别为二叉查找树。 +没有键值相等的节点(no duplicate nodes)。 +因为一棵由n个结点随机构造的二叉查找树的高度为lgn,所以顺理成章,二叉查找树的一般操作的执行时间为O(lgn)。但二叉查找树若退化成了一棵具有n个结点的线性链后,则这些操作最坏情况运行时间为O(n)。 + +红黑树虽然本质上是一棵二叉查找树,但它在二叉查找树的基础上增加了着色和相关的性质使得红黑树相对平衡,从而保证了红黑树的查找、插入、删除的时间复杂度最坏为O(log n)。 + +但它是如何保证一棵n个结点的红黑树的高度始终保持在logn的呢?这就引出了红黑树的5个性质: + +每个结点要么是红的要么是黑的。   +根结点是黑的。   +每个叶结点(叶结点即指树尾端NIL指针或NULL结点)都是黑的。   +如果一个结点是红的,那么它的两个儿子都是黑的。   + 对于任意结点而言,其到叶结点树尾端NIL指针的每条路径都包含相同数目的黑结点。  diff --git a/Week_06/G20200343030433/Week6_36_433 b/Week_06/G20200343030433/Week6_36_433 new file mode 100644 index 00000000..c8e5d74d --- /dev/null +++ b/Week_06/G20200343030433/Week6_36_433 @@ -0,0 +1,28 @@ +class Solution { +public: + bool isValidSudoku(vector>& board) { + int xsp[9][9] = {0}; + int ysp[9][9] = {0}; + int lsp[9][9] = {0}; + for(int i = 0; i < 9; i++) + { + for(int j = 0; j < 9; j++) + { + if(board[i][j] != '.') + { + if(( ++xsp[board[i][j]-'1'][i] > 1) || + (++ysp[board[i][j]-'1'][j] >1) || + (++lsp[board[i][j]-'1'][(i/3)*3 + j/3] >1)) + { + return false; + } + + } + } + } + + + return true; + } + +}; diff --git a/Week_06/G20200343030433/Week_127_433 b/Week_06/G20200343030433/Week_127_433 new file mode 100644 index 00000000..db97d8a5 --- /dev/null +++ b/Week_06/G20200343030433/Week_127_433 @@ -0,0 +1,43 @@ +class Solution{ +public: + int ladderLength(string beginWord, string endWord, vector& wordList){ + //加入所有节点,访问过一次,删除一个。 + unordered_set s; + for (auto &i : wordList) s.insert(i); + + queue> q; + //加入beginword + q.push({beginWord, 1}); + + string tmp; //每个节点的字符 + int step; //抵达该节点的step + + while ( !q.empty() ){ + if ( q.front().first == endWord){ + return (q.front().second); + } + tmp = q.front().first; + step = q.front().second; + q.pop(); + + //寻找下一个单词了 + char ch; + for (int i = 0; i < tmp.length(); i++){ + ch = tmp[i]; + for (char c = 'a'; c <= 'z'; c++){ + //从'a'-'z'尝试一次 + if ( ch == c) continue; + tmp[i] = c ; + //如果找到的到 + if ( s.find(tmp) != s.end() ){ + q.push({tmp, step+1}); + s.erase(tmp) ; //删除该节点 + } + tmp[i] = ch; //复原 + } + + } + } + return 0; + } +}; diff --git a/Week_06/G20200343030435/LeetCode_22_435.js b/Week_06/G20200343030435/LeetCode_22_435.js new file mode 100644 index 00000000..2d7fbe34 --- /dev/null +++ b/Week_06/G20200343030435/LeetCode_22_435.js @@ -0,0 +1,31 @@ +let generateParenthesis = function(n) { + const result = []; + const _generate = (left, right, n, str) => { + // terminator + if (left === n && right === n) { + // filter the invalid str + //1、left 随时加,不能超n + //2、right 必须之前有左括号 && 左括号个数 > 右括号个数 + console.log(str); + result.push(str); + return; + } + // process + // var s1 = s +'('; + // var s2 = s + ')'; + // drill down + if (left < n) { + // 加一个左括号 + _generate(left + 1, right, n, str + "("); + } + if (left > right) { + // 加一个右括号 + // 此处 right 一定小于 n 因为 left 小于 n + _generate(left, right + 1, n, str + ")"); + } + // reverse states + // 没有全局变量所以忽略局部变量它自动会最后清除 + }; + _generate(0, 0, n, ""); + return result; +}; diff --git a/Week_06/G20200343030435/LeetCode_70_435.js b/Week_06/G20200343030435/LeetCode_70_435.js new file mode 100644 index 00000000..be489179 --- /dev/null +++ b/Week_06/G20200343030435/LeetCode_70_435.js @@ -0,0 +1,9 @@ +let climbStairs = function(n) { + const dp = []; + dp[0] = 1; + dp[1] = 1; + for (let i = 2; i <= n; i++) { + dp[i] = dp[i - 1] + dp[i - 2]; + } + return dp[n]; +}; diff --git a/Week_06/G20200343030437/implement-trie-prefix-tree.java b/Week_06/G20200343030437/implement-trie-prefix-tree.java new file mode 100644 index 00000000..59d3901b --- /dev/null +++ b/Week_06/G20200343030437/implement-trie-prefix-tree.java @@ -0,0 +1,89 @@ +class Trie { + + private TrieNode root; + + /** + * Initialize your data structure here. + */ + public Trie() { + root = new TrieNode(); + } + + /** + * Inserts a word into the trie. + */ + public void insert(String word) { + TrieNode trieNode = root; + for (int i = 0; i < word.length(); i++) { + char ch = word.charAt(i); + if (!trieNode.containsKey(ch)) { + trieNode.childs.add(new TrieNode(ch)); + } + trieNode = trieNode.get(ch); + } + trieNode.isEnd = true; + } + + /** + * Returns if the word is in the trie. + */ + public boolean search(String word) { + TrieNode trieNode = root; + for (int i = 0; i < word.length(); i++) { + char ch = word.charAt(i); + if (!trieNode.containsKey(ch)) { + return false; + } + trieNode = trieNode.get(ch); + } + return trieNode.isEnd; + } + + /** + * Returns if there is any word in the trie that starts with the given prefix. + */ + public boolean startsWith(String prefix) { + TrieNode trieNode = root; + for (int i = 0; i < prefix.length(); i++) { + char ch = prefix.charAt(i); + if (!trieNode.containsKey(ch)) { + return false; + } + trieNode = trieNode.get(ch); + } + return true; + } + + class TrieNode { + Boolean isEnd = false; + List childs = new ArrayList<>(); + char value; + + public TrieNode(){} + public TrieNode(char ch) { + value = ch; + } + + public Boolean containsKey(char ch) { + for (TrieNode node : childs) { + if (node.value == ch) return true; + } + return false; + } + + public TrieNode get(char ch) { + for (TrieNode node : childs) { + if (node.value == ch) return node; + } + return null; + } + } +} + +/** + * Your Trie object will be instantiated and called as such: + * Trie obj = new Trie(); + * obj.insert(word); + * boolean param_2 = obj.search(word); + * boolean param_3 = obj.startsWith(prefix); + */ diff --git a/Week_06/G20200343030437/word-search-ii.java b/Week_06/G20200343030437/word-search-ii.java new file mode 100644 index 00000000..15997ec4 --- /dev/null +++ b/Week_06/G20200343030437/word-search-ii.java @@ -0,0 +1,97 @@ +class Solution { + Trie trie; + int len; + int col; + List resultList = new LinkedList<>(); + public List findWords(char[][] board, String[] words) { + trie = new Trie(); + for (String word: words) { + trie.insert(word); + } + len = board.length; + col = board[0].length; + boolean[][] visited = new boolean[len][col]; + TrieNode root = trie.root; + for (int i = 0; i < len; i++) { + for (int j = 0; j < col; j++) { + // 判断周边是否满足条件 -- dfs + _DFS(board, i, j, root, visited); + } + } + return resultList; + } + + public void _DFS(char[][] board, int i, int j, TrieNode root, boolean[][] visited) { + if (i < 0 || i >= len || j < 0 || j >= col || visited[i][j]) return; + visited[i][j] = true; + char ch = board[i][j]; + if (root.containsKey(ch)){ + TrieNode node = root.get(ch); + if (node.isEnd) { + resultList.add(node.word); + node.isEnd = false; + } + + _DFS(board, i-1, j, node,visited); + _DFS(board, i+1, j, node,visited); + _DFS(board, i, j-1, node,visited); + _DFS(board, i, j+1, node,visited); + } + visited[i][j] = false; + } + + + class Trie { + + private TrieNode root; + + /** + * Initialize your data structure here. + */ + public Trie() { + root = new TrieNode(); + } + + /** + * Inserts a word into the trie. + */ + public void insert(String word) { + TrieNode trieNode = root; + for (int i = 0; i < word.length(); i++) { + char ch = word.charAt(i); + if (!trieNode.containsKey(ch)) { + trieNode.childs.add(new TrieNode(ch)); + } + trieNode = trieNode.get(ch); + } + trieNode.isEnd = true; + trieNode.word = word; + } + } + + class TrieNode { + Boolean isEnd = false; + List childs = new ArrayList<>(); + char value; + String word; + + public TrieNode(){} + public TrieNode(char ch) { + value = ch; + } + + public Boolean containsKey(char ch) { + for (TrieNode node : childs) { + if (node.value == ch) return true; + } + return false; + } + + public TrieNode get(char ch) { + for (TrieNode node : childs) { + if (node.value == ch) return node; + } + return null; + } + } + } diff --git a/Week_06/G20200343030439/LeetCode_547_439.java b/Week_06/G20200343030439/LeetCode_547_439.java new file mode 100644 index 00000000..c6937cfb --- /dev/null +++ b/Week_06/G20200343030439/LeetCode_547_439.java @@ -0,0 +1,97 @@ +/* + * @lc app=leetcode.cn id=547 lang=java + * + * [547] 朋友圈 + * + * https://leetcode-cn.com/problems/friend-circles/description/ + * + * algorithms + * Medium (53.95%) + * Likes: 198 + * Dislikes: 0 + * Total Accepted: 29.6K + * Total Submissions: 53.4K + * Testcase Example: '[[1,1,0],[1,1,0],[0,0,1]]' + * + * 班上有 N 名学生。其中有些人是朋友,有些则不是。他们的友谊具有是传递性。如果已知 A 是 B 的朋友,B 是 C 的朋友,那么我们可以认为 A 也是 + * C 的朋友。所谓的朋友圈,是指所有朋友的集合。 + * + * 给定一个 N * N 的矩阵 M,表示班级中学生之间的朋友关系。如果M[i][j] = 1,表示已知第 i 个和 j + * 个学生互为朋友关系,否则为不知道。你必须输出所有学生中的已知的朋友圈总数。 + * + * 示例 1: + * + * + * 输入: + * [[1,1,0], + * ⁠[1,1,0], + * ⁠[0,0,1]] + * 输出: 2 + * 说明:已知学生0和学生1互为朋友,他们在一个朋友圈。 + * 第2个学生自己在一个朋友圈。所以返回2。 + * + * + * 示例 2: + * + * + * 输入: + * [[1,1,0], + * ⁠[1,1,1], + * ⁠[0,1,1]] + * 输出: 1 + * 说明:已知学生0和学生1互为朋友,学生1和学生2互为朋友,所以学生0和学生2也是朋友,所以他们三个在一个朋友圈,返回1。 + * + * + * 注意: + * + * + * N 在[1,200]的范围内。 + * 对于所有学生,有M[i][i] = 1。 + * 如果有M[i][j] = 1,则有M[j][i] = 1。 + * + * + */ + +// @lc code=start +class Solution { + public static void main(String[] args) { + int[][] bills = { { 1, 1, 0 }, { 1, 1, 0 }, { 0, 0, 1 } }; + int result = findCircleNum(bills); + System.out.println(result); + } + + private static int n; + private static int m; + + // DFS + public static int findCircleNum(int[][] M) { + int count = 0; + n = M.length; + if (n == 0) { + return count; + } + m = M[0].length; + for (int i = 0; i < n; i++) { + for (int j = 0; j < m; j++) { + if (M[i][j] == 1) { + DFSMarking(M, i, j); + count++; + } + + } + } + return count; + } + + private static void DFSMarking(int[][] M, int i, int j) { + if (i < 0 || j < 0 || i >= n || j >= m || M[i][j] != 1) { + return; + } + M[i][j] = 0; + DFSMarking(M, i + 1, j); + DFSMarking(M, i - 1, j); + DFSMarking(M, i, j + 1); + DFSMarking(M, i, j - 1); + } +} +// @lc code=end diff --git a/Week_06/G20200343030439/LeetCode_70_439.java b/Week_06/G20200343030439/LeetCode_70_439.java new file mode 100644 index 00000000..6d01bac2 --- /dev/null +++ b/Week_06/G20200343030439/LeetCode_70_439.java @@ -0,0 +1,94 @@ +/* + * @lc app=leetcode.cn id=70 lang=java + * + * [70] 爬楼梯 + * + * https://leetcode-cn.com/problems/climbing-stairs/description/ + * + * algorithms + * Easy (47.49%) + * Likes: 885 + * Dislikes: 0 + * Total Accepted: 155.5K + * Total Submissions: 323.3K + * Testcase Example: '2' + * + * 假设你正在爬楼梯。需要 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 阶 + * + * + */ + +// @lc code=start +class Solution { + // 暴力法-超时 + public static int climbStairs(int n) { + return getUp(0, n); + } + + public static int getUp(int i, int n) { + if (i > n) { + return 0; + } + if (i == n) { + return 1; + } + return getUp(i + 1, n) + getUp(i + 2, n); + } + + // 记忆化递归 + public static int climbStairs2(int n) { + int temp[] = new int[n + 1]; + return getUp2(0, n, temp); + } + + public static int getUp2(int i, int n, int temp[]) { + if (i > n) { + return 0; + } + if (i == n) { + return 1; + } + if (temp[i] > 0) { + return temp[i]; + } + temp[i] = getUp2(i + 1, n, temp) + getUp2(i + 2, n, temp); + return temp[i]; + } + + // 动态规划 + public static int climbStairs3(int n) { + if (n <= 1) { + return n; + } + 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]; + } + +} +// @lc code=end diff --git a/Week_06/G20200343030441/LeetCode_208_441.java b/Week_06/G20200343030441/LeetCode_208_441.java new file mode 100644 index 00000000..826117fd --- /dev/null +++ b/Week_06/G20200343030441/LeetCode_208_441.java @@ -0,0 +1,93 @@ +/* + * @lc app=leetcode.cn id=208 lang=java + * + * [208] 实现 Trie (前缀树) + */ + +// @lc code=start +class Trie { + class TrieNode { + + // R links to node children + private TrieNode[] links; + + private final int R = 26; + + private boolean isEnd; + + public TrieNode() { + links = new TrieNode[R]; + } + + public boolean containsKey(char ch) { + return links[ch -'a'] != null; + } + public TrieNode get(char ch) { + return links[ch -'a']; + } + public void put(char ch, TrieNode node) { + links[ch -'a'] = node; + } + public void setEnd() { + isEnd = true; + } + public boolean isEnd() { + return isEnd; + } + } + + private TrieNode root; + + /** Initialize your data structure here. */ + public Trie() { + root = new TrieNode(); + } + + /** Inserts a word into the trie. */ + public void insert(String word) { + TrieNode node = root; + for (int i = 0; i < word.length(); i++) { + char currentChar = word.charAt(i); + if (!node.containsKey(currentChar)) { + node.put(currentChar, new TrieNode()); + } + node = node.get(currentChar); + } + node.setEnd(); + } + + private TrieNode searchPrefix(String word) { + TrieNode node = root; + for (int i = 0; i < word.length(); i++) { + char curLetter = word.charAt(i); + if (node.containsKey(curLetter)) { + node = node.get(curLetter); + } else { + return null; + } + } + return node; + } + + /** Returns if the word is in the trie. */ + public boolean search(String word) { + TrieNode node = searchPrefix(word); + return node != null && node.isEnd(); + } + + /** Returns if there is any word in the trie that starts with the given prefix. */ + public boolean startsWith(String prefix) { + TrieNode node = searchPrefix(prefix); + return node != null; + } +} + +/** + * Your Trie object will be instantiated and called as such: + * Trie obj = new Trie(); + * obj.insert(word); + * boolean param_2 = obj.search(word); + * boolean param_3 = obj.startsWith(prefix); + */ +// @lc code=end + diff --git a/Week_06/G20200343030441/LeetCode_547_441.java b/Week_06/G20200343030441/LeetCode_547_441.java new file mode 100644 index 00000000..3c50aa87 --- /dev/null +++ b/Week_06/G20200343030441/LeetCode_547_441.java @@ -0,0 +1,63 @@ +/* + * @lc app=leetcode.cn id=547 lang=java + * + * [547] 朋友圈 + */ + +// @lc code=start +class Solution { + class UnionFind { + private int count = 0; + private int[] parent, rank; + + public UnionFind(int n) { + count = n; + parent = new int[n]; + rank = new int[n]; + for (int i = 0; i < n; i++) { + parent[i] = i; + } + } + + public int find(int p) { + while (p != parent[p]) { + parent[p] = parent[parent[p]]; // path compression by halving + p = parent[p]; + } + return p; + } + + public void union(int p, int q) { + int rootP = find(p); + int rootQ = find(q); + if (rootP == rootQ) return; + if (rank[rootQ] > rank[rootP]) { + parent[rootP] = rootQ; + } + else { + parent[rootQ] = rootP; + if (rank[rootP] == rank[rootQ]) { + rank[rootP]++; + } + } + count--; + } + + public int count() { + return count; + } + } + + public int findCircleNum(int[][] M) { + int n = M.length; + UnionFind uf = new UnionFind(n); + for (int i = 0; i < n - 1; i++) { + for (int j = i + 1; j < n; j++) { + if (M[i][j] == 1) uf.union(i, j); + } + } + return uf.count(); + } +} +// @lc code=end + diff --git a/Week_06/G20200343030445/LeetCode_130_445.py b/Week_06/G20200343030445/LeetCode_130_445.py new file mode 100644 index 00000000..7ee6f685 --- /dev/null +++ b/Week_06/G20200343030445/LeetCode_130_445.py @@ -0,0 +1,40 @@ +# +# @lc app=leetcode.cn id=130 lang=python3 +# +# [130] 被围绕的区域 +# + +# @lc code=start +class Solution: + def solve(self, board: List[List[str]]) -> None: + """ + Do not return anything, modify board in-place instead. + """ + if not board: + return + + m = len(board) + n = len(board[0]) + + def dfs(i, j): + # termination + if i < 0 or j < 0 or i >= m or j >= n or board[i][j] == "X" or board[i][j] == "#": + return + board[i][j] = '#' + # for 4 directions: search + for d in ((-1,0), (1,0), (0,-1), (0,1)): + dfs(i+d[0], j+d[1]) + + for i in range(m): + for j in range(n): + if (i == 0 or j == 0 or i == m-1 or j == n-1) and board[i][j] == "O": + dfs(i, j) + for i in range(m): + for j in range(n): + if board[i][j] == "O": + board[i][j] = "X" + if board[i][j] == "#": + board[i][j] = "O" + +# @lc code=end + diff --git a/Week_06/G20200343030445/LeetCode_37_445.py b/Week_06/G20200343030445/LeetCode_37_445.py new file mode 100644 index 00000000..113a889d --- /dev/null +++ b/Week_06/G20200343030445/LeetCode_37_445.py @@ -0,0 +1,53 @@ +# +# @lc app=leetcode.cn id=37 lang=python3 +# +# [37] 解数独 +# + +# @lc code=start +class Solution: + def solveSudoku(self, board: List[List[str]]) -> None: + """ + Do not return anything, modify board in-place instead. + """ + row = [set(range(1,10)) for _ in range(9)] + col = [set(range(1,10)) for _ in range(9)] + block = [set(range(1,10)) for _ in range(9)] + + empty = [] + for i in range(9): + for j in range(9): + if board[i][j] == ".": + empty.append((i, j)) + else: + row[i].remove(int(board[i][j])) + col[j].remove(int(board[i][j])) + block[(i // 3) * 3 + j // 3].remove(int(board[i][j])) + + def recur(level): + if len(empty) == level: + return True + e = empty[level] + i, j = e[0], e[1] + + for c in row[i] & col[j] & block[(i // 3) * 3 + j // 3]: + row[i].remove(c) + col[j].remove(c) + block[(i // 3) * 3 + j // 3].remove(c) + board[i][j] = str(c) + + if recur(level + 1): + return True + + row[i].add(c) + col[j].add(c) + block[(i // 3) * 3 + j // 3].add(c) + board[i][j] = "." + + return False + + recur(0) + + +# @lc code=end + diff --git a/Week_06/G20200343030445/LeetCode_547_445.py b/Week_06/G20200343030445/LeetCode_547_445.py new file mode 100644 index 00000000..7cb84167 --- /dev/null +++ b/Week_06/G20200343030445/LeetCode_547_445.py @@ -0,0 +1,38 @@ +# +# @lc app=leetcode.cn id=547 lang=python3 +# +# [547] 朋友圈 +# + +# @lc code=start +class Solution: + def findCircleNum(self, M: List[List[int]]) -> int: + if not M or len(M) == 0: + return 0 + + n = len(M) + p = [i for i in range(n)] + + def union(i, j): + p1 = parent(i) + p2 = parent(j) + p[p1] = p2 + + def parent(i): + root = i + while p[root] != root: + root = p[root] + while p[i] != i: + x = i; i = p[i]; p[x] = root + return root + + for i in range(n): + for j in range(n): + if M[i][j] == 1: + union(i, j) + + return len([i for i in range(n) if p[i] == i]) + + +# @lc code=end + diff --git a/Week_06/G20200343030449/LeetCode_208_449.cpp b/Week_06/G20200343030449/LeetCode_208_449.cpp new file mode 100644 index 00000000..bfea9a61 --- /dev/null +++ b/Week_06/G20200343030449/LeetCode_208_449.cpp @@ -0,0 +1,96 @@ +class TrieNode; +typedef unordered_map TrieNodeArray; + +class TrieNode { +public: + TrieNode() { + child=nullptr; + mIsEnd=false; + } + bool mIsEnd; + TrieNodeArray* child; +}; + +class Trie { +public: + /** Initialize your data structure here. */ + Trie() { + mRoot = new TrieNodeArray(); + } + + /** Inserts a word into the trie. */ + void insert(string word) { + TrieNodeArray* node = mRoot; + for (int i=0; ifind(word[i]); + if (iter==node->end()) { + node->insert(make_pair(word[i],TrieNode())); + } + auto iter2 = node->find(word[i]); + if (i==word.size()-1) { + (iter2->second).mIsEnd=true; + } + else { + if ((iter2->second).child==nullptr) { + (iter2->second).child = new TrieNodeArray(); + } + + node = (iter2->second).child; + } + } + + return; + } + + /** Returns if the word is in the trie. */ + bool search(string word) { + TrieNodeArray* node = mRoot; + TrieNodeArray* pre = nullptr; + for (auto &i:word) { + if (node==nullptr) return false; + + auto iter = node->find(i); + + if (iter!=node->end()) { + pre = node; + node = (iter->second).child; + } + else { + return false; + } + } + + auto iter2 = pre->find(word.back()); + + return (iter2->second).mIsEnd; + } + + /** Returns if there is any word in the trie that starts with the given prefix. */ + bool startsWith(string prefix) { + TrieNodeArray* node = mRoot; + for (auto &i:prefix) { + if (node==nullptr) return false; + + auto iter = node->find(i); + + if (iter!=node->end()) { + node = (iter->second).child; + } + else { + return false; + } + } + + return true; + } +private: + TrieNodeArray* mRoot; +}; + +/** + * Your Trie object will be instantiated and called as such: + * Trie* obj = new Trie(); + * obj->insert(word); + * bool param_2 = obj->search(word); + * bool param_3 = obj->startsWith(prefix); + */ diff --git a/Week_06/G20200343030449/LeetCode_70_449.cpp b/Week_06/G20200343030449/LeetCode_70_449.cpp new file mode 100644 index 00000000..bf1aad60 --- /dev/null +++ b/Week_06/G20200343030449/LeetCode_70_449.cpp @@ -0,0 +1,17 @@ +class Solution { +public: + int climbStairs(int n) { + + if (n==0) return 1; + + vector dp(n+1); + dp[0] = 1; + dp[1] = 1; + + for (int i = 2; i<=n;i++) { + dp[i] = dp[i-1]+dp[i-2]; + } + + return dp[n]; + } +}; diff --git a/Week_06/G20200343030451/208.cpp b/Week_06/G20200343030451/208.cpp new file mode 100644 index 00000000..455ca0a3 --- /dev/null +++ b/Week_06/G20200343030451/208.cpp @@ -0,0 +1,55 @@ +class Trie { +public: + /** Initialize your data structure here. */ + bool isEnd; + Trie* next[26]; + + Trie() { + isEnd = false; + memset(next, 0, sizeof(next)); + } + + /** Inserts a word into the trie. */ + void insert(string word) { + Trie* node = this; + for (char c : word) { + if (node->next[c-'a'] == NULL) { + node->next[c-'a'] = new Trie(); + } + node = node->next[c-'a']; + } + node->isEnd = true; + } + + /** Returns if the word is in the trie. */ + bool search(string word) { + Trie* node = this; + for (char c : word) { + node = node->next[c - 'a']; + if (node == NULL) { + return false; + } + } + return node->isEnd; + } + + /** Returns if there is any word in the trie that starts with the given prefix. */ + bool startsWith(string prefix) { + Trie* node = this; + for (char c : prefix) { + node = node->next[c-'a']; + if (node == NULL) { + return false; + } + } + return true; + } +}; + +/** + * Your Trie object will be instantiated and called as such: + * Trie* obj = new Trie(); + * obj->insert(word); + * bool param_2 = obj->search(word); + * bool param_3 = obj->startsWith(prefix); + */ diff --git a/Week_06/G20200343030451/547.cpp b/Week_06/G20200343030451/547.cpp new file mode 100644 index 00000000..76516632 --- /dev/null +++ b/Week_06/G20200343030451/547.cpp @@ -0,0 +1,86 @@ + +class UF +{ +public: + + UF(int n) + { + count = n; + parent.resize(n); + size.resize(n); + for(int i = 0; i < n; i++) + { + parent[i] =i; + size[i] = 1; + } + } + + void Union(int p, int q) + { + int rootP = find(p); + int rootQ = find(q); + if(rootP == rootQ) + return; + + if(size[rootP] > size[rootQ]) + { + parent[rootQ] = rootP; + size[rootP] += size[rootQ]; + } + else + { + parent[rootP] = rootQ; + size[rootQ] += rootP; + } + count--; + } + + bool connected(int p, int q) + { + int rootP = find(p); + int rootQ = find(q); + return rootP==rootQ; + } + + int count_num() + { + return count; + } +private: + int count; + vector parent; + vector size; + int find(int x) + { + while(parent[x] != x) + { + parent[x] = parent[parent[x]]; + x = parent[x]; + } + return x; + } +}; + +class Solution { +public: + int findCircleNum(vector>& M) { + + if(M.size()==0) + return 0; + + int m = M.size(); + int n = M[0].size(); + UF* uf = new UF(m); + for(int i = 0; i < m; i++) + { + for(int j = i+1; j < n; j++) + { + if(M[i][j] == 1) + { + uf->Union(i,j); + } + } + } + return uf->count_num(); + } +}; \ No newline at end of file diff --git a/Week_06/G20200343030451/NOTE.md b/Week_06/G20200343030451/NOTE.md index 50de3041..0711ad20 100644 --- a/Week_06/G20200343030451/NOTE.md +++ b/Week_06/G20200343030451/NOTE.md @@ -1 +1,12 @@ -学习笔记 \ No newline at end of file +学习笔记 +【451-Week 06】学习总结 + +这周作业确实很难,需要认真学习与总结。 +查看别人的解法,并且专注相关的题目。 +这个平台是一个很好的交流沉淀的地方。 +本周学习了字典树trie树、并查集、几类高级搜索(不重复、剪枝、双向搜索、启发式搜索),以及红黑树、AVL树。 +1 trie树的思想是用空间换时间; +2 trie树的实现题目要做。学会分析使用trie进行单词查找的复杂度。 +3 并查集的题目模式比较固定。 一般就是组团配对问题、确认两个个体是不是在一个集合当中的问题。 +那些AVL树面试概念必考的,之前看书旋转一片模糊,这次听课总算懂了,这部分内容概率比较多。 +总结:学本次学习,30%看视频,留下更多的时间60%来解题,10%来进行总结。 \ No newline at end of file diff --git a/Week_06/G20200343030459/208.implement-trie-prefix-tree.py b/Week_06/G20200343030459/208.implement-trie-prefix-tree.py new file mode 100644 index 00000000..00cf1be9 --- /dev/null +++ b/Week_06/G20200343030459/208.implement-trie-prefix-tree.py @@ -0,0 +1,95 @@ +# +# @lc app=leetcode id=208 lang=python3 +# +# [208] Implement Trie (Prefix Tree) +# +# https://leetcode.com/problems/implement-trie-prefix-tree/description/ +# +# algorithms +# Medium (43.70%) +# Likes: 2430 +# Dislikes: 44 +# Total Accepted: 247.1K +# Total Submissions: 559K +# Testcase Example: '["Trie","insert","search","search","startsWith","insert","search"]\n[[],["apple"],["apple"],["app"],["app"],["app"],["app"]]' +# +# Implement a trie with insert, search, and startsWith methods. +# +# Example: +# +# +# Trie trie = new Trie(); +# +# trie.insert("apple"); +# trie.search("apple"); // returns true +# trie.search("app"); // returns false +# trie.startsWith("app"); // returns true +# trie.insert("app"); +# trie.search("app"); // returns true +# +# +# Note: +# +# +# You may assume that all inputs are consist of lowercase letters a-z. +# All inputs are guaranteed to be non-empty strings. +# +# +# + +# @lc code=start +class Trie: + + def __init__(self): + """ + Initialize your data structure here. + """ + self.root = TrieNode() + + def insert(self, word: str) -> None: + """ + Inserts a word into the trie. + """ + node = self.root + for c in word: + if c not in node.children: + node.children[c] = TrieNode() + node = node.children[c] + node.is_word = True + + def find(self, word: str): + node = self.root + for c in word: + node = node.children.get(c) + if not node: + return None + return node + + def search(self, word: str) -> bool: + """ + Returns if the word is in the trie. + """ + node = self.find(word) + return node is not None and node.is_word + + def startsWith(self, prefix: str) -> bool: + """ + Returns if there is any word in the trie that starts with the given prefix. + """ + node = self.find(prefix) + return node is not None + +class TrieNode: + def __init__(self): + self.children = {} + self.is_word = False + + + +# Your Trie object will be instantiated and called as such: +# obj = Trie() +# obj.insert(word) +# param_2 = obj.search(word) +# param_3 = obj.startsWith(prefix) +# @lc code=end + diff --git a/Week_06/G20200343030459/211.add-and-search-word-data-structure-design.py b/Week_06/G20200343030459/211.add-and-search-word-data-structure-design.py new file mode 100644 index 00000000..8af8d710 --- /dev/null +++ b/Week_06/G20200343030459/211.add-and-search-word-data-structure-design.py @@ -0,0 +1,103 @@ +# +# @lc app=leetcode id=211 lang=python3 +# +# [211] Add and Search Word - Data structure design +# +# https://leetcode.com/problems/add-and-search-word-data-structure-design/description/ +# +# algorithms +# Medium (33.95%) +# Likes: 1378 +# Dislikes: 73 +# Total Accepted: 156.4K +# Total Submissions: 455.5K +# Testcase Example: '["WordDictionary","addWord","addWord","addWord","search","search","search","search"]\n[[],["bad"],["dad"],["mad"],["pad"],["bad"],[".ad"],["b.."]]' +# +# Design a data structure that supports the following two operations: +# +# +# void addWord(word) +# bool search(word) +# +# +# search(word) can search a literal word or a regular expression string +# containing only letters a-z or .. A . means it can represent any one letter. +# +# Example: +# +# +# addWord("bad") +# addWord("dad") +# addWord("mad") +# search("pad") -> false +# search("bad") -> true +# search(".ad") -> true +# search("b..") -> true +# +# +# Note: +# You may assume that all words are consist of lowercase letters a-z. +# +# + +# @lc code=start + + +class TrieNode: + def __init__(self): + self.children = {} + self.is_word = False + + +class WordDictionary: + + def __init__(self): + self.root = TrieNode() + + """ + @param: word: Adds a word into the data structure. + @return: nothing + """ + + def addWord(self, word): + node = self.root + for c in word: + if c not in node.children: + node.children[c] = TrieNode() + node = node.children[c] + node.is_word = True + + """ + @param: word: A word could contain the dot character '.' to represent any one letter. + @return: if the word is in the data structure. + """ + + def search(self, word): + if word is None: + return False + return self.search_helper(self.root, word, 0) + + def search_helper(self, node, word, index): + if node is None: + return False + + if index >= len(word): + return node.is_word + + char = word[index] + if char != '.': + return self.search_helper(node.children.get(char), word, index + 1) + + for child in node.children: + if self.search_helper(node.children[child], word, index + 1): + return True + + return False + + +# Your WordDictionary object will be instantiated and called as such: +# obj = WordDictionary() +# obj.addWord(word) +# param_2 = obj.search(word) +# @lc code=end + diff --git a/Week_06/G20200343030459/547.friend-circles.py b/Week_06/G20200343030459/547.friend-circles.py new file mode 100644 index 00000000..c3e426a8 --- /dev/null +++ b/Week_06/G20200343030459/547.friend-circles.py @@ -0,0 +1,101 @@ +# +# @lc app=leetcode id=547 lang=python3 +# +# [547] Friend Circles +# +# https://leetcode.com/problems/friend-circles/description/ +# +# algorithms +# Medium (56.70%) +# Likes: 1533 +# Dislikes: 120 +# Total Accepted: 137.3K +# Total Submissions: 241.2K +# Testcase Example: '[[1,1,0],[1,1,0],[0,0,1]]' +# +# +# There are N students in a class. Some of them are friends, while some are +# not. Their friendship is transitive in nature. For example, if A is a direct +# friend of B, and B is a direct friend of C, then A is an indirect friend of +# C. And we defined a friend circle is a group of students who are direct or +# indirect friends. +# +# +# +# Given a N*N matrix M representing the friend relationship between students in +# the class. If M[i][j] = 1, then the ith and jth students are direct friends +# with each other, otherwise not. And you have to output the total number of +# friend circles among all the students. +# +# +# Example 1: +# +# Input: +# [[1,1,0], +# ⁠[1,1,0], +# ⁠[0,0,1]] +# Output: 2 +# Explanation:The 0th and 1st students are direct friends, so they are in a +# friend circle. The 2nd student himself is in a friend circle. So return 2. +# +# +# +# Example 2: +# +# Input: +# [[1,1,0], +# ⁠[1,1,1], +# ⁠[0,1,1]] +# Output: 1 +# Explanation:The 0th and 1st students are direct friends, the 1st and 2nd +# students are direct friends, so the 0th and 2nd students are indirect +# friends. All of them are in the same friend circle, so return 1. +# +# +# +# +# Note: +# +# N is in range [1,200]. +# M[i][i] = 1 for all students. +# If M[i][j] = 1, then M[j][i] = 1. +# +# +# + +# @lc code=start +class Solution: + def findCircleNum(self, M: List[List[int]]) -> int: + n = len(M) + uf = UnionFind(n) + for i in range(n): + for j in range(i + 1, n): + if not M[i][j]: + continue + uf.union(i, j) + return uf.count + +class UnionFind: + def __init__(self, n): + self.father = [i for i in range(n)] + self.count = n + + def union(self, a, b): + root_a = self.find(a) + root_b = self.find(b) + if root_a != root_b: + self.father[root_b] = root_a + self.count -= 1 + + def find(self, node): + root = node + while self.father[root] != root: + root = self.father[root] + while self.father[node] != node: + temp = node + node = self.father[node] + self.father[temp] = root + return root + +# @lc code=end + diff --git a/Week_06/G20200343030459/721.accounts-merge.py b/Week_06/G20200343030459/721.accounts-merge.py new file mode 100644 index 00000000..db07eb0e --- /dev/null +++ b/Week_06/G20200343030459/721.accounts-merge.py @@ -0,0 +1,118 @@ +# +# @lc app=leetcode id=721 lang=python3 +# +# [721] Accounts Merge +# +# https://leetcode.com/problems/accounts-merge/description/ +# +# algorithms +# Medium (45.44%) +# Likes: 1062 +# Dislikes: 255 +# Total Accepted: 62.3K +# Total Submissions: 135.7K +# Testcase Example: '[["John","johnsmith@mail.com","john_newyork@mail.com"],["John","johnsmith@mail.com","john00@mail.com"],["Mary","mary@mail.com"],["John","johnnybravo@mail.com"]]' +# +# Given a list accounts, each element accounts[i] is a list of strings, where +# the first element accounts[i][0] is a name, and the rest of the elements are +# emails representing emails of the account. +# +# Now, we would like to merge these accounts. Two accounts definitely belong +# to the same person if there is some email that is common to both accounts. +# Note that even if two accounts have the same name, they may belong to +# different people as people could have the same name. A person can have any +# number of accounts initially, but all of their accounts definitely have the +# same name. +# +# After merging the accounts, return the accounts in the following format: the +# first element of each account is the name, and the rest of the elements are +# emails in sorted order. The accounts themselves can be returned in any +# order. +# +# Example 1: +# +# Input: +# accounts = [["John", "johnsmith@mail.com", "john00@mail.com"], ["John", +# "johnnybravo@mail.com"], ["John", "johnsmith@mail.com", +# "john_newyork@mail.com"], ["Mary", "mary@mail.com"]] +# Output: [["John", 'john00@mail.com', 'john_newyork@mail.com', +# 'johnsmith@mail.com'], ["John", "johnnybravo@mail.com"], ["Mary", +# "mary@mail.com"]] +# Explanation: +# The first and third John's are the same person as they have the common email +# "johnsmith@mail.com". +# The second John and Mary are different people as none of their email +# addresses are used by other accounts. +# We could return these lists in any order, for example the answer [['Mary', +# 'mary@mail.com'], ['John', 'johnnybravo@mail.com'], +# ['John', 'john00@mail.com', 'john_newyork@mail.com', 'johnsmith@mail.com']] +# would still be accepted. +# +# +# +# Note: +# The length of accounts will be in the range [1, 1000]. +# The length of accounts[i] will be in the range [1, 10]. +# The length of accounts[i][j] will be in the range [1, 30]. +# +# + +# @lc code=start +from collections import defaultdict +class Solution: + def accountsMerge(self, accounts: List[List[str]]) -> List[List[str]]: + self.father = [i for i in range(len(accounts))] + email_to_ids = self.get_email_to_id(accounts) + + for email, user_ids in email_to_ids.items(): + root_id = user_ids[0] + for user_id in user_ids[1:]: + self.union(root_id, user_id) + + id_to_email_set = self.get_id_to_email_set(accounts) + + result = [] + for user_id, emails in id_to_email_set.items(): + name = accounts[user_id][0] + result.append([ + name, + *sorted(emails) + ]) + + return result + + def get_id_to_email_set(self, accounts): + id_to_email_set = {} + for user_id, account in enumerate(accounts): + root_id = self.find(user_id) + email_set = id_to_email_set.get(root_id, set()) + for email in account[1:]: + email_set.add(email) + id_to_email_set[root_id] = email_set + + return id_to_email_set + + def get_email_to_id(self, accounts): + email_to_ids = defaultdict(list) + for user_id, account in enumerate(accounts): + for email in account[1:]: + email_to_ids[email].append(user_id) + return email_to_ids + + def union(self, a, b): + self.father[self.find(b)] = self.find(a) + + def find(self, node): + root = node + while self.father[root] != root: + root = self.father[root] + while self.father[node] != node: + temp = node + node = self.father[node] + self.father[temp] = root + return root + + + +# @lc code=end + diff --git a/Week_06/G20200343030463/463-Week 06/LeetCode_127_463.cpp b/Week_06/G20200343030463/463-Week 06/LeetCode_127_463.cpp new file mode 100644 index 00000000..a0a5fdcb --- /dev/null +++ b/Week_06/G20200343030463/463-Week 06/LeetCode_127_463.cpp @@ -0,0 +1,45 @@ +学习笔记 +https://leetcode.com/problems/word-ladder/discuss/40707/C%2B%2B-BFS + +class Solution { +public: + int ladderLength(string beginWord, string endWord, vector& wordList) { + unordered_set dict(wordList.begin(), wordList.end()), head, tail, *phead, *ptail; + if (dict.find(endWord) == dict.end()) { + return 0; + } + head.insert(beginWord); + tail.insert(endWord); + int ladder = 2; + while (!head.empty() && !tail.empty()) { + if (head.size() < tail.size()) { + phead = &head; + ptail = &tail; + } else { + phead = &tail; + ptail = &head; + } + unordered_set temp; + for (auto it = phead -> begin(); it != phead -> end(); it++) { + string word = *it; + for (int i = 0; i < word.size(); i++) { + char t = word[i]; + for (int j = 0; j < 26; j++) { + word[i] = 'a' + j; + if (ptail -> find(word) != ptail -> end()) { + return ladder; + } + if (dict.find(word) != dict.end()) { + temp.insert(word); + dict.erase(word); + } + } + word[i] = t; + } + } + ladder++; + phead -> swap(temp); + } + return 0; + } +}; diff --git a/Week_06/G20200343030463/463-Week 06/LeetCode_130_463.cpp b/Week_06/G20200343030463/463-Week 06/LeetCode_130_463.cpp new file mode 100644 index 00000000..2cc35b63 --- /dev/null +++ b/Week_06/G20200343030463/463-Week 06/LeetCode_130_463.cpp @@ -0,0 +1,73 @@ +学习笔记 +class Solution { + struct DSU { + vector data; + + void makeSet(int n){ + data.resize(n); + for(int i =0; i< n; i++) data[i] = i; + } + + bool unionSet(int i, int j){ + int p1 = parent(i); + int p2 = parent(j); + if(p1 != p2){ + data[p1] = p2; + } + return p1!=p2; + } + + int parent(int i){ + int root = i; + while(data[root] != root){ + root = data[root]; + } + return root; + } + + }; +public: + int dx[4] = {-1,1,0,0}; + int dy[4] = {0,0,-1,1}; + + void solve(vector>& board) { + if (board.size() == 0) return; + int rows = board.size(); + int cols = board[0].size(); + + DSU dsu; + + dsu.makeSet(rows*cols+1); + int dummy = rows * cols; + + for(int i =0; i < rows; i++){ + for(int j =0; j < cols; j++){ + if(board[i][j]=='O'){ + if(i ==0 || i ==rows-1 || j ==0 || j == cols -1){ + dsu.unionSet(node(i,j,cols),dummy); + }else{ + for(int k = 0; k < 4;k++){ + int nx = i + dx[k]; + int ny = j + dy[k]; + if(board[nx][ny] == 'O'){ + dsu.unionSet(node(nx,ny,cols),node(i,j,cols)); + } + } + } + } + } + } + + for(int i = 0;i < rows; i++){ + for(int j = 0; j < cols; j++){ + if(board[i][j]=='O' && dsu.parent(node(i,j,cols))!=dsu.parent(dummy)){ + board[i][j] = 'X'; + } + } + } + } + + int node(int i, int j, int cols){ + return i * cols +j; + } +}; diff --git a/Week_06/G20200343030463/463-Week 06/LeetCode_200_463.cpp b/Week_06/G20200343030463/463-Week 06/LeetCode_200_463.cpp new file mode 100644 index 00000000..d658e0d7 --- /dev/null +++ b/Week_06/G20200343030463/463-Week 06/LeetCode_200_463.cpp @@ -0,0 +1,60 @@ +岛屿数量 + +class Solution { + struct DSU{ + vector data; + + void makeSet(int n){ + data.resize(n); + for(int i =0; i< n;i++) data[i] =i; + + } + + bool unionSet(int i, int j){ + int p1 = parent(i); + int p2 = parent(j); + if(p1 != p2){ + data[p1] = p2; + } + return p1 != p2; + } + + int parent(int i){ + int root = i; + while(data[root] !=root){ + root = data[root]; + } + return root; + } + }; + +public: + + int numIslands(vector>& grid) { + if (grid.size() == 0) return 0; + + int m = grid.size(); + int n = grid[0].size(); + int ans = 0; + + for(int i = 0; i < m; i++){ + for (int j = 0; j < n; j++){ + if(grid[i][j] == '1') ans++; + } + } + + DSU dsu; + dsu.makeSet(m*n); + for(int i =0;i < m ;i++){ + for(int j =0;j < n ; j++){ + if(i>0 && grid[i][j]=='1' && grid[i-1][j] == '1'){ + ans -= dsu.unionSet(n*i+j,n*(i-1)+j); + } + if(j >0 && grid[i][j] == '1' && grid[i][j-1] == '1'){ + ans -= dsu.unionSet(i*n+j,i*n+j-1); + } + } + } + return ans; + } +}; diff --git a/Week_06/G20200343030463/463-Week 06/LeetCode_212_463.cpp b/Week_06/G20200343030463/463-Week 06/LeetCode_212_463.cpp new file mode 100644 index 00000000..b5e49e94 --- /dev/null +++ b/Week_06/G20200343030463/463-Week 06/LeetCode_212_463.cpp @@ -0,0 +1,87 @@ +学习笔记 +class Solution { +private: +struct TrieNode { + +unordered_map leaves; + +string word = ""; + +TrieNode() {} +}; +TrieNode* _root; +vector > _board; +vector _result; + +public: + +vector findWords(vector>& board, vector& words) { +int row_size = (int)board.size(); + +this->_root = new TrieNode(); + + for (const auto& word : words){ + TrieNode* node = this->_root; + for (const auto& letter : word){ + auto it = node->leaves.find(letter); + auto end = node->leaves.end(); + if (it != end) + node = node->leaves[letter]; + else{ + TrieNode* new_node = new TrieNode(); + node->leaves.emplace(letter, new_node); + node = new_node; + } + } + node->word = word; + } + + this->_board = board; + + for (int row = 0; row < row_size; ++row){ + for (int col = 0; col < board[row].size(); ++col){ + auto it = this->_root->leaves.find(board[row][col]); + auto end = this->_root->leaves.end(); + if (it != end) + backtracking(row, col, this->_root); + } + } + return this->_result; + } + +void backtracking(int row, int col, TrieNode* parent) { + char curr_letter = this->_board[row][col]; + + TrieNode* curr_node = parent->leaves[curr_letter]; + if (curr_node->word != ""){ + this->_result.emplace_back(curr_node->word); + curr_node->word = ""; + } + + this->_board[row][col] = '#'; + + vector row_offset = {-1, 0, 1, 0}; + vector col_offset = {0, 1, 0, -1}; + + for (int i = 0; i < 4; ++i) { + int new_row = row + row_offset[i]; + int new_col = col + col_offset[i]; + + if (new_row < 0 || new_row >= this->_board.size() || new_col < 0 +|| new_col >= this->_board[0].size()) { + continue; +} + + auto it = curr_node->leaves.find(this->_board[new_row][new_col]); + auto end = curr_node->leaves.end(); + if (it != end) + backtracking(new_row, new_col, curr_node); + } + + this->_board[row][col] = curr_letter; + + if (curr_node->leaves.empty()) { + parent->leaves.erase(curr_letter); + } + } +}; diff --git a/Week_06/G20200343030463/463-Week 06/LeetCode_22_463.cpp b/Week_06/G20200343030463/463-Week 06/LeetCode_22_463.cpp new file mode 100644 index 00000000..342398ad --- /dev/null +++ b/Week_06/G20200343030463/463-Week 06/LeetCode_22_463.cpp @@ -0,0 +1,22 @@ +学习笔记 + +class Solution { +public: + vector generateParenthesis(int n) { + vector res; + + helper(res,"",n,n); + + return res; + } + + void helper( vector&ret,string str,int left,int right){ + if(left == 0 && right ==0){ + ret.push_back(str); + return; + } + + if(left > 0) helper(ret,str+"(",left-1,right); + if(right > left) helper(ret,str+")",left,right-1); + } +}; diff --git a/Week_06/G20200343030463/463-Week 06/LeetCode_36_463.cpp b/Week_06/G20200343030463/463-Week 06/LeetCode_36_463.cpp new file mode 100644 index 00000000..02d952af --- /dev/null +++ b/Week_06/G20200343030463/463-Week 06/LeetCode_36_463.cpp @@ -0,0 +1,22 @@ +学习笔记 + +class Solution { +public: + bool isValidSudoku(vector>& board) { + vector col(9, 0); + vector block(9, 0); + vector row(9, 0); + for (int i = 0; i < 9; i++) + for (int j = 0; j < 9; j++) { + if (board[i][j] != '.') { + int idx = 1 << (board[i][j] - '1'); + if (row[i] & idx || col[j] & idx || block[i/3 * 3 + j / 3] & idx) + return false; + row[i] |= idx; + col[j] |= idx; + block[i/3 * 3 + j/3] |= idx; + } + } + return true; + } +}; diff --git a/Week_06/G20200343030463/463-Week 06/LeetCode_51_463.cpp b/Week_06/G20200343030463/463-Week 06/LeetCode_51_463.cpp new file mode 100644 index 00000000..2fd90a20 --- /dev/null +++ b/Week_06/G20200343030463/463-Week 06/LeetCode_51_463.cpp @@ -0,0 +1,46 @@ +学习笔记 +class Solution { +public: +vector> solveNQueens(int n) { +vector> res; +vector nQueens(n,string(n,'.')); +solveNQueens(res, nQueens, 0, n); +return res; +} +private: +void solveNQueens(vector> &res, vector &nQueens, int row, int &n){ + +if(row == n){ +res.push_back(nQueens); +return; +} + +for(int col = 0; col !=n; ++col){ +if(isValid(nQueens,row, col,n)){ +nQueens[row][col] = 'Q'; +solveNQueens(res,nQueens,row+1,n); +nQueens[row][col] = '.'; +} +} +} + +bool isValid(vector &nQueens, int row, int col, int &n){ +//检测每一列是否有Q +for(int i = 0; i !=row; ++i){ +if(nQueens[i][col] == 'Q') +return false; +} +//检测左边45度对角是否有Q +for(int i = row -1, j = col -1; i>=0&&j>=0;--i,--j){ +if(nQueens[i][j] == 'Q') +return false; +} +//检测右边45度对角是否有Q +for(int i = row -1, j = col +1; i>=0&& j&pre){ + while(pre[x] !=x) x=pre[x]; + return x; + } +public: + int findCircleNum(vector>& M) { + int N = M.size(),ans = N; + vectorpre(N); + for(int i =0;i wordList) { + if (wordList == null || wordList.size() == 0) return 0; + + HashSet start = new HashSet<>(); + + HashSet end = new HashSet<>(); + + HashSet dic = new HashSet<>(wordList); + start.add(beginWord); + end.add(endWord); + if (!dic.contains(endWord)) return 0; + + return bfs(start, end, dic, 2); + + } + + public int bfs(HashSet st, HashSet ed, HashSet dic, int l) { + if (st.size() == 0) return 0; + if (st.size() > ed.size()) { + return bfs(ed, st, dic, l); + } + dic.removeAll(st); + HashSet next = new HashSet<>(); + for (String s : st) { + char[] arr = s.toCharArray(); + for (int i = 0; i < arr.length; i++) { + char tmp = arr[i]; + for (char c = 'a'; c <= 'z'; c++) { + if (tmp == c) continue; + arr[i] = c; + String nstr = new String(arr); + if (dic.contains(nstr)) { + if (ed.contains(nstr)) return l; + else next.add(nstr); + } + } + + arr[i] = tmp; + } + } + return bfs(next, ed, dic, l + 1); + } +} \ No newline at end of file diff --git a/Week_06/G20200343030465/LeetCode_547_465.java b/Week_06/G20200343030465/LeetCode_547_465.java new file mode 100644 index 00000000..9224e968 --- /dev/null +++ b/Week_06/G20200343030465/LeetCode_547_465.java @@ -0,0 +1,38 @@ +class Solution { + public int findCircleNum(int[][] M) { + //corner case + if (M == null || M.length == 0) return 0; + + //initialization: count = n, each id = id + int m = M.length; + int count = m; + int[] roots = new int[m]; + for (int i = 0; i < m; i++) roots[i] = i; + + //for loop and union find + for (int i = 0; i < m; i++) { + for (int j = i + 1; j < m; j++) { + //if there is an edge, do union find + if (M[i][j] == 1) { + int root0 = find (roots, i); + int root1 = find (roots, j); + + if (root0 != root1) { + roots[root1] = root0; + count--; + } + } + } + } + + //return count + return count; + } + + public int find (int[] roots, int id) { + while (id != roots[id]) { + id = roots[roots[id]]; + } + return id; + } +} \ No newline at end of file diff --git a/Week_06/G20200343030485/LeetCode_36_485.cs b/Week_06/G20200343030485/LeetCode_36_485.cs new file mode 100644 index 00000000..1dc01d6e --- /dev/null +++ b/Week_06/G20200343030485/LeetCode_36_485.cs @@ -0,0 +1,22 @@ +public class Solution { + public bool IsValidSudoku(char[,] board) { + for (var i = 0; i < 9; i++) + { + var hsr = new HashSet(); + var hsc = new HashSet(); + var hsx = new HashSet(); + + for (var j = 0; j < 9; j++) + { + if (board[i, j] != '.' && !hsr.Add(board[i, j])) return false; + if (board[j, i] != '.' && !hsc.Add(board[j, i])) return false; + + var x = (i % 3) * 3 + j % 3; + var y = (i / 3) * 3 + j / 3; + if (board[x, y] != '.' && !hsx.Add(board[x, y])) return false; + } + } + + return true; + } +} \ No newline at end of file diff --git a/Week_06/G20200343030485/LeetCode_433_485.cs b/Week_06/G20200343030485/LeetCode_433_485.cs new file mode 100644 index 00000000..99abd8c2 --- /dev/null +++ b/Week_06/G20200343030485/LeetCode_433_485.cs @@ -0,0 +1,46 @@ +public class Solution { + public int MinMutation(string start, string end, string[] bank) { + if (start == end) return 0; + + var bankSet = new HashSet(bank); + var isVisited = new HashSet(); + + var queue = new Queue(); + queue.Enqueue(start); + + var choices = new char[] { 'A', 'C', 'G', 'T' }; + + var steps = 1; + + while (queue.Any()) { + var size = queue.Count; + + for (int s = 0; s < size; s++) { + var cur = queue.Dequeue(); + var curArray = cur.ToArray(); + for (int i = 0; i < curArray.Length; i++) { + foreach (var c in choices) { + curArray[i] = c; + var tempCur = new string(curArray); + if (isVisited.Contains(tempCur)) continue; + + if (bankSet.Contains(tempCur)) { + if (tempCur == end) { + return steps; + } + isVisited.Add(tempCur); + queue.Enqueue(tempCur); + } + + curArray[i] = cur[i]; + } + } + } + + steps++; + } + + return -1; + + } +} \ No newline at end of file diff --git a/Week_06/G20200343030489/LeetCode_127_489.cpp b/Week_06/G20200343030489/LeetCode_127_489.cpp new file mode 100644 index 00000000..962c5531 --- /dev/null +++ b/Week_06/G20200343030489/LeetCode_127_489.cpp @@ -0,0 +1,46 @@ +/* + * @lc app=leetcode.cn id=127 lang=cpp + * + * [127] 单词接龙 + */ + +// @lc code=start +class Solution +{ +public: + int ladderLength(string beginWord, string endWord, vector &wordList) + { + unordered_set wordS(wordList.begin(),wordList.end()); + if(wordS.count(endWord)==0) + return 0; + unordered_set begin({beginWord}); + unordered_set end({endWord}); + int res=2; + while(!begin.empty()){ + unordered_set next; + for(auto& word:begin) + wordS.erase(word); + for(auto& word:begin){ + for(int i=0;iend.size()) + swap(begin,end); + res++; + } + return 0; + } +}; + +// @lc code=end \ No newline at end of file diff --git a/Week_06/G20200343030489/LeetCode_208_489.cpp b/Week_06/G20200343030489/LeetCode_208_489.cpp new file mode 100644 index 00000000..9d768a3c --- /dev/null +++ b/Week_06/G20200343030489/LeetCode_208_489.cpp @@ -0,0 +1,61 @@ +/* + * @lc app=leetcode.cn id=208 lang=cpp + * + * [208] 实现 Trie (前缀树) + */ + +// @lc code=start +class Trie { +private: + bool isEnd; + Trie* next[26]; +public: + /** Initialize your data structure here. */ + Trie() { + isEnd=false; + memset(next,0,sizeof(next)); + } + + /** Inserts a word into the trie. */ + void insert(string word) { + Trie* node=this; + for(char c:word){ + if(node->next[c-'a']==NULL) + node->next[c-'a']=new Trie(); + node=node->next[c-'a']; + } + node->isEnd=true; + } + + /** Returns if the word is in the trie. */ + bool search(string word) { + Trie* node=this; + for(char c:word){ + node=node->next[c-'a']; + if(node==NULL) + return false; + } + return node->isEnd; + } + + /** Returns if there is any word in the trie that starts with the given prefix. */ + bool startsWith(string prefix) { + Trie* node=this; + for(char c:prefix){ + node=node->next[c-'a']; + if(node==NULL) + return false; + } + return true; + } +}; + +/** + * Your Trie object will be instantiated and called as such: + * Trie* obj = new Trie(); + * obj->insert(word); + * bool param_2 = obj->search(word); + * bool param_3 = obj->startsWith(prefix); + */ +// @lc code=end + diff --git a/Week_06/G20200343030489/LeetCode_36_489.cpp b/Week_06/G20200343030489/LeetCode_36_489.cpp new file mode 100644 index 00000000..8465a265 --- /dev/null +++ b/Week_06/G20200343030489/LeetCode_36_489.cpp @@ -0,0 +1,34 @@ +/* + * @lc app=leetcode.cn id=36 lang=cpp + * + * [36] 有效的数独 + */ + +// @lc code=start +class Solution { +public: + bool isValidSudoku(vector>& board) { + int row[9][10]={0}; + int col[9][10]={0}; + int box[9][10]={0}; + for(int i=0;i<9;i++){ + for(int j=0;j<9;j++){ + if(board[i][j]=='.') + continue; + int curNum=board[i][j]-'0'; + if(row[i][curNum]) + return false; + if(col[j][curNum]) + return false; + if(box[j/3+(i/3)*3][curNum]) + return false; + row[i][curNum]=1; + col[j][curNum]=1; + box[j/3+(i/3)*3][curNum]=1; + } + } + return true; + } +}; +// @lc code=end + diff --git a/Week_06/G20200343030489/LeetCode_37_489.cpp b/Week_06/G20200343030489/LeetCode_37_489.cpp new file mode 100644 index 00000000..bd62b14c --- /dev/null +++ b/Week_06/G20200343030489/LeetCode_37_489.cpp @@ -0,0 +1,79 @@ +/* + * @lc app=leetcode.cn id=37 lang=cpp + * + * [37] 解数独 + */ + +// @lc code=start +class Solution { +public: + bitset<9> getPossibleStatus(int x,int y){ + return ~(rows[x]|cols[y]|cells[x/3][y/3]); + } + vector getNext(vector>& board){ + vector res; + int mincount=10; + for(int i=0;i=mincount) + continue; + res={i,j}; + mincount=cur.count(); + } + } + return res; + } + void fillNum(int x,int y,int n,bool fillFlag){ + bitset<9> pick(1<>& board,int count){ + if(count==0) + return true; + auto next=getNext(board); + auto bits=getPossibleStatus(next[0],next[1]); + for(int n=0;n>& board) { + rows=vector>(9,bitset<9>()); + cols=vector>(9,bitset<9>()); + cells=vector>>(3, vector>(3, bitset<9>())); + + int count=0; + for(int i=0;i> rows; + vector> cols; + vector>> cells; +}; +// @lc code=end + diff --git a/Week_06/G20200343030489/LeetCode_547_489.cpp b/Week_06/G20200343030489/LeetCode_547_489.cpp new file mode 100644 index 00000000..cf1bf58b --- /dev/null +++ b/Week_06/G20200343030489/LeetCode_547_489.cpp @@ -0,0 +1,37 @@ +/* + * @lc app=leetcode.cn id=547 lang=cpp + * + * [547] 朋友圈 + */ + +// @lc code=start +class Solution { +public: + int findCircleNum(vector>& M) { + if(M.empty()) + return 0; + int n=M.size(); + vector leads(n,0); + for(int i=0;i& parents){ + return parents[x]==x?x:find(parents[x],parents); + } +}; +// @lc code=end + diff --git a/Week_06/G20200343030489/LeetCode_773_489.cpp b/Week_06/G20200343030489/LeetCode_773_489.cpp new file mode 100644 index 00000000..a2b50feb --- /dev/null +++ b/Week_06/G20200343030489/LeetCode_773_489.cpp @@ -0,0 +1,44 @@ +/* + * @lc app=leetcode.cn id=773 lang=cpp + * + * [773] 滑动谜题 + */ + +// @lc code=start +class Solution +{ +public: + int slidingPuzzle(vector> &board) + { + string target = "123450"; + string begin = to_string(board[0][0]) + to_string(board[0][1]) + to_string(board[0][2]) + to_string(board[1][0]) + to_string(board[1][1]) + to_string(board[1][2]); + vector> nextMoves{{1, 3}, {0, 2, 4}, {1, 5}, {0, 4}, {1, 3, 5}, {2, 4}}; + unordered_set visited{begin}; + queue que; + que.push(begin); + for (int depth = 0; !que.empty(); depth++) + { + int size = (int)que.size(); + for (int i = 0; i < size; i++) + { + auto curr = que.front(); + que.pop(); + if (curr == target) + return depth; + int zero = (int)curr.find("0"); + for (auto next : nextMoves[zero]) + { + auto candidate = curr; + swap(candidate[zero], candidate[next]); + if (visited.find(candidate) == visited.end()) + { + visited.insert(candidate); + que.push(candidate); + } + } + } + } + return -1; + } +}; +// @lc code=end diff --git a/Week_06/G20200343030491/LeetCode_1091_491.py b/Week_06/G20200343030491/LeetCode_1091_491.py new file mode 100644 index 00000000..b5be3519 --- /dev/null +++ b/Week_06/G20200343030491/LeetCode_1091_491.py @@ -0,0 +1,110 @@ +class Solution: + def shortestPathBinaryMatrix(self, grid: List[List[int]]) -> int: + if not grid or not grid[0]: return -1 + if grid[0][0] == 1: return -1 + m, n = len(grid), len(grid[0]) + dx = [-1,0,1,0,-1,1,1,-1] + dy = [0,-1,0,1,-1,-1,1,1] + q = deque() + q.append((0,0,1)) + visited = set() + visited.add((0,0)) + while q: + x,y,lev = q.popleft() + if x == m-1 and y == n-1: + return lev + for i in range(len(dx)): + if 0<=x+dx[i] int: + if not grid or not grid[0]: return -1 + if grid[0][0] == 1: return -1 + m, n = len(grid), len(grid[0]) + dx = [-1,0,1,0,-1,1,1,-1] + dy = [0,-1,0,1,-1,-1,1,1] + q = deque() + q.append((0,0)) + visited = set() + visited.add((0,0)) + step = 1 + while q: + newQ = q + q = deque([]) + while newQ: + x,y = newQ.popleft() + if x == m-1 and y == n-1: + return step + for i in range(len(dx)): + if 0<=x+dx[i] int: + if not grid or not grid[0]: return -1 + m, n = len(grid), len(grid[0]) + if grid[0][0] == 1 or grid[m-1][n-1] == 1: return -1 + dx = [-1,0,1,0,-1,1,1,-1] + dy = [0,-1,0,1,-1,-1,1,1] + q = deque() + q.append((0,0)) + visited = [[0]*n for _ in range(m)] + visited[0][0] = 1 + while q: + newQ = q + q = deque([]) + while newQ: + x,y = newQ.popleft() + if x == m-1 and y == n-1: + return visited[x][y] + for i in range(len(dx)): + if 0<=x+dx[i] int: + if not grid or not grid[0]: return -1 + m = len(grid) + n = len(grid[0]) + if grid[0][0] != 0 or grid[m-1][n-1] != 0: return -1 + + dx = [-1,-1,0,1,1,1,0,-1] + dy = [0,-1,-1,-1,0,1,1,1] + + visited = set() + visited.add((0,0)) + beginQ, endQ = deque(), deque() + beginQ.append((0,0)) + endQ.append((m-1,n-1)) + step = 1 + + while beginQ: + nextQ = beginQ + beginQ = deque([]) + while nextQ: + x, y = nextQ.popleft() + if (x,y) in endQ: + return step + for k in range(len(dx)): + if 0<=x+dx[k] int: + size = len(beginWord) + general_dic = defaultdict(list) + + for word in wordList: + for i in range(size): + general_dic[word[:i]+'*'+word[i+1:]].append(word) + + visited = set() + visited.add(beginWord) + q = deque() + q.append((beginWord,1)) + + while q: + cur,lev = q.popleft() + for i in range(size): + for distaneOne in general_dic[cur[:i]+'*'+cur[i+1:]]: + if endWord == distaneOne: + return lev + 1 + else: + if distaneOne not in visited: + visited.add(distaneOne) + q.append((distaneOne,lev + 1)) + + return 0 + +class Solution: + def ladderLength(self, beginWord: str, endWord: str, wordList: List[str]) -> int: + q = deque([(beginWord,1)]) + wordList = set(wordList) + visited = set() + + while q: + word, lev = q.popleft() + if word == endWord: + return lev + + for char in string.ascii_lowercase: + for i in range(len(word)): + newWord = word[:i] + char + word[i+1:] + if newWord in wordList and newWord not in visited: + q.append((newWord,lev+1)) + visited.add(newWord) + + return 0 + +class Solution: + def ladderLength(self, beginWord: str, endWord: str, wordList: List[str]) -> int: + if endWord not in wordList: return 0 + + wordList = set(wordList) + + beginQ, endQ = deque([beginWord]), deque([endWord]) + + step = 1 + + while beginQ: + nextQ = beginQ + beginQ = deque([]) + step += 1 + while nextQ: + word = nextQ.popleft() + for i in range(len(word)): + for c in string.ascii_lowercase: + if c != word[i]: + nextWord = word[:i]+c+word[i+1:] + if nextWord in endQ: + return step + if nextWord in wordList: + beginQ.append(nextWord) + wordList.remove(nextWord) + + if len(endQ) int: + wordList = set(wordList) + if endWord not in wordList: + return 0 + + def nextWords(word,visited): + for i in range(len(word)): + for char in string.ascii_lowercase: + nextWord = word[:i] + char + word[i+1:] + if nextWord in wordList and nextWord not in visited: + yield nextWord + + beginQueue, endQueue = deque([beginWord]), deque([endWord]) + beginVisited, endVisited = set([beginWord]), set([endWord]) + + step = 1 + + while beginQueue and endQueue: + newQueue = beginQueue + beginQueue = deque([]) + while newQueue: + word = newQueue.popleft() + for nextWord in nextWords(word,beginVisited): + if nextWord in endQueue: + return step+1 + + beginQueue.append(nextWord) + beginVisited.add(nextWord) + step += 1 + beginQueue, endQueue = endQueue, beginQueue + beginVisited, endVisited = endVisited, beginVisited + return 0 \ No newline at end of file diff --git a/Week_06/G20200343030491/LeetCode_130_491.py b/Week_06/G20200343030491/LeetCode_130_491.py new file mode 100644 index 00000000..d790aac7 --- /dev/null +++ b/Week_06/G20200343030491/LeetCode_130_491.py @@ -0,0 +1,91 @@ +class Solution: + def __init__(self): + self.parent = {} + def _union(self,i,j): + p1 = self._parent(i) + p2 = self._parent(j) + if p2 != p1: + self.parent[p1] = p2 + + def _parent(self,i): + self.parent.setdefault(i,i) + if self.parent[i] != i: + self.parent[i] = self._parent(self.parent[i]) + return self.parent[i] + + def solve(self, board: List[List[str]]) -> None: + """ + Do not return anything, modify board in-place instead. + """ + if not board or not board[0]: + return [] + m = len(board) + n = len(board[0]) + dummy = m*n + + for i in range(m): + for j in range(n): + if board[i][j] == "O": + if i==0 or i==m-1 or j==0 or j==n-1: + self._union(i*n+j,dummy) + continue + if i>0 and board[i-1][j] == "O": + self._union(i*n+j, (i-1)*n+j) + if i0 and board[i][j-1] == "O": + self._union(i*n+j, i*n+j-1) + if j None: + """ + Do not return anything, modify board in-place instead. + """ + + if not board or not board[0]: + return [] + + m = len(board) + n = len(board[0]) + dx = [-1,0,1,0] + dy = [0,-1,0,1] + visited = set() + def dfs(x,y): + if x<0 or x>m-1 or y<0 or y>n-1: + return + visited.add((x,y)) + if board[x][y] == "O": + board[x][y] = "G" + + for k in range(len(dx)): + if 0 int: + counter = 0 + + def dfs(row,col): + if row<0 or row>len(grid)-1 or col<0 or col>len(grid[0])-1: + return + if grid[row][col] == '0': + return + else: + grid[row][col] = '0' + dfs(row-1,col) + dfs(row+1,col) + dfs(row,col-1) + dfs(row,col+1) + + for row, line in enumerate(grid): + for col, value in enumerate(line): + if value=='1': + counter +=1 + dfs(row, col) + + return counter + + +class Solution: + def numIslands(self, grid: List[List[str]]) -> int: + counter = 0 + + def dfs(row,col): + r = len(grid) + c = len(grid[0]) + grid[row][col] = '0' + if row>0 and grid[row-1][col]=='1': + dfs(row-1,col) + if row0 and grid[row][col-1]=='1': + dfs(row,col-1) + if col int: + counter = 0 + + def bfs(row,col): + q = deque() + q.append((row,col)) + while q: + row,col = q.popleft() + + if row>0 and grid[row-1][col]=='1': + grid[row-1][col] = '0' + q.append((row-1,col)) + if row0 and grid[row][col-1]=='1': + grid[row][col-1] = '0' + q.append((row,col-1)) + if col None: + """ + Inserts a word into the trie. + """ + node = self.root + for char in word: + node = node.setdefault(char, {}) + node[self.end_of_word] = self.end_of_word + + def search(self, word: str) -> bool: + """ + Returns if the word is in the trie. + """ + node = self.root + for char in word: + if char not in node: + return False + node = node[char] + return self.end_of_word in node + + def startsWith(self, prefix: str) -> bool: + """ + Returns if there is any word in the trie that starts with the given prefix. + """ + node = self.root + for char in prefix: + if char not in node: + return False + node = node[char] + return True + + + +# Your Trie object will be instantiated and called as such: +# obj = Trie() +# obj.insert(word) +# param_2 = obj.search(word) +# param_3 = obj.startsWith(prefix) \ No newline at end of file diff --git a/Week_06/G20200343030491/LeetCode_212_491.py b/Week_06/G20200343030491/LeetCode_212_491.py new file mode 100644 index 00000000..96ce78ba --- /dev/null +++ b/Week_06/G20200343030491/LeetCode_212_491.py @@ -0,0 +1,92 @@ +def findWords(board,words): + if not board or not board[0]:return [] + if not words: return [] + + dx = [-1,0,1,0] + dy = [0,1,0,-1] + m = len(board) + n = len(board[0]) + root = {} + end_of_word = '#' + ans = set() + + # insert each word + for word in words: + node = root + for char in word: + node = node.setdefault(char,{}) + node[end_of_word] = end_of_word + + # search a word + def _search(word): + node = root + for char in word: + if char not in node: + return False + node = node[char] + return end_of_word in node + + # search a prefix: + def _startWith(prefix): + node = root + for char in prefix: + if char not in node: + return False + node = node[char] + return True + + def dfs(board,x,y,curWord,curDict): + print(x,y,curWord,curDict) + # pass + curWord += board[x][y] + curDict = curDict[board[x][y]] + + if end_of_word in curDict: + ans.add(curWord) + temp, board[x][y] = board[x][y], '@' + for i in range(len(dx)): + if 0<=x+dx[i] List[str]: + + res = [] + + def dfs(left, right, s): + if left==n and right==n: + res.append(s) + return + if left bool: + rows = [[] for _ in range(9)] + cols = [[] for _ in range(9)] + boxes = [[] for _ in range(9)] + + for i in range(9): + for j in range(9): + if board[i][j] != ".": + if board[i][j] in rows[i] or board[i][j] in cols[j] or board[i][j] in boxes[i//3 * 3 + j//3]: + + return False + + rows[i].append(board[i][j]) + cols[j].append(board[i][j]) + boxes[i//3*3 + j//3].append(board[i][j]) + + return True \ No newline at end of file diff --git a/Week_06/G20200343030491/LeetCode_37_491.py b/Week_06/G20200343030491/LeetCode_37_491.py new file mode 100644 index 00000000..72fa056a --- /dev/null +++ b/Week_06/G20200343030491/LeetCode_37_491.py @@ -0,0 +1,35 @@ +class Solution: + def solveSudoku(self, board: List[List[str]]) -> None: + """ + Do not return anything, modify board in-place instead. + """ + rows = [set(range(1,10)) for _ in range(9)] + cols = [set(range(1,10)) for _ in range(9)] + boxes = [set(range(1,10)) for _ in range(9)] + empty = [] + for i in range(9): + for j in range(9): + if board[i][j] != ".": + rows[i].remove(int(board[i][j])) + cols[j].remove(int(board[i][j])) + boxes[i//3*3+j//3].remove(int(board[i][j])) + else: + empty.append((i,j)) + + def dfs(iter=0): + if iter == len(empty): + return True + i, j = empty[iter] + for val in rows[i] & cols[j] & boxes[i//3*3+j//3]: + rows[i].remove(val) + cols[j].remove(val) + boxes[i//3*3+j//3].remove(val) + board[i][j] = str(val) + if dfs(iter+1): + return True + rows[i].add(val) + cols[j].add(val) + boxes[i//3*3+j//3].add(val) + return False + + dfs() \ No newline at end of file diff --git a/Week_06/G20200343030491/LeetCode_433_491.py b/Week_06/G20200343030491/LeetCode_433_491.py new file mode 100644 index 00000000..a70e8361 --- /dev/null +++ b/Week_06/G20200343030491/LeetCode_433_491.py @@ -0,0 +1,101 @@ +class Solution: + def __init__(self): + self.res = 0 + def compare(self, str1,str2): + counter = 0 + for i in range(len(str1)): + if str1[i] != str2[i]: + counter += 1 + + if counter==1: + return True + else: + return False + + def minMutation(self, start: str, end: str, bank: List[str]) -> int: + if not bank: + return -1 + + def rec(_start, _bank, k): + if _start == end: + self.res = k + for i in range(len(_bank)): + if self.compare(_start, _bank[i]): + rec(_bank[i],_bank[:i]+_bank[i+1:],k+1) + + rec(start, bank, 0) + + return self.res if self.res != 0 else -1 + +class Solution: + def minMutation(self, start: str, end: str, bank: List[str]) -> int: + q = deque([(start,0)]) + bank = set(bank) + visited = set() + + while q: + + word, lev = q.popleft() + if word == end: + return lev + + for char in 'ACGT': + for i in range(len(word)): + newWord = word[:i] + char + word[i+1:] + + if newWord in bank and newWord not in visited: + q.append((newWord,lev+1)) + visited.add(newWord) + + return -1 + +class Solution: + def minMutation(self, start: str, end: str, bank: List[str]) -> int: + size = len(start) + general_dic = defaultdict(list) + + for gene in bank: + for i in range(size): + general_dic[gene[:i]+'*'+gene[i+1:]].append(gene) + + visited = set([start]) + q = deque() + q.append((start,0)) + while q: + cur, lev = q.popleft() + for i in range(size): + for distanceOne in general_dic[cur[:i]+'*'+cur[i+1:]]: + if end == distanceOne: + return lev+1 + else: + if distanceOne not in visited: + visited.add(distanceOne) + q.append((distanceOne, lev+1)) + +class Solution: + def minMutation(self, start: str, end: str, bank: List[str]) -> int: + if end not in bank: return -1 + beginD = {start} + endD = {end} + step = 0 + bank = set(bank) + geneLen = len(start) + + while beginD: + nextD = set() + step += 1 + for gene in beginD: + for i in range(geneLen): + for g in 'ACGT': + if g != gene[i]: + newGene = gene[:i]+g+gene[i+1:] + if newGene in endD: + return step + if newGene in bank: + nextD.add(newGene) + bank.remove(newGene) + beginD = nextD + if len(endD) List[List[str]]: + board = [['.']*n for _ in range(n)] + ans = [] + + def isValid(board, row, col): + n = len(board) + for i in range(n): + if board[i][col] == "Q": + return False + + r, c = row-1, col+1 + while r>=0 and c=0 and c>=0: + if board[r][c] == "Q": + return False + r -= 1 + c -= 1 + + return True + + def backtrack(board,row): + if row == len(board): + tmpList = [] + for row in board: + tmp = ''.join(row) + tmpList.append(tmp) + ans.append(tmpList) + return + + col = len(board[row]) + for j in range(col): + if not isValid(board, row, j): + continue + + board[row][j] = "Q" + backtrack(board,row+1) + board[row][j] = "." + + backtrack(board,0) + + return ans + + +class Solution: + def solveNQueens(self, n: int) -> List[List[str]]: + res = [] + def dfs(queen,rightup,leftup): + row = len(queen) + if row==n: + res.append(queen) + return + for col in range(n): + if col not in queen and col+row not in rightup and col-row not in leftup: + dfs(queen+[col], rightup+[col+row], leftup+[col-row]) + + dfs([],[],[]) + print(res) + return [['.'*i + 'Q' + '.'*(n-i-1) for i in sol] for sol in res] \ No newline at end of file diff --git a/Week_06/G20200343030491/LeetCode_547_491.py b/Week_06/G20200343030491/LeetCode_547_491.py new file mode 100644 index 00000000..46184293 --- /dev/null +++ b/Week_06/G20200343030491/LeetCode_547_491.py @@ -0,0 +1,55 @@ +class Solution: + def _union(self,p,i,j): + p1 = self._parent(p,i) + p2 = self._parent(p,j) + p[p1] = p2 + + def _parent(self,p,i): + root = i + while p[root] != root: + root = p[root] + + # while p[i] != i: + # x = i; i = p[i]; p[x] = root + return root + def findCircleNum(self, M: List[List[int]]) -> int: + if not M: return 0 + + n = len(M) + p = [i for i in range(n)] + + for i in range(n): + for j in range(n): + if M[i][j] == 1: + self._union(p,i,j) + + + return len(set([self._parent(p,i) for i in range(n)])) + +class Solution: + def _union(self,p,i,j): + p1 = self._parent(p,i) + p2 = self._parent(p,j) + p[p1] = p2 + + def _parent(self,p,i): + root = i + while p[root] != root: + root = p[root] + + while p[i] != i: + x = i; i = p[i]; p[x] = root + return root + def findCircleNum(self, M: List[List[int]]) -> int: + if not M: return 0 + + n = len(M) + p = [i for i in range(n)] + + for i in range(n): + for j in range(n): + if M[i][j] == 1: + self._union(p,i,j) + + + return len(set([self._parent(p,i) for i in range(n)])) \ No newline at end of file diff --git a/Week_06/G20200343030493/212_wordSearch2.java b/Week_06/G20200343030493/212_wordSearch2.java new file mode 100644 index 00000000..160f80d4 --- /dev/null +++ b/Week_06/G20200343030493/212_wordSearch2.java @@ -0,0 +1,84 @@ +class TrieNode { + public TrieNode[] children; + public String word; //节点直接存当前的单词 + + public TrieNode() { + children = new TrieNode[26]; + word = null; + for (int i = 0; i < 26; i++) { + children[i] = null; + } + } +} +class Trie { + TrieNode root; + /** Initialize your data structure here. */ + public Trie() { + root = new TrieNode(); + } + + /** Inserts a word into the trie. */ + public void insert(String word) { + char[] array = word.toCharArray(); + TrieNode cur = root; + for (int i = 0; i < array.length; i++) { + // 当前孩子是否存在 + if (cur.children[array[i] - 'a'] == null) { + cur.children[array[i] - 'a'] = new TrieNode(); + } + cur = cur.children[array[i] - 'a']; + } + // 当前节点结束,存入当前单词 + cur.word = word; + } +}; + +class Solution { + public List findWords(char[][] board, String[] words) { + Trie trie = new Trie(); + //将所有单词存入前缀树中 + List res = new ArrayList<>(); + for (String word : words) { + trie.insert(word); + } + int rows = board.length; + if (rows == 0) { + return res; + } + int cols = board[0].length; + //从每个位置开始遍历 + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + existRecursive(board, i, j, trie.root, res); + } + } + return res; + } + + private void existRecursive(char[][] board, int row, int col, TrieNode node, List res) { + if (row < 0 || row >= board.length || col < 0 || col >= board[0].length) { + return; + } + char cur = board[row][col];//将要遍历的字母 + //当前节点遍历过或者将要遍历的字母在前缀树中不存在 + if (cur == '$' || node.children[cur - 'a'] == null) { + return; + } + node = node.children[cur - 'a']; + //判断当前节点是否是一个单词的结束 + if (node.word != null) { + //加入到结果中 + res.add(node.word); + //将当前单词置为 null,防止重复加入 + node.word = null; + } + char temp = board[row][col]; + //上下左右去遍历 + board[row][col] = '$'; + existRecursive(board, row - 1, col, node, res); + existRecursive(board, row + 1, col, node, res); + existRecursive(board, row, col - 1, node, res); + existRecursive(board, row, col + 1, node, res); + board[row][col] = temp; + } +} \ No newline at end of file diff --git a/Week_06/G20200343030493/36_shudu.java b/Week_06/G20200343030493/36_shudu.java new file mode 100644 index 00000000..e8dd0bfb --- /dev/null +++ b/Week_06/G20200343030493/36_shudu.java @@ -0,0 +1,34 @@ +class Solution { + public boolean isValidSudoku(char[][] board) { + // init data + HashMap [] rows = new HashMap[9]; + HashMap [] columns = new HashMap[9]; + HashMap [] boxes = new HashMap[9]; + for (int i = 0; i < 9; i++) { + rows[i] = new HashMap(); + columns[i] = new HashMap(); + boxes[i] = new HashMap(); + } + + // validate a board + for (int i = 0; i < 9; i++) { + for (int j = 0; j < 9; j++) { + char num = board[i][j]; + if (num != '.') { + int n = (int)num; + int box_index = (i / 3 ) * 3 + j / 3; + + // keep the current cell value + rows[i].put(n, rows[i].getOrDefault(n, 0) + 1); + columns[j].put(n, columns[j].getOrDefault(n, 0) + 1); + boxes[box_index].put(n, boxes[box_index].getOrDefault(n, 0) + 1); + + // check if this value has been already seen before + if (rows[i].get(n) > 1 || columns[j].get(n) > 1 || boxes[box_index].get(n) > 1) + return false; + } + } + } + return true; + } + } \ No newline at end of file diff --git a/Week_06/G20200343030493/547_friend_circle.java b/Week_06/G20200343030493/547_friend_circle.java new file mode 100644 index 00000000..0ad988a2 --- /dev/null +++ b/Week_06/G20200343030493/547_friend_circle.java @@ -0,0 +1,31 @@ +class Solution { + int find(int parent[], int i) { + if (parent[i] == -1) + return i; + return find(parent, parent[i]); + } + + void union(int parent[], int x, int y) { + int xset = find(parent, x); + int yset = find(parent, y); + if (xset != yset) + parent[xset] = yset; + } + public int findCircleNum(int[][] M) { + int[] parent = new int[M.length]; + Arrays.fill(parent, -1); + for (int i = 0; i < M.length; i++) { + for (int j = 0; j < M.length; j++) { + if (M[i][j] == 1 && i != j) { + union(parent, i, j); + } + } + } + int count = 0; + for (int i = 0; i < parent.length; i++) { + if (parent[i] == -1) + count++; + } + return count; + } + } diff --git a/Week_06/G20200343030497/LeetCode_130_497.cpp b/Week_06/G20200343030497/LeetCode_130_497.cpp new file mode 100644 index 00000000..5f857835 --- /dev/null +++ b/Week_06/G20200343030497/LeetCode_130_497.cpp @@ -0,0 +1,36 @@ +class Solution { +public: + void solve(vector>& board){ + if(board.empty()) return; + int row=board.size(), col=board[0].size(); + + for(int i = 0; i < row; ++i){ + check(board, i, 0); + check(board, i, col-1); + } + + for(int j = 1; j < col - 1; ++j){ + check(board, 0, j); + check(board, row-1, j); + } + + for(int i = 0; i < row; ++i){ + for(int j = 0; j < col; ++j){ + if(board[i][j] == 'O') + board[i][j] = 'X'; + else if(board[i][j] == '1') + board[i][j] = 'O'; + } + } + } + + void check(vector> & board, int i, int j){ + if(board[i][j] == 'O'){ + board[i][j] = '1'; + if(i > 1) check(board, i-1, j); + if(j > 1) check(board, i, j-1); + if(i+1 < board.size()) check(board, i+1, j); + if(j+1 < board[0].size()) check(board, i, j+1); + } + } +}; diff --git a/Week_06/G20200343030497/LeetCode_200_497.cpp b/Week_06/G20200343030497/LeetCode_200_497.cpp new file mode 100644 index 00000000..2b7513d6 --- /dev/null +++ b/Week_06/G20200343030497/LeetCode_200_497.cpp @@ -0,0 +1,83 @@ +class Solution { +public: + // 深度优先搜索 + // 时间复杂度:O(mn) + // 空间复杂度:O(1) + // 参考:https://leetcode.com/problems/number-of-islands/discuss/56589/C%2B%2B-BFSDFS + int numIslands(vector>& grid) { + int m = grid.size(), n = m ? grid[0].size() : 0, islands = 0; + for(int i = 0; i < m; i++){ + for(int j = 0; j < n; j++){ + if(grid[i][j] == '1'){ + removeIsland(grid, i, j, m, n); + islands++; + } + } + } + + return islands; + } + + void removeIsland(vector>& grid, int m, int n, int rows, int cols){ + if(m < 0 || m == rows || n < 0 || n == cols || grid[m][n] == '0'){ + return; + } + grid[m][n] = '0'; // 把原数组的1都删除 + // 分别遍历四个方向 + removeIsland(grid, m-1, n, rows, cols); + removeIsland(grid, m, n-1, rows, cols); + removeIsland(grid, m+1, n, rows, cols); + removeIsland(grid, m, n+1, rows, cols); + } + + // 广度优先搜索 + // 时间复杂度:O(mn) + // 空间复杂度:O(mn) + // 参考:https://leetcode-cn.com/problems/number-of-islands/solution/dfs-bfs-bing-cha-ji-python-dai-ma-java-dai-ma-by-l/ + int numIslands(vector>& grid) { + int rows = grid.size(), cols = rows ? grid[0].size() :0 , islands = 0; + if(rows == 0){ + return 0; + } + int directions[4][2] = {{-1, 0}, {0, -1}, {1, 0}, {0, 1}}; + vector> marked(rows, vector(cols, false)); + queue q; + + for(int i = 0; i < rows; i++){ + for(int j = 0; j < cols; j++){ + if(!marked[i][j] && grid[i][j] == '1'){ + islands++; + q.push(i * cols + j); // 将当前元素的坐标存入队列 + marked[i][j] = true; + + while(!q.empty()){ + int curP = q.front(); + q.pop(); + int curX = curP / cols; + int curY = curP % cols; + + // 遍历四个方向 + for(int k = 0; k < 4; k++){ + int newX = curX + directions[k][0]; + int newY = curY + directions[k][1]; + if(newX >= 0 && newX < rows && newY >= 0 && newY < cols && + grid[newX][newY] == '1' && !marked[newX][newY]){ + marked[newX][newY] = true; + q.push(newX * cols + newY); + } + } + } + } + } + } + + return islands; + } + + // 并查集 + // 时间复杂度: + // 空间复杂度: + int numIslands(vector>& grid) { + + } +}; diff --git a/Week_06/G20200343030501/LeetCode_547_501.go b/Week_06/G20200343030501/LeetCode_547_501.go new file mode 100644 index 00000000..d72fc7e8 --- /dev/null +++ b/Week_06/G20200343030501/LeetCode_547_501.go @@ -0,0 +1,61 @@ +package G20200343030501 + +import "fmt" + +func findCircleNum(M [][]int) int { + rowLength := len(M) + if rowLength == 0 { + return 0 + } + relationHead := make([]int, rowLength) + for k := 0; k < rowLength; k++ { + relationHead[k] = -1 + } + for i := 0; i < rowLength; i++ { + for j := 0; j < rowLength; j++ { + if M[i][j] == 0 { + continue + } + if relationHead[i] != -1 { + fix(relationHead[i], j, relationHead) + } + fix(i, j, relationHead) + } + } + + for _, value := range relationHead { + fmt.Printf("%d \n", value) + } + + count := 0 + memo := make([]int, rowLength) + for index := 0; index < rowLength; index++ { + if relationHead[index] == -1 { + continue + } + temp := index + for { + if relationHead[temp] == temp { + if memo[temp] == 0 { + count += 1 + memo[temp] = 1 + } + break + } + temp = relationHead[temp] + } + } + + return count +} + +func fix(i int, j int, container []int) { + last := j + for { + if container[last] == last || container[last] == -1 { + break + } + last = container[last] + } + container[i] = last +} diff --git a/Week_06/G20200343030501/LeetCode_70_501.go b/Week_06/G20200343030501/LeetCode_70_501.go new file mode 100644 index 00000000..1498ba1d --- /dev/null +++ b/Week_06/G20200343030501/LeetCode_70_501.go @@ -0,0 +1,14 @@ +package G20200343030501 + +func climbStairs(n int) int { + if n == 1 { + return 1 + } + container := make([]int, n + 1) + container[1] = 1 + container[2] = 2 + for i := 3; i <= n; i++ { + container[i] = container[i - 1] + container[i - 2] + } + return container[n] +} \ No newline at end of file diff --git a/Week_06/G20200343030503/LeetCode_102_503.java b/Week_06/G20200343030503/LeetCode_102_503.java new file mode 100644 index 00000000..bac1f665 --- /dev/null +++ b/Week_06/G20200343030503/LeetCode_102_503.java @@ -0,0 +1,31 @@ +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; } + * } + */ +class Solution { + List> result = new ArrayList<>(); + public List> levelOrder(TreeNode root) { + if (root == null) return result; + helper(root,0); + return result; + } + + public void helper(TreeNode node, int level) { + if (result.size() == level) { + result.add(new ArrayList()); + } + + result.get(level).add(node.val); + if (node.left != null) { + helper(node.left, level + 1); + } + if (node.right != null) { + helper(node.right, level + 1); + } + } +} \ No newline at end of file diff --git a/Week_06/G20200343030503/LeetCode_547_503.java b/Week_06/G20200343030503/LeetCode_547_503.java new file mode 100644 index 00000000..fb094e35 --- /dev/null +++ b/Week_06/G20200343030503/LeetCode_547_503.java @@ -0,0 +1,25 @@ +/** + * + * + */ +class Solution { + public int findCircleNum(int[][] M) { + int[] visited = new int[M.length]; + int count = 0; + for (int i = 0; i < M.length; i++) { + if (visited[i] == 0) { + dfs(M, visited, i); + count++; + } + } + return count; + } + public void dfs(int[][] M, int[] visited, int i) { + for (int j = 0; j < M.length; j++) { + if (M[i][j] == 1 && visited[j] == 0) { + visited[j] = 1; + dfs(M, visited, j); + } + } + } +} \ No newline at end of file diff --git a/Week_06/G20200343030503/LeetCode_70_503.java b/Week_06/G20200343030503/LeetCode_70_503.java new file mode 100644 index 00000000..645af87c --- /dev/null +++ b/Week_06/G20200343030503/LeetCode_70_503.java @@ -0,0 +1,30 @@ +class Solution { + // public int climbStairs(int n) { + // if (n <= 2) { + // return n; + // } + // int first = 1; + // int second = 2; + // int third = 0; + // for (int i = 3; i <= n; i++) { + // third = first + second; + // first = second; + // second = third; + // } + // return third; + // } + //动态规划 + public int climbStairs(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]; + } +} \ No newline at end of file diff --git a/Week_06/G20200343030503/NOTE.md b/Week_06/G20200343030503/NOTE.md index 50de3041..b223a9c3 100644 --- a/Week_06/G20200343030503/NOTE.md +++ b/Week_06/G20200343030503/NOTE.md @@ -1 +1,115 @@ -学习笔记 \ No newline at end of file +学习笔记 + +课程进行到中后期, 很明显就是难度加大, 对待算法的态度明显没有刚开始那么有激情, 好多问题不懂,只能去反复看视频,和题解, 然后照着抄,强制自己去理解这种解法.希望自己能坚持下去 + + + +#### AVL树 + + 1. 平衡二叉树也叫平衡二叉搜索树(Self-balancingbinarysearchtree)又被称为AVL树,可以保证查询效率较高。 + 2. 它是一棵空树或它的左右两个子树的高度差的绝对值不超过**1**,并且左右两个子树都是一棵平衡二叉树。平衡二叉树的常用实现方法有红黑树、AVL、替罪羊树、Treap、伸展树等。 + + + +#### Trie 树代码模板 + +```python +class Trie(object): + + def __init__(self): + self.root = {} + self.end_of_word = "#" + + def insert(self, word): + node = self.root + for char in word: + node = node.setdefault(char, {}) + node[self.end_of_word] = self.end_of_word + + def search(self, word): + node = self.root + for char in word: + if char not in node: + return False + node = node[char] + return self.end_of_word in node + + def startsWith(self, prefix): + node = self.root + for char in prefix: + if char not in node: + return False + node = node[char] + return True +``` + +​ + +#### 并查集代码模板 + +```java +class UnionFind { + private int count = 0; + private int[] parent; + public UnionFind(int n) { + count = n; + parent = new int[n]; + for (int i = 0; i < n; i++) { + parent[i] = i; + } + } + public int find(int p) { + while (p != parent[p]) { + parent[p] = parent[parent[p]]; + p = parent[p]; + } + return p; + } + public void union(int p, int q) { + int rootP = find(p); + int rootQ = find(q); + if (rootP == rootQ) return; + parent[rootP] = rootQ; + count--; + } +} +``` + +```python +def init(p): + # for i = 0 .. n: p[i] = i; + p = [i for i in range(n)] + +def union(self, p, i, j): + p1 = self.parent(p, i) + p2 = self.parent(p, j) + p[p1] = p2 + +def parent(self, p, i): + root = i + while p[root] != root: + root = p[root] + while p[i] != i: # 路径压缩 ? + x = i; i = p[i]; p[x] = root + return root +``` + +#### A*代码模板 + +```python +def AstarSearch(graph, start, end): + + pq = collections.priority_queue() # 优先级 —> 估价函数 + pq.append([start]) + visited.add(start) + + while pq: + node = pq.pop() # can we add more intelligence here ? + visited.add(node) + + process(node) + nodes = generate_related_nodes(node) + unvisited = [node for node in nodes if node not in visited] + pq.push(unvisited) +``` + diff --git a/Week_06/G20200343030505/LeetCode_130_505.java b/Week_06/G20200343030505/LeetCode_130_505.java new file mode 100644 index 00000000..6a32a499 --- /dev/null +++ b/Week_06/G20200343030505/LeetCode_130_505.java @@ -0,0 +1,41 @@ + + +class LeetCode_130_505 { + public void solve(char[][] board) { + if (board == null || board.length == 0) return; + int m = board.length; + int n = board[0].length; + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + // 从边缘o开始搜索 + boolean isEdge = i == 0 || j == 0 || i == m - 1 || j == n - 1; + if (isEdge && board[i][j] == 'O') { + dfs(board, i, j); + } + } + } + + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + if (board[i][j] == 'O') { + board[i][j] = 'X'; + } + if (board[i][j] == '#') { + board[i][j] = 'O'; + } + } + } + } + + public void dfs(char[][] board, int i, int j) { + if (i < 0 || j < 0 || i >= board.length || j >= board[0].length || board[i][j] == 'X' || board[i][j] == '#') { + // board[i][j] == '#' 说明已经搜索过了. + return; + } + board[i][j] = '#'; + dfs(board, i - 1, j); // 上 + dfs(board, i + 1, j); // 下 + dfs(board, i, j - 1); // 左 + dfs(board, i, j + 1); // 右 + } +} \ No newline at end of file diff --git a/Week_06/G20200343030505/LeetCode_200_505.java b/Week_06/G20200343030505/LeetCode_200_505.java new file mode 100644 index 00000000..b72f3afb --- /dev/null +++ b/Week_06/G20200343030505/LeetCode_200_505.java @@ -0,0 +1,55 @@ +class LeetCode_200_505 { + + private int count; + private boolean[][] marked; + private int[] dx; + private int[] dy; + private int len; + private int colum; + + public int numIslands(char[][] grid) { + if (grid == null) { + return 0; + } + len = grid.length; + if (len == 0) { + return 0; + } + colum = grid[0].length; + //标记已经访问过的节点 + marked = new boolean[len][colum]; + //定义方向 如dx[0]和dy[0]表示朝x轴右边走 其他以此类推 + dx = new int[]{1, 0, -1, 0}; + dy = new int[]{0, -1, 0, 1}; + + for (int i=0;i=0 && i=0 && j result = new ArrayList(); + public List generateParenthesis(int n) { + if (n <= 0) { + return result; + } + + String path = ""; + generateParenthesis(n, 0, 0, path); + return result; + } + + public void generateParenthesis(int n, int left , int right, String path) { + if (left == n && right == n) { + result.add(path); + return; + } + + if (left < n) { + generateParenthesis(n, left + 1, right, path + "("); + } + + if (left > right) { + generateParenthesis(n, left, right + 1, path + ")"); + } + } +} \ No newline at end of file diff --git a/Week_06/G20200343030505/LeetCode_51_505.java b/Week_06/G20200343030505/LeetCode_51_505.java new file mode 100644 index 00000000..211fcd0b --- /dev/null +++ b/Week_06/G20200343030505/LeetCode_51_505.java @@ -0,0 +1,82 @@ + +class LeetCode_51_505 { + private List> result = new ArrayList(); + private int[] cols;//标记i列是否有棋子 + private int[] arr;//标记反斜对角线有棋子 + private int[] brr; //标记对角线是否有棋子 + private int[] queens;//标记第i,queens[i]位置是否有棋子 + private int n; + + public List> solveNQueens(int n) { + if (n <= 0) { + return result; + } + + this.cols = new int[n];//列 + this.arr = new int[2 * n - 1];//斜对角线 + this.brr = new int[2 * n - 1];//反斜对角线 + this.n = n; + this.queens = new int[n];//队列存放皇后位置 + solve(0); + return result; + } + + public void solve(int row) { + if (row == n) { + return; + } + //依次判断row和i位置是否能放棋子 + for (int i=0;i list = new ArrayList(); + for (int i=0;i size[rootq]) { + parent[rootq] = rootp; + size[rootp] += size[rootq]; + } else { + parent[rootq] = rootp; + size[rootq] += size[rootq]; + } + --count; + } + + public boolean isUnited(int p, int q) { + int rootp = find(p); + int rootq = find(q); + return rootp == rootq; + } + + public int getCount() { + return count; + } + +} + +class LeetCode_547_505 { + public int findCircleNum(int[][] M) { + if (M == null) { + return 0; + } + int len = M.length; + if (len == 0) { + return 0; + } + Union union = new Union(len); + for (int i=0;i findWords(char[][] board, String[] words) { + if (board.length == 0) return null; + + List res = new ArrayList<>(); + + TrieNode root = buildTrie(words); + + for (int i = 0; i < board.length; i++) { + for (int j = 0; j < board[i].length; j++) { + dfs(board, i, j, root, res); + } + } + + return res; + } + + private void dfs(char[][] board, int i, int j, TrieNode node, List res) { + char ch = board[i][j]; + if (ch == '#' || node.next[ch - 'a'] == null) return; + node = node.next[ch - 'a']; + if (node.word != null) { + res.add(node.word); + // 删除避免重复 + node.word = null; + } + + board[i][j] = '#'; + if (i > 0) dfs(board, i - 1, j, node, res); + if (j > 0) dfs(board, i, j-1, node, res); + if (i < board.length - 1) dfs(board, i+1, j, node, res); + if (j < board[0].length - 1) dfs(board, i, j+1, node, res); + board[i][j] = ch; + } + + + public TrieNode buildTrie(String[] words) { + TrieNode root = new TrieNode(); + for (String word: words) { + TrieNode node = root; + for (char ch: word.toCharArray()) { + int i = ch - 'a'; + if (node.next[i] == null) { + node.next[i] = new TrieNode(); + } + node = node.next[i]; + } + node.word = word; + } + return root; + } + + class TrieNode { + TrieNode[] next = new TrieNode[26]; + String word; + } +} \ No newline at end of file diff --git a/Week_06/G20200343030509/Solution547_509.java b/Week_06/G20200343030509/Solution547_509.java new file mode 100644 index 00000000..1a7899ce --- /dev/null +++ b/Week_06/G20200343030509/Solution547_509.java @@ -0,0 +1,61 @@ +package com.leetcode.week06; + +/* + * @lc app=leetcode.cn id=547 lang=java + * + * [547] 朋友圈 + */ + + +class Solution547_509 { + public static void main(String[] args) { + long startTime=System.nanoTime(); //获取开始时间 + + Solution547_509 sol = new Solution547_509(); + int[][] M = {{1,1,0},{1,1,0},{0,0,1}}; + + System.out.println(sol.findCircleNum(M)); + + long endTime=System.nanoTime(); //获取结束时间 + System.out.println( "程序运行时间: " + (endTime-startTime) + "ns"); + } + + public int findCircleNum(int[][] M) { + UnionFind uf = new UnionFind(M.length); + for (int i = 0; i < M.length - 1; i++) { + for ( int j = i + 1; j < M.length; j++) { + if (M[i][j] == 1) uf.union(i, j); + } + } + for(int i: uf.parent) System.out.println(i); + return uf.count; + } + + class UnionFind { + private int count = 0; + private int[] parent; + public UnionFind(int n) { + count = n; + parent = new int[n]; + for (int i = 0; i < n; i++) { + parent[i] = i; + } + } + public int find(int p) { + while (p != parent[p]) { + parent[p] = parent[parent[p]]; + p = parent[p]; + } + return p; + } + public void union(int p, int q) { + int rootP = find(p); + int rootQ = find(q); + if (rootP == rootQ) return; + parent[rootP] = rootQ; + count--; + return; + } + } + +} \ No newline at end of file diff --git a/Week_06/G20200343030509/Trie.java b/Week_06/G20200343030509/Trie.java new file mode 100644 index 00000000..94640224 --- /dev/null +++ b/Week_06/G20200343030509/Trie.java @@ -0,0 +1,109 @@ +package com.leetcode.week06; + +/* + * @lc app=leetcode.cn id=208 lang=java + * + * [208] 实现 Trie (前缀树) + */ + +// @lc code=start +class Trie { + + private TrieNode root; + + public Trie () { + root = new TrieNode(); + } + + class TrieNode { + private TrieNode[] links; + private final int size = 26; + private boolean isEnd; + + /** Initialize your data structure here. */ + public TrieNode() { + links = new TrieNode[26]; + } + + public boolean containsKey (char ch) { + return links[ch - 'a'] != null; + } + + public TrieNode get (char ch) { + return links[ch - 'a']; + } + + public void put (char ch, TrieNode node) { + links[ch - 'a'] = node; + } + + public void setEnd () { + isEnd = true; + } + + public boolean isEnd() { + return isEnd; + } + } + + + /** Inserts a word into the trie. */ + public void insert(String word) { + TrieNode node = root; + for (int i = 0; i < word.length(); i++) { + char ch = word.charAt(i); + if (!node.containsKey(ch)) { + node.put(ch, new TrieNode()); + } + node = node.get(ch); + } + node.setEnd(); + } + + /** Returns if the word is in the trie. */ + public boolean search(String word) { + TrieNode node = searchPrefix(word); + return node != null && node.isEnd(); + } + + private Trie.TrieNode searchPrefix(String word) { + TrieNode node = root; + for (int i = 0; i < word.length(); i++) { + char ch = word.charAt(i); + if (node.containsKey(ch)) { + node = node.get(ch); + } + else { + return null; + } + } + return node; + } + + /** Returns if there is any word in the trie that starts with the given prefix. */ + public boolean startsWith(String prefix) { + TrieNode node = searchPrefix(prefix); + return node != null; + } + + public static void main(String[] args) { + Trie trie = new Trie(); + + trie.insert("apple"); + System.out.println(trie.search("apple")); + System.out.println(trie.search("app")); + System.out.println(trie.startsWith("app")); + trie.insert("app"); + System.out.println(trie.search("app")); + } +} + +/** + * Your Trie object will be instantiated and called as such: + * Trie obj = new Trie(); + * obj.insert(word); + * boolean param_2 = obj.search(word); + * boolean param_3 = obj.startsWith(prefix); + */ +// @lc code=end + diff --git a/Week_06/G20200343030511/LeetCode_127_511.java b/Week_06/G20200343030511/LeetCode_127_511.java new file mode 100644 index 00000000..3c8fdeb9 --- /dev/null +++ b/Week_06/G20200343030511/LeetCode_127_511.java @@ -0,0 +1,71 @@ +class Solution { + public int ladderLength(String beginWord, String endWord, List wordList) { + if (!wordList.contains(endWord)) { + return 0; + } + // visited修改为boolean数组 + boolean[] leftVisited = new boolean[wordList.size()]; + int idx = wordList.indexOf(beginWord); + if (idx != -1) { + leftVisited[idx] = true; + } + Queue leftQueue = new LinkedList<>(); + leftQueue.offer(beginWord); + int leftCount = 0; + + Queue rightQueue = new LinkedList<>(); + rightQueue.offer(endWord); + int rightCount = 0; + + boolean[] rightVisited = new boolean[wordList.size()]; + int end = wordList.indexOf(endWord); + if (end == -1) { + return 0; + } + rightVisited[end] = true; + while (leftQueue.size() > 0 && rightQueue.size() > 0) { + leftCount++; + if(leftQueue.size()>rightQueue.size()){ + Queue tmp =leftQueue; + leftQueue = rightQueue; + rightQueue =tmp; + boolean[] t = leftVisited; + leftVisited =rightVisited; + rightVisited =t; + + } + int leftSize = leftQueue.size(); + for (int i = 0; i < leftSize; i++) { + String leftWord = leftQueue.poll(); + for (int j = 0; j < wordList.size(); j++) { + if (leftVisited[j]) + continue; + + if (!isValid(leftWord, wordList.get(j))) { + continue; + } + if (rightVisited[j]) { + return leftCount + 1; + } + leftQueue.offer(wordList.get(j)); + leftVisited[j] = true; + } + } + } + return 0; + } + + boolean isValid(String word1, String word2) { + char[] word1char = word1.toCharArray(); + char[] word2char = word2.toCharArray(); + int count = 0; + for (int i = 0; i < word2char.length; i++) { + if (word1char[i] != word2char[i]) { + count++; + } + } + if (count == 1) + return true; + return false; + } +} \ No newline at end of file diff --git a/Week_06/G20200343030511/LeetCode_130_511.java b/Week_06/G20200343030511/LeetCode_130_511.java new file mode 100644 index 00000000..9ec3abf2 --- /dev/null +++ b/Week_06/G20200343030511/LeetCode_130_511.java @@ -0,0 +1,77 @@ +public class Solution { + int rows, cols; + + public void solve(char[][] board) { + if(board == null || board.length == 0) return; + + rows = board.length; + cols = board[0].length; + + + UnionFind uf = new UnionFind(rows * cols + 1); + + int dummyNode = rows * cols; + + for(int i = 0; i < rows; i++) { + for(int j = 0; j < cols; j++) { + if(board[i][j] == 'O') { + if(i == 0 || i == rows-1 || j == 0 || j == cols-1) { + uf.union( dummyNode,node(i,j)); + } + else { + if(board[i-1][j] == 'O') uf.union(node(i,j), node(i-1,j)); + if(board[i+1][j] == 'O') uf.union(node(i,j), node(i+1,j)); + if(board[i][j-1] == 'O') uf.union(node(i,j), node(i, j-1)); + if( board[i][j+1] == 'O') uf.union(node(i,j), node(i, j+1)); + } + } + } + } + + for(int i = 0; i < rows; i++) { + for(int j = 0; j < cols; j++) { + //判断是否和 dummy 节点是一类 + if(uf.isConnected(node(i,j), dummyNode)) { + board[i][j] = 'O'; + } + else { + board[i][j] = 'X'; + } + } + } + } + + int node(int i, int j) { + return i * cols + j; + } +} + +class UnionFind { + int [] parents; + public UnionFind(int totalNodes) { + parents = new int[totalNodes]; + for(int i = 0; i < totalNodes; i++) { + parents[i] = i; + } + } + + void union(int node1, int node2) { + int root1 = find(node1); + int root2 = find(node2); + if(root1 != root2) { + parents[root2] = root1; + } + } + + int find(int node) { + while(parents[node] != node) { + parents[node] = parents[parents[node]]; + node = parents[node]; + } + return node; + } + + boolean isConnected(int node1, int node2) { + return find(node1) == find(node2); + } +} \ No newline at end of file diff --git a/Week_06/G20200343030513/LeetCode_208_513.java b/Week_06/G20200343030513/LeetCode_208_513.java new file mode 100644 index 00000000..d040c26c --- /dev/null +++ b/Week_06/G20200343030513/LeetCode_208_513.java @@ -0,0 +1,107 @@ +//实现一个 Trie (前缀树),包含 insert, search, 和 startsWith 这三个操作。 +// +// 示例: +// +// Trie trie = new Trie(); +// +//trie.insert("apple"); +//trie.search("apple"); // 返回 true +//trie.search("app"); // 返回 false +//trie.startsWith("app"); // 返回 true +//trie.insert("app"); +//trie.search("app"); // 返回 true +// +// 说明: +// +// +// 你可以假设所有的输入都是由小写字母 a-z 构成的。 +// 保证所有输入均为非空字符串。 +// +// Related Topics 设计 字典树 + + +//leetcode submit region begin(Prohibit modification and deletion) +class Trie { + private TrieNode root; + + /** Initialize your data structure here. */ + public Trie() { + root = new TrieNode(); + } + + /** Inserts a word into the trie. */ + public void insert(String word) { + TrieNode node = root; + for (int i = 0; i < word.length(); i++) { + char currentChar = word.charAt(i); + if (!node.containsKey(currentChar)) { + node.put(currentChar, new TrieNode()); + } + node = node.get(currentChar); + } + node.setEnd(); + } + + private TrieNode searchPrefix(String word) { + TrieNode node = root; + for (int i = 0; i < word.length(); i++) { + char curLetter = word.charAt(i); + if (node.containsKey(curLetter)) { + node = node.get(curLetter); + } else { + return null; + } + } + return node; + } + + /** Returns if the word is in the trie. */ + public boolean search(String word) { + TrieNode node = searchPrefix(word); + return node != null && node.isEnd(); + } + + /** Returns if there is any word in the trie that starts with the given prefix. */ + public boolean startsWith(String prefix) { + TrieNode node = searchPrefix(prefix); + return node != null; + } +} +class TrieNode { + + // R links to node children + private TrieNode[] links; + + private final int R = 26; + + private boolean isEnd; + + public TrieNode() { + links = new TrieNode[R]; + } + + public boolean containsKey(char ch) { + return links[ch -'a'] != null; + } + public TrieNode get(char ch) { + return links[ch -'a']; + } + public void put(char ch, TrieNode node) { + links[ch -'a'] = node; + } + public void setEnd() { + isEnd = true; + } + public boolean isEnd() { + return isEnd; + } +} + +/** + * Your Trie object will be instantiated and called as such: + * Trie obj = new Trie(); + * obj.insert(word); + * boolean param_2 = obj.search(word); + * boolean param_3 = obj.startsWith(prefix); + */ +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week_06/G20200343030513/LeetCode_70_513.java b/Week_06/G20200343030513/LeetCode_70_513.java new file mode 100644 index 00000000..8f13f5f2 --- /dev/null +++ b/Week_06/G20200343030513/LeetCode_70_513.java @@ -0,0 +1,35 @@ +//假设你正在爬楼梯。需要 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 动态规划 + + +//leetcode submit region begin(Prohibit modification and deletion) +class Solution { + public int climbStairs(int n) { + double sqrt5 = Math.sqrt(5); + double fibn = Math.pow((1+sqrt5)/2,n+1)-Math.pow((1-sqrt5)/2,n+1); + return (int)(fibn/sqrt5); + } +} +//leetcode submit region end(Prohibit modification and deletion) diff --git a/Week_06/G20200343030519/Week 06/LeetCode_1091_519.js b/Week_06/G20200343030519/Week 06/LeetCode_1091_519.js new file mode 100644 index 00000000..0769e7c8 --- /dev/null +++ b/Week_06/G20200343030519/Week 06/LeetCode_1091_519.js @@ -0,0 +1,32 @@ +// https://leetcode-cn.com/problems/shortest-path-in-binary-matrix/ + +var shortestPathBinaryMatrix = function(grid) { + if (grid[0][0]) return -1; + + const queue = [{ coord: [0, 0], dist: 1 }]; + const directs = [[-1, -1], [-1, 0], [-1, 1], [0, 1], [1, 1], [1, 0], [1, -1], [0, -1]]; + const N = grid.length; + const isValidCoord = (x, y) => x >= 0 && x < N && y >= 0 && y < N; + + grid[0][0] = 1; + + while (queue.length) { + const { coord: [x, y], dist } = queue.shift(); + + if (x === N - 1 && y === N - 1) { + return dist; + } + + for (let [moveX, moveY] of directs) { + const nextX = x + moveX; + const nextY = y + moveY; + + if (isValidCoord(nextX, nextY) && grid[nextX][nextY] === 0) { + queue.push({ coord: [nextX, nextY], dist: dist + 1 }); + grid[nextX][nextY] = 1; + } + } + } + + return -1; +}; \ No newline at end of file diff --git a/Week_06/G20200343030519/Week 06/LeetCode_130_519.js b/Week_06/G20200343030519/Week 06/LeetCode_130_519.js new file mode 100644 index 00000000..583e1ef1 --- /dev/null +++ b/Week_06/G20200343030519/Week 06/LeetCode_130_519.js @@ -0,0 +1,34 @@ +// https://leetcode-cn.com/problems/surrounded-regions/ + +function solve(board) { + if (!board.length) return; + + for (let i = 0; i < board.length; i++) { + mark(board, i, 0); + mark(board, i, board[0].length - 1); + } + + for (let i = 1; i < board[0].length - 1; i++) { + mark(board, 0, i); + mark(board, board.length - 1, i); + } + + for (let i = 0; i < board.length; i++) { + for (let j = 0; j < board[0].length; j++) { + if (board[i][j] === 'O') board[i][j] = 'X'; + if (board[i][j] === '#') board[i][j] = 'O'; + } + } + } + + function mark(board, i ,j) { + if (i < 0 || i > board.length - 1 || j < 0 || j > board[0].length - 1) return; + if (board[i][j] !== 'O') return; + + board[i][j] = '#'; + + mark(board, i - 1, j); + mark(board, i + 1, j); + mark(board, i, j - 1); + mark(board, i, j + 1); + } \ No newline at end of file diff --git a/Week_06/G20200343030519/Week 06/LeetCode_208_519.js b/Week_06/G20200343030519/Week 06/LeetCode_208_519.js new file mode 100644 index 00000000..a3241752 --- /dev/null +++ b/Week_06/G20200343030519/Week 06/LeetCode_208_519.js @@ -0,0 +1,31 @@ +// https://leetcode-cn.com/problems/implement-trie-prefix-tree/ + +class Trie { + constructor() { + this.root = {} + } + + insert(word) { + let curr = this.root + word.split('').forEach(ch => (curr = curr[ch] = curr[ch] || {})) + curr.isWord = true + } + + traverse(word) { + let curr = this.root + for (let i = 0; i < word.length; i++) { + if (!curr) return null + curr = curr[word[i]] + } + return curr + } + + search(word) { + let node = this.traverse(word) + return !!node && !!node.isWord + } + + startsWith(word) { + return !!this.traverse(word) + } +} \ No newline at end of file diff --git a/Week_06/G20200343030519/Week 06/LeetCode_212_519.js b/Week_06/G20200343030519/Week 06/LeetCode_212_519.js new file mode 100644 index 00000000..a369261e --- /dev/null +++ b/Week_06/G20200343030519/Week 06/LeetCode_212_519.js @@ -0,0 +1,44 @@ +// https://leetcode-cn.com/problems/word-search-ii/ + +function findWords(board, words) { + let res = []; + + function buildTrie() { + const root = {}; + for (let w of words) { + let node = root; + for (let c of w) { + if (node[c] == null) node[c] = {}; + node = node[c]; + } + node.word = w; + } + return root; + } + + function search(node, i, j) { + if (node.word != null) { + res.push(node.word); + node.word = null; + } + + if (i < 0 || i >= board.length || j < 0 || j >= board[0].length) return; + if (node[board[i][j]] == null) return; + + const c = board[i][j]; + board[i][j] = '#'; + search(node[c], i + 1, j); + search(node[c], i - 1, j); + search(node[c], i, j + 1); + search(node[c], i, j - 1); + board[i][j] = c; + } + + const root = buildTrie(); + for (let i = 0; i < board.length; i++) { + for (let j = 0; j < board[0].length; j++) { + search(root, i, j); + } + } + return res; +} \ No newline at end of file diff --git a/Week_06/G20200343030519/Week 06/LeetCode_36_519.js b/Week_06/G20200343030519/Week 06/LeetCode_36_519.js new file mode 100644 index 00000000..f0e14a02 --- /dev/null +++ b/Week_06/G20200343030519/Week 06/LeetCode_36_519.js @@ -0,0 +1,22 @@ +// https://leetcode-cn.com/problems/valid-sudoku/description/ + +var isValidSudoku = function(board) { + let rows = {}; + let columns = {}; + let boxes = {}; + for(let i = 0;i < 9;i++){ + for(let j = 0;j < 9;j++){ + let num = board[i][j]; + if(num != '.'){ + let boxIndex = parseInt((i/3)) * 3 + parseInt(j/3); + if(rows[i+'-'+num] || columns[j+'-'+num] || boxes[boxIndex+'-'+num]){ + return false; + } + rows[i+'-'+num] = true; + columns[j+'-'+num] = true; + boxes[boxIndex+'-'+num] = true; + } + } + } + return true; +}; \ No newline at end of file diff --git a/Week_06/G20200343030519/Week 06/LeetCode_37_519.js b/Week_06/G20200343030519/Week 06/LeetCode_37_519.js new file mode 100644 index 00000000..3dac9bd4 --- /dev/null +++ b/Week_06/G20200343030519/Week 06/LeetCode_37_519.js @@ -0,0 +1,35 @@ +// https://leetcode-cn.com/problems/sudoku-solver/#/description + +var solveSudoku = function(board) { + let isValid = (row,col,num) => { + for (let i = 0; i < 9; i++) { + let boxRow = parseInt(row / 3) * 3; + let boxCol = parseInt(col / 3) * 3; + if (board[row][i] == num || board[i][col] == num || board[boxRow + parseInt(i / 3)][boxCol + i % 3] == num) { + return false; + } + } + return true; + } + let solve = () => { + for (let i = 0; i < 9; i++) { + for (let j = 0 ;j < 9; j++) { + if (board[i][j] == '.') { + for (let num = 1; num <10; num++) { + if (isValid(i, j, num)) { + board[i][j] = String(num); + if (solve(board)) { + return true; + } + board[i][j] = '.'; + } + } + return false; + } + } + } + return true; + } + solve(board); + return board; +}; \ No newline at end of file diff --git a/Week_06/G20200343030519/Week 06/LeetCode_547_519.js b/Week_06/G20200343030519/Week 06/LeetCode_547_519.js new file mode 100644 index 00000000..56762bf5 --- /dev/null +++ b/Week_06/G20200343030519/Week 06/LeetCode_547_519.js @@ -0,0 +1,30 @@ +// https://leetcode-cn.com/problems/friend-circles/ + +const findCircleNum = (M) => { + if (!M.length) return 0 + let n = M.length, count = n + let parent = new Array(n) + for (let i = 0; i < n; i++) parent[i] = i + + const findParent = (p) => { + while (parent[p] != p) { + parent[p] = parent[parent[p]] + p = parent[p] + } + return p + } + + const union = (p, q) => { + let rootP = findParent(p), rootQ = findParent(q) + if (rootP === rootQ) return + parent[rootP] = rootQ + count-- + } + + for (let i = 0; i < n; i++) { + for (let j = 0; j < n; j++) { + if (M[i][j] === 1) union(i, j) + } + } + return count + } \ No newline at end of file diff --git a/Week_06/G20200343030519/Week 06/LeetCode_773_519.js b/Week_06/G20200343030519/Week 06/LeetCode_773_519.js new file mode 100644 index 00000000..2b053ce3 --- /dev/null +++ b/Week_06/G20200343030519/Week 06/LeetCode_773_519.js @@ -0,0 +1,36 @@ +// https://leetcode-cn.com/problems/sliding-puzzle/ + +function slidingPuzzle(board) { + let min = Number.MAX_VALUE; + const target = '1,2,3,4,5,0'; + const cost = {}; + + for (let r = 0; r < 2; r++) { + for (let c = 0; c < 3; c++) { + if (board[r][c] === 0) { + dfs(r, c, 0); + return min === Number.MAX_VALUE ? -1 : min; + } + } + } + + function dfs(r, c, len) { + let hash = board[0].join(',') + ',' + board[1].join(','); + if (cost[hash] !== undefined && len >= cost[hash]) return; + cost[hash] = len; + + if (hash === target) { + min = Math.min(min, len); + return; + } + + for (let move of [[-1, 0], [1, 0], [0, -1], [0, 1]]) { + const [rr, cc] = [r+move[0], c+move[1]]; + if (rr < 0 || cc < 0 || rr === 2 || cc === 3) continue; + + [board[r][c], board[rr][cc]] = [board[rr][cc], board[r][c]]; + dfs(rr, cc, len+1); + [board[r][c], board[rr][cc]] = [board[rr][cc], board[r][c]]; + } + } + } \ No newline at end of file diff --git a/Week_06/G20200343030523/id_523/LeetCode_212_523.java b/Week_06/G20200343030523/id_523/LeetCode_212_523.java new file mode 100644 index 00000000..1231f746 --- /dev/null +++ b/Week_06/G20200343030523/id_523/LeetCode_212_523.java @@ -0,0 +1,126 @@ +package dynamic; + +/** + * https://leetcode-cn.com/problems/word-search-ii/ + */ +class Solution { + public List findWords(char[][] board, String[] words) { + Trie trie = new Trie(); + + //把words放到Trie里 + for (String word : words) { + trie.insert(word); + } + + //遍历board + int rows = board.length; + int cols = board[0].length; + boolean[][] visited = new boolean[rows][cols]; + Set result = new HashSet<>(); + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + fun(trie, "", board, i, j, visited, result); + } + } + + return new ArrayList<>(result); + } + + private void fun(Trie trie, String str, char[][] board, int i, int j, boolean[][] visited, Set result) { + + if (i < 0 || i >= board.length || j < 0 || j >= board[0].length) { + return; + } + + if (visited[i][j]) { + return; + } + + str += board[i][j]; + if (!trie.startsWith(str)) { + return; + } + + if (trie.search(str)) { + result.add(str); + } + + visited[i][j] = true; + fun(trie, str, board, i, j + 1, visited, result); + fun(trie, str, board, i, j - 1, visited, result); + fun(trie, str, board, i + 1, j, visited, result); + fun(trie, str, board, i - 1, j, visited, result); + visited[i][j] = false; + } +} + +class Trie { + + private TrieNode root; + + /** + * Initialize your data structure here. + */ + public Trie() { + root = new TrieNode(); + } + + /** + * Inserts a word into the trie. + */ + public void insert(String word) { + TrieNode node = root; + for (int i = 0; i < word.length(); i++) { + char c = word.charAt(i); + if (node.children[c - 'a'] == null) { + node.children[c - 'a'] = new TrieNode(c); + } + node = node.children[c - 'a']; + } + node.endOfWord = true; + } + + /** + * Returns if the word is in the trie. + */ + public boolean search(String word) { + TrieNode node = root; + for (int i = 0; i < word.length(); i++) { + char c = word.charAt(i); + if (node.children[c - 'a'] == null) { + return false; + } + node = node.children[c - 'a']; + } + return node.endOfWord; + } + + /** + * Returns if there is any word in the trie that starts with the given prefix. + */ + public boolean startsWith(String prefix) { + TrieNode node = root; + for (int i = 0; i < prefix.length(); i++) { + char c = prefix.charAt(i); + if (node.children[c - 'a'] == null) { + return false; + } + node = node.children[c - 'a']; + } + return true; + } +} + +class TrieNode { + + public boolean endOfWord; + public char val; + public TrieNode[] children = new TrieNode[26]; + + public TrieNode() { + } + + public TrieNode(char val) { + this.val = val; + } +} diff --git a/Week_06/G20200343030523/id_523/LeetCode_51_523.java b/Week_06/G20200343030523/id_523/LeetCode_51_523.java new file mode 100644 index 00000000..7927bf15 --- /dev/null +++ b/Week_06/G20200343030523/id_523/LeetCode_51_523.java @@ -0,0 +1,85 @@ + +import java.util.ArrayList; +import java.util.List; + +/** + * https://leetcode-cn.com/problems/n-queens + */ +public class NQueens { + + public List> solveNQueens(int n) { + List> result = new ArrayList<>(); + + if (n < 1) { + return result; + } + + int[][] board = new int[n][n]; + backtrack(board, 0, n, result); + return result; + } + + private void backtrack(int[][] board, int row, int n, List> result) { + + if (row == n) { + result.add(trans(board, n)); + return; + } + + for (int col = 0; col < n; col++) { + if (!valid(board, row, col, n)) { + continue; + } + board[row][col] = 1; + backtrack(board, row + 1, n, result); + board[row][col] = 0; + } + + } + + private List trans(int[][] board, int n) { + List each = new ArrayList<>(); + for (int i = 0; i < n; i++) { + StringBuilder eachRow = new StringBuilder(); + for (int j = 0; j < n; j++) { + if (board[i][j] == 1) { + eachRow.append("Q"); + } else { + eachRow.append("."); + } + } + each.add(eachRow.toString()); + } + return each; + } + + private boolean valid(int[][] board, int row, int col, int n) { + + for (int i = row - 1; i >= 0; i--) { + if (board[i][col] == 1) { + return false; + } + } + + for (int i = row - 1, j = col - 1; i >= 0 && j >= 0; i--, j--) { + if (board[i][j] == 1) { + return false; + } + } + + for (int i = row - 1, j = col + 1; i >= 0 && j < n; i--, j++) { + if (board[i][j] == 1) { + return false; + } + } + + return true; + } + + + public static void main(String[] args) { + backtracking.NQueens nQueens = new backtracking.NQueens(); + System.out.println(nQueens.solveNQueens(4)); + } + +} diff --git a/Week_06/G20200343030527/LeetCode_200_527.java b/Week_06/G20200343030527/LeetCode_200_527.java new file mode 100644 index 00000000..972eb727 --- /dev/null +++ b/Week_06/G20200343030527/LeetCode_200_527.java @@ -0,0 +1,32 @@ +class Solution { + public int numIslands(char[][] grid) { + if (grid == null || grid.length == 0) { + return 0; + } + int num = 0; + for (int i = 0; i < grid.length; i++) { + for (int j = 0; j < grid[i].length; j++) { + if (grid[i][j] == '1') { + num += dfs(grid, i, j); + } + } + } + + return num; + } + + private int dfs(char[][] grid, int i, int j) { + if (i < 0 || i >= grid.length || j < 0 || j >= grid[i].length || grid[i][j] == '0') { + return 0; + } + + grid[i][j] = '0'; + + dfs(grid, i + 1, j); + dfs(grid, i - 1, j); + dfs(grid, i, j + 1); + dfs(grid, i, j - 1); + + return 1; + } +} \ No newline at end of file diff --git a/Week_06/G20200343030527/LeetCode_70_527.java b/Week_06/G20200343030527/LeetCode_70_527.java new file mode 100644 index 00000000..e94c8e09 --- /dev/null +++ b/Week_06/G20200343030527/LeetCode_70_527.java @@ -0,0 +1,15 @@ +class Solution { + public int climbStairs(int n) { + if (n <= 2) { + return n; + } + int s1 = 1; + int s2 = 2; + for (int i = 3; i <= n; ++i) { + int temp = s1 + s2; + s1 = s2; + s2 = temp; + } + return s2; + } +} \ No newline at end of file diff --git a/Week_06/G20200343030529/LeetCode_208_529.java b/Week_06/G20200343030529/LeetCode_208_529.java new file mode 100644 index 00000000..24780008 --- /dev/null +++ b/Week_06/G20200343030529/LeetCode_208_529.java @@ -0,0 +1,70 @@ +public class Trie { + + class TrieNode { + private TrieNode[] links = new TrieNode[26]; + private boolean isEnd; + + public boolean containKey(char ch) { + return links[ch - 'a'] != null; + } + + public TrieNode get(char ch) { + return links[ch - 'a']; + } + + public void put(char ch, TrieNode node) { + links[ch - 'a'] = node; + } + + public boolean isEnd() { + return isEnd; + } + + public void setEnd(boolean end) { + isEnd = end; + } + } + + private TrieNode root; + + /** Initialize your data structure here. */ + public Trie() { + root = new TrieNode(); + } + + /** Inserts a word into the trie. */ + public void insert(String word) { + TrieNode node = root; + for (char c : word.toCharArray()) { + if (!node.containKey(c)) { + node.put(c, new TrieNode()); + } + node = node.get(c); + } + node.setEnd(true); + } + + private TrieNode searchPrefix(String word) { + TrieNode node = root; + for (char c : word.toCharArray()) { + node = node.get(c); + if (node == null) { + return null; + } + } + return node; + } + + /** Returns if the word is in the trie. */ + public boolean search(String word) { + TrieNode node = searchPrefix(word); + return node != null && node.isEnd(); + } + + /** Returns if there is any word in the trie that starts with the given prefix. */ + public boolean startsWith(String prefix) { + TrieNode node = searchPrefix(prefix); + return node != null; + } + +} \ No newline at end of file diff --git a/Week_06/G20200343030529/LeetCode_37_529.java b/Week_06/G20200343030529/LeetCode_37_529.java new file mode 100644 index 00000000..f474b191 --- /dev/null +++ b/Week_06/G20200343030529/LeetCode_37_529.java @@ -0,0 +1,72 @@ +class Solution { + int n = 9; + boolean[][] rows = new boolean[n][10]; + boolean[][] columns = new boolean[n][10]; + boolean[][] blocks = new boolean[n][10]; + + public void solveSudoku(char[][] board) { + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + if (board[i][j] != '.') { + int pos = board[i][j] - '0'; + rows[i][pos] = true; + columns[j][pos] = true; + blocks[blockIndex(i, j)][pos] = true; + } + } + } + + solveHelper(board, 0, 0); + } + + private boolean solveHelper(char[][] board, int row, int column) { + if (column == n) { + return true; + } + + while (board[row][column] != '.') { + if (row + 1 < n) { + row += 1; + } else { + row = 0; + column += 1; + } + if (column == n) { + return true; + } + } + + for (int i = 1; i <= n; i++) { + if (rows[row][i] || columns[column][i] || blocks[blockIndex(row, column)][i]) { + continue; + } + board[row][column] = (char) (i + '0'); + rows[row][i] = true; + columns[column][i] = true; + blocks[blockIndex(row, column)][i] = true; + + int nextRow = row; + int nextColumn = column; + if (nextRow + 1 < n) { + nextRow += 1; + } else { + nextRow = 0; + nextColumn += 1; + } + + if (!solveHelper(board, nextRow, nextColumn)) { + board[row][column] = '.'; + rows[row][i] = false; + columns[column][i] = false; + blocks[blockIndex(row, column)][i] = false; + } else { + return true; + } + } + return false; + } + + private int blockIndex(int row, int column) { + return (row / 3) * 3 + column / 3; + } +} \ No newline at end of file diff --git a/Week_06/G20200343030529/LeetCode_547_529.java b/Week_06/G20200343030529/LeetCode_547_529.java new file mode 100644 index 00000000..5143af6b --- /dev/null +++ b/Week_06/G20200343030529/LeetCode_547_529.java @@ -0,0 +1,49 @@ +class Solution { + class DisjoinSet { + + private int count = 0; + private int[] parent; + + public DisjoinSet(int n) { + parent = new int[n + 1]; + this.count = n; + for (int i = 0; i < parent.length; i++) { + parent[i] = i; + } + } + + public int find(int p) { + while (p != parent[p]) { + parent[p] = parent[parent[p]]; + p = parent[p]; + } + return p; + } + + public void union(int p, int q) { + int rootp = find(p); + int rootq = find(q); + if (rootp == rootq) return; + parent[rootp] = rootq; + count--; + } + + public int getCount() { + return count; + } +} + public int findCircleNum(int[][] M) { + if (M.length == 0) { + return 0; + } + DisjoinSet disjoinSet = new DisjoinSet(M[0].length); + for (int i = 0; i < M.length; i++) { + for (int j = 0; j < M[i].length; j++) { + if (M[i][j] == 1) { + disjoinSet.union(i, j); + } + } + } + return disjoinSet.getCount(); + } +} \ No newline at end of file diff --git a/Week_06/G20200343030531/LeetCode_200_531.go b/Week_06/G20200343030531/LeetCode_200_531.go new file mode 100644 index 00000000..130c4257 --- /dev/null +++ b/Week_06/G20200343030531/LeetCode_200_531.go @@ -0,0 +1,42 @@ +package main + +func main() { + island := [][]byte{{1, 1, 1, 1, 0}, {1, 1, 0, 1, 0}, {1, 1, 0, 0, 0}, {0, 0, 0, 0, 0}} + numIslands(island) +} + +// DFS的写法,找到为"1"的岛屿起始点,对其进行深度优先搜索, +// 并将被搜索到的相邻岛屿全部"沉掉"设置为"0" +// 进行下一轮寻找岛屿 +var dx = [4]int{-1, 1, 0, 0} +var dy = [4]int{0, 0, 1, -1} + +func numIslands(grid [][]byte) int { + m := len(grid) + if m == 0 { + return 0 + } + + n := len(grid[0]) + count := 0 + for i := 0; i < m; i++ { + for j := 0; j < n; j++ { + if grid[i][j] == '1' { + DFS(grid, i, j) + count++ + } + } + } + return count +} + +func DFS(grid [][]byte, i, j int) { + if i < 0 || j < 0 || i >= len(grid) || j >= len(grid[0]) || grid[i][j] != '1' { + return + } + + grid[i][j] = '0' + for k := 0; k < 4; k++ { + DFS(grid, i+dx[k], j+dy[k]) + } +} diff --git a/Week_06/G20200343030531/LeetCode_22_531.go b/Week_06/G20200343030531/LeetCode_22_531.go new file mode 100644 index 00000000..67d53bce --- /dev/null +++ b/Week_06/G20200343030531/LeetCode_22_531.go @@ -0,0 +1,37 @@ +package main + +import "fmt" + +func main() { + fmt.Println(generateParenthesis(4)) +} + +// +func generateParenthesis(n int) []string { + ans := make([]string, 0) + + for i := 1; i < n*2; i += 2 { + buffer := "(" + // 求解子问题 + left := generateParenthesis((i - 1) / 2) + right := generateParenthesis((2*n - i - 1) / 2) + + // 如果子问题返回的切片是空的,就加一个空字符串方便下面的循环 + if len(left) == 0 { + left = append(left, "") + } + + if len(right) == 0 { + right = append(right, "") + } + // 组合两个子问题返回的子字符串 + for _, vl := range left { + for _, vr := range right { + temp := buffer + vl + ")" + vr + ans = append(ans, temp) + } + } + } + + return ans +} diff --git a/Week_06/G20200343030533/LeetCode_022_533.cpp b/Week_06/G20200343030533/LeetCode_022_533.cpp new file mode 100644 index 00000000..45b80497 --- /dev/null +++ b/Week_06/G20200343030533/LeetCode_022_533.cpp @@ -0,0 +1,38 @@ +#include +#include +#include +#include +#include +using namespace std; + +class Solution { + vector ans; +public: + vector generateParenthesis(int n) { + string s = ""; + DFS(s, 0, 0, n); + return ans; + + } + + void DFS(string s, int left, int right, int n){ + if (left == n && right == n){ + ans.push_back(s); + } + if ( left < n){ + s.push_back('('); + DFS(s, left + 1, right, n); + s.pop_back(); + } + if ( right < left){ + s.push_back(')'); + DFS(s, left, right+1 ,n ); + s.pop_back(); + } + return ; + } +}; + +int main(int argc, char *argv[]){ + return 0; +} \ No newline at end of file diff --git a/Week_06/G20200343030533/LeetCode_070_533.cpp b/Week_06/G20200343030533/LeetCode_070_533.cpp new file mode 100644 index 00000000..331f3f8f --- /dev/null +++ b/Week_06/G20200343030533/LeetCode_070_533.cpp @@ -0,0 +1,17 @@ +#include + +// 爬楼梯, 剪枝 + +class Solution { +std::unordered_map dict; +public: + int climbStairs(int n) { + if ( n == 0 ) return 1; + if ( n <= 2 ) return n; + + if ( dict.find(n) != dict.end() ) return dict[n]; + dict[n] = climbStairs(n-1) + climbStairs(n-2); + return dict[n]; + + } +}; \ No newline at end of file diff --git a/Week_06/G20200343030533/LeetCode_079_533.cpp b/Week_06/G20200343030533/LeetCode_079_533.cpp new file mode 100644 index 00000000..804f3af9 --- /dev/null +++ b/Week_06/G20200343030533/LeetCode_079_533.cpp @@ -0,0 +1,20 @@ + + +bool find(char **board, int col, int row, int boardSize, int* boardColSize, chr *word){ + +} + + +bool exist(char** board, int boardSize, int* boardColSize, char * word){ + int x[4] = {-1, 1, 0, 0}; + int y[4] = { 0, 0, -1, 1}; + + for (int i = 0; i < boardSize; i++){ + for (int j = 0; j < boardColSize[i]; j++){ + char c = board[i][j]; + if ( c == word[0] ){ + } + } + } + +} \ No newline at end of file diff --git a/Week_06/G20200343030533/LeetCode_127.533.cpp b/Week_06/G20200343030533/LeetCode_127.533.cpp new file mode 100644 index 00000000..95d949a7 --- /dev/null +++ b/Week_06/G20200343030533/LeetCode_127.533.cpp @@ -0,0 +1,110 @@ +#include +#include +#include +#include +#include +#include +#include + + +using namespace std; + +//单向BFS +class Solution1{ +public: + int ladderLength(string beginWord, string endWord, vector& wordList){ + //加入所有节点,访问过一次,删除一个。相当于visited,访问一个加入一个 + unordered_set s; + for (auto &i : wordList) s.insert(i); + + queue> q; + //加入beginword + q.push({beginWord, 1}); + + string tmp; //每个节点的字符 + int step; //抵达该节点的step + + while ( !q.empty() ){ + if ( q.front().first == endWord){ + return (q.front().second); + } + tmp = q.front().first; + step = q.front().second; + q.pop(); + + //寻找下一个单词了 + char ch; + for (int i = 0; i < tmp.length(); i++){ + ch = tmp[i]; + for (char c = 'a'; c <= 'z'; c++){ + //从'a'-'z'尝试一次 + if ( ch == c) continue; + tmp[i] = c ; + //如果找到的到 + if ( s.find(tmp) != s.end() ){ + q.push({tmp, step+1}); + s.erase(tmp) ; //删除该节点 + } + tmp[i] = ch; //复原 + } + + } + } + return 0; + } +}; + +//双向BFS +class Solution { +public: + int ladderLength(string beginWord, string endWord, vector& wordList) { + + unordered_set dict(wordList.begin(), wordList.end()); + if (dict.find(endWord) == dict.end() ) return 0; + // 初始化起始和重点 + unordered_set beginSet, endSet, tmp, visited; + beginSet.insert(beginWord); + endSet.insert(endWord); + int len = 1; + + while (!beginSet.empty() && !endSet.empty()){ + if (beginSet.size() > endSet.size()){ + tmp = beginSet; + beginSet = endSet; + endSet = tmp; + } + tmp.clear(); + for ( string word : beginSet){ + for (int i = 0; i < word.size(); i++){ + char old = word[i]; + for ( char c = 'a'; c <= 'z'; c++){ + if ( old == c) continue; + word[i] = c; + if (endSet.find(word) != endSet.end()){ + return len+1; + } + if (visited.find(word) == visited.end() && dict.find(word) != dict.end()){ + tmp.insert(word); + visited.insert(word); + } + } + word[i] = old; + } + } + beginSet = tmp; + len++; + + + } + return 0; + } +}; + + + +int main(int argc, char *argv[]){ + Solution sol; + vector lst{"hot","dot","dog","lot","log","cog"}; + cout << sol.ladderLength("hit","cog", lst) << endl; + return 0; +} \ No newline at end of file diff --git a/Week_06/G20200343030533/LeetCode_130_533.cpp b/Week_06/G20200343030533/LeetCode_130_533.cpp new file mode 100644 index 00000000..ee4526d2 --- /dev/null +++ b/Week_06/G20200343030533/LeetCode_130_533.cpp @@ -0,0 +1,93 @@ +#include + +using namespace std; + +struct DSU{ + std::vector data; + void makeSet(int n){ + data.resize(n); + for (int i = 0; i < n; i++) data[i] = i; + }; + + bool unionSet(int i, int j){ + int p1 = parent(i); + int p2 = parent(j); + if ( p1 != p2 ){ + data[p1] = p2; + } + return p1 != p2; + }; + + int parent(int i){ + int root = i; + while (data[root] != root ){ + root = data[root]; + } + int x; + while ( data[i] != i){ + x = i; + i = data[i]; + data[x] = root; + } + return root; + }; + +}; + +/* +初始化并查集, 之后遍历最外圈 +*/ + +class Solution { +private: + int dx[4] = {-1, 1, 0, 0}; + int dy[4] = { 0, 0,-1, 1}; +public: + void solve(vector>& board) { + if ( board.size() == 0 ) return ; + + int rows = board.size(); + int cols = board[0].size(); + + DSU dsu; + dsu.makeSet( rows * cols + 1); + int dummy = rows * cols; //虚拟节点作为边界0的父节点 + for (int i = 0; i < rows; i++){ + for (int j = 0; j < cols; j++){ + if ( board[i][j] == 'O'){ + //边界 + if ( i == 0 || i == rows - 1 || j == 0 || j == cols - 1){ + dsu.unionSet( node(i,j,cols), dummy ); + } else{ + //无需边界检查 + for (int k = 0; k < 4; k++){ + int nx = i + dx[k]; + int ny = j + dy[k]; + if (board[nx][ny] == 'O'){ + dsu.unionSet(node(nx, ny, cols), node(i,j,cols)); + } + } + } + } + } + } + for (int i = 0; i < rows; i++){ + for (int j = 0; j < cols; j++){ + if ( board[i][j] == 'O' && dsu.parent(node(i,j,cols)) != dsu.parent(dummy)){ + board[i][j] = 'X'; + } + //以下是错的 + // if ( dsu.parent(node(i,j,cols)) == dsu.parent(dummy)){ + // board[i][j] = 'O'; + // } else{ + // board[i][j] = 'X'; + // } + } + } + + } + + int node(int i, int j, int cols){ + return i * cols + j; + } +}; diff --git a/Week_06/G20200343030533/LeetCode_200_533.cpp b/Week_06/G20200343030533/LeetCode_200_533.cpp new file mode 100644 index 00000000..68c704f5 --- /dev/null +++ b/Week_06/G20200343030533/LeetCode_200_533.cpp @@ -0,0 +1,64 @@ +#include + +using namespace std; + +struct DSU{ + vector data; + + void makeSet(int n){ + data.resize(n); + for (int i = 0; i < n; i++) data[i] = i; + }; + + bool unionSet(int i, int j){ + int p1 = parent(i); + int p2 = parent(j); + if ( p1 != p2 ){ + data[p1] = p2; + } + return p1 != p2; + + }; + + int parent(int i){ + int root = i; + while ( data[root] != root){ + root = data[root]; + } + return root; + + }; +}; + +class Solution { +public: + int numIslands(vector>& grid) { + if (grid.size() == 0 ) return 0; + + int m = grid.size(); + int n = grid[0].size(); + int ans = 0; + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++){ + if (grid[i][j] == '1') ans++; + } + } + DSU dsu; + dsu.makeSet( m * n); + for (int i = 0 ; i < m ; i++){ + for ( int j = 0; j < n ; j++){ + //检查当前元素和上一个元素 + if ( i > 0 && grid[i][j] == '1' && grid[i-1][j] == '1'){ + ans -= dsu.unionSet(i*n +j, (i-1)*n+j); + } + //检查当前元素和左边元素 + if ( j > 0 && grid[i][j] == '1' && grid[i][j-1] == '1'){ + ans -= dsu.unionSet(i*n +j, i*n+j-1); + } + + } + } + return ans; + + } +};; \ No newline at end of file diff --git a/Week_06/G20200343030533/LeetCode_208_533.c b/Week_06/G20200343030533/LeetCode_208_533.c new file mode 100644 index 00000000..39ebd45f --- /dev/null +++ b/Week_06/G20200343030533/LeetCode_208_533.c @@ -0,0 +1,76 @@ +#include +#include +#include +#include + +#define MAX_CHILD 26 + + +typedef struct trie{ + int isEnd; + struct trie* next[MAX_CHILD]; + +} Trie; + +/** Initialize your data structure here. */ + +Trie* trieCreate() { + Trie *root; + root = (Trie *)malloc(sizeof(Trie) * 1 ); + memset(root, 0, sizeof(*root)); //不是root, 是*root + return root; +} + +/** Inserts a word into the trie. */ +void trieInsert(Trie* obj, char * word) { + Trie *node = obj; + + for (int i = 0; word[i] != '\0'; i++) { + char c = word[i]; + if ( node->next[c-'a'] == NULL){ + node->next[c-'a'] = trieCreate(); + } + node = node->next[c-'a']; + } + node->isEnd = 1; +} + +/** Returns if the word is in the trie. */ +bool trieSearch(Trie* obj, char * word) { + Trie *node = obj; + for (int i = 0; word[i] != '\0'; i++){ + char c = word[i]; + if ( node->next[c-'a'] == NULL){ + return false; + } + node = node->next[c-'a']; + } + return node->isEnd > 0; + +} + +/** Returns if there is any word in the trie that starts with the given prefix. */ +bool trieStartsWith(Trie* obj, char * prefix) { + Trie *node = obj; + for (int i = 0; prefix[i] != '\0'; i++){ + char c = prefix[i]; + if ( node->next[c-'a'] == NULL){ + return false; + } + node = node->next[c-'a']; + } + return true; + +} + +//递归的方法 +void trieFree(Trie* obj) { + if (obj == NULL ) return; + for (int i = 0; i < MAX_CHILD; i++){ + if (obj->next[i]){ + trieFree(obj->next[i]); + } + } + free(obj); +} + diff --git a/Week_06/G20200343030533/LeetCode_208_533.cpp b/Week_06/G20200343030533/LeetCode_208_533.cpp new file mode 100644 index 00000000..b32a5e80 --- /dev/null +++ b/Week_06/G20200343030533/LeetCode_208_533.cpp @@ -0,0 +1,111 @@ +#include +#include +#include +#include + +using namespace std; + +//第一种实现方法: 基于class, 声明两个成员变量(isEnd和next), 每次都需要创建新的类。速度慢 +class Trie { +private: + bool isEnd; + Trie* next[26]; +public: + /** Initialize your data structure here. */ + Trie() { + isEnd=false; + memset(next, 0, sizeof(next)); + + } + + /** Inserts a word into the trie. */ + void insert(string word) { + Trie* node = this; + for ( char c : word){ + if (node->next[c-'a'] == NULL){ + node->next[c-'a'] = new Trie(); + } + node = node->next[c-'a']; + } + node->isEnd = true; + } + + /** Returns if the word is in the trie. */ + bool search(string word) { + Trie* node = this; + for ( char c : word){ + node = node->next[c-'a']; + if ( node == NULL){ + return false; + } + } + return node->isEnd; + } + + /** Returns if there is any word in the trie that starts with the given prefix. */ + bool startsWith(string prefix) { + Trie* node = this; + for ( char c : prefix){ + node = node->next[c-'a']; + if ( node == NULL){ + return false; + } + } + return true; + } +}; + +// 第二种方法: 和方法一,整体相同,只不过通过结构体定义Node, 执行速度快 +class Trie { + //定义每个节点的结构 + struct Node{ + int isEnd; + Node *next[26] ={NULL}; + Node(int val) { isEnd = val;}; + }; +private: + Node* root; +public: + /** Initialize your data structure here. */ + Trie() { + root = new Node(0); + } + + /** Inserts a word into the trie. */ + void insert(string word) { + Node *node = root; + for ( char c : word){ + if ( node->next[c-'a'] == NULL){ + node->next[c-'a'] = new Node(0); + } + node = node->next[c-'a']; + } + node->isEnd = 1; + } + + /** Returns if the word is in the trie. */ + bool search(string word) { + Node *node = root; + for ( char c : word){ + if ( node->next[c-'a'] == NULL){ + return false; + } + node = node->next[c-'a']; + } + return node->isEnd > 0; + + } + + /** Returns if there is any word in the trie that starts with the given prefix. */ + bool startsWith(string prefix) { + Node *node = root; + for ( char c : prefix){ + if ( node->next[c-'a'] == NULL){ + return false; + } + node = node->next[c-'a']; + } + return true; + + } +}; diff --git a/Week_06/G20200343030533/LeetCode_547_533.cpp b/Week_06/G20200343030533/LeetCode_547_533.cpp new file mode 100644 index 00000000..2f642c60 --- /dev/null +++ b/Week_06/G20200343030533/LeetCode_547_533.cpp @@ -0,0 +1,88 @@ +#include + +using namespace std; + +/* +并查集的两种实现思想: + +方案1: 将值初始化为-1, 大于0则表示指向另一个组织者 + +方法2: 将值初始化为索引,如果值不等于索引,说明指向另外的组织者 + +*/ + + +struct DSU{ + //init, -1 表示独立, 不为0 记录的是group leader + std::vector data; + void makeSet(int n) { data.assign(n, -1 );} + //union + bool unionSet(int x, int y){ + x = root(x); + y = root(y); + if ( x != y){ + if (data[y] < data[x]){ + std::swap(x,y); + } + data[x] += data[y]; //越负,圈子人越多 + data[y] = x; + } + return x !=y ; + } + + bool same(int x, int y) { return root(x) == root(y); } + + //递归, 查找group leader + int root(int x) { + return data[x] < 0 ? x : data[x] = root(data[x]); + } + + int size( int x) { return -data[root(x)];} +}; + +struct DSU2{ + std::vector data; + void makeSet(int n){ + data.resize(n); + for (int i = 0 ; i < n; i++) data[i] = i; + } + bool unionSet(int i, int j){ + int p1 = parent(i); + int p2 = parent(j); + if ( p1 != p2){ + data[p1] = p2; + } + return p1 != p2; + + } + + int parent(int i){ + int root = i; + while ( data[root] != root){ + root = data[root]; + } + //路径压缩 + while ( data[i] != i){ + int x = i; + i = data[i]; + data[x] = root; + } + return root; + } +}; + +class Solution { +public: + int findCircleNum(vector>& M) { + int ans = M.size(); + DSU2 dsu; + dsu.makeSet(M.size()); + for (size_t i = 0; i < M.size(); i++){ + for (size_t j = i+1; j < M.size(); j++){ + if (M[i][j] == 0 ) continue; + ans -= dsu.unionSet(i,j); + } + } + return ans; + } +}; diff --git "a/Week_06/G20200343030537/212.\345\215\225\350\257\215\346\220\234\347\264\242-ii.py" "b/Week_06/G20200343030537/212.\345\215\225\350\257\215\346\220\234\347\264\242-ii.py" new file mode 100644 index 00000000..a6be6e47 --- /dev/null +++ "b/Week_06/G20200343030537/212.\345\215\225\350\257\215\346\220\234\347\264\242-ii.py" @@ -0,0 +1,35 @@ +# +# @lc app=leetcode.cn id=212 lang=python3 +# +# [212] 单词搜索 II +# + +# @lc code=start +class Solution: + def findWords(self, board: List[List[str]], words: List[str]) -> List[str]: + trie = {} # 构造字典树 + for word in words: + node = trie + for char in word: + node = node.setdefault(char, {}) + node['#'] = True + + def search(i, j, node, pre, visited): # (i,j)当前坐标,node当前trie树结点,pre前面的字符串,visited已访问坐标 + if '#' in node: # 已有字典树结束 + res.add(pre) # 添加答案 + for (di, dj) in ((-1, 0), (1, 0), (0, -1), (0, 1)): + _i, _j = i+di, j+dj + if -1 < _i < h and -1 < _j < w and board[_i][_j] in node and (_i, _j) not in visited: # 可继续搜索 + search(_i, _j, node[board[_i][_j]], pre+board[_i][_j], visited | {(_i, _j)}) # dfs搜索 + + res, h, w = set(), len(board), len(board[0]) + for i in range(h): + for j in range(w): + if board[i][j] in trie: # 可继续搜索 + search(i, j, trie[board[i][j]], board[i][j], {(i, j)}) # dfs搜索 + return list(res) + + + +# @lc code=end + diff --git "a/Week_06/G20200343030537/51.n\347\232\207\345\220\216.py" "b/Week_06/G20200343030537/51.n\347\232\207\345\220\216.py" new file mode 100644 index 00000000..c476ce26 --- /dev/null +++ "b/Week_06/G20200343030537/51.n\347\232\207\345\220\216.py" @@ -0,0 +1,49 @@ +# +# @lc app=leetcode.cn id=51 lang=python3 +# +# [51] N皇后 +# + +# @lc code=start +class Solution: + def solveNQueens(self, n: int) -> List[List[str]]: + def could_place(row, col): + return not (cols[col] + hill_diagonals[row - col] + dale_diagonals[row + col]) + + def place_queen(row, col): + queens.add((row, col)) + cols[col] = 1 + hill_diagonals[row - col] = 1 + dale_diagonals[row + col] = 1 + + def remove_queen(row, col): + queens.remove((row, col)) + cols[col] = 0 + hill_diagonals[row - col] = 0 + dale_diagonals[row + col] = 0 + + def add_solution(): + solution = [] + for _, col in sorted(queens): + solution.append('.' * col + 'Q' + '.' * (n - col - 1)) + output.append(solution) + + def backtrack(row = 0): + for col in range(n): + if could_place(row, col): + place_queen(row, col) + if row + 1 == n: + add_solution() + else: + backtrack(row + 1) + remove_queen(row, col) + + cols = [0] * n + hill_diagonals = [0] * (2 * n - 1) + dale_diagonals = [0] * (2 * n - 1) + queens = set() + output = [] + backtrack() + return output +# @lc code=end + diff --git a/Week_06/G20200343030543/LeetCode_127_543.java b/Week_06/G20200343030543/LeetCode_127_543.java new file mode 100644 index 00000000..b3e56acc --- /dev/null +++ b/Week_06/G20200343030543/LeetCode_127_543.java @@ -0,0 +1,85 @@ +import javafx.util.Pair; + +class Solution { + + private int L; + private HashMap> allComboDict; + + Solution() { + this.L = 0; + this.allComboDict = new HashMap>(); + } + + private int visitWordNode( + Queue> Q, + HashMap visited, + HashMap othersVisited) { + Pair node = Q.remove(); + String word = node.getKey(); + int level = node.getValue(); + + for (int i = 0; i < this.L; i++) { + + String newWord = word.substring(0, i) + '*' + word.substring(i + 1, L); + + for (String adjacentWord : this.allComboDict.getOrDefault(newWord, new ArrayList())) { + if (othersVisited.containsKey(adjacentWord)) { + return level + othersVisited.get(adjacentWord); + } + + if (!visited.containsKey(adjacentWord)) { + + visited.put(adjacentWord, level + 1); + Q.add(new Pair(adjacentWord, level + 1)); + } + } + } + return -1; + } + + public int ladderLength(String beginWord, String endWord, List wordList) { + + if (!wordList.contains(endWord)) { + return 0; + } + this.L = beginWord.length(); + + wordList.forEach( + word -> { + for (int i = 0; i < L; i++) { + String newWord = word.substring(0, i) + '*' + word.substring(i + 1, L); + ArrayList transformations = + this.allComboDict.getOrDefault(newWord, new ArrayList()); + transformations.add(word); + this.allComboDict.put(newWord, transformations); + } + }); + + Queue> Q_begin = new LinkedList>(); + Queue> Q_end = new LinkedList>(); + Q_begin.add(new Pair(beginWord, 1)); + Q_end.add(new Pair(endWord, 1)); + + HashMap visitedBegin = new HashMap(); + HashMap visitedEnd = new HashMap(); + visitedBegin.put(beginWord, 1); + visitedEnd.put(endWord, 1); + + while (!Q_begin.isEmpty() && !Q_end.isEmpty()) { + + // One hop from begin word + int ans = visitWordNode(Q_begin, visitedBegin, visitedEnd); + if (ans > -1) { + return ans; + } + + // One hop from end word + ans = visitWordNode(Q_end, visitedEnd, visitedBegin); + if (ans > -1) { + return ans; + } + } + + return 0; + } +} \ No newline at end of file diff --git a/Week_06/G20200343030543/LeetCode_212_543.java b/Week_06/G20200343030543/LeetCode_212_543.java new file mode 100644 index 00000000..4e92234c --- /dev/null +++ b/Week_06/G20200343030543/LeetCode_212_543.java @@ -0,0 +1,81 @@ +class TrieNode { + public TrieNode[] children; + public String word; + + public TrieNode() { + children = new TrieNode[26]; + word = null; + for (int i = 0; i < 26; i++) { + children[i] = null; + } + } +} +class Trie { + TrieNode root; + public Trie() { + root = new TrieNode(); + } + + public void insert(String word) { + char[] array = word.toCharArray(); + TrieNode cur = root; + for (int i = 0; i < array.length; i++) { + // 当前孩子是否存在 + if (cur.children[array[i] - 'a'] == null) { + cur.children[array[i] - 'a'] = new TrieNode(); + } + cur = cur.children[array[i] - 'a']; + } + cur.word = word; + } +}; + +class Solution { + public List findWords(char[][] board, String[] words) { + Trie trie = new Trie(); + //将所有单词存入前缀树中 + List res = new ArrayList<>(); + for (String word : words) { + trie.insert(word); + } + int rows = board.length; + if (rows == 0) { + return res; + } + int cols = board[0].length; + //从每个位置开始遍历 + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + existRecursive(board, i, j, trie.root, res); + } + } + return res; + } + + private void existRecursive(char[][] board, int row, int col, TrieNode node, List res) { + if (row < 0 || row >= board.length || col < 0 || col >= board[0].length) { + return; + } + char cur = board[row][col];//将要遍历的字母 + //当前节点遍历过或者将要遍历的字母在前缀树中不存在 + if (cur == '$' || node.children[cur - 'a'] == null) { + return; + } + node = node.children[cur - 'a']; + //判断当前节点是否是一个单词的结束 + if (node.word != null) { + //加入到结果中 + res.add(node.word); + //将当前单词置为 null,防止重复加入 + node.word = null; + } + char temp = board[row][col]; + //上下左右去遍历 + board[row][col] = '$'; + existRecursive(board, row - 1, col, node, res); + existRecursive(board, row + 1, col, node, res); + existRecursive(board, row, col - 1, node, res); + existRecursive(board, row, col + 1, node, res); + board[row][col] = temp; + } +} diff --git a/Week_06/G20200343030545/LeetCode_102_545.py b/Week_06/G20200343030545/LeetCode_102_545.py new file mode 100644 index 00000000..ee33ac78 --- /dev/null +++ b/Week_06/G20200343030545/LeetCode_102_545.py @@ -0,0 +1,75 @@ +""" +给定一个二叉树,返回其按层次遍历的节点值。 (即逐层地,从左到右访问所有节点)。 + +例如: +给定二叉树: [3,9,20,null,null,15,7], + + 3 + / \ + 9 20 + / \ + 15 7 +返回其层次遍历结果: + +[ + [3], + [9,20], + [15,7] +] +""" +from typing import List + + +class TreeNode: + def __init__(self, x): + self.val = x + self.left = None + self.right = None + + +class Solution: + def levelOrder(self, root: TreeNode) -> List[List[int]]: + """ + 二叉树的层次遍历 + """ + return self.dfs(root) + + @classmethod + def bfs(cls, root: TreeNode) -> List[List[int]]: + """ + 广度优先 + """ + queue = [root] + res = [] + while queue: + tmp_res = [] + tmp_queue = [] + for node in queue: + if node: + tmp_res.append(node.val) + if node.left: + tmp_queue.append(node.left) + if node.right: + tmp_queue.append(node.right) + queue = tmp_queue + if tmp_res: + res.append(tmp_res) + return res + + @classmethod + def dfs(cls, root: TreeNode) -> List[List[int]]: + + def helper(node: TreeNode, level: int): + if node: + if level == len(res): + res.append([]) + res[level].append(node.val) + + if node.left: + helper(node.left, level + 1) + if node.right: + helper(node.right, level + 1) + + res = [] + helper(root, 0) + return res diff --git a/Week_06/G20200343030545/LeetCode_127_545.py b/Week_06/G20200343030545/LeetCode_127_545.py new file mode 100644 index 00000000..7e735967 --- /dev/null +++ b/Week_06/G20200343030545/LeetCode_127_545.py @@ -0,0 +1,107 @@ +""" + 给定两个单词(beginWord 和 endWord)和一个字典,找到从 beginWord 到 endWord 的最短转换序列的长度。转换需遵循如下规则: + 每次转换只能改变一个字母。 + 转换过程中的中间单词必须是字典中的单词。 + + 说明: + 如果不存在这样的转换序列,返回 0。 + 所有单词具有相同的长度。 + 所有单词只由小写字母组成。 + 字典中不存在重复的单词。 + 你可以假设 beginWord 和 endWord 是非空的,且二者不相同。 + + 示例 1: + 输入: + beginWord = "hit", + endWord = "cog", + wordList = ["hot","dot","dog","lot","log","cog"] + 输出: 5 + 解释: 一个最短转换序列是 "hit" -> "hot" -> "dot" -> "dog" -> "cog", + 返回它的长度 5。 + + 示例 2: + 输入: + beginWord = "hit" + endWord = "cog" + wordList = ["hot","dot","dog","lot","log"] + 输出: 0 + + 解释: endWord "cog" 不在字典中,所以无法进行转换。 +""" +from typing import List + + +class Solution: + def ladderLength(self, beginWord: str, endWord: str, wordList: List[str]) -> int: + return self.two_end_bfs(beginWord, endWord, wordList) + + @classmethod + def two_end_bfs(cls, begin_word, end_word, word_list: List[str]) -> int: + if begin_word and end_word and end_word in word_list: + word_dict = dict() + begin_word_len = len(begin_word) + + for word in word_list: + for i in range(begin_word_len): + key = word[:i] + "*" + word[i + 1:] + word_dict[key] = word_dict.get(key, []) + [word] + + begin_word_queue = [begin_word] + end_word_queue = [end_word] + visited = set() + + res = 1 + while begin_word_queue: + tmp_queue = [] + res += 1 + for tmp_word in begin_word_queue: + for i in range(begin_word_len): + like_word = tmp_word[:i] + "*" + tmp_word[i + 1:] + for check_word in word_dict.get(like_word, []): + if check_word in end_word_queue: + return res + if check_word not in visited: + visited.add(check_word) + tmp_queue.append(check_word) + begin_word_queue = tmp_queue + + if len(begin_word_queue) > len(end_word_queue): + begin_word_queue, end_word_queue = end_word_queue, begin_word_queue + return 0 + + @classmethod + def bfs(cls, begin_word: str, end_word: str, word_list: List[str]) -> int: + if end_word and end_word in word_list: + word_dict = dict() + begin_word_len = len(begin_word) + for word in word_list: + for i in range(begin_word_len): + key = word[:i] + "*" + word[i + 1:] + word_dict[key] = word_dict.get(key, []) + [word] + + # bfs + queue = [begin_word] + visit = {} + + res = 1 # z这里求的是最短路径 包括开始给的begin_word,所以初始res=1 + while queue: + res += 1 + tmp_queue = [] + for tmp_word in queue: + for i in range(begin_word_len): + like_word = tmp_word[:i] + "*" + tmp_word[i + 1:] + for check_word in word_dict.get(like_word, []): + if check_word == end_word: + return res + if check_word not in visit: + visit[check_word] = True + tmp_queue.append(check_word) + queue = tmp_queue + return 0 + + +if __name__ == '__main__': + b = "hit" + e = "cog" + w = ["hot", "dot", "dog", "lot", "log", "cog"] + print(Solution.bfs(b, e, w)) diff --git a/Week_06/G20200343030545/LeetCode_130_545.py b/Week_06/G20200343030545/LeetCode_130_545.py new file mode 100644 index 00000000..0e64369a --- /dev/null +++ b/Week_06/G20200343030545/LeetCode_130_545.py @@ -0,0 +1,72 @@ +""" + 给定一个二维的矩阵,包含 'X' 和 'O'(字母 O)。 + 找到所有被 'X' 围绕的区域,并将这些区域里所有的 'O' 用 'X' 填充。 + + 示例: + + X X X X + X O O X + X X O X + X O X X + + 运行你的函数后,矩阵变为: + X X X X + X X X X + X X X X + X O X X + + 解释: + 被围绕的区间不会存在于边界上,换句话说,任何边界上的 'O' 都不会被填充为 'X'。 + 任何不在边界上,或不与边界上的 'O' 相连的 'O' 最终都会被填充为 'X'。 + 如果两个元素在水平或垂直方向相邻,则称它们是“相连”的。 +""" +from typing import List + + +class Solution: + DIRECTION = ((1, 0), (-1, 0), (0, 1), (0, -1)) + + def solve(self, board: List[List[str]]) -> None: + """ + Do not return anything, modify board in-place instead. + """ + return self.dfs(board) + + def dfs(self, board: List[List[str]]) -> None: + row_len = len(board) + col_len = len(board[0]) if row_len else 0 + + def helper(row_index, col_index): + board[row_index][col_index] = "B" + for tmp_row_index, tmp_col_index in self.DIRECTION: + new_row_index = tmp_row_index + row_index + new_col_index = tmp_col_index + col_index + if 1 <= new_row_index < row_len and 1 <= new_col_index < col_len and board[new_row_index][ + new_col_index] == "O": + helper(new_row_index, new_col_index) + + # 按行来处理 + for i in range(row_len): + # 第一列 + if board[i][0] == "O": + helper(i, 0) + + # 最后一列 + if board[i][col_len - 1] == "O": + helper(i, col_len - 1) + + # 按列来处理 + for j in range(col_len): + # 第一行 + if board[0][j] == "O": + helper(0, j) + # 最后一行 + if board[row_len - 1][j] == "0": + helper(row_len - 1, j) + + for i in range(row_len): + for j in range(col_len): + if board[i][j] == "O": + board[i][j] = "X" + if board[i][j] == "B": + board[i][j] = "O" diff --git a/Week_06/G20200343030545/LeetCode_200_545.py b/Week_06/G20200343030545/LeetCode_200_545.py new file mode 100644 index 00000000..b3b1dcbc --- /dev/null +++ b/Week_06/G20200343030545/LeetCode_200_545.py @@ -0,0 +1,132 @@ +""" + 给定一个由 '1'(陆地)和 '0'(水)组成的的二维网格,计算岛屿的数量。 + 一个岛被水包围,并且它是通过水平方向或垂直方向上相邻的陆地连接而成的。你可以假设网格的四个边均被水包围。 + + 示例 1: + 输入: + 11110 + 11010 + 11000 + 00000 + 输出: 1 + + 示例 2: + 输入: + 11000 + 11000 + 00100 + 00011 + 输出: 3 +""" + +from typing import List + + +class Solution: + def numIslands(self, grid: List[List[str]]) -> int: + return self.dis_join_set(grid) + + @classmethod + def dis_join_set(cls, grid: List[List[str]]) -> int: + """ + 并查集 + """ + row_len = len(grid) + col_len = len(grid[0]) if row_len else 0 + count = sum([grid[i][j] == '1' for j in range(col_len) for i in range(row_len)]) + parent = [i for i in range(row_len * col_len)] + + def union(p, e1, e2): + p1 = find(p, e1) + p2 = find(p, e2) + if p1 == p2: + return + p[p1] = p2 + nonlocal count + count -= 1 + + def find(p, e): + while e != p[e]: + e = p[e] + return p[e] + + for i in range(row_len): + for j in range(col_len): + if grid[i][j] == "0": + continue + index = i * col_len + j + if j < col_len - 1 and grid[i][j + 1] == "1": + union(parent, index, index + 1) + if i < row_len - 1 and grid[i + 1][j] == "1": + union(parent, index, index + col_len) + return count + + @classmethod + def bfs(cls, grid: List[List[str]]) -> int: + """ + 广度优先遍历 + 一层一层遍历,没从遍历每个元素时,判断其四个方向的元素 + 时间复杂度:O(M*N) + 空间负载度:O(min(M,N)) + """ + ret = 0 + if grid: + m = len(grid) + n = len(grid[0]) + + for i in range(m): + for j in range(n): + if grid[i][j] == "1": + ret += 1 + grid[i][j] = "0" + queue = [(i, j)] + while queue: + cur_i, cur_j = queue.pop() + + for tmp_i, tmp_j in ((1, 0), (-1, 0), (0, -1), (0, 1)): + new_i = tmp_i + cur_i + new_j = tmp_j + cur_j + + if 0 <= new_i < m and 0 <= new_j < n and grid[new_i][new_j] == "1": + grid[new_i][new_j] = "0" + queue.append((new_i, new_j)) + return ret + + @classmethod + def dfs(cls, grid: List[List[str]]) -> int: + """ + 深度优先遍历 + 时间复杂度:O(M*N) M为行数 N为列数 + 空间复杂度:O(M*N) + + 思路 + 1)从下标0,0开始出发,如果对应的元素内容是1, 则深度优先遍历 判断其相邻的节点,相邻相邻的节点,相邻相邻.....然后回溯。 + 2)如果现在判断的下标元素所在的节点是1,则把其置为0 + 3)第一步每次开始发起深度优先遍历时,则对应的岛屿的数量+1 + """ + + def helper(grid_: List[List[str]], row_index, col_index): + row_len = len(grid) + col_len = len(grid[0]) + # terminator + if 0 <= row_index < row_len and 0 <= col_index < col_len and grid_[row_index][col_index] == "1": + # process + grid_[row_index][col_index] = "0" + + for tmp_row_index, tmp_col_index in ((1, 0), (-1, 0), (0, 1), (0, -1)): + new_row_index = row_index + tmp_row_index + new_col_index = col_index + tmp_col_index + # drill down + helper(grid, new_row_index, new_col_index) + + ret = 0 + if grid: + m = len(grid) + n = len(grid[0]) + for i in range(m): + for j in range(n): + if grid[i][j] == "1": + helper(grid, i, j) + ret += 1 + + return ret diff --git a/Week_06/G20200343030545/LeetCode_208_545.py b/Week_06/G20200343030545/LeetCode_208_545.py new file mode 100644 index 00000000..44a1eab9 --- /dev/null +++ b/Week_06/G20200343030545/LeetCode_208_545.py @@ -0,0 +1,58 @@ +""" + 实现一个 Trie (前缀树),包含 insert, search, 和 startsWith 这三个操作。 + + 示例: + Trie trie = new Trie(); + + trie.insert("apple"); + trie.search("apple"); // 返回 true + trie.search("app"); // 返回 false + trie.startsWith("app"); // 返回 true + trie.insert("app"); + trie.search("app"); // 返回 true + + 说明: + 你可以假设所有的输入都是由小写字母 a-z 构成的。 + 保证所有输入均为非空字符串。 +""" + + +class Trie: + + def __init__(self): + """ + Initialize your data structure here. + """ + self.root = {} + self._end_flag = "#" + + def insert(self, word: str) -> None: + """ + Inserts a word into the trie. + """ + node = self.root + for char in word: + node = node.setdefault(char, {}) + node[self._end_flag] = self._end_flag + + def search(self, word: str) -> bool: + """ + Returns if the word is in the trie. + """ + node = self.root + for char in word: + if char not in node: + return False + node = node[char] + return self._end_flag in node + + def startsWith(self, prefix: str) -> bool: + """ + Returns if there is any word in the trie that starts with the given prefix. + """ + node = self.root + for char in prefix: + if char not in node: + return False + node = node[char] + return True diff --git a/Week_06/G20200343030545/LeetCode_212_545.py b/Week_06/G20200343030545/LeetCode_212_545.py new file mode 100644 index 00000000..07b5e09d --- /dev/null +++ b/Week_06/G20200343030545/LeetCode_212_545.py @@ -0,0 +1,82 @@ +""" + 给定一个二维网格 board 和一个字典中的单词列表 words,找出所有同时在二维网格和字典中出现的单词。 + 单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。 + 同一个单元格内的字母在一个单词中不允许被重复使用。 + + 示例: + + 输入: + words = ["oath","pea","eat","rain"] and board = + [ + ['o','a','a','n'], + ['e','t','a','e'], + ['i','h','k','r'], + ['i','f','l','v'] + ] + + 输出: ["eat","oath"] + 说明: + 你可以假设所有输入都由小写字母 a-z 组成。 + + 提示: + 你需要优化回溯算法以通过更大数据量的测试。你能否早点停止回溯? + 如果当前单词不存在于所有单词的前缀中,则可以立即停止回溯。 + 什么样的数据结构可以有效地执行这样的操作?散列表是否可行?为什么? + 前缀树如何?如果你想学习如何实现一个基本的前缀树,请先查看这个问题: 实现Trie(前缀树)。 +""" +from typing import List, Dict + + +class Solution: + TRIE_END_CHAR = "#" + DIRECTION_SET = ((1, 0), (-1, 0), (0, -1), (0, 1)) # 代表上下左右 + + def findWords(self, board: List[List[str]], words: List[str]) -> List[str]: + trie = self.build_trie(words) + + res = [] + for i in range(len(board)): + for j in range(len(board[0])): + self.dfs(board, trie, i, j, '', res) + return res + + @classmethod + def dfs(cls, board: List[List[str]], trie: Dict, i: int, j: int, s: str, res: List[str]): + char = board[i][j] + m = len(board) + n = len(board[0]) if m else 0 + if char not in trie: + return + + trie = trie[char] + s += char + if cls.TRIE_END_CHAR in trie: + res.append(s) + return + + board[i][j] = cls.TRIE_END_CHAR + + for tmp_i, tmp_j in cls.DIRECTION_SET: + new_i = tmp_i + i + new_j = tmp_j + j + + if 0 <= new_i < m and 0 <= new_j < n and board[new_i][new_j] != cls.TRIE_END_CHAR: + cls.dfs(board, trie, new_i, new_j, s, res) + + board[i][j] = char + + @classmethod + def build_trie(cls, words: List[str]): + root = {} + for word in words: + node = root + for char in word: + node = node.setdefault(char, {}) + node[cls.TRIE_END_CHAR] = cls.TRIE_END_CHAR + return root + + +if __name__ == '__main__': + b = [["o", "a", "a", "n"], ["e", "t", "a", "e"], ["i", "h", "k", "r"], ["i", "f", "l", "v"]] + w = ["oath", "pea", "eat", "rain"] + print(Solution().findWords(b, w)) diff --git a/Week_06/G20200343030545/LeetCode_22_545.py b/Week_06/G20200343030545/LeetCode_22_545.py new file mode 100644 index 00000000..47553067 --- /dev/null +++ b/Week_06/G20200343030545/LeetCode_22_545.py @@ -0,0 +1,65 @@ +""" + 给出 n 代表生成括号的对数,请你写出一个函数,使其能够生成所有可能的并且有效的括号组合。 + 例如,给出 n = 3,生成结果为: + + [ + "((()))", + "(()())", + "(())()", + "()(())", + "()()()" + ] +""" + +from typing import List + + +class Solution: + def generateParenthesis(self, n: int) -> List[str]: + return self.dp(n) + + @classmethod + def dfs(cls, n: int) -> List[str]: + + def helper(left_index: int, right_index: int, need_n: int, tmp_str: str, tmp_res: List[str]) -> None: + # terminator + if left_index == right_index == need_n: + tmp_res.append(tmp_str) + return + # process + if left_index < n: + # drill down + helper(left_index + 1, right_index, need_n, tmp_str + "(", tmp_res) + if right_index < left_index: + # drill down + helper(left_index, right_index + 1, need_n, tmp_str + ")", tmp_res) + + res = [] + helper(0, 0, n, "", res) + return res + + @classmethod + def dp(cls, n: int) -> List[str]: + """ + #TODO 没有理解 先过编数 + + dp[i] 表示 使用 i 对括号能够生成的组合 + 状态转移方程: + dp[i] = "(" + dp[j] + ")" + dp[i- j - 1] , j = 0, 1, ..., i - 1 + """ + res = [] + if n: + dp = [[] for i in range(n + 1)] + dp[0] = [""] + + for i in range(1, n + 1): + cur = [] + for j in range(i): + left = dp[j] + right = dp[i - j - 1] + for s1 in left: + for s2 in right: + cur.append("(" + s1 + ")" + s2) + dp[i] = cur + res = dp[n] + return res diff --git a/Week_06/G20200343030545/LeetCode_36_545.py b/Week_06/G20200343030545/LeetCode_36_545.py new file mode 100644 index 00000000..e2edcc80 --- /dev/null +++ b/Week_06/G20200343030545/LeetCode_36_545.py @@ -0,0 +1,40 @@ +""" + 判断一个 9x9 的数独是否有效。只需要根据以下规则,验证已经填入的数字是否有效即可。 + 数字 1-9 在每一行只能出现一次。 + 数字 1-9 在每一列只能出现一次。 + 数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。 + 数独部分空格内已填入了数字,空白格用 '.' 表示。 +""" +from typing import List, Tuple, Dict + + +class Solution: + + def isValidSudoku(self, board: List[List[str]]) -> bool: + # 1、初始化数据 + rows, cols, box = self.init_data() + + # 2、循环遍历board 判断这对应上非.的数字是否合法 + for i in range(9): + for j in range(9): + num = board[i][j] + if num != ".": + box_index = self.get_box_index(i, j) + rows[i][num] = rows[i].get(num, 0) + 1 + cols[j][num] = cols[j].get(num, 0) + 1 + box[box_index][num] = box[box_index].get(num, 0) + 1 + + if rows[i][num] > 1 or cols[j][num] > 1 or box[box_index][num] > 1: + return False + return True + + @classmethod + def init_data(cls) -> Tuple[List[Dict], List[Dict], List[Dict]]: + rows = [{} for i in range(9)] + cols = [{} for i in range(9)] + box = [{} for i in range(9)] + return rows, cols, box + + @classmethod + def get_box_index(cls, row_index, col_index): + return (row_index // 3) * 3 + col_index // 3 diff --git a/Week_06/G20200343030545/LeetCode_433_545.py b/Week_06/G20200343030545/LeetCode_433_545.py new file mode 100644 index 00000000..15430743 --- /dev/null +++ b/Week_06/G20200343030545/LeetCode_433_545.py @@ -0,0 +1,110 @@ +""" + 一条基因序列由一个带有8个字符的字符串表示,其中每个字符都属于 "A", "C", "G", "T"中的任意一个。 + 假设我们要调查一个基因序列的变化。一次基因变化意味着这个基因序列中的一个字符发生了变化。 + 例如,基因序列由"AACCGGTT" 变化至 "AACCGGTA" 即发生了一次基因变化。 + 与此同时,每一次基因变化的结果,都需要是一个合法的基因串,即该结果属于一个基因库。 + + 现在给定3个参数 — start, end, bank,分别代表起始基因序列,目标基因序列及基因库, + 请找出能够使起始基因序列变化为目标基因序列所需的最少变化次数。如果无法实现目标变化,请返回 -1。 + + 注意: + 起始基因序列默认是合法的,但是它并不一定会出现在基因库中。 + 所有的目标基因序列必须是合法的。 + 假定起始基因序列与目标基因序列是不一样的。 + + 示例 1: + start: "AACCGGTT" + end: "AACCGGTA" + bank: ["AACCGGTA"] + 返回值: 1 + + 示例 2: + start: "AACCGGTT" + end: "AAACGGTA" + bank: ["AACCGGTA", "AACCGCTA", "AAACGGTA"] + 返回值: 2 + + 示例 3: + start: "AAAAACCC" + end: "AACCCCCC" + bank: ["AAAACCCC", "AAACCCCC", "AACCCCCC"] + 返回值: 3 +""" +from typing import List + + +class Solution: + MAPPING = { + "A": "GCT", + "G": "ACT", + "C": "AGT", + "T": "AGC", + } + + def minMutation(self, start: str, end: str, bank: List[str]) -> int: + return self.two_end_bfs(start, end, bank) + + @classmethod + def two_end_bfs(cls, start: str, end: str, bank: List[str]) -> int: + if end and end in bank: + start_len = len(start) + start_queue = [start] + end_queue = [end] + visit = {} + + res = 0 + while start_queue: + res += 1 + tmp_queue = [] + for tmp_info in start_queue: + for i in range(start_len): + for char in cls.MAPPING[tmp_info[i]]: + check_info = tmp_info[:i] + char + tmp_info[i + 1:] + + if check_info not in bank: + continue + + if check_info in end_queue: + return res + + if check_info not in visit: + visit[check_info] = True + tmp_queue.append(check_info) + start_queue = tmp_queue + if len(start_queue)> len(end_queue): + start_queue, end_queue = end_queue, start_queue + return -1 + + @classmethod + def bfs(cls, start: str, end: str, bank: List[str]) -> int: + if end and end in bank: + queue = [start] + start_len = len(start) + visit = {} + + res = 0 + while queue: + tmp_queue = [] + res += 1 + for cur_start in queue: + for i in range(start_len): + for tmp_char in cls.MAPPING[cur_start[i]]: + check_start = cur_start[:i] + tmp_char + cur_start[i + 1:] + if check_start not in bank: + continue + + if check_start == end: + return res + + if check_start not in visit: + visit[check_start] = 1 + tmp_queue.append(check_start) + queue = tmp_queue + return -1 + + +if __name__ == '__main__': + start = "AACCTTGG" + end = "AATTCCGG" + bank = ["AATTCCGG", "AACCTGGG", "AACCCCGG", "AACCTACC"] + print(Solution.bfs(start, end, bank)) diff --git a/Week_06/G20200343030545/LeetCode_51_545.py b/Week_06/G20200343030545/LeetCode_51_545.py new file mode 100644 index 00000000..83f8bf03 --- /dev/null +++ b/Week_06/G20200343030545/LeetCode_51_545.py @@ -0,0 +1,61 @@ +""" + n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。 + 上图为 8 皇后问题的一种解法。 + 给定一个整数 n,返回所有不同的 n 皇后问题的解决方案。 + 每一种解法包含一个明确的 n 皇后问题的棋子放置方案,该方案中 'Q' 和 '.' 分别代表了皇后和空位。 + 示例: + 输入: 4 + 输出: [ + [".Q..", // 解法 1 + "...Q", + "Q...", + "..Q."], + + ["..Q.", // 解法 2 + "Q...", + "...Q", + ".Q.."] + ] + 解释: 4 皇后问题存在两个不同的解法。 +""" + +from typing import List + + +class Solution: + def solveNQueens(self, n: int) -> List[List[str]]: + res = self.dfs(n) + return [["." * col + "Q" + "." * (n - col - 1) for col in row] for row in res] + + @classmethod + def dfs(cls, n: int) -> List[List[int]]: + def helper(queue: List[int], xy_diff: List[int], xy_sum: List[int], check_n: int, tmp_res: List[List[int]]): + # terminator + if len(queue) == check_n: + tmp_res.append(queue[:]) + return + + # process + row = len(queue) + for col in range(n): + if col not in queue and row - col not in xy_diff and row + col not in xy_sum: + queue.append(col) + xy_diff.append(row - col) + xy_sum.append(row + col) + + # drill down + helper(queue, xy_diff, xy_sum, check_n, tmp_res) + + # reverse state + queue.pop(-1) + xy_diff.pop(-1) + xy_sum.pop(-1) + + res = [] + helper([], [], [], n, res) + + return res + + +if __name__ == '__main__': + print(Solution().solveNQueens(4)) diff --git a/Week_06/G20200343030545/LeetCode_547_545.py b/Week_06/G20200343030545/LeetCode_547_545.py new file mode 100644 index 00000000..67255e92 --- /dev/null +++ b/Week_06/G20200343030545/LeetCode_547_545.py @@ -0,0 +1,104 @@ +""" + 班上有 N 名学生。其中有些人是朋友,有些则不是。他们的友谊具有是传递性。 + 如果已知 A 是 B 的朋友,B 是 C 的朋友,那么我们可以认为 A 也是 C 的朋友。所谓的朋友圈,是指所有朋友的集合。 + + 给定一个 N * N 的矩阵 M,表示班级中学生之间的朋友关系。 + 如果M[i][j] = 1,表示已知第 i 个和 j 个学生互为朋友关系,否则为不知道。你必须输出所有学生中的已知的朋友圈总数。 + + 示例 1: + 输入: + [[1,1,0], + [1,1,0], + [0,0,1]] + 输出: 2 + 说明:已知学生0和学生1互为朋友,他们在一个朋友圈。 + 第2个学生自己在一个朋友圈。所以返回2。 + + 示例 2: + 输入: + [[1,1,0], + [1,1,1], + [0,1,1]] + 输出: 1 + 说明:已知学生0和学生1互为朋友,学生1和学生2互为朋友,所以学生0和学生2也是朋友,所以他们三个在一个朋友圈,返回1。 + 注意: + + N 在[1,200]的范围内。 + 对于所有学生,有M[i][i] = 1。 + 如果有M[i][j] = 1,则有M[j][i] = 1。 +""" + +from typing import List + + +class Solution: + DIRECTION = ((1, 0), (-1, 0), (0, 1), (0, -1)) + + def findCircleNum(self, M: List[List[int]]) -> int: + return self.dis_join_set(M) + + @classmethod + def dis_join_set(cls, M: List[List[int]]) -> int: + def union(p, i1, i2): + r1 = find(p, i1) + r2 = find(p, i2) + p[r1] = r2 + + def find(p, i): + root = i + + while p[root] != root: + root = p[root] + + while p[i] != i: + x = i + i = p[i] + p[x] = root + return root + + p_list = [i for i in range(len(M))] + for i in range(len(M)): + for j in range(len(M[0])): + if M[i][j] == 1: + union(p_list, i, j) + return len(set([find(p_list, i) for i in range(len(M))])) + + @classmethod + def dfs(cls, M: List[List[int]]) -> int: + """ + 时间复杂度:O(n**2) + 空间复杂度:O(n) + """ + if not M: + return 0 + m = len(M) + visited = [False] * m + + def dfs(u): + for j in range(m): + if M[u][j] == 1 and visited[j] is False: + visited[j] = True + dfs(j) + + count = 0 + for i in range(m): + if visited[i] is False: + count += 1 + visited[i] = True + dfs(i) + return count + + @classmethod + def bfs(cls, M: List[List[int]]) -> int: + pass + + +if __name__ == '__main__': + print(Solution().findCircleNum( + [ + [1, 0, 0, 1], + [0, 1, 1, 0], + [0, 1, 1, 1], + [1, 0, 1, 1] + ] + )) diff --git a/Week_06/G20200343030545/LeetCode_70_545.py b/Week_06/G20200343030545/LeetCode_70_545.py new file mode 100644 index 00000000..ebd7311f --- /dev/null +++ b/Week_06/G20200343030545/LeetCode_70_545.py @@ -0,0 +1,42 @@ +""" + 假设你正在爬楼梯。需要 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 阶 +""" +from functools import lru_cache + + +class Solution: + def climbStairs(self, n: int) -> int: + return self.recursive(n) + + @classmethod + @lru_cache(None) + def recursive(cls, n: int) -> int: + # terminator + if n <= 0: + return 0 + if n < 3: + return n + + # process + + # drill down + return cls.recursive(n - 1) + cls.recursive(n - 2) + + # reverse_state diff --git a/Week_06/G20200343030545/LeetCode_79_545.py b/Week_06/G20200343030545/LeetCode_79_545.py new file mode 100644 index 00000000..c8eb2900 --- /dev/null +++ b/Week_06/G20200343030545/LeetCode_79_545.py @@ -0,0 +1,72 @@ +""" + 给定一个二维网格和一个单词,找出该单词是否存在于网格中。 + 单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。 + + 示例: + board = + [ + ['A','B','C','E'], + ['S','F','C','S'], + ['A','D','E','E'] + ] + + 给定 word = "ABCCED", 返回 true + 给定 word = "SEE", 返回 true + 给定 word = "ABCB", 返回 false + + + 提示: + board 和 word 中只包含大写和小写英文字母。 + 1 <= board.length <= 200 + 1 <= board[i].length <= 200 + 1 <= word.length <= 10^3 +""" + +from typing import List + + +class Solution: + + def exist(self, board: List[List[str]], word: str) -> bool: + + word_len = len(word) + for i in range(len(board)): + for j in range(len(board[0])): + if self.dfs(board, i, j, word, 0, word_len): + return True + return False + + @classmethod + def dfs(cls, board, i, j, word, index, word_len): + char = board[i][j] + + if index == word_len - 1: + return word[index] == char + + m = len(board) + n = len(board[0]) if board else 0 + board[i][j] = "#" + + if char == word[index]: + for tmp_i, tmp_j in ((1, 0), (-1, 0), (0, 1), (0, -1)): + new_i = tmp_i + i + new_j = tmp_j + j + if 0 <= new_i < m and 0 <= new_j < n and board[new_i][new_j] != "#" and cls.dfs(board, new_i, new_j, + word, index + 1, + word_len): + return True + board[i][j] = char + return False + + +if __name__ == '__main__': + print( + Solution().exist( + [ + ["A", "B", "C", "E"], + ["S", "F", "C", "S"], + ["A", "D", "E", "E"] + ], + "ASAD" + ) + ) diff --git a/Week_06/G20200343030545/NOTE.md b/Week_06/G20200343030545/NOTE.md index 50de3041..93fa6e00 100644 --- a/Week_06/G20200343030545/NOTE.md +++ b/Week_06/G20200343030545/NOTE.md @@ -1 +1,40 @@ -学习笔记 \ No newline at end of file +##字典树: +####基本概念: +```text字典树,trie树,又称单词树或者键树。典型的应用是用于统计和排序大量的字符串(但不限于字符串),所以经常被搜索引擎系统用于文本词频统计。``` + +####优点: ++ 1、最大限度的减少无谓的字符串比较。
++ 2、查询效率比哈希表高。 + +####基本性质: ++ 1、节点本身不存储完成单词。 ++ 2、从根节点到某一节点,路径上经过的字符串连接起来,为该节点对应的字符串。 ++ 3、每个节点的所有子节点路径代表的字符都不相同。 ++ 4、节点可以存储额外信息,比如出现的频次。 + +####核心思想: ++ 1、空间换时间。 ++ 2、利用字符串的公共前缀来降低查询目的。时间的开销以达到提高效率。 + +##并查集: +####解决的场景: ++ 1、组团或者配对。 +####基本操作: ++ 1、makeSet(s):建立一个新的并查集,其中包含s个单元素集合。 ++ 2、unionSet(x,y):把元素x和元素y所在的集合合并,要求x和y所在的集合不相交,如果相交则不合并。 ++ 3、find(x):找到元素x所在集合的代表,该操作也可以用于判断两个元素是否位于同一个集合,只要将它们各自的的代表比较一下即可。 + + +##高级搜索: + 相关:剪枝、双向BFS、启发式搜索 + + 初级搜索: + 1、朴素搜索 + 2、优化方式:不重复,剪枝。 + 3、搜索方向:DFS、BFS、双向BFS。 + +####AVL树和红黑树的区别: ++ 1、AVL树提供了更快的查询操作。 ++ 2、添加和删除操作红黑树更快。 ++ 3、 AVL需要存储更多的信息(平衡因子和高度)占用额外空间比红黑树多,红黑树只需要一位来表示当前节点是红还是黑。 ++ 4、 如果读操作多写操作少用AVL,如果插入或者更新操作多用红黑树。高级语言的库(Java Set Map)用的都是红黑树,database用的是AVL。 diff --git a/Week_06/G20200343030551/LeetCode_127_Word-Ladder_551.cpp b/Week_06/G20200343030551/LeetCode_127_Word-Ladder_551.cpp new file mode 100644 index 00000000..0de44e2f --- /dev/null +++ b/Week_06/G20200343030551/LeetCode_127_Word-Ladder_551.cpp @@ -0,0 +1,48 @@ +#include +#include +#include +#include +using namespace std; + +class Solution { +public: + int minMutation(string start, string end, vector& bank) { + + //记录所有需要访问的节点 + unordered_set candidate(bank.begin(), bank.end()); + //记录基因和step + queue> q; + + q.push({start, 0}); + + string gene; + int step; + + while( ! q.empty()) { + //终止条件 + if (q.front().first == end){ + return q.front().second; + } + + gene = q.front().first; + step = q.front().second; + q.pop(); + + for (int i = 0; i < gene.length(); i++){ + char tmp = gene[i]; //记录原状态 + for (char base : "ATCG"){ + if (gene[i] == base) continue; //相同就不变化 + gene[i] = base; //修改碱基 + if( candidate.find(gene) != candidate.end()){ + q.push({gene, step+1}); + candidate.erase(gene); + } + } + gene[i] = tmp; + + } + } + return -1; + + } +}; \ No newline at end of file diff --git a/Week_06/G20200343030551/LeetCode_208_implement-tire-prefix-tree_551.cpp b/Week_06/G20200343030551/LeetCode_208_implement-tire-prefix-tree_551.cpp new file mode 100644 index 00000000..46982953 --- /dev/null +++ b/Week_06/G20200343030551/LeetCode_208_implement-tire-prefix-tree_551.cpp @@ -0,0 +1,58 @@ +#include + +using namespace std; + +class Trie +{ +public: + /** Initialize your data structure here. */ + Trie() + { + isEnd = false; + for (int i = 0; i < 26; i++) + next[i] = NULL; + } + + /** Inserts a word into the trie. */ + void insert(string word) + { + Trie *root = this; + for (const auto &item:word) + { + if (root->next[item - 'a'] == NULL) + root->next[item - 'a'] = new Trie(); + root = root->next[item - 'a']; + } + root->isEnd = true; + } + + /** Returns if the word is in the trie. */ + bool search(string word) + { + Trie *root = this; + for (const auto &item:word) + { + if (root->next[item - 'a'] == NULL) + return false; + root = root->next[item - 'a']; + } + return root->isEnd; + } + + /** Returns if there is any word in the trie that starts with the given prefix. */ + bool startsWith(string prefix) + { + Trie *root = this; + for (const auto &item:prefix) + { + if (root->next[item - 'a'] == NULL) + return false; + root = root->next[item - 'a']; + } + return true; + } + +private: + bool isEnd; + Trie *next[26]; +}; diff --git a/Week_06/G20200343030551/LeetCode_212_Word-Search-II_551.cpp b/Week_06/G20200343030551/LeetCode_212_Word-Search-II_551.cpp new file mode 100644 index 00000000..fc79df3c --- /dev/null +++ b/Week_06/G20200343030551/LeetCode_212_Word-Search-II_551.cpp @@ -0,0 +1,82 @@ +#include +#include +#include + +using namespace std; + +class Trie +{ +public: + bool is_end; + Trie *next[26]; // 单词在a - z之间 + Trie() + { + is_end = false; + for (int i = 0; i < 26; ++i) next[i] =NULL; + } + + void insert(const string &word) + { + Trie *t = this; + for (auto i : word) + { + if (t->next[i - 'a'] == nullptr) t->next[i - 'a'] = new Trie(); + t = t->next[i - 'a']; + } + t->is_end = true; + } +}; + +class Solution +{ + Trie *root; + int row, col; + int dx[4] = {0, -1, 0, 1}, dy[4] = {1, 0, -1, 0}; + set aws; // 暂存遍历时的存在的单词,可能会有重复元素,去重用set + string temp; // 用来存储遍历时生成的中间字符串 + vector> vis; // 标记是否访问过 +public: + Solution() + { root = new Trie(); } + + void DFS(int i, int j, const vector> &board, const Trie *t) + { + char c = board[i][j]; + temp.push_back(c); + if (t->next[c - 'a'] == nullptr) + { + temp.pop_back(); + // 每次生成字符串时不能访问这次已经访问过的点,但是下一次开始时能访问与上一次重复的点,要重置vis + vis[i][j] = false; + return; + } + vis[i][j] = true; + if (t->next[c - 'a']->is_end == true) aws.insert(temp); // 组成前缀树中的一个单词 + for (int k = 0; k < 4; ++k) + { + int I = dx[k] + i, J = dy[k] + j; + if (I >= 0 && I < row && J >= 0 && J < col && vis[I][J] == false) + DFS(I, J, board, t->next[c - 'a']); + } + // 运行到这里重置vis和temp + vis[i][j] = false; + temp.pop_back(); + } + + vector findWords(vector> &board, vector &words) + { + for (auto s : words) root->insert(s); // 先将单词插入到前缀树中 + row = board.size(), col = board[0].size(); + vis.resize(row); + for (int i = 0; i < row; ++i) + { + vis[i].resize(col); + fill(vis[i].begin(), vis[i].end(), false); + } + for (int i = 0; i < row; ++i) // 对整个图DFS + for (int j = 0; j < col; ++j) + DFS(i, j, board, root); + vector ans(aws.begin(), aws.end()); // set转换为vector + return ans; + } +}; \ No newline at end of file diff --git a/Week_06/G20200343030551/LeetCode_36_Valid-Sudoku_551.cpp b/Week_06/G20200343030551/LeetCode_36_Valid-Sudoku_551.cpp new file mode 100644 index 00000000..466153c0 --- /dev/null +++ b/Week_06/G20200343030551/LeetCode_36_Valid-Sudoku_551.cpp @@ -0,0 +1,27 @@ +#include +#include +#include + +using namespace std; + +class Solution +{ +public: + bool isValidSudoku(vector> &board) + { + unordered_map row[9]; + unordered_map col[9]; + unordered_map sub[9]; + for (int i = 0; i < 9; i++) + { + for (int j = 0; j < 9; j++) + { + char temp = board[i][j]; + int sub_index = (i / 3) * 3 + j / 3; + if(temp!='.' && (row[i][temp]++ || col[j][temp]++ ||sub[sub_index][temp]++)) + return false; + } + } + return true; + } +}; \ No newline at end of file diff --git a/Week_06/G20200343030551/LeetCode_433_Minimum-Genetic-Mutation_551.cpp b/Week_06/G20200343030551/LeetCode_433_Minimum-Genetic-Mutation_551.cpp new file mode 100644 index 00000000..21a3f91b --- /dev/null +++ b/Week_06/G20200343030551/LeetCode_433_Minimum-Genetic-Mutation_551.cpp @@ -0,0 +1,51 @@ +#include +#include +#include + +using namespace std; + +class Solution +{ +public: + //解法2:双向bfs + int minMutation(string start, string end, vector &bank) + { + //1:建立hashmap表,顺便去掉重复元素 + unordered_map mp; + for (const auto &b:bank)mp[b] = 0; + + //2:排除极端情况,end不在基因库中 + if (mp.count(end) == 0)return -1; + + //3:bfs的初始化工作 + queue q1({start}), q2({end});//前向队列,后向队列 + int step = 0; + const char table[4] = {'A', 'C', 'G', 'T'};//基因的字符 + //或1表示前向队列由前往后遍历,或2表示后向队列由后向前遍历,每次我们选用较小的队列进行遍历 + for (mp[start] |= 1, mp[end] |= 2; q1.size() && q2.size(); ++step)//每遍历完一次,步长+1 + { + bool first = q1.size() < q2.size(); + queue &q = first ? q1 : q2;//选择较小的队列进行遍历节约时间 + int flag = first ? 1 : 2;//此次遍历的方式 + + for (int n = q.size(); n--; q.pop()) + { + string &temp = q.front(); + if (mp[temp] == 3)return step;//两个队列碰头,返回步长 + for (int i = 0; i < temp.size(); ++i) + { + for (int j = 0; j < 4; ++j) + { + string s = temp; + if (s[i] == table[j])continue;//重复字符,跳出循环,寻找下一个字符 + s[i] = table[j]; + if (mp.count(s) == 0 || mp[s] & flag)continue;//该单词不在map中或该单词已经被遍历过了,跳出循环,寻找下一个单词 + mp[s] |= flag;//标记该单词已经被遍历过了 + q.push(s); + } + } + } + } + return -1; + } +}; diff --git a/Week_06/G20200343030553/LeetCode_200_553.java b/Week_06/G20200343030553/LeetCode_200_553.java new file mode 100644 index 00000000..9b0832e1 --- /dev/null +++ b/Week_06/G20200343030553/LeetCode_200_553.java @@ -0,0 +1,27 @@ +class Solution { + public int numIslands(char[][] grid) { + int count = 0; + for(int i=0; i< grid.length;i++){ + for(int j=0;j(n-1) || j>(m-1) || grid[i][j]=='0') + return; + grid[i][j] = '0'; + xiaochu(i-1,j,grid); + xiaochu(i+1,j,grid); + xiaochu(i,j-1,grid); + xiaochu(i,j+1,grid); + } +} \ No newline at end of file diff --git a/Week_06/G20200343030553/LeetCode_64_553.java b/Week_06/G20200343030553/LeetCode_64_553.java new file mode 100644 index 00000000..ea1f1958 --- /dev/null +++ b/Week_06/G20200343030553/LeetCode_64_553.java @@ -0,0 +1,33 @@ +class Solution { + public int minPathSum(int[][] grid) { + int[][] dp = grid; + // 初始化第一行 + for(int i=1;i queue = new PriorityQueue<>(); + queue.offer(start); + while (!queue.isEmpty()) { + Node node = queue.poll(); + int step = grid[node.x][node.y]; + for (int[] d : dir) { + int x = node.x + d[0]; + int y = node.y + d[1]; + if (x == n - 1 && y == n - 1) return step + 1; + if (x < 0 || x >= n || y < 0 || y >= n) continue; + if (grid[x][y] != 0 && grid[x][y] <= step + 1) continue; + Node next = new Node(x, y, grid[x][y] = step + 1); + queue.offer(next); + } + } + return -1; + } + + class Node implements Comparable { + int x; + int y; + int step; + int distance; + int heuristic; + + public Node(int x, int y, int step) { + this.x = x; + this.y = y; + this.step = step; + this.distance = Math.max(n - 1 - x, n - 1 - y); + this.heuristic = this.distance + this.step; + } + + @Override + public int compareTo(Node o) { + return this.heuristic - o.heuristic; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof Node)) return false; + Node node = (Node) o; + return x == node.x && y == node.y; + } + + @Override + public int hashCode() { + return Integer.hashCode(x * n + y); + } + } +} +// @lc code=end + diff --git a/Week_06/G20200343030561/Leetcode_127_561.java b/Week_06/G20200343030561/Leetcode_127_561.java new file mode 100644 index 00000000..25f5ecb1 --- /dev/null +++ b/Week_06/G20200343030561/Leetcode_127_561.java @@ -0,0 +1,158 @@ +import java.util.*; +/* + * @lc app=leetcode.cn id=127 lang=java + * + * [127] 单词接龙 + */ + + +// bfs +// class Solution { +// public int ladderLength(String beginWord, String endWord, List wordList) { +// Set wordSet = new HashSet<>(wordList); +// if (!wordSet.contains(endWord)) return 0; +// Queue queue = new LinkedList<>(); +// queue.offer(beginWord); +// wordSet.remove(beginWord); +// int step = 0, wordLength = beginWord.length(); +// while (!queue.isEmpty()) { +// step ++; +// for (int i = queue.size(); i > 0; i --) { +// String word = queue.poll(); +// for (Iterator it = wordSet.iterator(); it.hasNext();) { +// String element = it.next(); +// int diff = 0; +// for (int j = 0; j < wordLength; j ++) { +// if (word.charAt(j) != element.charAt(j)) +// if (++diff > 1) break; +// } +// if (diff == 1) { +// if (endWord.equals(element)) +// return step + 1; +// queue.offer(element); +// it.remove(); +// } +// } +// } +// } +// return 0; +// } +// } + +// @date Mar 072020 +// @solution bfs +// class Solution { +// public int ladderLength(String beginWord, String endWord, List wordList) { +// Set dict = new HashSet<>(wordList); +// if (!dict.contains(endWord)) return 0; +// Queue queue = new LinkedList<>(); +// queue.offer(beginWord); +// dict.remove(beginWord); +// int step = 0; +// while (!queue.isEmpty()) { +// step ++; +// for (int i = queue.size(); i > 0; i --) { +// String word = queue.poll(); +// for (int j = word.length() - 1; j >= 0; j --) { +// char[] letter = word.toCharArray(); +// for (char alphabet = 'a'; alphabet <= 'z'; alphabet ++) { +// if (letter[j] == alphabet) continue; +// letter[j] = alphabet; +// String newWord = new String(letter); +// if (newWord.equals(endWord)) return step + 1; +// if (dict.contains(newWord)) { +// queue.offer(newWord); +// dict.remove(newWord); +// } +// } +// } +// } +// } +// return 0; +// } +// } + +// visited 是不需要的,从dict中减去word就可以了 +// two-end bfs +// @date Mar 20 2020 +// class Solution { +// public int ladderLength(String beginWord, String endWord, List wordList) { +// Set dict = new HashSet<>(wordList); +// Set begin = new HashSet<>(), end = new HashSet<>(), visited = new HashSet<>(); +// if (!dict.contains(endWord)) return 0; +// int step = 1; +// begin.add(beginWord); +// end.add(endWord); + +// while(!begin.isEmpty() && !end.isEmpty()) { +// if (begin.size() > end.size()) { // todo +// Set set = begin; +// begin = end; +// end = set; +// } +// Set temp = new HashSet<>(); +// for(String word : begin) { +// char[] letters = word.toCharArray(); +// for(int i = 0; i < letters.length; i ++) { +// for (char alphabet = 'a'; alphabet <= 'z'; alphabet ++) { +// char c = letters[i]; +// letters[i] = alphabet; +// String target = String.valueOf(letters); +// if (end.contains(target)) return step + 1; +// if (!visited.contains(target) && dict.contains(target)) { +// temp.add(target); +// visited.add(target); +// } +// letters[i] = c; +// } +// } +// } +// begin = temp; +// step ++; +// } +// return 0; +// } +// } + +// @lc code=start +// @date Mar 20 2020 +// @solution two-end bfs best +class Solution { + public int ladderLength(String beginWord, String endWord, List wordList) { + Set dict = new HashSet<>(wordList), temp = new HashSet<>(); + Set front = new HashSet<>(), back = new HashSet<>(); + if (!dict.contains(endWord)) return 0; + int step = 1; + front.add(beginWord); + back.add(endWord); + dict.remove(beginWord); + while(!front.isEmpty() && !back.isEmpty()) { + if (front.size() > back.size()) { // todo + temp = front; + front = back; + back = temp; + } + temp = new HashSet<>(); + for(String word : front) { + for(int i = beginWord.length() - 1; i >= 0 ; i --) { + char[] letters = word.toCharArray(); + for (char alphabet = 'a'; alphabet <= 'z'; alphabet ++) { + if (letters[i] == alphabet) continue; + letters[i] = alphabet; + String target = String.valueOf(letters); + if (back.contains(target)) return step + 1; + if (dict.contains(target)) { + temp.add(target); + dict.remove(target); + } + } + } + } + front = temp; + step ++; + } + return 0; + } +} +// @lc code=end + diff --git a/Week_06/G20200343030561/Leetcode_130_561.java b/Week_06/G20200343030561/Leetcode_130_561.java new file mode 100644 index 00000000..69436129 --- /dev/null +++ b/Week_06/G20200343030561/Leetcode_130_561.java @@ -0,0 +1,72 @@ +/* + * @lc app=leetcode.cn id=130 lang=java + * + * [130] 被围绕的区域 + */ + +// @lc code=start +// @date Mar 22 2020 +// @solution disjoint-set best +class Solution { + public void solve(char[][] board) { + if (board == null || board.length == 0) return; + int rl = board.length, cl = board[0].length; + UnionFind uf = new UnionFind(rl * cl + 1); + int O = rl * cl; + for (int r = 0; r < rl; r ++) { + for (int c = 0; c < cl; c ++) { + if (board[r][c] == 'X') continue; + if (r == 0 || c == 0 || r == rl - 1 || c == cl - 1) { + uf.union(r * cl + c, O); + continue; + } + if (board[r - 1][c] == 'O') + uf.union(r * cl + c, (r - 1) * cl + c); + if (board[r + 1][c] == 'O') + uf.union(r * cl + c, (r + 1) * cl + c); + if (board[r][c - 1] == 'O') + uf.union(r * cl + c, r * cl + c - 1); + if (board[r][c + 1] == 'O') + uf.union(r * cl + c, r * cl + c + 1); + } + } + for (int r = 0; r < rl; r ++) { + for (int c = 0; c < cl; c ++) { + if (board[r][c] == 'X') continue; + if (!uf.isConnected(r * cl + c, O)) + board[r][c] = 'X'; + } + } + } + class UnionFind { + int count = 0; + int[] parent; + public UnionFind(int n) { + count = n; + parent = new int[n]; + for (int i = 0; i < n; i ++) { + parent[i] = i; + } + } + public int find(int p) { + while (p != parent[p]) { + parent[p] = parent[parent[p]]; + p = parent[p]; + } + return p; + } + public void union(int p, int q) { + if (p == q) return; + int rp = find(p); + int rq = find(q); + if (rp == rq) return; + parent[rp] = rq; + count --; + } + public boolean isConnected(int p, int q) { + return find(p) == find(q); + } + } +} +// @lc code=end + diff --git a/Week_06/G20200343030561/Leetcode_200_561.java b/Week_06/G20200343030561/Leetcode_200_561.java new file mode 100644 index 00000000..fe0a9ff2 --- /dev/null +++ b/Week_06/G20200343030561/Leetcode_200_561.java @@ -0,0 +1,89 @@ +/* + * @lc app=leetcode.cn id=200 lang=java + * + * [200] 岛屿数量 + */ + +// @solution dfs best +// class Solution { +// public int numIslands(char[][] grid) { +// if (grid == null || grid.length == 0) return 0; +// int nr = grid.length; +// int nc = grid[0].length; +// int ni = 0; +// for (int r = 0; r < nr; r++) { +// for(int c = 0; c < nc; c++) { +// if(grid[r][c] == '1') { +// ni ++; +// dfs(grid, r, c); +// } +// } +// } +// return ni; +// } + +// private void dfs(char[][] grid, int r, int c) { +// int nr = grid.length; +// int nc = grid[0].length; +// if (r < 0 || c < 0 || r >= nr || c >= nc || grid[r][c] == '0') +// return; + +// grid[r][c] = '0'; +// dfs(grid, r - 1, c); +// dfs(grid, r + 1, c); +// dfs(grid, r, c - 1); +// dfs(grid, r, c + 1); +// } +// } + +// @lc code=start +// @date Mar 22 2020 +// @solution disjoint-set +class Solution { + public int numIslands(char[][] grid) { + int rl = grid.length, cl = grid[0].length, waterCount = 0; + UnionFind uf = new UnionFind(rl * cl); + for (int r = 0; r < rl; r ++) { + for (int c = 0; c < cl; c ++) { + if (grid[r][c] == '1') { + if (r > 0 && grid[r - 1][c] == '1') + uf.union(r * cl + c, (r - 1) * cl +c); + else if (c > 0 && grid[r][c - 1] == '1') + uf.union(r * cl + c, r * cl + c - 1); + } else { + waterCount ++; + } + } + } + return uf.count - waterCount; + } + class UnionFind { + int count = 0; + int[] parent; + public UnionFind(int n) { + count = n; + parent = new int[n]; + for (int i = 0; i < n; i ++) + parent[i] = i; + } + public int find(int p) { + while (p != parent[p]) { + parent[p] = parent[parent[p]]; + p = parent[p]; + } + return p; + } + public void union(int p, int q) { + if (p == q) return; + int rp = find(p); + int rq = find(q); + if (rp == rq) return; + parent[rp] = rq; + count --; + } + } +} + + +// @lc code=end + diff --git a/Week_06/G20200343030561/Leetcode_208_561.java b/Week_06/G20200343030561/Leetcode_208_561.java new file mode 100644 index 00000000..ee31d983 --- /dev/null +++ b/Week_06/G20200343030561/Leetcode_208_561.java @@ -0,0 +1,86 @@ +/* + * @lc app=leetcode.cn id=208 lang=java + * + * [208] 实现 Trie (前缀树) + */ + +// @lc code=start +class Trie { + private TrieNode root; + + /** Initialize your data structure here. */ + public Trie() { + root = new TrieNode(); + } + + /** Inserts a word into the trie. */ + public void insert(String word) { + TrieNode node = root; + for (char c : word.toCharArray()) { + if (!node.containsKey(c)) + node.put(new TrieNode(), c); + node = node.get(c); + } + + node.setEnd(); + } + + /** Returns if the word is in the trie. */ + public boolean search(String word) { + TrieNode node = root; + for (char c : word.toCharArray()) { + if (node.containsKey(c)) + node = node.get(c); + else + return false; + } + return node != null && node.isEnd(); + } + + /** Returns if there is any word in the trie that starts with the given prefix. */ + public boolean startsWith(String prefix) { + TrieNode node = root; + for (char c : prefix.toCharArray()) { + if (node.containsKey(c)) + node = node.get(c); + else + return false; + } + return node != null; + } + + class TrieNode { + private TrieNode[] nodes; + private final int len = 26; + private boolean isEnd = false; + public TrieNode() { + nodes = new TrieNode[len]; + } + public boolean containsKey (char c) { + return nodes[c - 'a'] != null; + } + public TrieNode get(char c) { + return nodes[c - 'a']; + } + public void put (TrieNode node, char c) { + nodes[c - 'a'] = node; + } + public void setEnd() { + isEnd = true; + } + public boolean isEnd() { + return isEnd; + } + + } +} + +/** + * Your Trie object will be instantiated and called as such: + * Trie obj = new Trie(); + * obj.insert(word); + * boolean param_2 = obj.search(word); + * boolean param_3 = obj.startsWith(prefix); + */ +// @lc code=end + diff --git a/Week_06/G20200343030561/Leetcode_212_561.java b/Week_06/G20200343030561/Leetcode_212_561.java new file mode 100644 index 00000000..8cb1f5f0 --- /dev/null +++ b/Week_06/G20200343030561/Leetcode_212_561.java @@ -0,0 +1,133 @@ +import java.util.*; +/* + * @lc app=leetcode.cn id=212 lang=java + * + * [212] 单词搜索 II + */ + +// 四连通 +// @date Mar 17 2020 +// class Solution { +// int rl, cl; +// Set res; +// boolean[][] visited; +// public List findWords(char[][] board, String[] words) { +// rl = board.length; +// cl = board[0].length; +// visited = new boolean[rl][cl]; +// res = new HashSet(); +// Trie trie = new Trie(); + +// for (String s : words) +// trie.insert(s); + + // for (int r = 0; r < rl; r ++) + // for (int c = 0; c < cl; c ++) +// dfs(board, r, c, trie.root); +// return new ArrayList(res); +// } +// void dfs(char[][] board, int r, int c, TrieNode node) { +// if (r < 0 || c < 0 || r >= rl || c >= cl || visited[r][c]) +// return; +// node = node.children[board[r][c] - 'a']; +// if (node == null) +// return; +// if (node.isEnd) +// res.add(node.val); +// visited[r][c] = true; +// dfs(board, r + 1, c, node); +// dfs(board, r - 1, c, node); +// dfs(board, r, c + 1, node); +// dfs(board, r, c - 1, node); +// visited[r][c] = false; +// } + +// class Trie { +// public TrieNode root = new TrieNode(); +// public void insert(String str) { +// TrieNode node = root; +// for (char c : str.toCharArray()) { +// if (node.children[c - 'a'] == null) +// node.children[c - 'a'] = new TrieNode(); +// node = node.children[c - 'a']; +// } +// node.isEnd = true; +// node.val = str; +// } +// } +// class TrieNode { +// public String val; +// public TrieNode[] children; +// public boolean isEnd = false; +// TrieNode() { +// children = new TrieNode[26]; +// } +// } +// } + +// @lc code=start +// @date Mar 19 2020 +// @solution trie +class Solution { + int rl, cl; + Set res; + boolean[][] visited; + public List findWords(char[][] board, String[] words) { + rl = board.length; + cl = board[0].length; + res = new HashSet<>(); + Trie trie = new Trie(); + + for (String s: words) + trie.insert(s); + + for (int r = 0; r < rl; r ++) { + for (int c = 0; c < cl; c ++) { + dfs(board, r, c, trie.root); + } + } + return new ArrayList(res); + } + + void dfs(char[][] board, int r, int c, TrieNode node) { + if (r < 0 || c < 0 || r >= rl || c >= cl || board[r][c] == '\0') + return; + node = node.children[board[r][c] - 'a']; + if (node == null) + return; + if (node.isEnd) + res.add(node.val); + + char tmp = board[r][c]; + board[r][c] = '\0'; + dfs(board, r + 1, c, node); + dfs(board, r - 1, c, node); + dfs(board, r, c + 1, node); + dfs(board, r, c - 1, node); + board[r][c] = tmp; + } + + class Trie { + public TrieNode root = new TrieNode(); + public void insert (String str) { + TrieNode node = root; + for(char c : str.toCharArray()) { + if (node.children[c - 'a'] == null) + node.children[c - 'a'] = new TrieNode(); + node = node.children[c - 'a']; + } + node.isEnd = true; + node.val = str; + } + } + class TrieNode { + public String val; + public TrieNode[] children; + public boolean isEnd = false; + TrieNode() { + children = new TrieNode[26]; + } + } +} +// @lc code=end + diff --git a/Week_06/G20200343030561/Leetcode_22_561.java b/Week_06/G20200343030561/Leetcode_22_561.java new file mode 100644 index 00000000..b1f9af27 --- /dev/null +++ b/Week_06/G20200343030561/Leetcode_22_561.java @@ -0,0 +1,104 @@ +import java.util.*; + +/* + * @lc app=leetcode.cn id=22 lang=java + * + * [22] 括号生成 + */ + +// 递归 +// @date Feb 20 2020 +// class Solution { +// private List ans; + +// public List generateParenthesis(int n) { +// ans = new ArrayList(); +// addParenthesis(0, 0, n, ""); +// return ans; +// } + +// private void addParenthesis(int left, int right, int max, String str) { +// // terminator +// if (left == max && right == max){ +// ans.add(str); +// return; +// } +// if (left + 1 <= max) +// addParenthesis(left + 1, right, max, str + "("); +// if (right < left) +// addParenthesis(left, right + 1, max, str + ")"); +// } +// } + +// dfs +// @date Mar 05 2020 +// class Solution { +// public List generateParenthesis(int n) { +// List res = new ArrayList<>(); +// dfs(res, 0, 0, n, ""); +// return res; +// } +// void dfs(List res, int l, int r, int n, String s){ +// if (l == n && r == n){ +// res.add(s); +// return; +// } +// if (l < n) +// dfs(res, l + 1, r, n, s + "("); +// if (r < l) +// dfs(res, l, r + 1, n, s + ")"); +// } +// } + +// bfs +// @date Mar 05 2020 +// class Solution { +// public List generateParenthesis(int n) { +// List res = new ArrayList<>(); +// if (n == 0) return res; +// Queue queue = new LinkedList<>(); +// queue.offer(""); +// while(!queue.isEmpty()) { +// String str = queue.poll(); +// char[] arr = str.toCharArray(); +// int left = 0, right = 0; +// for (char c: arr) { +// if (c == '(') left++; +// if (c == ')') right++; +// } +// if (left == n && right == n) { +// res.add(str); +// } + +// if (left < n) { +// queue.offer(str + "("); +// } +// if (right < left) { +// queue.offer(str + ")"); +// } +// } +// return res; +// } +// } + +// @lc code=start +// @date Mar 22 2020 +// @solution backtracking +class Solution { + List res = new ArrayList<>(); + public List generateParenthesis(int n) { + dfs(n, "", 0, 0); + return res; + } + void dfs(int n, String str, int l, int r) { + if (l == n && r == n) { + res.add(str); + return; + } + if (l < n) + dfs(n, str + "(", l + 1, r); + if (r < l) + dfs(n, str + ")", l, r + 1); + } +} +// @lc code=end diff --git a/Week_06/G20200343030561/Leetcode_36_561.java b/Week_06/G20200343030561/Leetcode_36_561.java new file mode 100644 index 00000000..3e965e93 --- /dev/null +++ b/Week_06/G20200343030561/Leetcode_36_561.java @@ -0,0 +1,24 @@ +/* + * @lc app=leetcode.cn id=36 lang=java + * + * [36] 有效的数独 + */ + +// @lc code=start +class Solution { + public boolean isValidSudoku(char[][] board) { + int[][] row = new int[9][9], col = new int[9][9], box = new int[9][9]; + for (int r = 0; r < 9; r ++) { + for (int c = 0; c < 9; c ++) { + if (board[r][c] == '.') continue; + int val = (int) board[r][c] - '1'; + if (++row[r][val] > 1) return false; + if (++col[c][val] > 1) return false; + if (++box[(r/3)*3 + (c/3)][val] > 1) return false; + } + } + return true; + } +} +// @lc code=end + diff --git a/Week_06/G20200343030561/Leetcode_37_561.java b/Week_06/G20200343030561/Leetcode_37_561.java new file mode 100644 index 00000000..66896360 --- /dev/null +++ b/Week_06/G20200343030561/Leetcode_37_561.java @@ -0,0 +1,49 @@ +/* + * @lc app=leetcode.cn id=37 lang=java + * + * [37] 解数独 + */ + +// @lc code=start +// @date Mar 22 2020 +// @solution backtracking +class Solution { + public void solveSudoku(char[][] board) { + dfs(board, 0); + } + + boolean dfs (char[][] board, int pos) { + if (pos == 81) return true; + + int r = pos / 9, c = pos % 9; + if (board[r][c] != '.') return dfs(board, pos + 1); + char digit = '0'; + for (boolean valid: getValid(board, r, c)) { + digit ++; + if (!valid) continue; + board[r][c] = digit; + if (dfs(board, pos + 1)) return true; + } + + board[r][c] = '.'; + return false; + } + boolean[] getValids(char[][] board, int r, int c) { + boolean[] valids = new boolean[9]; + Arrays.fill(valids, true); + for (int i = 0; i < 9; i ++) { + char[] toValid = { + board[r][i], // current row + board[i][c], // current column + board[r/3*3+i/3][c/3*3+i%3] // current block + }; + // if any toValid has digit, then false. + for (char tv: toValid) + if (tv != '.') + valids[tv - '1'] = false; + } + return valid; + } +} +// @lc code=end + diff --git a/Week_06/G20200343030561/Leetcode_433_561.java b/Week_06/G20200343030561/Leetcode_433_561.java new file mode 100644 index 00000000..17fcd3c0 --- /dev/null +++ b/Week_06/G20200343030561/Leetcode_433_561.java @@ -0,0 +1,156 @@ +import java.util.*; +/* + * @lc app=leetcode.cn id=433 lang=java + * + * [433] 最小基因变化 + */ + +// @lc code=start +// dfs +// @date Feb 26 2020 +/* class Solution { + int minStepCount = Integer.MAX_VALUE; + public int minMutation(String start, String end, String[] bank) { + dfs(new HashSet(), 0, start, end, bank); + return (minStepCount == Integer.MAX_VALUE) ? -1 : minStepCount; + } + private void dfs (HashSet step, int stepCount, + String current, String end, String[] bank) { + if (current.intern() == end.intern()) + minStepCount = Math.min(stepCount, minStepCount); + for (String str: bank) { + int diff = 0; + for (int i = 0; i < str.length(); i++) + if (current.charAt(i) != str.charAt(i)) + if (++diff > 1) break; + if (diff == 1 && !step.contains(str)) { + step.add(str); + dfs(step, stepCount + 1, str, end, bank); + step.remove(str); + } + } + } +} +*/ +// bfs +// @date Feb 26 2020 +/* class Solution { + public int minMutation(String start, String end, String[] bank) { + HashSet pool = new HashSet<>(Arrays.asList(bank)); + if (! pool.contains(end)) return -1; + char[] nucleobases = {'A', 'C', 'G', 'T'}; + Queue queue = new LinkedList(); + queue.offer(start); + pool.remove(start); + int step = 0; + while (!queue.isEmpty()) { + step ++; + for (int c = queue.size(); c > 0; c--) { + char[] gene = queue.poll().toCharArray(); + for (int i = 0; i < gene.length; i++ ) { + char replaced = gene[i]; + for (int j = 0; j < 4; j ++) { + gene[i] = nucleobases[j]; + String mutation = new String(gene); + if (end.equals(mutation)) + return step; + if (pool.contains(mutation)) { + pool.remove(mutation); + queue.offer(mutation); + } + } + gene[i] = replaced; + } + } + } + return -1; + } +} */ +// bidirectional bfs(two-end bfs) +// @date Feb 26 2020 +// class Solution { +// public int minMutation(String start, String end, String[] bank) { +// HashSet pool = new HashSet<>(Arrays.asList(bank)); +// if (!pool.contains(end)) return -1; +// char[] nucleobases = {'A', 'C', 'G', 'T'}; +// Queue pos = new LinkedList(); +// Queue neg = new LinkedList(); +// pos.offer(start); +// neg.offer(end); +// int step = 0; +// char[] gene; +// while (!pos.isEmpty() && !neg.isEmpty()) { +// if (pos.size() > neg.size()) { +// Queue t = pos; +// pos = neg; +// neg = t; +// } +// Queue queue = new LinkedList(); +// for (int p = pos.size(); p > 0; p --) { +// gene = pos.poll().toCharArray(); +// for (int i = 0; i < gene.length; i++ ) { +// char replaced = gene[i]; +// for (int j = 0; j < 4; j ++) { +// gene[i] = nucleobases[j]; +// String mutation = new String(gene); +// // String mutation = String.valueOf(gene); +// if (neg.contains(mutation)) +// return step + 1; +// if (pool.contains(mutation)) { +// pool.remove(mutation); +// queue.offer(mutation); +// } +// } +// gene[i] = replaced; +// } +// } +// step ++; +// pos = queue; +// } +// return -1; +// } +// } + +// @solution two-end bfs best +// todo hashset is better than linkedlist +class Solution { + public int minMutation(String start, String end, String[] bank) { + Set dict = new HashSet<>(Arrays.asList(bank)), temp = new HashSet<>(); + Set front = new HashSet<>(), back = new HashSet<>(); + if (!dict.contains(end)) return -1; + char[] nucleobases = {'A', 'C', 'G', 'T'}; + int step = 0; + front.add(start); + back.add(end); + dict.remove(start); + while (!front.isEmpty() && !back.isEmpty()) { + if (front.size() > back.size()) { + temp = front; + front = back; + back = temp; + } + temp = new HashSet<>(); + for (String sequence : front) { + for (int i = sequence.length() - 1; i >= 0; i --) { + char[] genes = sequence.toCharArray(); + for (char base : nucleobases) { + if (genes[i] == base) continue; + genes[i] = base; + String mutation = String.valueOf(genes); + if (back.contains(mutation)) return step + 1; + if (dict.contains(mutation)) { + dict.remove(mutation); + temp.add(mutation); + } + + } + } + } + step ++; + front = temp; + } + return -1; + } +} +// @lc code=end + diff --git a/Week_06/G20200343030561/Leetcode_51_561.java b/Week_06/G20200343030561/Leetcode_51_561.java new file mode 100644 index 00000000..2e1a00c9 --- /dev/null +++ b/Week_06/G20200343030561/Leetcode_51_561.java @@ -0,0 +1,99 @@ +import java.util.*; +/* + * @lc app=leetcode.cn id=51 lang=java + * + * [51] N皇后 + */ + +// @solution +// class Solution { +// List> res = new ArrayList<>(); +// public List> solveNQueens(int n) { +// int[][] board = new int[n][n]; +// bt(board, 0, n); +// return res; +// } +// private void bt(int[][] board, int i, int n) { +// if (i == n) { +// List l = new ArrayList<>(); +// for (var k = 0; k < n; k++) { +// StringBuilder sb = new StringBuilder(); +// for (var m = 0; m < n; m++) { +// sb.append((board[k][m] == 0) ? '.' : 'Q'); +// } +// l.add(sb.toString()); +// } +// res.add(l); +// return ; +// } +// for (int j = 0; j < n; j ++) { +// if (available(i, j, board)) { +// board[i][j] = 1; +// bt(board, i+1, n); +// board[i][j] = 0; +// } +// } +// } +// private boolean available(int i, int j, int[][] board) { +// for (int h = 0; h < i; h ++) +// if (board[h][j] == 1) return false; + +// int max = board.length; +// int offset; +// for (offset = 0; i - offset >= 0 && j + offset < max; offset ++) +// if (board[i-offset][j+offset] == 1) return false; + +// for (offset = 0; i + offset < max && j - offset >= 0; offset ++) +// if (board[i+offset][j-offset] == 1) return false; + +// for (offset = 0; i - offset >= 0 && j - offset >= 0; offset ++) +// if (board[i-offset][j-offset] == 1) return false; + +// for (offset = 0; i + offset < max && j + offset < max; offset ++) +// if (board[i+offset][j+offset] == 1) return false; + +// return true; +// } +// } + +// @lc code=start +// @date Mar 22 2020 +// @solution backtracking best +class Solution { + int rl, cl; + List> res = new ArrayList<>(); + public List> solveNQueens(int n) { + rl = cl = n; + dfs(new ArrayList<>(), new ArrayList<>(), new ArrayList<>()); + return res; + } + void dfs(List queenInRows, List lowerRight, List lowerLeft) { + int r = queenInRows.size(); + if (r == rl) { + List solution = new ArrayList<>(); + for (int idx: queenInRows) { + solution.add(".".repeat(idx) + "Q" + ".".repeat(rl - 1 - idx)); + } + res.add(solution); + return; + } + for (int c = 0; c < cl; c ++) { + if (queenInRows.contains(c)) continue; + // if x1 - y1 = x2 - y2, [x1, y1] and [x2, y2] are in same lowerright line; + if (lowerRight.contains(r - c)) continue; + // if x1 + y1 = x2 + y2, [x1, y1] and [x2, y2] are in same lowerleft line; + if (lowerLeft.contains(r + c)) continue; + queenInRows.add(c); + lowerRight.add(r - c); + lowerLeft.add(r + c); + dfs(new ArrayList<>(queenInRows), new ArrayList<>(lowerRight), new ArrayList<>(lowerLeft)); + int lastIdx = r; + queenInRows.remove(lastIdx); + lowerRight.remove(lastIdx); + lowerLeft.remove(lastIdx); + } + } +} + +// @lc code=end + diff --git a/Week_06/G20200343030561/Leetcode_547_561.java b/Week_06/G20200343030561/Leetcode_547_561.java new file mode 100644 index 00000000..34f8f09e --- /dev/null +++ b/Week_06/G20200343030561/Leetcode_547_561.java @@ -0,0 +1,51 @@ +import java.util.Arrays; + +/* + * @lc app=leetcode.cn id=547 lang=java + * + * [547] 朋友圈 + */ + +// @lc code=start +// @date Mar 22 2020 +// @solution disjoint-set best +class Solution { + public int findCircleNum(int[][] M) { + if (M == null || M.length == 0) return 0; + int len = M.length; + UnionFind uf = new UnionFind(len); + for (int i = 0; i < len; i ++) { + for (int j = 0; j < len; j ++) { + if (M[i][j] == 1) + uf.union(i, j); + } + } + return uf.count; + } + class UnionFind { + int count = 0; + int[] parent; + public UnionFind(int n) { + count = n; + parent = new int[n]; + for (int i = 0; i < n; i ++) + parent[i] = i; + } + public int find(int p) { + while (p != parent[p]) { + parent[p] = parent[parent[p]]; + p = parent[p]; + } + return p; + } + public void union(int p, int q) { + int rp = find(p); + int rq = find(q); + if (rp == rq) return; + parent[rp] = rq; + count --; + } + } +} +// @lc code=end + diff --git a/Week_06/G20200343030561/Leetcode_70_561.java b/Week_06/G20200343030561/Leetcode_70_561.java new file mode 100644 index 00000000..eb93fda4 --- /dev/null +++ b/Week_06/G20200343030561/Leetcode_70_561.java @@ -0,0 +1,78 @@ +/* + * @lc app=leetcode.cn id=70 lang=java + * + * [70] 爬楼梯 + */ + +// @date Feb 13 2020 +/* class Solution { + public int climbStairs(int n) { + if(n <= 2) return n; + var sol1 = 1; + var sol2 = 2; + var sol3 = 3; + for (var i = 2; i < n; ++i) { + sol3 = sol1 + sol2; + sol1 = sol2; + sol2 = sol3; + } + return sol3; + } +} */ + +// @date Feb 20 2020 +// @solution backtracking 2 +// class Solution { +// // an int is a primitive type and cannot be null +// public Integer[] sol = new Integer[100]; +// public int climbStairs(int i) { +// sol[1] = 1; +// sol[2] = 2; +// if (i <= 2) return sol[i]; +// if (sol[i - 1] == null) sol[i - 1] = climbStairs(i - 1); +// if (sol[i - 2] == null) sol[i - 2] = climbStairs(i - 2); +// return sol[i-1] + sol[i-2]; +// } +// } + +// 斐波那契公式 +// @date Mar 02 2020 +// class Solution { +// public int climbStairs(int i) { +// int n = i + 1; +// double sqrt_5 = Math.sqrt(5); +// double fib_n = Math.pow((1 + sqrt_5) / 2, n) - Math.pow((1 - sqrt_5) / 2, n); +// return (int)(fib_n / sqrt_5); +// } +// } + +// DP +// @date Mar 11 2020 +// class Solution { +// public int climbStairs(int n) { +// if (n < 3) return n; +// 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]; +// } +// } + +// @lc code=start +// @date Mar 22 2020 +// @solution backtracking 1 +class Solution { + int[] sol = new int[100]; + public int climbStairs(int i) { + sol[1] = 1; + sol[2] = 2; + if (i <= 2) return sol[i]; + if (sol[i] != 0) return sol[i]; + sol[i] = climbStairs(i - 1) + climbStairs(i - 2); + return sol[i]; + } +} + +// @lc code=end \ No newline at end of file diff --git a/Week_06/G20200343030561/Leetcode_773_561.java b/Week_06/G20200343030561/Leetcode_773_561.java new file mode 100644 index 00000000..cedc8d2a --- /dev/null +++ b/Week_06/G20200343030561/Leetcode_773_561.java @@ -0,0 +1,144 @@ +import java.util.*; +/* + * @lc app=leetcode.cn id=773 lang=java + * + * [773] 滑动谜题 + */ + +// @date Mar 21 2020 +// @solution bfs +// class Solution { +// public int slidingPuzzle(int[][] board) { +// List b = new ArrayList<>(); +// Set visited = new HashSet<>(); +// Queue> queue = new LinkedList<>(); +// for (int r = 0; r < board.length; r ++) { +// for (int c = 0; c < board[0].length; c ++) { +// b.add(board[r][c]); +// } +// } +// int[][] moves = new int[][]{ +// {1, 3, -1}, {0, 2, 4}, {1, 5, -1}, +// {0, 4, -1}, {1, 3, 5}, {2, 4, -1} +// }; +// queue.offer(b); +// visited.add(b.toString()); +// int step = 0; +// while(!queue.isEmpty()) { +// for (int i = queue.size(); i > 0; i --) { +// b = queue.poll(); +// System.out.println(b.toString()); +// if (b.toString().equals("[1, 2, 3, 4, 5, 0]")) +// return step; +// int j = b.indexOf(0); +// for (int next : moves[j]) { +// if (next == -1) continue; +// List _b = new ArrayList(b); +// _b.set(j, _b.get(next)); +// _b.set(next, 0); +// if (!visited.contains(_b.toString())) +// queue.offer(_b); +// visited.add(_b.toString()); +// } + +// } +// step ++; +// } +// return -1; +// } +// } + +// @lc code=start +// @date Mar 21 2020 +// @solutions a* +class Solution { + public int slidingPuzzle(int[][] board) { + Box box = new Box(board); + int[] endBoard = {1, 2, 3, 4, 5, 0}; + int[] wrongBoard = {1, 2, 3, 5, 4, 0}; + if (Arrays.equals(box.board, endBoard)) return 0; + if (Arrays.equals(box.board, wrongBoard)) return -1; + HashSet visited = new HashSet<>(); + PriorityQueue queue = new PriorityQueue<>(); + int[][] dir = { + {1, 3}, {0, 2, 4}, {1, 5}, + {0, 4}, {1, 3, 5}, {2, 4} + }; + queue.offer(box); + visited.add(box); + while (!queue.isEmpty()) { + box = queue.poll(); + for (int nextZero : dir[box.zero]) { + int[] nextBoard = Arrays.copyOf(box.board, 6); + nextBoard[box.zero] = nextBoard[nextZero]; + nextBoard[nextZero] = 0; + if (Arrays.equals(nextBoard, endBoard)) return box.step + 1; + if (Arrays.equals(nextBoard, wrongBoard)) return -1; + Box next = new Box(nextBoard, nextZero, box.step + 1); + if (visited.contains(next)) continue; + queue.offer(next); + visited.add(next); + } + } + return -1; + } + + static class Box implements Comparable { + int[] board; + int zero; + int step; // g(n) + int distance; // h(n) + int f; // f(n) = g(n) + h(n) + + public Box(int[][] board) { + this.board = new int[6]; + for (int i = 0; i < 6; i++) { + this.board[i] = board[i / 3][i % 3]; + if (this.board[i] == 0) this.zero = i; + } + this.step = 0; + this.distance = calcDistance(); + this.f = this.step + this.distance; + } + + public Box(int[] board, int zero, int step) { + this.board = board; + this.zero = zero; + this.step = step; + this.distance = calcDistance(); + this.f = this.step + this.distance; + } + + private int calcDistance() { + int distance = 0; + for (int i = 0; i < 6; i++) { + int v = board[i] - 1; // target idx of board; + distance += Math.abs(v / 3 - i / 3) + Math.abs(v % 3 - i % 3);// row + col + } + return distance; + } + + @Override + public int compareTo(Box box) { + return this.f - box.f; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof Box)) return false; + Box box = (Box) o; + return zero == box.zero && Arrays.equals(board, box.board); + } + + @Override + public int hashCode() { + int result = Objects.hash(zero); + result = 31 * result + Arrays.hashCode(board); + return result; + } + } +} + +// @lc code=end + diff --git a/Week_06/G20200343030561/NOTE.md b/Week_06/G20200343030561/NOTE.md deleted file mode 100644 index 50de3041..00000000 --- a/Week_06/G20200343030561/NOTE.md +++ /dev/null @@ -1 +0,0 @@ -学习笔记 \ No newline at end of file diff --git a/Week_06/G20200343030561/NOTE.org b/Week_06/G20200343030561/NOTE.org new file mode 100644 index 00000000..5938249f --- /dev/null +++ b/Week_06/G20200343030561/NOTE.org @@ -0,0 +1,60 @@ +* 岛屿问题是在问什么? +* 并查集 +两种实现方式: +1. 我将其命名为 UnionFind,对应 Java 的模板 +#+begin_src java + class UnionFind { + int count = 0; + int[] parent; + public UnionFind(int n) { + count = n; + parent = new int[n]; + for (int i = 0; i < n; i ++) + parent[i] = i; + } + public int find(int p) { + while (p != parent[p]) { + parent[p] = parent[parent[p]]; + p = parent[p]; + } + return p; + } + public void union(int p, int q) { + int rp = find(p); + int rq = find(q); + if (rp == rq) return; + parent[rp] = rq; + count --; + } + } +#+end_src +2. 我将其命名为 DisjointSet,对应 Python 的模板 +#+begin_src java + class DisjointSet { + int count; + int[] parent; + public DisjointSet(int n) { + count = n; + parent = new int[n]; + for (int i = 0; i < n; i ++) + parent[i] = i; + } + public void union (int p, int q) { + int rp = find(p); + int rq = find(q); + parent[rp] = rq; + count --; + } + public int find (i) { + int root = i; + while (parent[root] != root) + root = parent[root]; + while (parent[i] != i) { + int temp = i; + i = parent[i]; + p[temp] = root; + } + } + } +#+end_src +DisjointSet 是绝对压缩。UnionFind 是隔代压缩,如 parent 为 [0, 0, 1, 2, 3] 的实例执行 find(4) 后,parent 被压缩为 [0, 0, 0, 2, 2] diff --git a/Week_06/G20200343030563/LeetCode_208_563.java b/Week_06/G20200343030563/LeetCode_208_563.java new file mode 100644 index 00000000..4be12e3a --- /dev/null +++ b/Week_06/G20200343030563/LeetCode_208_563.java @@ -0,0 +1,75 @@ +public class TrieNode { + public char val; + private boolean isWord = false; + public TrieNode[] children = new TrieNode[26]; + + public TrieNode() { + } + + public TrieNode(char c) { + TrieNode node = new TrieNode(); + node.val = c; + } + + public boolean IsWord(){ + return isWord; + } + public void SetWord(){ + isWord = true; + } +} + +class Trie { + private TrieNode root; + + /** Initialize your data structure here. */ + public Trie() { + root = new TrieNode(); + root.val = ' '; + } + + /** Inserts a word into the trie. */ + public void insert(String word) { + TrieNode node = root; + for (int i = 0; i < word.length(); i++) { + char c = word.charAt(i); + if(node.children[c - 'a'] == null) { + node.children[c - 'a'] = new TrieNode(c); + } + node = node.children[c - 'a']; + } + node.SetWord(); + } + + + public TrieNode searchPrefix(String word) { + TrieNode node = root; + for (int i = 0; i < word.length(); i++) { + char c = word.charAt(i); + if(node.children[c - 'a'] != null){ + node = node.children[c - 'a']; + } else return null; + } + return node; + } + + /** Returns if the word is in the trie. */ + public boolean search(String word) { + TrieNode node = searchPrefix(word); + return (node != null && node.IsWord()); + } + + /** Returns if there is any word in the trie that starts with the given prefix. */ + public boolean startsWith(String prefix) { + TrieNode node = searchPrefix(prefix); + return node != null; + } +} + +/** + * Your Trie object will be instantiated and called as such: + * Trie obj = new Trie(); + * obj.insert(word); + * boolean param_2 = obj.search(word); + * boolean param_3 = obj.startsWith(prefix); + */ \ No newline at end of file diff --git a/Week_06/G20200343030563/LeetCode_547_563.java b/Week_06/G20200343030563/LeetCode_547_563.java new file mode 100644 index 00000000..56d4febf --- /dev/null +++ b/Week_06/G20200343030563/LeetCode_547_563.java @@ -0,0 +1,61 @@ +class Solution { + public int findCircleNum(int[][] M) { + UnioFind unioAarry = new UnioFind(M.length); + + for (int i = 0; i < M.length; i++) + for(int j = i; j < M.length; j++){ + if (M[i][j] == 1 && i != j) { + unioAarry.union(i, j); + } + } + + return unioAarry.GetCount(); + } +} + +class UnioFind{ + int[] parent; + int[] size; + int count; + + public UnioFind(int n){ + parent = new int[n]; + size = new int[n]; + + for(int i = 0; i < parent.length; i++) { + parent[i] = i; + size[i] = 1; + } + count = n; + } + public int find(int p) { + while(parent[p] != p) { + parent[p] = parent[parent[p]]; + p = parent[p]; + } + return p; + } + + public void union(int p ,int q){ + if (p == q) return; + int pRoot = find(p); + int qRoot = find(q); + if (pRoot == qRoot) return; + + //Сӵ棬ƽ + if (size[pRoot] > size[qRoot]) { + parent[qRoot] = pRoot; + size[pRoot] += size[qRoot]; + } else { + parent[qRoot] = pRoot; + size[qRoot] += pRoot; + } + + count--; + } + + + public int GetCount(){ + return count; + } +} \ No newline at end of file diff --git a/Week_06/G20200343030569/LeetCode_130_569.java b/Week_06/G20200343030569/LeetCode_130_569.java new file mode 100644 index 00000000..038744e4 --- /dev/null +++ b/Week_06/G20200343030569/LeetCode_130_569.java @@ -0,0 +1,59 @@ +/* + * 130. Surrounded Regions + * 被围绕的区域 + * 给定一个二维的矩阵,包含 'X' 和 'O'(字母 O)。 + +找到所有被 'X' 围绕的区域,并将这些区域里所有的 'O' 用 'X' 填充。 + +示例: + +X X X X +X O O X +X X O X +X O X X +运行你的函数后,矩阵变为: + +X X X X +X X X X +X X X X +X O X X + + */ +public class LeetCode_130_569 { + + public static void main(String[] args) { + // TODO Auto-generated method stub + + } + + class Solution { + public void solve(char[][] board) { + for( int i = 0; i < board.length; i++ ) { + for( int j = 0; j < board[0].length; j++ ) { + if( ( (i==0) || (j==0) || (i==board.length-1) || (j==board[0].length-1) ) + && board[i][j] == 'O' ) { + dfs(board, i, j); + } + } + } + for( int i = 0; i < board.length; i++ ) { + for( int j = 0; j < board[0].length; j++ ) { + if( board[i][j] == 'O' ) + board[i][j] = 'X'; + if( board[i][j] == '#' ) + board[i][j] = 'O'; + } + } + } + + void dfs( char[][] board, int i, int j ) { + if( i >= 0 && i < board.length && j >= 0 && j < board[0].length && board[i][j] == 'O') { + board[i][j] = '#'; + dfs(board, i-1, j); + dfs(board, i+1, j); + dfs(board, i, j-1); + dfs(board, i, j+1); + } + } + } +} diff --git a/Week_06/G20200343030569/LeetCode_208_569.java b/Week_06/G20200343030569/LeetCode_208_569.java new file mode 100644 index 00000000..f17529ff --- /dev/null +++ b/Week_06/G20200343030569/LeetCode_208_569.java @@ -0,0 +1,111 @@ +/* + * 208. Implement Trie (Prefix Tree) + * 实现 Trie (前缀树) + * 实现一个 Trie (前缀树),包含 insert, search, 和 startsWith 这三个操作。 + +示例: + +Trie trie = new Trie(); + +trie.insert("apple"); +trie.search("apple"); // 返回 true +trie.search("app"); // 返回 false +trie.startsWith("app"); // 返回 true +trie.insert("app"); +trie.search("app"); // 返回 true +说明: + +你可以假设所有的输入都是由小写字母 a-z 构成的。 +保证所有输入均为非空字符串。 + + */ +public class LeetCode_208_569 { + + public static void main(String[] args) { + // TODO Auto-generated method stub + + } + + + class Trie { + + class TrieNode { + char value; + boolean bWord; + TrieNode[] children = new TrieNode[26]; + + public TrieNode(){} + public TrieNode(char c) { + value = c; + } + + public TrieNode get( char c ) { + return children[c-'a']; + } + + public void set( char c, TrieNode node ) { + children[c-'a'] = node; + } + + public boolean contain( char c ) { + return children[c-'a'] != null; + } + + public void setWord() { + bWord = true; + } + + public boolean isWord() { + return bWord; + } + } + + TrieNode root; + + /** Initialize your data structure here. */ + public Trie() { + root = new TrieNode(' '); + } + + /** Inserts a word into the trie. */ + public void insert(String word) { + TrieNode node = root; + for( int i = 0; i < word.length(); i++ ) { + if( !node.contain(word.charAt(i)) ) + node.set(word.charAt(i), new TrieNode(word.charAt(i))); + node = node.get(word.charAt(i)); + } + node.setWord(); + } + + /** Returns if the word is in the trie. */ + public boolean search(String word) { + TrieNode node = root; + for( int i = 0; i < word.length(); i++ ) { + if( !node.contain(word.charAt(i)) ) + return false; + node = node.get(word.charAt(i)); + } + return node.isWord(); + } + + /** Returns if there is any word in the trie that starts with the given prefix. */ + public boolean startsWith(String prefix) { + TrieNode node = root; + for( int i = 0; i < prefix.length(); i++ ) { + if( !node.contain(prefix.charAt(i)) ) + return false; + node = node.get(prefix.charAt(i)); + } + return true; + } + } + + /** + * Your Trie object will be instantiated and called as such: + * Trie obj = new Trie(); + * obj.insert(word); + * boolean param_2 = obj.search(word); + * boolean param_3 = obj.startsWith(prefix); + */ +} diff --git a/Week_06/G20200343030569/LeetCode_547_569.java b/Week_06/G20200343030569/LeetCode_547_569.java new file mode 100644 index 00000000..228d57ae --- /dev/null +++ b/Week_06/G20200343030569/LeetCode_547_569.java @@ -0,0 +1,74 @@ +/* + * 547. Friend Circles + * 朋友圈 + * + * 班上有 N 名学生。其中有些人是朋友,有些则不是。他们的友谊具有是传递性。如果已知 A 是 B 的朋友,B 是 C 的朋友,那么我们可以认为 A 也是 C 的朋友。所谓的朋友圈,是指所有朋友的集合。 + +给定一个 N * N 的矩阵 M,表示班级中学生之间的朋友关系。如果M[i][j] = 1,表示已知第 i 个和 j 个学生互为朋友关系,否则为不知道。你必须输出所有学生中的已知的朋友圈总数。 + +示例 1: + +输入: +[[1,1,0], + [1,1,0], + [0,0,1]] +输出: 2 +说明:已知学生0和学生1互为朋友,他们在一个朋友圈。 +第2个学生自己在一个朋友圈。所以返回2。 +示例 2: + +输入: +[[1,1,0], + [1,1,1], + [0,1,1]] +输出: 1 +说明:已知学生0和学生1互为朋友,学生1和学生2互为朋友,所以学生0和学生2也是朋友,所以他们三个在一个朋友圈,返回1。 + + + */ +public class LeetCode_547_569 { + + public static void main(String[] args) { + // TODO Auto-generated method stub + + } + + class Solution { + class UnionFind { + private int count = 0; + private int[] parent; + public UnionFind(int n) { + count = n; + parent = new int[n]; + for (int i = 0; i < n; i++) { + parent[i] = i; + } + } + public int find(int p) { + while (p != parent[p]) { + parent[p] = parent[parent[p]]; + p = parent[p]; + } + return p; + } + public void union(int p, int q) { + int rootP = find(p); + int rootQ = find(q); + if (rootP == rootQ) return; + parent[rootP] = rootQ; + count--; + } + } + public int findCircleNum(int[][] M) { + int n = M.length; + UnionFind uf = new UnionFind(n); + for( int i = 0; i < M.length - 1; i++ ) { + for( int j = i + 1; j < M.length; j++ ) { + if( M[i][j] == 1 ) + uf.union(i, j); + } + } + return uf.count; + } + } +} diff --git a/Week_06/G20200343030569/LeetCode_70_569.java b/Week_06/G20200343030569/LeetCode_70_569.java new file mode 100644 index 00000000..b23bb568 --- /dev/null +++ b/Week_06/G20200343030569/LeetCode_70_569.java @@ -0,0 +1,51 @@ +/* + * 70. Climbing Stairs + * + * 假设你正在爬楼梯。需要 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 阶 + + */ +public class LeetCode_70_569 { + + public static void main(String[] args) { + // TODO Auto-generated method stub + int n = 3; + int result = new LeetCode_70_569().new Solution().climbStairs(n); + System.out.println(result); + } + + class Solution { + public int climbStairs(int n) { + if( n <= 2) + return n; + int prepre = 1; + int pre = 2; + int result = 0; + for( int i = 2; i < n; i++ ) { + result = prepre + pre; + prepre = pre; + pre = result; + } + return result; + } + } +} diff --git a/Week_06/G20200343030571/LeetCode_127_571.go b/Week_06/G20200343030571/LeetCode_127_571.go new file mode 100644 index 00000000..bf1c464d --- /dev/null +++ b/Week_06/G20200343030571/LeetCode_127_571.go @@ -0,0 +1,243 @@ +package main + +import ( + "strings" +) + +/* + * @lc app=leetcode.cn id=127 lang=golang + * + * [127] 单词接龙 + * + * https://leetcode-cn.com/problems/word-ladder/description/ + * + * algorithms + * Medium (40.31%) + * Likes: 238 + * Dislikes: 0 + * Total Accepted: 27.3K + * Total Submissions: 67K + * Testcase Example: '"hit"\n"cog"\n["hot","dot","dog","lot","log","cog"]' + * + * 给定两个单词(beginWord 和 endWord)和一个字典,找到从 beginWord 到 endWord + * 的最短转换序列的长度。转换需遵循如下规则: + * + * + * 每次转换只能改变一个字母。 + * 转换过程中的中间单词必须是字典中的单词。 + * + * + * 说明: + * + * + * 如果不存在这样的转换序列,返回 0。 + * 所有单词具有相同的长度。 + * 所有单词只由小写字母组成。 + * 字典中不存在重复的单词。 + * 你可以假设 beginWord 和 endWord 是非空的,且二者不相同。 + * + * + * 示例 1: + * + * 输入: + * beginWord = "hit", + * endWord = "cog", + * wordList = ["hot","dot","dog","lot","log","cog"] + * + * 输出: 5 + * + * 解释: 一个最短转换序列是 "hit" -> "hot" -> "dot" -> "dog" -> "cog", + * ⁠ 返回它的长度 5。 + * + * + * 示例 2: + * + * 输入: + * beginWord = "hit" + * endWord = "cog" + * wordList = ["hot","dot","dog","lot","log"] + * + * 输出: 0 + * + * 解释: endWord "cog" 不在字典中,所以无法进行转换。 + * + */ + +// @lc code=start + +func ladderLength1(beginWord string, endWord string, wordList []string) int { + /* if wordList == nil || len(wordList) == 0 { + return 0 + } + + mapNew := make(map[string]bool, len(wordList)) + for _, str := range wordList { + mapNew[str] = true + } + if !mapNew[endWord] { + return 0 + } + + //dfsFind(beginWord, endWord, 1, wordList, mapVisited) + return bfsFind(beginWord, endWord, wordList, mapNew) */ + wordMap := make(map[string]bool, len(wordList)) + for _, v := range wordList { + wordMap[v] = true + } + if !wordMap[endWord] { + return 0 + } + res := int(0) + queue := []string{beginWord} + + for len(queue) > 0 { + len := len(queue) + res++ + for i := 0; i < len; i++ { + popStr := queue[0] + queue = queue[1:] + for str, bNew := range wordMap { + if !bNew || !isOneChatDiff(popStr, str) { + continue + } + if strings.EqualFold(str, endWord) { + return res + 1 + } + + queue = append(queue, str) + wordMap[str] = false + + } + } + } + return 0 +} + +/* + 双向BFS + 笔记:实现起来比之前想象中,与单项的区别要大一点。主要在于注释了#处, + 这里的顺序要比单项要让人注意一些。主要原因有以下2点: + 1. 由于set2里初始化时就存了endword,所以必须先检查是否能转化再看set2里是否存在,否则每次运行必然直接返回1 + 2. 必须先检测set2里有没有再看是否是未访问状态,因为如果set2里有,即最终结果找到时,那个元素必然是被另一个访问过, + 如果先检测是否访问过,那么必然会每次都找不到最终返回0 + 所以双向BFS每次遍历的检测顺序很固定:1.是否可转化 2.是否找到 3.是否访问过 +*/ +func ladderLength(beginWord string, endWord string, wordList []string) int { + if wordList == nil || len(wordList) == 0 { + return 0 + } + + mapNew := make(map[string]bool, len(wordList)) + for _, word := range wordList { + mapNew[word] = true + } + if !mapNew[endWord] { + return 0 + } + + set1, set2 := map[string]bool{beginWord: true}, map[string]bool{endWord: true} + cnt := 0 //查找次数 + + for len(set1) != 0 && len(set2) != 0 { + len1, len2 := len(set1), len(set2) + if len1 > len2 { + set1, set2 = set2, set1 + } + + cnt++ + tmpSet := make(map[string]bool, 0) + for curWord := range set1 { + for _, w := range wordList { + //# + if !isOneChatDiff(w, curWord) { + continue + } + if set2[w] { + return cnt + 1 + } + if !mapNew[w] { + continue + } + + mapNew[w] = false + tmpSet[w] = true + } + } + set1 = tmpSet + } + return 0 +} + +/* +func dfsFind(curWord, endWord string, curLev int, wordList []string, mapVisited map[string]bool, res *int) { + if strings.EqualFold(curWord, endWord) { + if curLev < result || result == 0 { + result = curLev + return + } + } + + for _, str := range wordList { + bVisited, _ := mapVisited[str] + if bVisited || !isOneChatDiff(curWord, str) { + continue + } + mapVisited[str] = true + dfsFind(str, endWord, curLev+1, wordList, mapVisited) + mapVisited[str] = false + } + + return +} +*/ +func bfsFind(beginWord, endWord string, wordList []string, mapNew map[string]bool) int { + queue := []string{beginWord} + res := 0 + for len(queue) > 0 { + len := len(queue) + res++ + for i := 0; i < len; i++ { + popStr := queue[0] + queue = queue[1:] + for _, str := range wordList { + bNew, _ := mapNew[str] + if !bNew || !isOneChatDiff(popStr, str) { + continue + } + if strings.EqualFold(str, endWord) { + return res + 1 + } + + mapNew[str] = false + queue = append(queue, str) + } + } + } + return 0 +} + +func isOneChatDiff(wordA, wordB string) bool { + count := 0 + runeA, runeB := []rune(wordA), []rune(wordB) + len := len(runeA) + for i := 0; i < len; i++ { + if runeA[i] != runeB[i] { + count++ + } + if count > 1 { + return false + } + } + return count == 1 +} + +/* func main() { + beginWord, endWord := "hit", "cog" + wordList := []string{"hot", "dot", "dog", "lot", "log", "cog"} + //wordList := []string{"hot", "dot", "dog", "lot", "log"} + res := ladderLength(beginWord, endWord, wordList) + fmt.Println(res) + return +} */ + +// @lc code=end diff --git a/Week_06/G20200343030571/LeetCode_208_571.go b/Week_06/G20200343030571/LeetCode_208_571.go new file mode 100644 index 00000000..b2b3e141 --- /dev/null +++ b/Week_06/G20200343030571/LeetCode_208_571.go @@ -0,0 +1,98 @@ +package main + +/* + * @lc app=leetcode.cn id=208 lang=golang + * + * [208] 实现 Trie (前缀树) + * + * https://leetcode-cn.com/problems/implement-trie-prefix-tree/description/ + * + * algorithms + * Medium (65.17%) + * Likes: 223 + * Dislikes: 0 + * Total Accepted: 27.8K + * Total Submissions: 42.4K + * Testcase Example: '["Trie","insert","search","search","startsWith","insert","search"]\n' + + '[[],["apple"],["apple"],["app"],["app"],["app"],["app"]]' + * + * 实现一个 Trie (前缀树),包含 insert, search, 和 startsWith 这三个操作。 + * + * 示例: + * + * Trie trie = new Trie(); + * + * trie.insert("apple"); + * trie.search("apple"); // 返回 true + * trie.search("app"); // 返回 false + * trie.startsWith("app"); // 返回 true + * trie.insert("app"); + * trie.search("app"); // 返回 true + * + * 说明: + * + * + * 你可以假设所有的输入都是由小写字母 a-z 构成的。 + * 保证所有输入均为非空字符串。 + * + * +*/ + +// @lc code=start +/* const linkLen = 26 + +type Trie struct { + link [linkLen]*Trie + //value string + isEnd bool +} + + +func Constructor() Trie { + return Trie{} +} + + +func (this *Trie) Insert(word string) { + curNode := this + for _, c := range word { + if curNode.link[c-'a'] == nil { + curNode.link[c-'a'] = &Trie{} + } + curNode = curNode.link[c-'a'] + } + curNode.isEnd = true +} + + +func (this *Trie) Search(word string) bool { + curNode := this + for _, c := range word { + if curNode.link[c-'a'] == nil { + return false + } + curNode = curNode.link[c-'a'] + } + return curNode.isEnd +} + + +func (this *Trie) StartsWith(prefix string) bool { + curNode := this + for _, c := range prefix { + if curNode.link[c-'a'] == nil { + return false + } + curNode = curNode.link[c-'a'] + } + return true +} +*/ +/** + * Your Trie object will be instantiated and called as such: + * obj := Constructor(); + * obj.Insert(word); + * param_2 := obj.Search(word); + * param_3 := obj.StartsWith(prefix); + */ +// @lc code=end diff --git a/Week_06/G20200343030571/LeetCode_36_571.go b/Week_06/G20200343030571/LeetCode_36_571.go new file mode 100644 index 00000000..7621772c --- /dev/null +++ b/Week_06/G20200343030571/LeetCode_36_571.go @@ -0,0 +1,110 @@ +package main + +/* + * @lc app=leetcode.cn id=36 lang=golang + * + * [36] 有效的数独 + * + * https://leetcode-cn.com/problems/valid-sudoku/description/ + * + * algorithms + * Medium (58.62%) + * Likes: 288 + * Dislikes: 0 + * Total Accepted: 61.5K + * Total Submissions: 104.6K + * Testcase Example: '[["5","3",".",".","7",".",".",".","."],["6",".",".","1","9","5",".",".","."], + [".","9","8",".",".",".",".","6","."],["8",".",".",".","6",".",".",".","3"], + ["4",".",".","8",".","3",".",".","1"],["7",".",".",".","2",".",".",".","6"], + [".","6",".",".",".",".","2","8","."],[".",".",".","4","1","9",".",".","5"], + [".",".",".",".","8",".",".","7","9"]]' + * + * 判断一个 9x9 的数独是否有效。只需要根据以下规则,验证已经填入的数字是否有效即可。 + * + * + * 数字 1-9 在每一行只能出现一次。 + * 数字 1-9 在每一列只能出现一次。 + * 数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。 + * + * + * + * + * 上图是一个部分填充的有效的数独。 + * + * 数独部分空格内已填入了数字,空白格用 '.' 表示。 + * + * 示例 1: + * + * 输入: + * [ + * ⁠ ["5","3",".",".","7",".",".",".","."], + * ⁠ ["6",".",".","1","9","5",".",".","."], + * ⁠ [".","9","8",".",".",".",".","6","."], + * ⁠ ["8",".",".",".","6",".",".",".","3"], + * ⁠ ["4",".",".","8",".","3",".",".","1"], + * ⁠ ["7",".",".",".","2",".",".",".","6"], + * ⁠ [".","6",".",".",".",".","2","8","."], + * ⁠ [".",".",".","4","1","9",".",".","5"], + * ⁠ [".",".",".",".","8",".",".","7","9"] + * ] + * 输出: true + * + * + * 示例 2: + * + * 输入: + * [ + * ["8","3",".",".","7",".",".",".","."], + * ["6",".",".","1","9","5",".",".","."], + * [".","9","8",".",".",".",".","6","."], + * ["8",".",".",".","6",".",".",".","3"], + * ["4",".",".","8",".","3",".",".","1"], + * ["7",".",".",".","2",".",".",".","6"], + * [".","6",".",".",".",".","2","8","."], + * [".",".",".","4","1","9",".",".","5"], + * [".",".",".",".","8",".",".","7","9"] + * ] + * 输出: false + * 解释: 除了第一行的第一个数字从 5 改为 8 以外,空格内其他数字均与 示例1 相同。 + * ⁠ 但由于位于左上角的 3x3 宫内有两个 8 存在, 因此这个数独是无效的。 + * + * 说明: + * + * + * 一个有效的数独(部分已被填充)不一定是可解的。 + * 只需要根据以上规则,验证已经填入的数字是否有效即可。 + * 给定数独序列只包含数字 1-9 和字符 '.' 。 + * 给定数独永远是 9x9 形式的。 + * + * +*/ + +// @lc code=start + +/* + 发现在golang中用map充当set有时候还挺方便的,比如这个就可以把三条记录写成一行 +*/ + +/* func isValidSudoku(board [][]byte) bool { + setCol, setRow, setBlock := make(map[int]map[int]bool, 9), make(map[int]map[int]bool, 9), make(map[int]map[int]bool, 9) + for i := 0; i < 9; i++ { + setCol[i], setRow[i], setBlock[i] = make(map[int]bool, 9), make(map[int]bool, 9), make(map[int]bool, 9) + } + + for i := 0; i < 9; i++ { + for j := 0; j < 9; j++ { + if board[i][j] == '.' { + continue + } + n := int(board[i][j]) + idxCol, idxRow, idxBlock := i, j, i/3*3+j/3 + if setCol[idxCol][n] || setRow[idxRow][n] || setBlock[idxBlock][n] { + return false + } + setCol[idxCol][n], setRow[idxRow][n], setBlock[idxBlock][n] = true, true, true + } + } + return true +} */ + +// @lc code=end diff --git a/Week_06/G20200343030571/LeetCode_37_571.go b/Week_06/G20200343030571/LeetCode_37_571.go new file mode 100644 index 00000000..c3dc8eb5 --- /dev/null +++ b/Week_06/G20200343030571/LeetCode_37_571.go @@ -0,0 +1,95 @@ +package main + +/* + * @lc app=leetcode.cn id=37 lang=golang + * + * [37] 解数独 + * + * https://leetcode-cn.com/problems/sudoku-solver/description/ + * + * algorithms + * Hard (60.03%) + * Likes: 351 + * Dislikes: 0 + * Total Accepted: 22K + * Total Submissions: 36.4K + * Testcase Example: '[["5","3",".",".","7",".",".",".","."],["6",".",".","1","9","5",".",".","."],[".","9","8",".",".",".",".","6","."],["8",".",".",".","6",".",".",".","3"],["4",".",".","8",".","3",".",".","1"],["7",".",".",".","2",".",".",".","6"],[".","6",".",".",".",".","2","8","."],[".",".",".","4","1","9",".",".","5"],[".",".",".",".","8",".",".","7","9"]]' + * + * 编写一个程序,通过已填充的空格来解决数独问题。 + * + * 一个数独的解法需遵循如下规则: + * + * + * 数字 1-9 在每一行只能出现一次。 + * 数字 1-9 在每一列只能出现一次。 + * 数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。 + * + * + * 空白格用 '.' 表示。 + * + * + * + * 一个数独。 + * + * + * + * 答案被标成红色。 + * + * Note: + * + * + * 给定的数独序列只包含数字 1-9 和字符 '.' 。 + * 你可以假设给定的数独只有唯一解。 + * 给定数独永远是 9x9 形式的。 + * + * + */ + +// @lc code=start +func solveSudoku(board [][]byte) { + if board == nil || len(board) == 0 { + return + } + dfsSolve(board) +} + +func dfsSolve(board [][]byte) bool { + for i := 0; i < 9; i++ { + for j := 0; j < 9; j++ { + if board[i][j] != '.' { + continue + } + for n := '1'; n <= '9'; n++ { //用rune直接转byte,如果用int那么结果会出乱码 + + board[i][j] = byte(n) + if dfsSolve(board) { + return true + } + board[i][j] = byte('.') + } + return false + } + } + return true +} + +func isValid(n byte, i, j int, board [][]byte) bool { + for k := 0; k < 9; k++ { + if board[i][k] == byte(n) || board[k][j] == byte(n) { + return false + } + if board[3*(i/3)+k/3][3*(j/3)+k%3] == byte(n) { //? + return false + } + } + return true +} + +/* func main() { + i := 8 + var b byte = byte(i) + fmt.Printf("byte %#v \n int %d \n", b, b) + return +} +*/ +// @lc code=end diff --git a/Week_06/G20200343030571/LeetCode_773_571.go b/Week_06/G20200343030571/LeetCode_773_571.go new file mode 100644 index 00000000..221bbd7a --- /dev/null +++ b/Week_06/G20200343030571/LeetCode_773_571.go @@ -0,0 +1,129 @@ +package main + +/* + * @lc app=leetcode.cn id=773 lang=golang + * + * [773] 滑动谜题 + * + * https://leetcode-cn.com/problems/sliding-puzzle/description/ + * + * algorithms + * Hard (57.66%) + * Likes: 45 + * Dislikes: 0 + * Total Accepted: 2K + * Total Submissions: 3.4K + * Testcase Example: '[[1,2,3],[4,0,5]]' + * + * 在一个 2 x 3 的板上(board)有 5 块砖瓦,用数字 1~5 来表示, 以及一块空缺用 0 来表示. + * + * 一次移动定义为选择 0 与一个相邻的数字(上下左右)进行交换. + * + * 最终当板 board 的结果是 [[1,2,3],[4,5,0]] 谜板被解开。 + * + * 给出一个谜板的初始状态,返回最少可以通过多少次移动解开谜板,如果不能解开谜板,则返回 -1 。 + * + * 示例: + * + * + * 输入:board = [[1,2,3],[4,0,5]] + * 输出:1 + * 解释:交换 0 和 5 ,1 步完成 + * + * + * + * 输入:board = [[1,2,3],[5,4,0]] + * 输出:-1 + * 解释:没有办法完成谜板 + * + * + * + * 输入:board = [[4,1,2],[5,0,3]] + * 输出:5 + * 解释: + * 最少完成谜板的最少移动次数是 5 , + * 一种移动路径: + * 尚未移动: [[4,1,2],[5,0,3]] + * 移动 1 次: [[4,1,2],[0,5,3]] + * 移动 2 次: [[0,1,2],[4,5,3]] + * 移动 3 次: [[1,0,2],[4,5,3]] + * 移动 4 次: [[1,2,0],[4,5,3]] + * 移动 5 次: [[1,2,3],[4,5,0]] + * + * + * + * 输入:board = [[3,2,4],[1,5,0]] + * 输出:14 + * + * + * 提示: + * + * + * board 是一个如上所述的 2 x 3 的数组. + * board[i][j] 是一个 [0, 1, 2, 3, 4, 5] 的排列. + * + * + */ + +// @lc code=start +func slidingPuzzle(board [][]int) int { + move := [][]int{{1, 3}, {0, 2, 4}, {1, 5}, {0, 4}, {1, 3, 5}, {2, 4}} + startSlice := append(board[0], board[1]...) + var start [6]int + sliceToArr(startSlice, &start) + end := [...]int{1, 2, 3, 4, 5, 0} + queue := [][6]int{start} + visited := make(map[[6]int]bool, 0) + visited[start] = true + cnt := 0 + + for len(queue) > 0 { + len := len(queue) + for i := 0; i < len; i++ { + curState := queue[0] + queue = queue[1:] + if curState == end { + return cnt + } + + zeroIdx := getZeroIndex(&curState) + for _, v := range move[zeroIdx] { + tmp := curState + tmp[zeroIdx], tmp[v] = tmp[v], tmp[zeroIdx] + if visited[tmp] { + continue + } + visited[tmp] = true + queue = append(queue, tmp) + } + } + cnt++ + } + return -1 +} + +func sliceToArr(slice []int, arr *[6]int) { + for i, v := range slice { + arr[i] = v + } + return +} + +func getZeroIndex(a *[6]int) int { + for i, v := range *a { + if v == 0 { + return i + } + } + return -1 +} + +/* func main() { + input := [][]int{ + {4, 1, 2}, {5, 0, 3}} + res := slidingPuzzle(input) + fmt.Println(res) + return +} */ + +// @lc code=end diff --git a/Week_06/G20200343030573/LeetCode_127_573.py b/Week_06/G20200343030573/LeetCode_127_573.py new file mode 100644 index 00000000..aae51901 --- /dev/null +++ b/Week_06/G20200343030573/LeetCode_127_573.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- + +import sys +import string + +__author__ = "Onceabu" +__version__ = "v1.0" + +""" + Time + describe +""" + +reload(sys) +sys.setdefaultencoding('utf-8') + + +class Solution(object): + def ladderLength(self, beginWord, endWord, wordList): + """ + :type beginWord: str + :type endWord: str + :type wordList: List[str] + :rtype: int + """ + if endWord not in wordList: + return 0 + front = {beginWord} + back = {endWord} + # 步数 + dist = 1 + wordList = set(wordList) + word_len = len(beginWord) + while front: + dist += 1 + next_front = set() + for word in front: + for i in range(word_len): + for c in string.lowercase: + if c != word[i]: + new_word = word[:i] + c + word[i + 1:] + if new_word in back: + return dist + if new_word in wordList: + next_front.add(new_word) + wordList.remove(new_word) + front = next_front + if len(back) < len(front): + front, back = back, front + return 0 diff --git a/Week_06/G20200343030573/LeetCode_200_573.py b/Week_06/G20200343030573/LeetCode_200_573.py new file mode 100644 index 00000000..6dfcae65 --- /dev/null +++ b/Week_06/G20200343030573/LeetCode_200_573.py @@ -0,0 +1,32 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- + +import sys + +__author__ = "Onceabu" +__version__ = "v1.0" + +""" + Time + describe +""" + +reload(sys) +sys.setdefaultencoding('utf-8') + + +class Solution(object): + def numIslands(self, grid): + """ + :type grid: List[List[str]] + :rtype: int + """ + + def sink(i, j): + if 0 <= i < len(grid) and 0 <= j < len(grid[i]) and grid[i][j] == '1': + grid[i][j] = '0' + map(sink, (i + 1, i - 1, i, i), (j, j, j + 1, j - 1)) + return 1 + return 0 + + return sum(sink(i, j) for i in range(len(grid)) for j in range(len(grid[i]))) diff --git a/Week_06/G20200343030573/LeetCode_208_573.py b/Week_06/G20200343030573/LeetCode_208_573.py new file mode 100644 index 00000000..f3490ad0 --- /dev/null +++ b/Week_06/G20200343030573/LeetCode_208_573.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- + +import sys + +__author__ = "Onceabu" +__version__ = "v1.0" + +""" + Time + describe +""" + +reload(sys) +sys.setdefaultencoding('utf-8') + + +class Trie(object): + + def __init__(self): + self.set1 = set() + self.set2 = set() + + def insert(self, word): + self.set1.add(word) + for i in range(len(word)): + self.set2.add(word[:i + 1]) + + def search(self, word): + if word in self.set1: + return True + else: + return False + + def startsWith(self, prefix): + if prefix in self.set2: + return True + else: + return False diff --git a/Week_06/G20200343030573/LeetCode_212_573.py b/Week_06/G20200343030573/LeetCode_212_573.py new file mode 100644 index 00000000..087d1165 --- /dev/null +++ b/Week_06/G20200343030573/LeetCode_212_573.py @@ -0,0 +1,76 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- +import sys +from collections import defaultdict + +__author__ = "Onceabu" +__version__ = "v1.0" + +""" + Time + describe +""" + +reload(sys) +sys.setdefaultencoding('utf-8') + +# words = ["oath","pea","eat","rain"] +# board = [ +# ['o', 'a', 'a', 'n'], +# ['e', 't', 'a', 'e'], +# ['i', 'h', 'k', 'r'], +# ['i', 'f', 'l', 'v'] +# ] + +dx = [-1, 1, 0, 0] +dy = [0, 0, -1, 1] +END_OF_WORD = '#' + + +class Solution(object): + def findWords(self, board, words): + """ + :type board: List[List[str]] + :type words: List[str] + :rtype: List[str] + """ + if not board or not board[0]: + return [] + if not words: + return [] + + self.result = set() + + # O(N*k) N是words的长度 k是单词平均长度 + # 构建Trie树 + root = defaultdict() + for word in words: + node = root + for char in word: + # 返回子节点 + node = node.setdefault(char, defaultdict()) + node[END_OF_WORD] = END_OF_WORD + + # O(m*n*N*k) + self.m, self.n = len(board), len(board[0]) + for i in xrange(self.m): + for j in xrange(self.n): + if board[i][j] in root: + self._dfs(board, i, j, '', root) + return list(self.result) + + # O(N*k) + def _dfs(self, board, i, j, cur_word, cur_dict): + cur_word += board[i][j] + cur_dict = cur_dict[board[i][j]] + if END_OF_WORD in cur_dict: + self.result.add(cur_word) + tmp, board[i][j] = board[i][j], '@' + for k in xrange(4): + x, y = i + dx[k], j + dy[k] + if 0 <= x < self.m and 0 <= y < self.n and board[x][y] != '@' and board[x][y] in cur_dict: + self._dfs(board, x, y, cur_word, cur_dict) + board[i][j] = tmp + +# 完整的时间复杂度是 O(N*k)+O(m*n*N*k) +# 最终的时间复杂度就是 O(m*n*N*k) N是words的长度 k是单词平均长度 m是board的行数 n是列数 diff --git a/Week_06/G20200343030573/LeetCode_70_573.py b/Week_06/G20200343030573/LeetCode_70_573.py new file mode 100644 index 00000000..7f880ea2 --- /dev/null +++ b/Week_06/G20200343030573/LeetCode_70_573.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- + +import sys + +__author__ = "Onceabu" +__version__ = "v1.0" + +""" + Time + describe +""" + +reload(sys) +sys.setdefaultencoding('utf-8') + + +class Solution(object): + def climbStairs(self, n): + """ + :type n: int + :rtype: int + """ + if n <= 2: + return n + i, a, b = 0, 0, 1 + while i < n: + a, b = b, a + b + i += 1 + return b diff --git a/Week_06/G20200343030577/LeetCode_208_577.go b/Week_06/G20200343030577/LeetCode_208_577.go new file mode 100644 index 00000000..6fd89766 --- /dev/null +++ b/Week_06/G20200343030577/LeetCode_208_577.go @@ -0,0 +1,99 @@ +package leetcode + +/* + * @lc app=leetcode.cn id=208 lang=golang + * + * [208] 实现 Trie (前缀树) + * + * https://leetcode-cn.com/problems/implement-trie-prefix-tree/description/ + * + * algorithms + * Medium (64.22%) + * Likes: 225 + * Dislikes: 0 + * Total Accepted: 28.1K + * Total Submissions: 42.9K + * Testcase Example: '["Trie","insert","search","search","startsWith","insert","search"]\n' + + '[[],["apple"],["apple"],["app"],["app"],["app"],["app"]]' + * + * 实现一个 Trie (前缀树),包含 insert, search, 和 startsWith 这三个操作。 + * + * 示例: + * + * Trie trie = new Trie(); + * + * trie.insert("apple"); + * trie.search("apple"); // 返回 true + * trie.search("app"); // 返回 false + * trie.startsWith("app"); // 返回 true + * trie.insert("app"); + * trie.search("app"); // 返回 true + * + * 说明: + * + * + * 你可以假设所有的输入都是由小写字母 a-z 构成的。 + * 保证所有输入均为非空字符串。 + * + * +*/ + +// @lc code=start +type Trie struct { + ret map[string]bool +} + +/** Initialize your data structure here. */ +func Constructor() Trie { + return Trie{ + ret: make(map[string]bool), + } +} + +/** Inserts a word into the trie. */ +func (this *Trie) Insert(word string) { + this.ret[word] = true +} + +/** Returns if the word is in the trie. */ +func (this *Trie) Search(word string) bool { + return this.ret[word] + +} + +/** Returns if there is any word in the trie that starts with the given prefix. */ +func (this *Trie) StartsWith(prefix string) bool { + if this.ret[prefix] { + return true + } + + for i := range this.ret { + var flag int + if len(i) < len(prefix) { + continue + } + + for k := range prefix { + if i[k] != prefix[k] { + break + } else { + flag++ + } + + if flag == len(prefix) { + return true + } + } + } + return false + +} + +/** + * Your Trie object will be instantiated and called as such: + * obj := Constructor(); + * obj.Insert(word); + * param_2 := obj.Search(word); + * param_3 := obj.StartsWith(prefix); + */ +// @lc code=end diff --git a/Week_06/G20200343030577/Leetcode_547_577.go b/Week_06/G20200343030577/Leetcode_547_577.go new file mode 100644 index 00000000..503c8d28 --- /dev/null +++ b/Week_06/G20200343030577/Leetcode_547_577.go @@ -0,0 +1,126 @@ +package leetcode + +/* + * @lc app=leetcode.cn id=547 lang=golang + * + * [547] 朋友圈 + * + * https://leetcode-cn.com/problems/friend-circles/description/ + * + * algorithms + * Medium (54.65%) + * Likes: 198 + * Dislikes: 0 + * Total Accepted: 29.7K + * Total Submissions: 53.5K + * Testcase Example: '[[1,1,0],[1,1,0],[0,0,1]]' + * + * 班上有 N 名学生。其中有些人是朋友,有些则不是。他们的友谊具有是传递性。如果已知 A 是 B 的朋友,B 是 C 的朋友,那么我们可以认为 A 也是 + * C 的朋友。所谓的朋友圈,是指所有朋友的集合。 + * + * 给定一个 N * N 的矩阵 M,表示班级中学生之间的朋友关系。如果M[i][j] = 1,表示已知第 i 个和 j + * 个学生互为朋友关系,否则为不知道。你必须输出所有学生中的已知的朋友圈总数。 + * + * 示例 1: + * + * + * 输入: + * [[1,1,0], + * ⁠[1,1,0], + * ⁠[0,0,1]] + * 输出: 2 + * 说明:已知学生0和学生1互为朋友,他们在一个朋友圈。 + * 第2个学生自己在一个朋友圈。所以返回2。 + * + * + * 示例 2: + * + * + * 输入: + * [[1,1,0], + * ⁠[1,1,1], + * ⁠[0,1,1]] + * 输出: 1 + * 说明:已知学生0和学生1互为朋友,学生1和学生2互为朋友,所以学生0和学生2也是朋友,所以他们三个在一个朋友圈,返回1。 + * + * + * 注意: + * + * + * N 在[1,200]的范围内。 + * 对于所有学生,有M[i][i] = 1。 + * 如果有M[i][j] = 1,则有M[j][i] = 1。 + * + * + */ + +// @lc code=start +func findCircleNum(M [][]int) int { + // 使用并查集 + u := NewUFS(len(M)) + for i := 0; i < len(M); i++ { + for j := i + 1; j < len(M); j++ { + if M[i][j] == 0 { + continue + } + u.Union(i, j) + } + } + // 查找朋友圈个数 + m := make(map[int]struct{}) + for i := 0; i < len(M); i++ { + m[u.Find(i)] = struct{}{} + } + return len(m) +} + +type UFS struct { + s []int + sz []int +} + +func NewUFS(n int) *UFS { + s := make([]int, n) + sz := make([]int, n) + for i := 0; i < len(s); i++ { + s[i] = i + sz[i] = 1 + } + return &UFS{s: s, sz: sz} +} + +func (u *UFS) Find(n int) int { + if n > len(u.s) || n < 0 { + return -1 + } + r, j := u.s[n], n + for r != j { + j = r + r = u.s[j] + } + // 压缩路径 + p := 0 + for u.s[n] != n { + p = u.s[n] + u.s[n] = r + n = p + } + return r +} + +func (u *UFS) Union(i int, j int) { + p := u.Find(i) + q := u.Find(j) + if p == q { + return + } + if u.sz[p] < u.sz[q] { + u.s[p] = q + u.sz[q] += u.sz[p] + } else { + u.s[q] = p + u.sz[p] += u.sz[q] + } +} + +// @lc code=end diff --git a/Week_06/G20200343030577/NOTE.md b/Week_06/G20200343030577/NOTE.md index 50de3041..0b23f1d5 100644 --- a/Week_06/G20200343030577/NOTE.md +++ b/Week_06/G20200343030577/NOTE.md @@ -1 +1,34 @@ -学习笔记 \ No newline at end of file +# 第6周学习心得 +### 创建时间:2020-03-22 10:37 + +## Trie字典树 + - 字典顺序排列 + - "单词"结束标记 +## 剪枝 + - drill down 之前进行条件判断,不符合的跳过 + - 本质还是递归 +## 双向BFS + - 本质bfs + - 与普通bfs不同之处在于首尾轮流分层bfs,直到在中间层相遇 +## A*搜索 + - 基于bfs + - 普通队列->优先级队列 + - 优先级函数 + - 降低搜索节点的个数 +## AVL树 + - 严格的平衡二叉树 + - 每个节点只允许{-1,0,1}中的任一层差,即高度差最大为1 + - 适用于多读少写的场景 + - 通过旋转方式来平衡(4种基础旋转方式): + - 左左树 -> 右旋 + - 右右树 -> 左旋 + - 左右树 -> 右左旋 + - 右左树 -> 左右旋 +## 红黑树 + - 近似的平衡二叉树 + - 高度差不能超过两倍,与AVL相比,大大降低来插入和修改带来的平衡代价,但同时搜索性能下降,适用于多写的场景 + - 每个节点只能黑色或者红色 + - 根节点是黑色,叶子节点都是nil, + - 红色节点只能是左节点,右节点只能是黑色或者nil,红色节点的左节点只能是nil或者黑色节点(不存在连续的红色节点) + - 从根节点出发的任意路径上的黑色节点都相等,即黑色节点平衡 + \ No newline at end of file diff --git a/Week_06/G20200343030585/LeetCode_208_585.py b/Week_06/G20200343030585/LeetCode_208_585.py new file mode 100644 index 00000000..7d721407 --- /dev/null +++ b/Week_06/G20200343030585/LeetCode_208_585.py @@ -0,0 +1,68 @@ +# +# @lc app=leetcode.cn id=208 lang=python +# +# [208] 实现 Trie (前缀树) +# + +# @lc code=start + + +class Trie(object): + + def __init__(self): + """ + Initialize your data structure here. + """ + self.root = {} + self.end_of_word = "#" + + def insert(self, word): + """ + Inserts a word into the trie. + :type word: str + :rtype: None + """ + node = self.root + for char in word: + # 巧妙的实现,setdefault每次设置值如果值存在就返回值 + # 不存在就返回默认值 + node = node.setdefault(char, {}) + # 词尾用终止符标识 + node[self.end_of_word] = self.end_of_word + + def search(self, word): + """ + Returns if the word is in the trie. + :type word: str + :rtype: bool + """ + node = self.root + for char in word: + if char not in node: + return False + node = node[char] + + return self.end_of_word in node + + def startsWith(self, prefix): + """ + Returns if there is any word in the trie that starts with the given prefix. + :type prefix: str + :rtype: bool + """ + node = self.root + for char in prefix: + if char not in node: + return False + node = node[char] + return True + + + +# Your Trie object will be instantiated and called as such: +# obj = Trie() +# obj.insert(word) +# param_2 = obj.search(word) +# param_3 = obj.startsWith(prefix) +# @lc code=end + diff --git a/Week_06/G20200343030585/LeetCode_212_585.py b/Week_06/G20200343030585/LeetCode_212_585.py new file mode 100644 index 00000000..8561e5cc --- /dev/null +++ b/Week_06/G20200343030585/LeetCode_212_585.py @@ -0,0 +1,107 @@ +# -*- coding: utf-8 -*- +# +# @lc app=leetcode.cn id=212 lang=python +# +# [212] 单词搜索 II +# + +# 解题思路 +# 1.Trie树 +# 1.构建words的字典树 +# 在字典树的处理过程中可以简化,直接使用dict的setdefault方法解决赋值和返回 +# 2.对boards网格 进行 DFS,四个方向DFS +# 通过字典树过滤掉前缀不符合要求的部分 +# 3.题目要求一个词里面不能重复使用字母,所以要记录这一次使用的位置,使用完后要清理 +# 这里用set不用dict,因为set和dict本质存储类似,set不存储value所以更快, +# 而且可以用set | {(i,j)}的结构解决回溯问题,避免dict的添加和删除两次操作 + +# @lc code=start + +class Solution(object): + def findWords(self, board, words): + """ + :type board: List[List[str]] + :type words: List[str] + :rtype: List[str] + """ + trie = {} # 构造字典树 + for word in words: + node = trie + for char in word: + node = node.setdefault(char, {}) + node['#'] = True + + res = set() + m = len(board) + n = len(board[0]) + # cnt = {'cnt':1} + + # DFS + def dfs(x, y, node, word, used): + if '#' in node: + res.add(word) + + + for x1,y1 in [[-1,0], [1,0], [0,1], [0,-1]]: # 四个方向 + _x,_y = x+x1, y+y1 + if 0 <= _x < m and 0 <= _y < n and board[_x][_y] in node: + if (_x, _y) not in used: + # cnt['cnt'] +=1 + dfs(_x, _y, node[board[_x][_y]], word + board[_x][_y], used | {(_x, _y)}) + + + + for i in range(m): + for j in range(n): + if board[i][j] in trie: # 可继续搜索 + dfs(i,j, trie[board[i][j]], board[i][j], {(i,j)}) + # print(cnt) + return list(res) + +if __name__ == "__main__": + obj = Solution() + ret = obj.findWords([ + ["b","a","a","b","a","b"], + ["a","b","a","a","a","a"], + ["a","b","a","a","a","b"], + ["a","b","a","b","b","a"], + ["a","a","b","b","a","b"], + ["a","a","b","b","b","a"], + ["a","a","b","a","a","b"] + ], + [ + "bbaabaabaaaaabaababaaaaababb", + "aabbaaabaaabaabaaaaaabbaaaba", + "babaababbbbbbbaabaababaabaaa", + "bbbaaabaabbaaababababbbbbaaa", + "babbabbbbaabbabaaaaaabbbaaab", + "bbbababbbbbbbababbabbbbbabaa", + "babababbababaabbbbabbbbabbba", + "abbbbbbaabaaabaaababaabbabba", + "aabaabababbbbbbababbbababbaa", + "aabbbbabbaababaaaabababbaaba", + "ababaababaaabbabbaabbaabbaba", + "abaabbbaaaaababbbaaaaabbbaab", + "aabbabaabaabbabababaaabbbaab", + "baaabaaaabbabaaabaabababaaaa", + "aaabbabaaaababbabbaabbaabbaa", + "aaabaaaaabaabbabaabbbbaabaaa", + "abbaabbaaaabbaababababbaabbb", + "baabaababbbbaaaabaaabbababbb", + "aabaababbaababbaaabaabababab", + "abbaaabbaabaabaabbbbaabbbbbb", + "aaababaabbaaabbbaaabbabbabab", + "bbababbbabbbbabbbbabbbbbabaa", + "abbbaabbbaaababbbababbababba", + "bbbbbbbabbbababbabaabababaab", + "aaaababaabbbbabaaaaabaaaaabb", + "bbaaabbbbabbaaabbaabbabbaaba", + "aabaabbbbaabaabbabaabababaaa", + "abbababbbaababaabbababababbb", + "aabbbabbaaaababbbbabbababbbb", + "babbbaabababbbbbbbbbaabbabaa"] + ) + print(ret) + +# @lc code=end + diff --git a/Week_06/G20200343030585/LeetCode_36_585.py b/Week_06/G20200343030585/LeetCode_36_585.py new file mode 100644 index 00000000..b8a7095f --- /dev/null +++ b/Week_06/G20200343030585/LeetCode_36_585.py @@ -0,0 +1,46 @@ +# +# @lc app=leetcode.cn id=36 lang=python +# +# [36] 有效的数独 +# + +# 解题思路 +# 1.回溯和剪枝 +# 1.对每个行、列,宫格都设置为一个集合Or数组 +# 2.循环每个行列,判断元素是否在行列和宫格里面只有一个 +# +# @lc code=start +class Solution(object): + def isValidSudoku(self, board): + """ + :type board: List[List[str]] + :rtype: bool + """ + if not board: + return False + + # 初始化行列和宫格数据 + m = 9 + cols = [[] * 9 for _ in range(9)] + rows = [[] * 9 for _ in range(9)] + boxs = [[] * 9 for _ in range(9)] + + def index(i, j): + return (i//3) * 3 + j // 3 + + + for i in range(m): + for j in range(m): + if board[i][j] != '.': + num = int(board[i][j]) + if num not in rows[i] and num not in cols[j] and num not in boxs[index(i,j)]: + rows[i].append(num) + cols[j].append(num) + boxs[index(i,j)].append(num) + else: + return False + return True + + + +# @lc code=end diff --git a/Week_06/G20200343030585/LeetCode_37_585.py b/Week_06/G20200343030585/LeetCode_37_585.py new file mode 100644 index 00000000..6fb9e742 --- /dev/null +++ b/Week_06/G20200343030585/LeetCode_37_585.py @@ -0,0 +1,180 @@ +# -*- coding:utf-8 -*- +# +# @lc app=leetcode.cn id=37 lang=python +# +# [37] 解数独 +# +# 解题思路 +# 1.回溯+剪枝 +# 1.遍历元素获取已经放入的1-9范围 +# 2.递归节点,查找所有可能,如果没有可能就剪枝 + +# @lc code=start +from collections import defaultdict +class Solution: + def solveSudoku(self, board): + """ + :type board: List[List[str]] + :rtype: void Do not return anything, modify board in-place instead. + """ + def could_place(d, row, col): + """ + Check if one could place a number d in (row, col) cell + """ + return not (d in rows[row] or d in columns[col] or \ + d in boxes[box_index(row, col)]) + + def place_number(d, row, col): + """ + Place a number d in (row, col) cell + """ + rows[row][d] += 1 + columns[col][d] += 1 + boxes[box_index(row, col)][d] += 1 + board[row][col] = str(d) + + def remove_number(d, row, col): + """ + Remove a number which didn't lead + to a solution + """ + del rows[row][d] + del columns[col][d] + del boxes[box_index(row, col)][d] + board[row][col] = '.' + + def place_next_numbers(row, col): + """ + Call backtrack function in recursion + to continue to place numbers + till the moment we have a solution + """ + # if we're in the last cell + # that means we have the solution + if col == N - 1 and row == N - 1: + sudoku_solved[0] = True + #if not yet + else: + # if we're in the end of the row + # go to the next row + if col == N - 1: + backtrack(row + 1, 0) + # go to the next column + else: + backtrack(row, col + 1) + + + def backtrack(row = 0, col = 0): + """ + Backtracking + """ + # if the cell is empty + if board[row][col] == '.': + # iterate over all numbers from 1 to 9 + for d in range(1, 10): + if could_place(d, row, col): + place_number(d, row, col) + place_next_numbers(row, col) + # print(board) + # if sudoku is solved, there is no need to backtrack + # since the single unique solution is promised + if not sudoku_solved[0]: + remove_number(d, row, col) + else: + place_next_numbers(row, col) + + # box size + n = 3 + # row size + N = n * n + # lambda function to compute box index + box_index = lambda row, col: (row // n ) * n + col // n + + # init rows, columns and boxes + rows = [defaultdict(int) for i in range(N)] + columns = [defaultdict(int) for i in range(N)] + boxes = [defaultdict(int) for i in range(N)] + for i in range(N): + for j in range(N): + if board[i][j] != '.': + d = int(board[i][j]) + place_number(d, i, j) + + sudoku_solved = {} + sudoku_solved[0] = False + backtrack() + + +# class Solution(object): +# def solveSudoku(self, board): +# """ +# :type board: List[List[str]] +# :rtype: None Do not return anything, modify board in-place instead. +# """ + +# def index(i, j): +# return (i//3) * 3 + j // 3 + +# def could_place(x, row, col): +# return not (x in rows[row] or x in cols[col] or \ +# x in boxs[index(col, row)]) + +# def place(x, i, j): +# rows[i].append(x) +# cols[j].append(x) +# boxs[index(i,j)].append(x) +# board[i][j] = x + +# def remove(x, i, j): +# board[i][j] = '.' +# rows[i].remove(x) +# cols[j].remove(x) +# boxs[index(i,j)].remove(x) + +# def place_next(row, col): +# if row == m - 1 and col == m - 1: +# sudu[0] = True +# else: +# if col + 1 == m: +# backtrace(row + 1, 0) +# else: +# backtrace(row, col + 1) + +# def backtrace(row = 0, col = 0): + +# if board[row][col] == '.': +# for x in range(1,10): +# if could_place(x, row, col): +# place(x, row, col) +# place_next(row, col) +# print(board) + +# if not sudu[0]: +# remove(x, row, col) +# else: +# place_next(row, col) + + +# m = 9 +# cols = [[0] * 9 for _ in range(9)] +# rows = [[0] * 9 for _ in range(9)] +# boxs = [[0] * 9 for _ in range(9)] +# sudu = {0:False} + +# for i in range(m): +# for j in range(m): +# if board[i][j] != '.': +# d = int(board[i][j]) +# place(d, i, j) + +# backtrace() +# return board + + +if __name__ == "__main__": + obj = Solution() + ret = obj.solveSudoku([["5","3",".",".","7",".",".",".","."],["6",".",".","1","9","5",".",".","."],[".","9","8",".",".",".",".","6","."],["8",".",".",".","6",".",".",".","3"],["4",".",".","8",".","3",".",".","1"],["7",".",".",".","2",".",".",".","6"],[".","6",".",".",".",".","2","8","."],[".",".",".","4","1","9",".",".","5"],[".",".",".",".","8",".",".","7","9"]]) + print(ret) + +# @lc code=end + diff --git a/Week_06/G20200343030585/LeetCode_547_585.py b/Week_06/G20200343030585/LeetCode_547_585.py new file mode 100644 index 00000000..8a2fde51 --- /dev/null +++ b/Week_06/G20200343030585/LeetCode_547_585.py @@ -0,0 +1,120 @@ +# +# @lc app=leetcode.cn id=547 lang=python +# +# [547] 朋友圈 +# +# 解题思路 +# 1、并查集 +# 1.首先建立并查集,并添加每位学生 +# 2.然后遍历矩阵,找到两两之间的关系,如果是朋友就放到一个集合里 +# 3.最后看有多少集合就知道有多少个朋友圈了,是朋友的都在一个集合里面 + +# 对并查集的压缩的理解 +# 1.比如有1,2,3,4以类似链表形式一次排列,每个指向上一级 +# 2.执行压缩,取出当前 p[i] != i的元素,证明这个元素不是根,那么就把他指向根,p[i] = root +# 3.他的上一级元素呢,他其实是原来p[i]的值为键的那个元素,所以要把原来的p[i]值保留一份 +# 4.然后依次loop上述过程,知道到达根为止 + +# @lc code=start +class Solution(object): + def findCircleNum(self, M): + """ + :type M: List[List[int]] + :rtype: int + """ + #边界判断 + if not M: + return 0 + + # 特别注意,逻辑不好理解 + def parent(p, i): + root = i + while p[root] != root: + root = p[root] + while p[i] != i: # 路径压缩 ? + x = i + i = p[i] + p[x] = root + return root + + + def union(p, i, j): + p1 = parent(p, i) + p2 = parent(p, j) + # 如果是同一个朋友圈(集合)就不用改了 + # 朋友圈矩阵有重复数据,朋友互相指对方为朋友的情况 + if p1 == p2: + return + p[p1] = p2 + + # 构建并查集 + n = len(M) + unionfind = [i for i in range(n)] + + # 遍历M,找到朋友关系 + for i in range(n): + for j in range(n): + if M[i][j] == 1 and i != j: + union(unionfind, i, j) + + count = 0 + for i in range(len(unionfind)): + if unionfind[i] == i: + count+=1 + return count + +# class unionFind(object): +# p = None + +# def init(self, n): +# # for i = 0 .. n: p[i] = i; +# self.p = [i for i in range(n)] + +# def union(self, i, j): +# p1 = self.parent(i) +# p2 = self.parent(j) +# self.p[p1] = p2 + +# def parent(self, i): +# p = self.p +# root = i +# while p[root] != root: +# root = p[root] +# while p[i] != i: # 路径压缩 ? +# x = i; i = p[i]; p[x] = root +# return root + +# def __len__(self): +# count = 0 +# for i in range(len(self.p)): +# if i == self.parent(i): +# count += 1 +# return count + +# class Solution(object): +# def findCircleNum(self, M): +# """ +# :type M: List[List[int]] +# :rtype: int +# """ +# #边界判断 +# if not M: +# return 0 + +# # 构建并查集 +# n = len(M) +# unionfind = unionFind(n) + +# # 遍历M,找到朋友关系 +# for i in range(n): +# for j in range(n): +# if M[i][j] == 1 and i != j: +# unionfind.union(i,j) + +# return len(unionfind) + + + + +# @lc code=end + diff --git a/Week_06/G20200343030587/src/main/java/com/jk/work/week06/LeetCode_212_587.java b/Week_06/G20200343030587/src/main/java/com/jk/work/week06/LeetCode_212_587.java new file mode 100644 index 00000000..8940fe8b --- /dev/null +++ b/Week_06/G20200343030587/src/main/java/com/jk/work/week06/LeetCode_212_587.java @@ -0,0 +1,129 @@ +package com.jk.work.week06; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +public class LeetCode_212_587 { + int n; + int m; + char[][] board; + Trie trie; + Set set = new HashSet<>(); + public List findWords(char[][] board, String[] words) { + this.board = board; + n = board.length; + m = board[0].length; + int k = 4; + //生成字典树 + trie = createTrie(words); + + //遍历二维数组 + for (int i = 0; i < n; i++) { + for (int j = 0 ; j < m; j++) { + dfs(i, j, "", trie.root); + } + } + return new ArrayList<>(set); + } + + void dfs(int i, int j, String s, Trie.TrieNode node) { + if (i < 0 || i >= n || j < 0 || j >= m || board[i][j] == '#') { + return; + } + char ch = board[i][j]; + if (node == null) return; + if (!node.contains(ch)) return; + node = node.get(ch); + s += ch; + if (node.isEnd) { + set.add(s); + } + //标记是边界防止进入递归后重复调用 + board[i][j] = '#'; + //进入递归 + dfs(i - 1, j, s, node); + dfs(i + 1, j, s, node); + dfs(i, j - 1, s, node); + dfs(i, j + 1, s, node); + board[i][j] = ch; + } + + private Trie createTrie(String[] words) { + Trie trie = new Trie(); + for (String word : words) { + trie.insert(word); + } + return trie; + } + + class Trie { + /** Initialize your data structure here. */ + private TrieNode root; + public Trie() { + root = new TrieNode(); + } + + /** Inserts a word into the trie. */ + public void insert(String word) { + TrieNode tn = root; + for (char ch : word.toCharArray()) { + if (!tn.contains(ch)) { + tn.put(ch, new TrieNode()); + } + tn = tn.get(ch); + } + tn.setIsEnd(); + } + + /** Returns if the word is in the trie. */ + public boolean search(String word) { + TrieNode tn = root; + for (char ch : word.toCharArray()) { + if (!tn.contains(ch)) return false; + tn = tn.get(ch); + } + return tn.getIsEnd(); + } + + /** Returns if there is any word in the trie that starts with the given prefix. */ + public boolean startsWith(String prefix) { + TrieNode tn = root; + for (char ch : prefix.toCharArray()) { + if (!tn.contains(ch)) return false; + tn = tn.get(ch); + } + return true; + } + class TrieNode { + TrieNode[] links; + private final int len = 26; + private boolean isEnd; + private String val; + + public TrieNode() { + links = new TrieNode[26]; + } + + public boolean contains(char ch) { + return links[ch - 'a'] != null; + } + + public TrieNode get(char ch) { + return links[ch - 'a']; + } + + public void put(char ch, TrieNode tn) { + links[ch - 'a'] = tn; + } + + public void setIsEnd() { + this.isEnd = true; + } + public boolean getIsEnd() { + return this.isEnd; + } + } + } +} diff --git a/Week_06/G20200343030587/src/main/java/com/jk/work/week06/LeetCode_36_587.java b/Week_06/G20200343030587/src/main/java/com/jk/work/week06/LeetCode_36_587.java new file mode 100644 index 00000000..a3db6142 --- /dev/null +++ b/Week_06/G20200343030587/src/main/java/com/jk/work/week06/LeetCode_36_587.java @@ -0,0 +1,24 @@ +package com.jk.work.week06; + +public class LeetCode_36_587 { + + public boolean isValidSudoku(char[][] board) { + int[][] rows = new int[9][9]; + int[][] cols = new int[9][9]; + int[][] blocks = new int[9][9]; + for (int i = 0; i < 9; i ++) { + for (int j = 0; j < 9; j++) { + if (board[i][j] != '.') { + //初始值为0, 行列块记录个数,不记录真实的数字,一共会出现 + //1-9个数字并且每个数字出现9次 按照真实数字值分区记录个数 大于1说明不合法 + if (++rows[board[i][j] - '1'][j] > 1 || + ++cols[board[i][j] - '1'][i] > 1 || + ++blocks[board[i][j] - '1'][(i/3)*3 + j/3] > 1) { + return false; + } + } + } + } + return true; + } +} diff --git a/Week_06/G20200343030587/src/main/java/com/jk/work/week06/LeetCode_37_587.java b/Week_06/G20200343030587/src/main/java/com/jk/work/week06/LeetCode_37_587.java new file mode 100644 index 00000000..ce3999e3 --- /dev/null +++ b/Week_06/G20200343030587/src/main/java/com/jk/work/week06/LeetCode_37_587.java @@ -0,0 +1,57 @@ +package com.jk.work.week06; + +public class LeetCode_37_587 { + boolean[][] rows = new boolean[9][9]; + boolean[][] cols = new boolean[9][9]; + boolean[][] blocks = new boolean[9][9]; + char[][] board; + + public void solveSudoku(char[][] board) { + this.board = board; + //初始化所有已添加的数字 + for (int r = 0; r < 9; r++) { + for (int c = 0; c < 9; c++) { + if (board[r][c] != '.') { + int idx = board[r][c] - '1'; + rows[r][idx] = cols[idx][c] = blocks[r/3*3 + c/3][idx] = true; + } + } + } + dfs(0); + } + + boolean dfs(int n) { + if (n == 81) return true; + int r = n/9; + int c = n%9; + if (board[r][c] != '.') return dfs(n + 1); + for(char k = '1'; k <= '9'; k++) { + //验证是否可填 + if (isAvailable(r, c, k)) continue; + //添加数字 + addNum(r, c, k); + //进入下层 + if (dfs(n + 1)) return true; + //回溯 + back(r, c, k); + } + return false; + } + + void addNum(int r, int c, char k) { + int idx = k - '1'; + rows[r][idx] = cols[idx][c] = blocks[r/3*3 + c/3][idx] = true; + board[r][c] = k; + } + + void back(int r, int c, char k) { + int idx = k - '1'; + rows[r][idx] = cols[idx][c] = blocks[r/3*3 + c/3][idx] = false; + board[r][c] = '.'; + } + + boolean isAvailable(int r, int c, char k) { + int idx = k - '1'; + return rows[r][idx] || cols[idx][c] || blocks[r/3*3 + c/3][idx]; + } +} diff --git a/Week_06/G20200343030587/src/main/java/com/jk/work/week06/LeetCode_433_587.java b/Week_06/G20200343030587/src/main/java/com/jk/work/week06/LeetCode_433_587.java new file mode 100644 index 00000000..e1c09254 --- /dev/null +++ b/Week_06/G20200343030587/src/main/java/com/jk/work/week06/LeetCode_433_587.java @@ -0,0 +1,52 @@ +package com.jk.work.week06; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.Set; + +public class LeetCode_433_587 { + + public int minMutation(String start, String end, String[] bank) { + char[] arrs = new char[]{'A','C','G','T'}; + LinkedList startQueue = new LinkedList<>(); + LinkedList endQueue = new LinkedList<>(); + Set set = new HashSet(Arrays.asList(bank)); + if (!set.contains(end)) return -1; + Set v1 = new HashSet(); + Set v2 = new HashSet(); + startQueue.add(start); + endQueue.add(end); + v1.add(start); + v2.add(end); + int step = 0; + while (!startQueue.isEmpty()) { + if (startQueue.size() > endQueue.size()) { + LinkedList t = startQueue; + startQueue = endQueue; + endQueue = t; + Set tv = new HashSet(); + tv = v1; + v1 = v2; + v2 = tv; + } + String startStr = startQueue.pop(); + char[] chars = startStr.toCharArray(); + for (int i = 0; i < chars.length; i++) { + char temp = chars[i]; + for (int j = 0; j < arrs.length; j++) { + chars[i] = arrs[j]; + String newString = new String(chars); + if (v1.contains(newString)) continue; + if (v2.contains(newString)) return ++step; + if (!set.contains(newString)) continue; + startQueue.add(newString); + v1.add(newString); + } + chars[i] = temp; + } + step++; + } + return -1; + } +} diff --git a/Week_06/G20200343030587/src/main/java/com/jk/work/week06/LeetCode_51_587.java b/Week_06/G20200343030587/src/main/java/com/jk/work/week06/LeetCode_51_587.java new file mode 100644 index 00000000..63150897 --- /dev/null +++ b/Week_06/G20200343030587/src/main/java/com/jk/work/week06/LeetCode_51_587.java @@ -0,0 +1,71 @@ +package com.jk.work.week06; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +public class LeetCode_51_587 { + int[] queens; + Set col = new HashSet<>(); + Set pie = new HashSet<>(); + Set na = new HashSet<>(); + List> res = new ArrayList<>(); + + public List> solveNQueens(int n) { + queens = new int[n]; + dfs(0, n); + return res; + } + + void dfs(int r, int n) { + if (r == n) { + saveRes(n); + return; + } + //遍历每列 + for (int c = 0; c < n; c++) { + //判断是否在攻击范围内 + if (isAvailable(r, c)) continue; + addQueen(r, c); + dfs(r + 1, n); + //回溯 + removeQueen(r, c); + } + } + + //判断是否在攻击范围内 + boolean isAvailable(int r, int c) { + return col.contains(c) || pie.contains(r + c) || na.contains(r - c); + } + + void addQueen(int r, int c) { + queens[r] = c; + col.add(c); + pie.add(r + c); + na.add(r - c); + } + + void removeQueen(int r, int c) { + queens[r] = 0; + col.remove(c); + pie.remove(r + c); + na.remove(r - c); + } + + void saveRes(int n) { + List qList = new ArrayList<>(); + for (int col : queens) { + StringBuffer sb = new StringBuffer(); + for (int i = 0; i< n; i++) { + if (i == col) { + sb.append("Q"); + continue; + } + sb.append("."); + } + qList.add(sb.toString()); + } + res.add(qList); + } +} diff --git a/Week_06/G20200343030591/LeetCode_208_591.java b/Week_06/G20200343030591/LeetCode_208_591.java new file mode 100644 index 00000000..b2117dac --- /dev/null +++ b/Week_06/G20200343030591/LeetCode_208_591.java @@ -0,0 +1,41 @@ +class Trie { + + private final int ALPHABET_SIZE = 26; + private Trie[] children = new Trie[ALPHABET_SIZE]; + boolean isEndOfWord = false; + public Trie() {} + + public void insert(String word) { + Trie tmp = this; + for (char i : word.toCharArray()) { + if (tmp.children[i-'a'] == null) { + tmp.children[i-'a'] = new Trie(); + } + tmp = tmp.children[i-'a']; + } + tmp.isEndOfWord = true; + } + + public boolean search(String word) { + Trie tmp = this; + for (char i : word.toCharArray()) { + if (tmp.children[i-'a'] == null) { + return false; + } + tmp = tmp.children[i-'a']; + } + return tmp.isEndOfWord ? true : false; + } + + public boolean startsWith(String prefix) { + Trie tmp = this; + for (char i : prefix.toCharArray()) { + if (tmp.children[i-'a'] == null) { + return false; + } + tmp = tmp.children[i-'a']; + } + return true; + } + +} \ No newline at end of file diff --git a/Week_06/G20200343030591/LeetCode_547_591.java b/Week_06/G20200343030591/LeetCode_547_591.java new file mode 100644 index 00000000..b527d1fa --- /dev/null +++ b/Week_06/G20200343030591/LeetCode_547_591.java @@ -0,0 +1,32 @@ +public class Solution { + int find(int parent[], int i) { + if (parent[i] == -1) + return i; + return find(parent, parent[i]); + } + + void union(int parent[], int x, int y) { + int xset = find(parent, x); + int yset = find(parent, y); + if (xset != yset) + parent[xset] = yset; + } + + public int findCircleNum(int[][] M) { + int[] parent = new int[M.length]; + Arrays.fill(parent, -1); + for (int i = 0; i < M.length; i++) { + for (int j = 0; j < M.length; j++) { + if (M[i][j] == 1 && i != j) { + union(parent, i, j); + } + } + } + int count = 0; + for (int i = 0; i < parent.length; i++) { + if (parent[i] == -1) + count++; + } + return count; + } +} \ No newline at end of file diff --git a/Week_06/G20200343030593/Leet_code_208_593.java b/Week_06/G20200343030593/Leet_code_208_593.java new file mode 100644 index 00000000..bfcd37e3 --- /dev/null +++ b/Week_06/G20200343030593/Leet_code_208_593.java @@ -0,0 +1,77 @@ +class Trie { + + public static class TrieNode{ + private TrieNode[] links; + private final int R=26; + private boolean isEnd; + public TrieNode(){ + links=new TrieNode[R]; + } + public boolean containsKey(char ch){ + return links[ch-'a']!=null; + } + public TrieNode get(char ch){ + return links[ch-'a']; + } + public void put(char ch,TrieNode node){ + links[ch-'a']=node; + } + public void setEnd(){ + this.isEnd=true; + } + public boolean isEnd(){ + return isEnd; + } + } + private TrieNode root; + /** Initialize your data structure here. */ + public Trie() { + root=new TrieNode(); + } + + /** Inserts a word into the trie. */ + public void insert(String word) { + TrieNode node=root; + for(int i=0;i m=new HashMap(); + public int climbStairs(int n) { + if(n==1||n==2){ + return n; + } + Integer v=m.get(n); + if(v==null){ + v=climbStairs(n-1)+climbStairs(n-2); + m.put(n,v); + } + return v; + } +} \ No newline at end of file diff --git a/Week_06/G20200343030595/LeetCode_22_595.go b/Week_06/G20200343030595/LeetCode_22_595.go new file mode 100644 index 00000000..21084cc6 --- /dev/null +++ b/Week_06/G20200343030595/LeetCode_22_595.go @@ -0,0 +1,23 @@ +package main + +var res []string +func generateParenthesis(n int) []string { + res = make([]string, 0) + gen(n, n , "") + return res +} + +func gen(left, right int, str string) { + if left == 0 && right == 0 { + res = append(res, str) + return + } + + if left > 0 { + gen(left - 1, right, str + "(") + } + + if left < right { + gen(left, right - 1, str + ")") + } +} diff --git a/Week_06/G20200343030595/LeetCode_547_595.go b/Week_06/G20200343030595/LeetCode_547_595.go new file mode 100644 index 00000000..a47e20ce --- /dev/null +++ b/Week_06/G20200343030595/LeetCode_547_595.go @@ -0,0 +1,47 @@ +package main + +var cnt int +var parent []int +func findCircleNum(M [][]int) int { + n := len(M) + if n < 1 { + return 0 + } + cnt = n + parent = make([]int, n) + + for i := 0; i < n; i++ { + parent[i] = i + } + + for i := 0; i < n; i++ { + for j := 0; j < n; j++ { + if i == j { + continue + } + if M[i][j] == 1 { + union(i, j) + } + } + } + + return cnt +} + +func union(p, q int) { + rootP := findRoot(p) + rootQ := findRoot(q) + if rootP == rootQ { + return + } + parent[rootP] = rootQ + cnt-- +} + +func findRoot(p int) int { + for p != parent[p] { + parent[p] = parent[parent[p]] + p = parent[p] + } + return p +} diff --git a/Week_06/G20200343030595/LeetCode_70_595.go b/Week_06/G20200343030595/LeetCode_70_595.go new file mode 100644 index 00000000..7af1dc51 --- /dev/null +++ b/Week_06/G20200343030595/LeetCode_70_595.go @@ -0,0 +1,17 @@ +package main + +func climbStairs(n int) int { + switch n { + case 1, 2: + return n + + default: + nums := make([]int, n+1) + nums[1] = 1 + nums[2] = 2 + for i := 3; i <= n; i++ { + nums[i] = nums[i-1] + nums[i-2] + } + return nums[n] + } +} diff --git a/Week_06/G20200343030597/Solution_70.java b/Week_06/G20200343030597/Solution_70.java new file mode 100644 index 00000000..e37be3fc --- /dev/null +++ b/Week_06/G20200343030597/Solution_70.java @@ -0,0 +1,12 @@ +public class Solution_70 { + public int climbStairs(int n) { + if (n <= 2) return n; + int dp = 0, pre1 = 1, pre2 = 2; + for (int i = 3; i <= n; ++i) { + dp = pre1 + pre2; + pre1 = pre2; + pre2 = dp; + } + return dp; + } +} diff --git a/Week_06/G20200343030597/Trie.java b/Week_06/G20200343030597/Trie.java new file mode 100644 index 00000000..b7e14dc0 --- /dev/null +++ b/Week_06/G20200343030597/Trie.java @@ -0,0 +1,75 @@ +public class Trie { + private TrieNode root; + + public Trie() { + root = new TrieNode(); + } + + public void insert(String word) { + TrieNode node = root; + for (int i = 0; i < word.length(); i++) { + char currentChar = word.charAt(i); + if (!node.containsKey(currentChar)) { + node.put(currentChar, new TrieNode()); + } + node = node.get(currentChar); + } + node.setEnd(); + } + + public boolean search(String word) { + TrieNode node = searchPrefix(word); + return node != null && node.isEnd(); + } + + public boolean startsWith(String prefix) { + TrieNode node = searchPrefix(prefix); + return node != null; + } + + private TrieNode searchPrefix(String word) { + TrieNode node = root; + for (int i = 0; i < word.length(); i++) { + char curLetter = word.charAt(i); + if (node.containsKey(curLetter)) { + node = node.get(curLetter); + } else { + return null; + } + } + return node; + } +} + +class TrieNode { + + private TrieNode[] links; + + private final int R = 26; + + private boolean isEnd; + + public TrieNode() { + links = new TrieNode[R]; + } + + public boolean containsKey(char ch) { + return links[ch - 'a'] != null; + } + + public TrieNode get(char ch) { + return links[ch - 'a']; + } + + public void put(char ch, TrieNode node) { + links[ch - 'a'] = node; + } + + public void setEnd() { + isEnd = true; + } + + public boolean isEnd() { + return isEnd; + } +} \ No newline at end of file diff --git "a/Week_06/G20200343030601/200.\345\262\233\345\261\277\346\225\260\351\207\217.java" "b/Week_06/G20200343030601/200.\345\262\233\345\261\277\346\225\260\351\207\217.java" new file mode 100644 index 00000000..2f792ae2 --- /dev/null +++ "b/Week_06/G20200343030601/200.\345\262\233\345\261\277\346\225\260\351\207\217.java" @@ -0,0 +1,193 @@ +/* + * @lc app=leetcode.cn id=200 lang=java + * + * [200] 岛屿数量 + * + * https://leetcode-cn.com/problems/number-of-islands/description/ + * + * algorithms + * Medium (47.20%) + * Likes: 417 + * Dislikes: 0 + * Total Accepted: 68K + * Total Submissions: 142.7K + * Testcase Example: '[["1","1","1","1","0"],["1","1","0","1","0"],["1","1","0","0","0"],["0","0","0","0","0"]]' + * + * 给定一个由 '1'(陆地)和 + * '0'(水)组成的的二维网格,计算岛屿的数量。一个岛被水包围,并且它是通过水平方向或垂直方向上相邻的陆地连接而成的。你可以假设网格的四个边均被水包围。 + * + * 示例 1: + * + * 输入: + * 11110 + * 11010 + * 11000 + * 00000 + * + * 输出: 1 + * + * + * 示例 2: + * + * 输入: + * 11000 + * 11000 + * 00100 + * 00011 + * + * 输出: 3 + * + * + */ + +// @lc code=start +import java.util.Queue; +import java.util.LinkedList; +class Solution { + // 并查集解决方案 + // 时间复杂度:O(N*M) N和M分别是行数和列数,并查集使用路径压缩、排名结合==>并操作时间复杂度为常数时间 + // 空间复杂度:O(N*M) 并查集数据结构的空间 + public int numIslands1(char[][] grid) { + if (null == grid || 0 == grid.length) { + return 0; + } + + int rowCount = grid.length; + int colCount = grid[0].length; + int[][] dirs = new int[][]{{-1, 0}, {1, 0}, {0, -1}, {0, 1}}; + UnionFind uf = new UnionFind(grid); + for (int r = 0; r < rowCount; r++) { + for (int c = 0; c < colCount; c++) { + if ('1' == grid[r][c]) + { + grid[r][c] = '0'; + for (int d = 0; d < dirs.length; d++) { + int dx = r + dirs[d][0]; + int dy = c + dirs[d][1]; + if (dx >= 0 && dx < rowCount && dy >= 0 && dy < colCount && '1' == grid[dx][dy]) { + uf.union(r * colCount + c, dx * colCount + dy); + } + } + } + } + } + return uf.getCount(); + } + + class UnionFind { + int count; // 集合数量 + int[] parent; + int[] rank; // 层次深度 + + public UnionFind(char[][] grid) { + count = 0; + int rowCount = grid.length; + int colCount = rowCount > 0 ? grid[0].length : 0; + parent = new int[rowCount * colCount]; + rank = new int[rowCount * colCount]; + for (int i = 0; i < rowCount; i++) { + for (int j = 0; j < colCount; j++) { + if ('1' == grid[i][j]) { + parent[i * colCount + j] = i * colCount + j; + count++; + } + rank[i * colCount + j] = 0; + } + } + } + + public int find(int i) { + if (i != parent[i]) // 路径压缩,方便之后的find + parent[i] = find(parent[i]); + return parent[i]; + } + + public void union(int x, int y) { + int rootX = find(x); + int rootY = find(y); + if (rootX != rootY) { // 尽量降低合并后的层次深度 + if (rank[rootX] > rank[rootY]) { + parent[rootY] = rootX; + } + else if (rank[rootX] < rank[rootY]) { + parent[rootX] = rootY; + } + else { + parent[rootY] = rootX; + rank[rootX] += 1; + } + --count; + } + } + + public int getCount() { + return count; + } + } + + // 深度优先: 递归版 + // 时间复杂度:O(N*M) 遍历一遍 + // 空间复杂度:O(N*M) 最坏情况(全相连)下递归深度达M*N + public int numIslands2(char[][] grid) { + if (null == grid || 0 == grid.length) return 0; + + int rowCount = grid.length; + int colCount = grid[0].length; + int countIslands = 0; + for (int r = 0; r < rowCount; r++) { + for (int c = 0; c < colCount; c++) { + if ('1' == grid[r][c]) { + countIslands++; + dfs(grid, r, c); + } + } + } + return countIslands; + } + + int[][] dirs = new int[][]{{1, 0}, {-1, 0}, {0, 1}, {0, -1}}; + private void dfs(char[][] grid, int r, int c) { + if (r < 0 || r >= grid.length || c < 0 || c >= grid[0].length || '0' == grid[r][c]) return; + + grid[r][c] = '0'; + for (int[] dir : dirs) { + dfs(grid, r + dir[0], c + dir[1]); + } + } + + // BFS + // 时间复杂度:O(M*N) 遍历整个矩阵 + // 空间复杂度:O(min(M, N)) 队列的空间,最坏为全为陆地时 + public int numIslands(char[][] grid) { + if (null == grid || 0 == grid.length) return 0; + + int countIslands = 0; + int rowCount = grid.length; + int colCount = grid[0].length; + Queue queue = new LinkedList(); // 格式:r * rowCount + c + for (int r = 0; r < rowCount; r++) { + for (int c = 0; c < colCount; c++) { + if ('1' == grid[r][c]) { + countIslands++; + grid[r][c] = '0'; + queue.add(r * colCount + c); + while(!queue.isEmpty()) { + int id = queue.remove(); + int row = id / colCount, col = id % colCount; + for (int[] dir : dirs) { + int dx = row + dir[0], dy = col + dir[1]; + if (dx >= 0 && dx < rowCount && dy >= 0 && dy < colCount && '1' == grid[dx][dy]) { + queue.add(dx * colCount + dy); + grid[dx][dy] = '0'; + } + } + } + } + } + } + + return countIslands; + } +} +// @lc code=end + diff --git "a/Week_06/G20200343030601/208.\345\256\236\347\216\260-trie-\345\211\215\347\274\200\346\240\221.java" "b/Week_06/G20200343030601/208.\345\256\236\347\216\260-trie-\345\211\215\347\274\200\346\240\221.java" new file mode 100644 index 00000000..bd0a9dad --- /dev/null +++ "b/Week_06/G20200343030601/208.\345\256\236\347\216\260-trie-\345\211\215\347\274\200\346\240\221.java" @@ -0,0 +1,145 @@ +/* + * @lc app=leetcode.cn id=208 lang=java + * + * [208] 实现 Trie (前缀树) + * + * https://leetcode-cn.com/problems/implement-trie-prefix-tree/description/ + * + * algorithms + * Medium (65.15%) + * Likes: 225 + * Dislikes: 0 + * Total Accepted: 28K + * Total Submissions: 42.8K + * Testcase Example: '["Trie","insert","search","search","startsWith","insert","search"]\n' + + '[[],["apple"],["apple"],["app"],["app"],["app"],["app"]]' + * + * 实现一个 Trie (前缀树),包含 insert, search, 和 startsWith 这三个操作。 + * + * 示例: + * + * Trie trie = new Trie(); + * + * trie.insert("apple"); + * trie.search("apple"); // 返回 true + * trie.search("app"); // 返回 false + * trie.startsWith("app"); // 返回 true + * trie.insert("app"); + * trie.search("app"); // 返回 true + * + * 说明: + * + * + * 你可以假设所有的输入都是由小写字母 a-z 构成的。 + * 保证所有输入均为非空字符串。 + * + * + */ + +// @lc code=start +class Trie { + private TrieNode root; + + /** Initialize your data structure here. */ + public Trie() { + root = new TrieNode(); + } + + /** Inserts a word into the trie. */ + // 时间复杂度:O(m) m为键长 + // 空间复杂度:O(m) 最坏时,新插入键和Trie树中没有公共前缀,需新添加m个节点 + public void insert(String word) { + TrieNode node = root; + for (int i = 0; i < word.length(); i++) { + char ch = word.charAt(i); + if (!node.containsKey(ch)) { // 如果该字符不存在Trie中,则插入 + node.put(ch, new TrieNode()); + } + node = node.get(ch); // 取出该分支(即使是刚插入的) + } + node.setEnd(); + } + + /** Returns if the word is in the trie. */ + // 时间复杂度:O(m) 每一步搜索一个键字符 + // 空间复杂度:O(1) + public boolean search(String word) { + // TrieNode node = root; + // for (int i = 0; i < word.length(); i++) { + // char ch = word.charAt(i); + // if (!node.containsKey(ch)) return false; + // node = node.get(ch); + // } + // return node.isEnd(); + + TrieNode node = searchPrefix(word); + return null != node && node.isEnd(); + } + + /** Returns if there is any word in the trie that starts with the given prefix. */ + // 时间复杂度:O(m) 每一步搜索一个键字符 + // 空间复杂度:O(1) + public boolean startsWith(String prefix) { + // TrieNode node = root; + // for (int i = 0; i < prefix.length(); i++) { + // char ch = prefix.charAt(i); + // if (!node.containsKey(ch)) return false; + // node = node.get(ch); + // } + // return null != node; + + return null != searchPrefix(prefix); + } + + // 写完search和startWith,发现出了最后判断之外,其他语句均相同,提取公用函数 + private TrieNode searchPrefix(String prefix) { + TrieNode node = root; + for (int i = 0; i < prefix.length(); i++) { + char ch = prefix.charAt(i); + if (!node.containsKey(ch)) return null; + node = node.get(ch); + } + + return node; + } +} + +class TrieNode { + private TrieNode[] links; + private final int R = 26; + private boolean isEnd; + + public TrieNode() { + links = new TrieNode[R]; + } + + public boolean containsKey(char ch) { + return null != links[ch - 'a']; + } + + public TrieNode get(char ch) { + return links[ch - 'a']; + } + + public void put(char ch, TrieNode node) { + links[ch - 'a'] = node; + } + + public void setEnd() { + isEnd = true; + } + + public boolean isEnd() { + return isEnd; + } +} + +/** + * Your Trie object will be instantiated and called as such: + * Trie obj = new Trie(); + * obj.insert(word); + * boolean param_2 = obj.search(word); + * boolean param_3 = obj.startsWith(prefix); + */ +// @lc code=end + diff --git "a/Week_06/G20200343030601/212.\345\215\225\350\257\215\346\220\234\347\264\242-ii.java" "b/Week_06/G20200343030601/212.\345\215\225\350\257\215\346\220\234\347\264\242-ii.java" new file mode 100644 index 00000000..dfa1bd27 --- /dev/null +++ "b/Week_06/G20200343030601/212.\345\215\225\350\257\215\346\220\234\347\264\242-ii.java" @@ -0,0 +1,105 @@ +import java.util.Set; + +/* + * @lc app=leetcode.cn id=212 lang=java + * + * [212] 单词搜索 II + * + * https://leetcode-cn.com/problems/word-search-ii/description/ + * + * algorithms + * Hard (39.31%) + * Likes: 120 + * Dislikes: 0 + * Total Accepted: 11K + * Total Submissions: 27.9K + * Testcase Example: '[["o","a","a","n"],["e","t","a","e"],["i","h","k","r"],["i","f","l","v"]]\n' + + '["oath","pea","eat","rain"]' + * + * 给定一个二维网格 board 和一个字典中的单词列表 words,找出所有同时在二维网格和字典中出现的单词。 + * + * + * 单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母在一个单词中不允许被重复使用。 + * + * 示例: + * + * 输入: + * words = ["oath","pea","eat","rain"] and board = + * [ + * ⁠ ['o','a','a','n'], + * ⁠ ['e','t','a','e'], + * ⁠ ['i','h','k','r'], + * ⁠ ['i','f','l','v'] + * ] + * + * 输出: ["eat","oath"] + * + * 说明: + * 你可以假设所有输入都由小写字母 a-z 组成。 + * + * 提示: + * + * + * 你需要优化回溯算法以通过更大数据量的测试。你能否早点停止回溯? + * 如果当前单词不存在于所有单词的前缀中,则可以立即停止回溯。什么样的数据结构可以有效地执行这样的操作?散列表是否可行?为什么? + * 前缀树如何?如果你想学习如何实现一个基本的前缀树,请先查看这个问题: 实现Trie(前缀树)。 + * + * + */ + +// @lc code=start +class Solution { + public List findWords(char[][] board, String[] words) { + TrieNode root = buildTrie(words); + List result = new ArrayList(); + + for (int r = 0 ; r < board.length ; r++) { + for (int c = 0 ; c < board[0].length ; c++) { + findWordCore(board, r, c, root, result); + } + } + + return result; + } + + int[][] dirs = new int[][]{{0, 1}, {0, -1}, {1, 0}, {-1, 0}}; + private void findWordCore(char[][] board, int row, int col, TrieNode curNode, List result) { + int nr = board.length, nc = board[0].length; + if (row < 0 || row >= nr || col < 0 || col >= nc) return; + char ch = board[row][col]; + if ('@' == ch || null == curNode.links[ch - 'a']) return; + + curNode = curNode.links[ch - 'a']; + if (null != curNode.word) { // 遇到word,加入结果集,并置为null,防止重复添加 + result.add(curNode.word); + curNode.word = null; + } + + board[row][col] = '@'; + for (int[] dir : dirs){ + findWordCore(board, row + dir[0], col + dir[1], curNode, result); + } + board[row][col] = ch; + } + + public TrieNode buildTrie(String[] words){ + TrieNode root = new TrieNode(); + for (String word : words) { + TrieNode node = root; + for (char ch : word.toCharArray()) { + int index = ch - 'a'; + if (null == node.links[index]) + node.links[index] = new TrieNode(); + node = node.links[index]; + } + node.word = word; + } + return root; + } + + class TrieNode { + TrieNode[] links = new TrieNode[26]; + String word; + } +} +// @lc code=end diff --git "a/Week_06/G20200343030601/22.\346\213\254\345\217\267\347\224\237\346\210\220.java" "b/Week_06/G20200343030601/22.\346\213\254\345\217\267\347\224\237\346\210\220.java" new file mode 100644 index 00000000..ff202f2d --- /dev/null +++ "b/Week_06/G20200343030601/22.\346\213\254\345\217\267\347\224\237\346\210\220.java" @@ -0,0 +1,64 @@ +/* + * @lc app=leetcode.cn id=22 lang=java + * + * [22] 括号生成 + * + * https://leetcode-cn.com/problems/generate-parentheses/description/ + * + * algorithms + * Medium (73.50%) + * Likes: 810 + * Dislikes: 0 + * Total Accepted: 87.7K + * Total Submissions: 119.1K + * Testcase Example: '3' + * + * 给出 n 代表生成括号的对数,请你写出一个函数,使其能够生成所有可能的并且有效的括号组合。 + * + * 例如,给出 n = 3,生成结果为: + * + * [ + * ⁠ "((()))", + * ⁠ "(()())", + * ⁠ "(())()", + * ⁠ "()(())", + * ⁠ "()()()" + * ] + * + * + */ + +// @lc code=start +import java.util.List; +import java.util.ArrayList; +class Solution { + // 动态规划解决方案 + // dp[i] = "(" + dp[j] + ")" + dp[i - j - 1], j = 0, 1, ..., i - 1 + // 时间复杂度:暂时不会分析 + // 空间复杂度: + public List generateParenthesis(int n) { + if (0 == n) return new ArrayList(); + + List> dp = new ArrayList<>(n+1); + List dp0 = new ArrayList<>(); + dp0.add(""); + dp.add(dp0); + for (int i = 1; i <= n; i++) { + List curStrList = new ArrayList<>(); + for (int j = 0; j < i; j++) { + List strList1 = dp.get(j); + List strList2 = dp.get(i - j - 1); + for (String str1 : strList1) { + for (String str2 : strList2) { + curStrList.add("(" + str1 + ")" + str2); + } + } + } + dp.add(curStrList); + } + + return dp.get(n); + } +} +// @lc code=end + diff --git "a/Week_06/G20200343030601/547.\346\234\213\345\217\213\345\234\210.java" "b/Week_06/G20200343030601/547.\346\234\213\345\217\213\345\234\210.java" new file mode 100644 index 00000000..1b8f1acf --- /dev/null +++ "b/Week_06/G20200343030601/547.\346\234\213\345\217\213\345\234\210.java" @@ -0,0 +1,173 @@ +/* + * @lc app=leetcode.cn id=547 lang=java + * + * [547] 朋友圈 + * + * https://leetcode-cn.com/problems/friend-circles/description/ + * + * algorithms + * Medium (55.16%) + * Likes: 198 + * Dislikes: 0 + * Total Accepted: 29.6K + * Total Submissions: 53.3K + * Testcase Example: '[[1,1,0],[1,1,0],[0,0,1]]' + * + * 班上有 N 名学生。其中有些人是朋友,有些则不是。他们的友谊具有是传递性。如果已知 A 是 B 的朋友,B 是 C 的朋友,那么我们可以认为 A 也是 + * C 的朋友。所谓的朋友圈,是指所有朋友的集合。 + * + * 给定一个 N * N 的矩阵 M,表示班级中学生之间的朋友关系。如果M[i][j] = 1,表示已知第 i 个和 j + * 个学生互为朋友关系,否则为不知道。你必须输出所有学生中的已知的朋友圈总数。 + * + * 示例 1: + * + * + * 输入: + * [[1,1,0], + * ⁠[1,1,0], + * ⁠[0,0,1]] + * 输出: 2 + * 说明:已知学生0和学生1互为朋友,他们在一个朋友圈。 + * 第2个学生自己在一个朋友圈。所以返回2。 + * + * + * 示例 2: + * + * + * 输入: + * [[1,1,0], + * ⁠[1,1,1], + * ⁠[0,1,1]] + * 输出: 1 + * 说明:已知学生0和学生1互为朋友,学生1和学生2互为朋友,所以学生0和学生2也是朋友,所以他们三个在一个朋友圈,返回1。 + * + * + * 注意: + * + * + * N 在[1,200]的范围内。 + * 对于所有学生,有M[i][i] = 1。 + * 如果有M[i][j] = 1,则有M[j][i] = 1。 + * + * + */ + +// @lc code=start +import java.util.Queue; +import java.util.LinkedList; +import java.util.Stack; +import java.util.Arrays; +class Solution { + // BFS (将矩阵看作图的邻接矩阵,关系是双向的,对称矩阵) + // 时间复杂度:O(N^2) 对角线上部矩阵都需要访问 + // 空间复杂度:O(N) N为学生数量 + public int findCircleNum1(int[][] M) { + int[] visited = new int[M.length]; + int circleNum = 0; + Queue queue = new LinkedList(); + for (int i = 0; i < M.length; i++) { + if (0 == visited[i]) { // 从一个未访问的节点进行扩散 + circleNum++; + queue.add(i); + while (!queue.isEmpty()) { + int s = queue.remove(); + visited[s] = 1; + for (int j = i + 1; j < M.length; j++) { // 对称矩阵,只需处理对角线上部即可 + if (1 == M[s][j] && 0 == visited[j]) { + queue.add(j); + } + } + } + } + } + + return circleNum; + } + + // DFS:递归版 (将矩阵看作图的邻接矩阵,关系是双向的,对称矩阵) + // 时间复杂度:O(N^2) 对角线上部矩阵都需要访问 + // 空间复杂度:O(N) N为学生数量 + public int findCircleNum2(int[][] M) { + int[] visited = new int[M.length]; + int circleNum = 0; + for (int i = 0; i < M.length; i++) { + if (0 == visited[i]) { + dfs(M, visited, i); + circleNum++; + } + } + + return circleNum; + } + + private void dfs(int[][] M, int[] visited, int i) { + for (int j = 0; j < M.length; j++) { // 对称矩阵,只需处理对角线上部即可 + if (0 == visited[j] && 1 == M[i][j]) { + visited[j] = 1; + dfs(M, visited, j); + } + } + } + + // DFS: 非递归版 (将矩阵看作图的邻接矩阵,关系是双向的,对称矩阵) + // 时间复杂度:O(N^2) 对角线上部矩阵都需要访问 + // 空间复杂度:O(N) N为学生数量 + public int findCircleNum3(int[][] M) { + int[] visited = new int[M.length]; + int circleNum = 0; + Stack stack = new Stack(); + + for (int i = 0; i < M.length; i++) { + if (0 == visited[i]) { + circleNum++; + stack.push(i); + while(!stack.empty()) { + int s = stack.pop(); + visited[s] = 1; + for (int j = i + 1; j < M.length; j++) { + if (0 == visited[j] && 1 == M[s][j]) { + stack.push(j); + } + } + } + } + } + + return circleNum; + } + + // 并查集解决方案 + // 时间复杂度:O(N^3) 遍历矩阵,并查集操作最坏时间时间复杂度O(n) + // 空间复杂度:O(N) parent所占空间 + int find(int parent[], int i) { + return -1 == parent[i]? i : find(parent, parent[i]); + } + + void union(int parent[], int i, int j) { + int iSet = find(parent, i); + int jSet = find(parent, j); + if (iSet != jSet) + parent[iSet] = jSet; + } + + public int findCircleNum(int[][] M) { + int[] parent = new int[M.length]; + Arrays.fill(parent, -1); + for (int i = 0; i < M.length; i++) { + for (int j = i + 1; j < M.length; j++) { + if (1 == M[i][j]) + union(parent, i, j); + } + } + + int circleNum = 0; + for (int i = 0; i < M.length; i++) { + if (-1 == parent[i]) + circleNum++; + } + return circleNum; + } + +} +// @lc code=end + diff --git "a/Week_06/G20200343030601/945.\344\275\277\346\225\260\347\273\204\345\224\257\344\270\200\347\232\204\346\234\200\345\260\217\345\242\236\351\207\217.java" "b/Week_06/G20200343030601/945.\344\275\277\346\225\260\347\273\204\345\224\257\344\270\200\347\232\204\346\234\200\345\260\217\345\242\236\351\207\217.java" new file mode 100644 index 00000000..0e48f864 --- /dev/null +++ "b/Week_06/G20200343030601/945.\344\275\277\346\225\260\347\273\204\345\224\257\344\270\200\347\232\204\346\234\200\345\260\217\345\242\236\351\207\217.java" @@ -0,0 +1,137 @@ +/* + * @lc app=leetcode.cn id=945 lang=java + * + * [945] 使数组唯一的最小增量 + * + * https://leetcode-cn.com/problems/minimum-increment-to-make-array-unique/description/ + * + * algorithms + * Medium (42.59%) + * Likes: 37 + * Dislikes: 0 + * Total Accepted: 5.6K + * Total Submissions: 12.7K + * Testcase Example: '[1,2,2]' + * + * 给定整数数组 A,每次 move 操作将会选择任意 A[i],并将其递增 1。 + * + * 返回使 A 中的每个值都是唯一的最少操作次数。 + * + * 示例 1: + * + * 输入:[1,2,2] + * 输出:1 + * 解释:经过一次 move 操作,数组将变为 [1, 2, 3]。 + * + * 示例 2: + * + * 输入:[3,2,1,2,1,7] + * 输出:6 + * 解释:经过 6 次 move 操作,数组将变为 [3, 4, 1, 2, 5, 7]。 + * 可以看出 5 次或 5 次以下的 move 操作是不能让数组的每个值唯一的。 + * + * + * 提示: + * + * + * 0 <= A.length <= 40000 + * 0 <= A[i] < 40000 + * + * + */ + +// @lc code=start +import java.util.HashSet; +import java.util.Arrays; +class Solution { + // 暴力法(超时) + // 时间复杂度:O(N*N) 最差情况是所有值都相等 + // 空间复杂度:O(N) + public int minIncrementForUnique1(int[] A) { + HashSet unique = new HashSet(); + int moveCount = 0; + for (int a : A) { + while(unique.contains(a)) { + a++; + moveCount++; + } + unique.add(a); + } + return moveCount; + } + + // 计数法 + // 未出现的数字和 - 重复的数字和 = move的步数 + // 未出现的数字个数 == 重复的数字个数,而且要先有重复数字,才能用未出现的数字抵消(因为数字只能增) + // 空间复杂度:O(L),L的数量级为数组A的长度加上其数据范围内的最大值 + // 空间复杂度:O(L) + public int minIncrementForUnique2(int[] A) { + int[] count = new int[80000]; + for (int a : A) count[a]++; + + int ans = 0, token = 0; // ans: move的步数 token: 重复的数字个数 + for (int i = 0; i < count.length; i++) { + if (count[i] >= 2) { + token += count[i] - 1; + ans -= i * (count[i] - 1); + } else if (token > 0 && count[i] == 0) { + ans += i; + token--; + } + } + + return ans; + } + + // 计数法(早停) + // 关键点:在已处理完A中最大值之后,且重复值也都处理完之后,就可以及时停止 + // 时间复杂度和空间复杂度同上 + public int minIncrementForUnique3(int[] A) { + int[] count = new int[80000]; + int maxA = 0; + for (int a : A) { + count[a]++; + if (a > maxA) maxA = a; + } + + int ans = 0, taken = 0; // ans: move的步数 token: (未处理的)重复的数字个数 + for (int i = 0; i < count.length && (i <= maxA || taken > 0); i++) { + if (count[i] >= 2) { + taken += count[i] - 1; + ans -= i * (count[i] - 1); + } else if (taken > 0 && count[i] == 0) { + ans += i; + taken--; + } + } + + return ans; + } + + // 排序法 + // 时间复杂度O(NlogN),N是数组长度 + // 空间复杂度O(logN),排序需要额外的栈空间 + public int minIncrementForUnique(int[] A) { + Arrays.sort(A); + int ans = 0, taken = 0; + + for (int i = 1; i < A.length; i++) { + if (A[i - 1] == A[i]) { // 针对重复值进行计数 + taken++; + ans-= A[i]; + } + else if (A[i] - A[i - 1] > 1){ // 在排序数组间出现空档时,计算填充需要的步数 + int give = Math.min(taken, A[i] - A[i - 1] - 1); // 可插入数值的总个数 + ans += give * (give + 1) /2 + give * A[i - 1]; // 可插入数值的和 + taken -= give; + } + } + + if (taken > 0) // 还有为抵消的重复值 + ans += taken * (taken + 1) / 2 + taken * A[A.length - 1]; + + return ans; + } +} +// @lc code=end + diff --git a/Week_06/G20200343030601/NOTE.md b/Week_06/G20200343030601/NOTE.md index 50de3041..30ccae2a 100644 --- a/Week_06/G20200343030601/NOTE.md +++ b/Week_06/G20200343030601/NOTE.md @@ -1 +1,73 @@ -学习笔记 \ No newline at end of file +# 学习笔记(第五周) + +**学号:** G20200343030601 + +**姓名:** 冯学智 + +**微信:** SDMrFeng + +## 本周学习总结 + +### 212. 单词搜索 II 用 Trie 树方式实现的时间复杂度 + +1. 尝试从board的每个位置作为初始位置查找,查找次数为O(M*N),M和N分别是Board的长和高; +2. 每次查找是DFS的递归实现,向四个方向分别探索,探索深度和Trie树的层次一致,记Trie树的平均层数(也就是words中单词的平均长度)为W,则每次查找的时间复杂度为O(4^W) +* 综上:单词搜索 II 用 Trie 树方式实现的时间复杂度为O(M*N*4^W) + +### DP解决括号配对问题 +```Java +class Solution { + // 动态规划解决方案 + // dp[i] = "(" + dp[j] + ")" + dp[i - j - 1], j = 0, 1, ..., i - 1 + // 时间复杂度:暂时不会分析 + // 空间复杂度: + public List generateParenthesis(int n) { + if (0 == n) return new ArrayList(); + + List> dp = new ArrayList<>(n+1); + List dp0 = new ArrayList<>(); + dp0.add(""); + dp.add(dp0); + for (int i = 1; i <= n; i++) { + List curStrList = new ArrayList<>(); + for (int j = 0; j < i; j++) { + List strList1 = dp.get(j); + List strList2 = dp.get(i - j - 1); + for (String str1 : strList1) { + for (String str2 : strList2) { + curStrList.add("(" + str1 + ")" + str2); + } + } + } + dp.add(curStrList); + } + + return dp.get(n); + } +} +``` + + +### 总结双向BFS的代码模板 +```Python +def BFS(graph, start, end): + front = {start} + back = {end} + visited = set() + visited.add(start) + + while front and back: + temp_front = {} + for node in front: + visited.add(node) + + process(node) + nodes = generate_related_nodes(node) + temp_front.add(nodes) + + front = temp_front + if len(back) < len(front): + front, back = back, front + # other processing work + ... +``` \ No newline at end of file diff --git a/Week_06/G20200343030603/LeetCode_1_603.java b/Week_06/G20200343030603/LeetCode_1_603.java new file mode 100644 index 00000000..1aed9b3b --- /dev/null +++ b/Week_06/G20200343030603/LeetCode_1_603.java @@ -0,0 +1,96 @@ +class Trie { + + private final int R = 26; + + class TrieNode { + // R links to node children + private TrieNode[] links; + + private boolean isEnd; + + public TrieNode() { + links = new TrieNode[R]; + } + + public boolean containsKey(char ch) { + return links[ch - 'a'] != null; + } + + public TrieNode get(char ch) { + return links[ch - 'a']; + } + + public void put(char ch, TrieNode node) { + links[ch - 'a'] = node; + } + + public void setEnd() { + isEnd = true; + } + + public boolean isEnd() { + return isEnd; + } + } + + private TrieNode root; + + /** Initialize your data structure here. */ + public Trie() { + root = new TrieNode(); + } + + /** Inserts a word into the trie. */ + //时间复杂度O(m) 空间复杂度O(m) + public void insert(String word) { + if (word == null || word.length() == 0) { + return; + } + TrieNode node = root; + for (int i = 0; i < word.length(); i++) { + char currentChar = word.charAt(i); + if (!node.containsKey(currentChar)) { + node.put(currentChar, new TrieNode()); + } + node = node.get(currentChar); + } + node.setEnd(); + } + + /** Returns if the word is in the trie. */ + //时间复杂度O(m) 空间复杂度O(1) + public boolean search(String word) { + TrieNode node = searchPrefix(word); + return node != null && node.isEnd(); + } + + /** Returns if there is any word in the trie that starts with the given prefix. */ + // 时间复杂度O(m) 空间复杂度O(1) + public boolean startsWith(String prefix) { + TrieNode node = searchPrefix(prefix); + return node != null; + } + + /** search a prefix or whole key in trie and returns the node where search ends*/ + private TrieNode searchPrefix(String word) { + TrieNode node = root; + for (int i = 0; i < word.length(); i++) { + char curLetter = word.charAt(i); + if (node.containsKey(curLetter)) { + node = node.get(curLetter); + } else { + return null; + } + } + return node; + } + +} + +/** + * Your Trie object will be instantiated and called as such: + * Trie obj = new Trie(); + * obj.insert(word); + * boolean param_2 = obj.search(word); + * boolean param_3 = obj.startsWith(prefix); + */ \ No newline at end of file diff --git a/Week_06/G20200343030603/LeetCode_2_603.java b/Week_06/G20200343030603/LeetCode_2_603.java new file mode 100644 index 00000000..a633ab6c --- /dev/null +++ b/Week_06/G20200343030603/LeetCode_2_603.java @@ -0,0 +1,85 @@ +//1. words 遍历 --> board search O(N * m * m * 4 ^k) + +class Solution { + public List findWords(char[][] board, String[] words) { + //构建字典树 + wordTrie myTrie=new wordTrie(); + trieNode root=myTrie.root; + for(String s:words) + myTrie.insert(s); + + //使用set防止重复 + Set result =new HashSet<>(); + int m=board.length; + int n=board[0].length; + boolean [][]visited=new boolean[m][n]; + //遍历整个二维数组 + for(int i=0;i(result); + } + private void find(char [] [] board, boolean [][]visited,int i,int j,int m,int n,Set result,trieNode cur){ + //边界以及是否已经访问判断 + if(i<0||i>=m||j<0||j>=n||visited[i][j]) + return; + //获取子节点状态,判断其是否有子节点 + cur=cur.child[board[i][j]-'a']; + //修改节点状态,防止重复访问 + visited[i][j]=true; + if(cur==null) + { + //如果单词不匹配,回退 + visited[i][j]=false; + return; + } + //找到单词加入 + if(cur.isLeaf) + { + result.add(cur.val); + //找到单词后不能回退,因为可能是“ad” “addd”这样的单词得继续回溯 +// visited[i][j]=false; +// return; + } + find(board,visited,i+1,j,m,n,result,cur); + find(board,visited,i,j+1,m,n,result,cur); + find(board,visited,i,j-1,m,n,result,cur); + find(board,visited,i-1,j,m,n,result,cur); + //最后要回退,因为下一个起点可能会用到上一个起点的字符 + visited[i][j]=false; + } + + +} + +//字典树 +class wordTrie{ + public trieNode root=new trieNode(); + public void insert(String s){ + trieNode cur=root; + for(char c:s.toCharArray()){ + //判断是否存在该字符的节点,不存在则创建 + if(cur.child[c-'a']==null){ + cur.child [c-'a'] = new trieNode(); + cur=cur.child[c-'a']; + }else + cur=cur.child [c-'a']; + } + //遍历结束后,修改叶子节点的状态,并存储字符串 + cur.isLeaf=true; + cur.val=s; + } +} +//字典树结点 +class trieNode{ + public String val; + public trieNode[] child=new trieNode[26]; + public boolean isLeaf=false; + + trieNode(){ + + } +} \ No newline at end of file diff --git a/Week_06/G20200343030603/LeetCode_3_603.java b/Week_06/G20200343030603/LeetCode_3_603.java new file mode 100644 index 00000000..c2621844 --- /dev/null +++ b/Week_06/G20200343030603/LeetCode_3_603.java @@ -0,0 +1,66 @@ +// 转化为 岛屿数目 +//1、DFS +//2、BFS +//3、并查集 disjoint set +// a. N --> 各自独立集合 +// b. 遍历好友关系矩阵 M:M[i][j] --> 合并 +// c. 看有多少孤立的集合 +class Solution { + + //方法一:DFS 时间复杂度O(n^2) 空间复杂度O(n) + public int findCircleNum(int[][] M) { + int[] visited = new int[M.length]; + int count = 0; + for (int i = 0; i < M.length; i++) { + if (visited[i] == 0) { + dfs(M, visited, i); + count++; + } + } + return count; + } + private void dfs(int[][] M, int[] visited, int i) { + for (int j = 0; j < M.length; j++) { + if (M[i][j] == 1 && visited[j] == 0) { + visited[j] = 1; + dfs(M, visited, j); + } + } + } + + // //方法二:并查集 时间复杂度O(n^3) 空间复杂度O(n) + // public int find(int parent[], int i){ + // if (parent[i] == -1) { + // return i; + // } + // return find(parent, parent[i]); + // } + + // public void union(int parent[], int x, int y) { + // int xset = find(parent, x); + // int yset = find(parent, y); + // if (xset != yset) { + // parent[xset] = yset; + // } + // } + + // public int findCircleNum(int[][] M) { + // int[] parent = new int[M.length]; + // Arrays.fill(parent, -1); + // for (int i = 0; i < M.length; i++) { + // for (int j = 0; j < M.length; j++) { + // if (M[i][j] == 1 && i != j) { + // union(parent, i, j); + // } + // } + // } + + // int count = 0; + // for (int i = 0; i < parent.length; i++) { + // if(parent[i] == -1) { + // count++; + // } + // } + // return count; + // } +} \ No newline at end of file diff --git a/Week_06/G20200343030603/LeetCode_4_603.java b/Week_06/G20200343030603/LeetCode_4_603.java new file mode 100644 index 00000000..19ebe63a --- /dev/null +++ b/Week_06/G20200343030603/LeetCode_4_603.java @@ -0,0 +1,115 @@ +class Solution { + + // //方法一:DFS 时间复杂度O(M*N) 空间复杂度O(M*N) + // public int numIslands(char[][] grid) { + // if (grid == null || grid.length == 0) { + // return 0; + // } + // int nr = grid.length; + // int nc = grid[0].length; + // int num_islands = 0; + // for (int r = 0; r < nr; r++) { + // for (int c = 0; c < nc; c++) { + // if (grid[r][c] == '1') { + // num_islands++; + // dfs(grid, r, c, nr, nc); + // } + // } + // } + // return num_islands; + // } + + // private void dfs(char[][] grid, int r, int c, int nr, int nc){ + + // if (r < 0 || c < 0 || r >= nr || c >= nc || grid[r][c] == '0') { + // return; + // } + + // grid[r][c] = '0'; + // dfs(grid, r - 1, c, nr, nc); + // dfs(grid, r + 1, c, nr, nc); + // dfs(grid, r, c - 1, nr, nc); + // dfs(grid, r, c + 1, nr, nc); + // } + + //方法二:并查集 + class UnionFind { + int count; // # of connected components + int[] parent; + int[] rank; + + public UnionFind(char[][] grid) { // for problem 200 + count = 0; + int m = grid.length; + int n = grid[0].length; + parent = new int[m * n]; + rank = new int[m * n]; + for (int i = 0; i < m; ++i) { + for (int j = 0; j < n; ++j) { + if (grid[i][j] == '1') { + parent[i * n + j] = i * n + j; + ++count; + } + rank[i * n + j] = 0; + } + } + } + + public int find(int i) { // path compression + if (parent[i] != i) parent[i] = find(parent[i]); + return parent[i]; + } + + public void union(int x, int y) { // union with rank + int rootx = find(x); + int rooty = find(y); + if (rootx != rooty) { + if (rank[rootx] > rank[rooty]) { + parent[rooty] = rootx; + } else if (rank[rootx] < rank[rooty]) { + parent[rootx] = rooty; + } else { + parent[rooty] = rootx; rank[rootx] += 1; + } + --count; + } + } + + public int getCount() { + return count; + } + } + + public int numIslands(char[][] grid) { + if (grid == null || grid.length == 0) { + return 0; + } + + int nr = grid.length; + int nc = grid[0].length; + int num_islands = 0; + UnionFind uf = new UnionFind(grid); + for (int r = 0; r < nr; ++r) { + for (int c = 0; c < nc; ++c) { + if (grid[r][c] == '1') { + grid[r][c] = '0'; + if (r - 1 >= 0 && grid[r-1][c] == '1') { + uf.union(r * nc + c, (r-1) * nc + c); + } + if (r + 1 < nr && grid[r+1][c] == '1') { + uf.union(r * nc + c, (r+1) * nc + c); + } + if (c - 1 >= 0 && grid[r][c-1] == '1') { + uf.union(r * nc + c, r * nc + c - 1); + } + if (c + 1 < nc && grid[r][c+1] == '1') { + uf.union(r * nc + c, r * nc + c + 1); + } + } + } + } + + return uf.getCount(); + } + +} \ No newline at end of file diff --git a/Week_06/G20200343030611/LeetCode_1091_611.java b/Week_06/G20200343030611/LeetCode_1091_611.java new file mode 100644 index 00000000..e7a5d0e3 --- /dev/null +++ b/Week_06/G20200343030611/LeetCode_1091_611.java @@ -0,0 +1,80 @@ +package datast.Axing; + +import java.util.Objects; +import java.util.PriorityQueue; +import java.util.Queue; + +public class LeetCode_1091_611 { + + class Solution { + + private int[] dx = {-1, 1, 0, 0, -1, 1, -1, 1}; + + private int[] dy = {0, 0, -1, 1, -1, -1, 1, 1}; + + public int shortestPathBinaryMatrix(int[][] grid) { + int n = grid.length; + if (grid[0][0] == 1 || grid[n - 1][n - 1] == 1) return -1; + if (n == 1) return 1; + int[][] distance = new int[n][n]; + distance[0][0] = 1; + int[][] visited = new int[n][n]; + Node start = new Node(0, 0, heuristic(n, 0, 0)); + Queue queue = new PriorityQueue<>(); + queue.offer(start); + while (!queue.isEmpty()) { + Node node = queue.poll(); + int x = node.x; + int y = node.y; + for (int j = 0; j < 8; j++) { + int nextx = x + dx[j]; + int nexty = y + dy[j]; + if (nextx >= 0 && nextx < n && nexty >= 0 && nexty < n && grid[nextx][nexty] == 0) { + if (nextx == n - 1 && nexty == n - 1) return distance[x][y] + 1; + if (visited[nextx][nexty] != 2 || distance[nextx][nexty] > distance[x][y] + 1) { + distance[x + dx[j]][y + dy[j]] = distance[x][y] + 1; + visited[nextx][nexty] = 2; + Node next = new Node(x + dx[j], y + dy[j], heuristic(n, x + dx[j], y + dy[j]) + distance[x + dx[j]][y + dy[j]]); + queue.offer(next); + } + } + } + } + return -1; + } + + int heuristic(int n, int x, int y) { + return Math.max(n - 1 - x, n - 1 - y); + } + + class Node implements Comparable { + Integer x; + Integer y; + Integer h; + + public Node(int x, int y, int h) { + this.x = x; + this.y = y; + this.h = h; + } + + @Override + public int compareTo(Node o) { + return this.h.compareTo(o.h); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Node node = (Node) o; + return x.equals(node.x) && y.equals(node.y); + } + + @Override + public int hashCode() { + return Objects.hash(x, y); + } + } + } +} diff --git a/Week_06/G20200343030611/LeetCode_130_611.java b/Week_06/G20200343030611/LeetCode_130_611.java new file mode 100644 index 00000000..bb82d162 --- /dev/null +++ b/Week_06/G20200343030611/LeetCode_130_611.java @@ -0,0 +1,71 @@ +package datast.unionFInd; + +public class LeetCode_130_611 { + + class Solution { + + private int[] dx = {-1, 1, 0, 0}; + + private int[] dy = {0, 0, -1, 1}; + + public void solve(char[][] board) { + int m = board.length; + if (m == 0) return; + int n = board[0].length; + UnionFind unionFind = new UnionFind(m * n + 1); + int dummyNode = m * n; + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + if (board[i][j] == 'O') { + if (i == 0 || j == 0 || i == m - 1 || j == n - 1) { + unionFind.union(i * n + j, dummyNode); + } else { + for (int k = 0; k < 4; k++) { + if (board[i + dx[k]][j + dy[k]] == 'O') { + unionFind.union(i * n + j, (i + dx[k]) * n + j + dy[k]); + } + } + } + } + } + } + + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + if (unionFind.find(i * n + j) != unionFind.find(dummyNode)) + board[i][j] = 'X'; + } + } + + } + + class UnionFind { + private int count = 0; + private int[] parent; + + public UnionFind(int n) { + count = n; + parent = new int[n]; + for (int i = 0; i < n; i++) { + parent[i] = i; + } + } + + public int find(int p) { + while (p != parent[p]) { + parent[p] = parent[parent[p]]; + p = parent[p]; + } + return p; + } + + public void union(int p, int q) { + int rootP = find(p); + int rootQ = find(q); + if (rootP == rootQ) return; + parent[rootP] = rootQ; + count--; + } + } + } +} diff --git a/Week_06/G20200343030611/LeetCode_200_611.java b/Week_06/G20200343030611/LeetCode_200_611.java new file mode 100644 index 00000000..34e61ce0 --- /dev/null +++ b/Week_06/G20200343030611/LeetCode_200_611.java @@ -0,0 +1,67 @@ +package datast.unionFInd; + +public class LeetCode_200_611 { + + class Solution { + + private int[] dx = {-1, 1, 0, 0}; + + private int[] dy = {0, 0, -1, 1}; + + public int numIslands(char[][] grid) { + int m = grid.length; + if (m == 0) return 0; + int n = grid[0].length; + // 构建并查集 + UnionFind unionFind = new UnionFind(grid); + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + if (grid[i][j] == '1') { + + for (int k = 0; k < 4; k++) { + if (i + dx[k] >= 0 && j + dy[k] >= 0 && i + dx[k] < m + && j + dy[k] < n && grid[i + dx[k]][j + dy[k]] == '1') + unionFind.union(i * n + j, (i + dx[k]) * n + j + dy[k]); + } + } + } + } + return unionFind.count; + } + + class UnionFind { + private int count = 0; + private int[] parent; + + public UnionFind(char[][] grid) { + int m = grid.length; + int n = grid[0].length; + parent = new int[m * n]; + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + if (grid[i][j] == '1') { + parent[i * n + j] = i * n + j; + count++; + } + } + } + } + + public int find(int p) { + while (p != parent[p]) { + parent[p] = parent[parent[p]]; + p = parent[p]; + } + return p; + } + + public void union(int p, int q) { + int rootP = find(p); + int rootQ = find(q); + if (rootP == rootQ) return; + parent[rootP] = rootQ; + count--; + } + } + } +} diff --git a/Week_06/G20200343030611/LeetCode_208_611.java b/Week_06/G20200343030611/LeetCode_208_611.java new file mode 100644 index 00000000..c71d15e0 --- /dev/null +++ b/Week_06/G20200343030611/LeetCode_208_611.java @@ -0,0 +1,94 @@ +package datast.trie; + +public class LeetCode_208_611 { + + class Trie { + + private TrieNode root; + + /** + * Initialize your data structure here. + */ + public Trie() { + root = new TrieNode(); + } + + /** + * Inserts a word into the trie. + */ + public void insert(String word) { + TrieNode node = root; + for (int i = 0; i < word.length(); i++) { + char c = word.charAt(i); + if (!node.contains(c)) { + node.put(c, new TrieNode()); + } + node = node.get(c); + } + node.setEnd(); + } + + /** + * Returns if the word is in the trie. + */ + public boolean search(String word) { + TrieNode node = searchPrefix(word); + return node != null && node.isEnd(); + } + + /** + * Returns if there is any word in the trie that starts with the given prefix. + */ + public boolean startsWith(String prefix) { + TrieNode node = searchPrefix(prefix); + return node != null; + } + + private TrieNode searchPrefix(String word) { + TrieNode node = root; + for (int i = 0; i < word.length(); i++) { + char c = word.charAt(i); + if (!node.contains(c)) { + return null; + } + node = node.get(c); + } + return node; + } + + class TrieNode { + + private TrieNode[] links; + + private int linksLength = 26; + + private boolean end; + + public TrieNode() { + links = new TrieNode[linksLength]; + } + + private boolean contains(char c) { + return links[c - 'a'] != null; + } + + private TrieNode get(char c) { + return links[c - 'a']; + } + + private void put(char c, TrieNode node) { + links[c - 'a'] = node; + } + + private void setEnd() { + end = true; + } + + private boolean isEnd() { + return end; + } + } + } + + +} diff --git a/Week_06/G20200343030611/LeetCode_212_611.java b/Week_06/G20200343030611/LeetCode_212_611.java new file mode 100644 index 00000000..73a27c53 --- /dev/null +++ b/Week_06/G20200343030611/LeetCode_212_611.java @@ -0,0 +1,150 @@ +package datast.trie; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +public class LeetCode_212_611 { + + class Solution { + + private Trie trie; + + private boolean[][] visted; + + private Set result = new HashSet<>(); + + public List findWords(char[][] board, String[] words) { + // 构建tire树 + trie = new Trie(); + for (String word : words) { + trie.insert(word); + } + int m = board.length; + int n = board[0].length; + visted = new boolean[m][n]; + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + dfs(i, j, m, n, board, trie.root); + } + } + return new ArrayList(result); + } + + private void dfs(int i, int j, int m, int n, char[][] board, TrieNode node) { + if (i < 0 || j < 0 || i >= m || j >= n || visted[i][j]) return; + node = node.get(board[i][j]); + if (node == null) return; + visted[i][j] = true; + if (node.isEnd()) result.add(node.getWord()); + dfs(i + 1, j, m, n, board, node); + dfs(i - 1, j, m, n, board, node); + dfs(i, j + 1, m, n, board, node); + dfs(i, j - 1, m, n, board, node); + visted[i][j] = false; + } + + class Trie { + + private TrieNode root; + + /** + * Initialize your data structure here. + */ + public Trie() { + root = new TrieNode(); + } + + /** + * Inserts a word into the trie. + */ + public void insert(String word) { + TrieNode node = root; + for (int i = 0; i < word.length(); i++) { + char c = word.charAt(i); + if (!node.contains(c)) { + node.put(c, new TrieNode()); + } + node = node.get(c); + } + node.setEnd(); + node.setWord(word); + } + + /** + * Returns if the word is in the trie. + */ + public boolean search(String word) { + TrieNode node = searchPrefix(word); + return node != null && node.isEnd(); + } + + /** + * Returns if there is any word in the trie that starts with the given prefix. + */ + public boolean startsWith(String prefix) { + TrieNode node = searchPrefix(prefix); + return node != null; + } + + private TrieNode searchPrefix(String word) { + TrieNode node = root; + for (int i = 0; i < word.length(); i++) { + char c = word.charAt(i); + if (!node.contains(c)) { + return null; + } + node = node.get(c); + } + return node; + } + + } + + class TrieNode { + + private TrieNode[] links; + + private int linksLength = 26; + + private boolean end; + + private String word; + + public TrieNode() { + links = new TrieNode[linksLength]; + } + + private boolean contains(char c) { + return links[c - 'a'] != null; + } + + private TrieNode get(char c) { + return links[c - 'a']; + } + + private void put(char c, TrieNode node) { + links[c - 'a'] = node; + } + + private void setEnd() { + end = true; + } + + private boolean isEnd() { + return end; + } + + private void setWord(String word) { + this.word = word; + } + + private String getWord() { + return word; + } + } + + + } +} diff --git a/Week_06/G20200343030611/LeetCode_22_611.java b/Week_06/G20200343030611/LeetCode_22_611.java new file mode 100644 index 00000000..a8a9ec29 --- /dev/null +++ b/Week_06/G20200343030611/LeetCode_22_611.java @@ -0,0 +1,28 @@ +package datast.prune; + +import java.util.ArrayList; +import java.util.List; + +public class LeetCode_22_611 { + + class Solution { + public List generateParenthesis(int n) { + List result = new ArrayList<>(); + generate(0, 0, n, "", result); + return result; + } + + private void generate(int left, int right, int n, String s, List result) { + if (left == n && right == n) { + result.add(s); + return; + } + if (left < n) + generate(left + 1, right, n, s + "(", result); + if (right < left) + generate(left, right + 1, n, s + ")", result); + } + + + } +} diff --git a/Week_06/G20200343030611/LeetCode_36_611.java b/Week_06/G20200343030611/LeetCode_36_611.java new file mode 100644 index 00000000..9a091e4c --- /dev/null +++ b/Week_06/G20200343030611/LeetCode_36_611.java @@ -0,0 +1,37 @@ +package datast.prune; + +import java.util.HashMap; + +public class LeetCode_36_611 { + + class Solution { + public boolean isValidSudoku(char[][] board) { + HashMap[] row = new HashMap[9]; + HashMap[] col = new HashMap[9]; + HashMap[] piece = new HashMap[9]; + for (int i = 0; i < 9; i++) { + row[i] = new HashMap(); + col[i] = new HashMap(); + piece[i] = new HashMap(); + } + + int m = board.length; + int n = board[0].length; + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + char c = board[i][j]; + if (c != '.') { + int index = (i / 3) * 3 + j / 3; + row[i].put(c, row[i].getOrDefault(c, 0) + 1); + col[j].put(c, col[j].getOrDefault(c, 0) + 1); + piece[index].put(c, piece[index].getOrDefault(c, 0) + 1); + if (row[i].get(c) > 1 || col[j].get(c) > 1 + || piece[index].get(c) > 1) + return false; + } + } + } + return true; + } + } +} diff --git a/Week_06/G20200343030611/LeetCode_37_611.java b/Week_06/G20200343030611/LeetCode_37_611.java new file mode 100644 index 00000000..3eba7a30 --- /dev/null +++ b/Week_06/G20200343030611/LeetCode_37_611.java @@ -0,0 +1,41 @@ +package datast.prune; + +public class LeetCode_37_611 { + + class Solution { + public void solveSudoku(char[][] board) { + if (board.length == 0) return; + solve(board); + } + + private boolean solve(char[][] board) { + for (int i = 0; i < board.length; i++) { + for (int j = 0; j < board[0].length; j++) { + if (board[i][j] == '.') { + for (char c = '1'; c <= '9'; c++) { + if (isValid(board, i, j, c)) { + board[i][j] = c; + if (solve(board)) { + return true; + } else { + board[i][j] = '.'; + } + } + } + return false; + } + } + } + return true; + } + + private boolean isValid(char[][] board, int i, int j, char c) { + for (int k = 0; k < 9; k++) { + if (board[i][k] == c) return false; + if (board[k][j] == c) return false; + if (board[3 * (i / 3) + k / 3][3 * (j / 3) + k % 3] == c) return false; + } + return true; + } + } +} diff --git a/Week_06/G20200343030611/LeetCode_433_611.java b/Week_06/G20200343030611/LeetCode_433_611.java new file mode 100644 index 00000000..e2057c35 --- /dev/null +++ b/Week_06/G20200343030611/LeetCode_433_611.java @@ -0,0 +1,50 @@ +package datast.twowaybfs; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +public class LeetCode_433_611 { + + class Solution { + public int minMutation(String start, String end, String[] bank) { + Set bankSet = new HashSet<>(Arrays.asList(bank)); + if (bank.length == 0) return -1; + if (!bankSet.contains(end)) return -1; + char[] baseGens = {'A', 'C', 'G', 'T'}; + Set positive = new HashSet<>(Collections.singletonList(start)); + Set negative = new HashSet<>(Collections.singleton(end)); + Set tempSet = new HashSet<>(); + int count = 0; + while (!positive.isEmpty() && !negative.isEmpty()) { + if (positive.size() > negative.size()) { + Set temp = new HashSet<>(positive); + positive = negative; + negative = temp; + } + for (String word : positive) { + char[] wordCharArray = word.toCharArray(); + for (int i = 0; i < wordCharArray.length; i++) { + char oldGen = wordCharArray[i]; + for (char gen : baseGens) { + wordCharArray[i] = gen; + String newWord = String.valueOf(wordCharArray); + if (negative.contains(newWord)) return ++count; + if (bankSet.contains(newWord)) { + bankSet.remove(newWord); + tempSet.add(newWord); + } + } + wordCharArray[i] = oldGen; + } + } + positive = new HashSet<>(tempSet); + tempSet.clear(); + count++; + } + + return -1; + } + } +} diff --git a/Week_06/G20200343030611/LeetCode_51_611.java b/Week_06/G20200343030611/LeetCode_51_611.java new file mode 100644 index 00000000..e0dd7e2f --- /dev/null +++ b/Week_06/G20200343030611/LeetCode_51_611.java @@ -0,0 +1,60 @@ +package datast.prune; + +import java.util.ArrayList; +import java.util.List; + +public class LeetCode_51_611 { + + class Solution { + + private List col = new ArrayList<>(); + private List master = new ArrayList<>(); + private List slave = new ArrayList<>(); + + private List> result = new ArrayList<>(); + + public List> solveNQueens(int n) { + List res = new ArrayList<>(); + backTrack(0, n, res); + return result; + } + + private void backTrack(int rows, int n, List res) { + if (rows == n) { + print(n, res); + return; + } + for (int i = 0; i < n; i++) { + if (!col.contains(i) && !master.contains(rows + i) + && !slave.contains(rows - i)) { + col.add(i); + master.add(rows + i); + slave.add(rows - i); + res.add(i); + backTrack(rows + 1, n, res); + col.remove(col.size() - 1); + master.remove(master.size() - 1); + slave.remove(slave.size() - 1); + res.remove(res.size() - 1); + } + } + } + + private void print(int n, List res) { + List list = new ArrayList<>(); + for (int i : res) { + StringBuilder str = new StringBuilder(); + for (int j = 0; j < n; j++) { + if (i == j) { + str.append("Q"); + } else { + str.append("."); + } + } + list.add(str.toString()); + } + result.add(list); + } + + } +} diff --git a/Week_06/G20200343030611/LeetCode_547_611.java b/Week_06/G20200343030611/LeetCode_547_611.java new file mode 100644 index 00000000..c2767d45 --- /dev/null +++ b/Week_06/G20200343030611/LeetCode_547_611.java @@ -0,0 +1,45 @@ +package datast.unionFInd; + +public class LeetCode_547_611 { + + class Solution { + public int findCircleNum(int[][] M) { + UnionFind unionFind = new UnionFind(M.length); + for (int i = 0; i < M.length; i++) { + for (int j = 0; j < M.length; j++) { + if (M[i][j] == 1) unionFind.union(i, j); + } + } + return unionFind.count; + } + + class UnionFind { + private int count = 0; + private int[] parent; + + public UnionFind(int n) { + count = n; + parent = new int[n]; + for (int i = 0; i < n; i++) { + parent[i] = i; + } + } + + public int find(int p) { + while (p != parent[p]) { + parent[p] = parent[parent[p]]; + p = parent[p]; + } + return p; + } + + public void union(int p, int q) { + int rootP = find(p); + int rootQ = find(q); + if (rootP == rootQ) return; + parent[rootP] = rootQ; + count--; + } + } + } +} diff --git a/Week_06/G20200343030627/LeetCode_1_627.js b/Week_06/G20200343030627/LeetCode_1_627.js new file mode 100644 index 00000000..5819a1fb --- /dev/null +++ b/Week_06/G20200343030627/LeetCode_1_627.js @@ -0,0 +1,17 @@ +// 回溯+不重复 +var climbStairs = function(n) { + var memory = {}; + return recursion(n); + + function recursion(step) { + if (step<=2) return step; + + if (memory[step]) { + return memory[step]; + } + + var currentSteps = recursion(step - 1) + recursion(step - 2); + memory[step] = currentSteps; + return currentSteps; + } +}; \ No newline at end of file diff --git a/Week_06/G20200343030627/LeetCode_2_627.js b/Week_06/G20200343030627/LeetCode_2_627.js new file mode 100644 index 00000000..c6431410 --- /dev/null +++ b/Week_06/G20200343030627/LeetCode_2_627.js @@ -0,0 +1,58 @@ +// implement-trie-prefix-tree + +/** + * Initialize your data structure here. + */ +var Trie = function() { + this.tree = {}; +}; + +/** + * Inserts a word into the trie. + * @param {string} word + * @return {void} + */ +Trie.prototype.insert = function(word) { + if (typeof word != 'string' || word.length == 0) return; + + var tempObj = this.tree; + for (var i=0; i< word.length; i++) { + if (!tempObj[word[i]]) tempObj[word[i]] = {}; + if (i == word.length -1) tempObj[word[i]].isEnd = true; + tempObj = tempObj[word[i]]; + } + return; +}; + +/** + * Returns if the word is in the trie. + * @param {string} word + * @return {boolean} + */ +Trie.prototype.search = function(word) { + if (typeof word != 'string' || word.length == 0) false; + + var tempObj = this.tree; + for (var i=0;i< word.length; i++) { + if (!tempObj[word[i]]) return false; + if (i == word.length -1 && tempObj[word[i]].isEnd) return true; + tempObj = tempObj[word[i]]; + } + return false; +}; + +/** + * Returns if there is any word in the trie that starts with the given prefix. + * @param {string} prefix + * @return {boolean} + */ +Trie.prototype.startsWith = function(prefix) { + if (typeof prefix != 'string' || prefix.length == 0) false; + + var tempObj = this.tree; + for (var i=0;i< prefix.length; i++) { + if (!tempObj[prefix[i]]) return false; + if (i == prefix.length -1) return true; + tempObj = tempObj[prefix[i]]; + } +}; \ No newline at end of file diff --git a/Week_06/G20200343030631/Leetcode_127_631.java b/Week_06/G20200343030631/Leetcode_127_631.java new file mode 100644 index 00000000..da7ff916 --- /dev/null +++ b/Week_06/G20200343030631/Leetcode_127_631.java @@ -0,0 +1,83 @@ +package com.dsx.hundred.twenty.seven; + +import java.util.*; + +/** + * 解题思路: 双向bfs方式查找,从结尾与开始同时开始,每轮循环只处理变化队列小的这一组 + * 超过leetcode执行时间限制 + * 时间复杂度: + * 空间复杂度: + * 执行用时: + * 内存消耗: + * + * @Author: loe881@163.com + * @Date: 2020/3/22 + */ +public class Solution { + public static void main(String[] args) { + String beginWord = "hit"; + String endWord = "cog"; + String[] wordList = new String[]{"hot", "dot", "dog", "lot", "log", "cog"}; + System.out.println(ladderLength(beginWord, endWord, new ArrayList<>(Arrays.asList(wordList)))); + } + + public static int ladderLength(String beginWord, String endWord, List wordList) { + int result = 1; + // 边界判断 + if (null == beginWord || null == endWord || null == wordList + || wordList.size() == 0 || !wordList.contains(endWord)) { + return 0; + } + + if (beginWord.equals(endWord)) { + return 0; + } + + // 字母字典表 + char[] chars = new char[26]; + generateCharDic(chars); + Queue fromStartladderTemp = new LinkedList<>(); + Queue fromEndladderTemp = new LinkedList<>(); + // 保存已访问的单词 + Set visited = new HashSet<>(); + fromStartladderTemp.offer(beginWord); + fromEndladderTemp.offer(endWord); + while (!fromStartladderTemp.isEmpty() && !fromEndladderTemp.isEmpty()) { + if (fromStartladderTemp.size() > fromEndladderTemp.size()) { + Queue tmpQueue = fromStartladderTemp; + fromStartladderTemp = fromEndladderTemp; + fromEndladderTemp = tmpQueue; + } + int fromStartladderTempSize = fromStartladderTemp.size(); + for (int i = 0; i < fromStartladderTempSize; i++) { + char[] tmpChars = fromStartladderTemp.poll().toCharArray(); + for (int k = 0; k < tmpChars.length; k++) { + char oldCharAtI = tmpChars[k]; + for (char aChar : chars) { + tmpChars[k] = aChar; + String tmpResult = new String(tmpChars); + if (fromEndladderTemp.contains(tmpResult)) { + return result + 1; + } else if (!visited.contains(tmpResult) && wordList.contains(tmpResult)) { + visited.add(tmpResult); + System.out.println(result + "||" + tmpResult); + fromStartladderTemp.offer(tmpResult); + } + } + tmpChars[k] = oldCharAtI; + } + } + result++; + } + return 0; + } + + private static void generateCharDic(char[] chars) { + for (int j = 97; ; j++) { + chars[j - 97] = (char) j; + if ('z' == (char) j) { + break; + } + } + } +} diff --git a/Week_06/G20200343030631/Leetcode_130_631.java b/Week_06/G20200343030631/Leetcode_130_631.java new file mode 100644 index 00000000..b2a88ce2 --- /dev/null +++ b/Week_06/G20200343030631/Leetcode_130_631.java @@ -0,0 +1,138 @@ +package com.dsx.hundred.thirty.zero; + +import java.util.Arrays; + +/** + * 解题思路: 构建并查集,对union进行处理,提高边界元素的权重,当一方的parent为边界元素时,讲另一方的parent指向边界元素 + * 时间复杂度: O(mn) + * 空间复杂度: O(mn) + * 执行用时: 18 ms, 在所有 Java 提交中击败了7.33%的用户 + * 内存消耗: 42.1 MB, 在所有 Java 提交中击败了38.50%的用户 + * + * @Author: loe881@163.com + * @Date: 2020/3/22 + */ +public class Solution { + public static void main(String[] args) { + char[][] board = new char[][]{ + {'O','X','O','O','X','X'}, + {'O','X','X','X','O','X'}, + {'X','O','O','X','O','O'}, + {'X','O','X','X','X','X'}, + {'O','O','X','O','X','X'}, + {'X','X','O','O','O','O'} + }; + solve(board); + for (int i = 0; i < board.length; i++) { + System.out.println(Arrays.toString(board[i])); + } + } + + public static void solve(char[][] board) { + // 边界条件 + if (null == board || board.length == 0 || board[0].length == 0) { + return; + } + + int rowCount = board.length; + int colCount = board[0].length; + UnionFind unionFind = new UnionFind(rowCount, colCount); + for (int row = 0; row < rowCount; row++) { + for (int col = 0; col < colCount; col++) { + if (board[row][col] == 'O'){ + // 和上下左右合并成一个连通区域. + if (row > 0 && board[row - 1][col] == 'O') { + unionFind.union(row * colCount + col, (row - 1) * colCount + col); + } + if (row < rowCount - 1 && board[row + 1][col] == 'O') { + unionFind.union(row * colCount + col, (row + 1) * colCount + col); + } + if (col > 0 && board[row][col - 1] == 'O') { + unionFind.union(row * colCount + col, row * colCount + (col - 1)); + } + if (col < colCount - 1 && board[row][col + 1] == 'O') { + unionFind.union(row * colCount + col, row * colCount + (col + 1)); + } + } + } + } + + for (int row = 0; row < rowCount; row++) { + for (int col = 0; col < colCount; col++) { + if (board[row][col] == 'O'){ + int currentParent = unionFind.find(row * colCount + col); + int currentParentDx = currentParent / colCount; + int currentParentDy = currentParent % colCount; + boolean isCurrentParentOnEdge = currentParentDx == 0 || currentParentDx == rowCount - 1 + || currentParentDy == 0 || currentParentDy == colCount - 1; + if (!isCurrentParentOnEdge){ + board[row][col] = 'X'; + } + } + } + } + + } + + static class UnionFind { + private int count = 0; + private int[] parents; + private int row; + private int col; + + public UnionFind(int row, int col) { + this.row = row; + this.col = col; + this.count = row * col; + this.parents = new int[row * col]; + for (int i = 0; i < count; i++) { + parents[i] = i; + } + } + + public int find(int p) { + while (p != parents[p]) { + parents[p] = parents[parents[p]]; + p = parents[p]; + } + return p; + } + + public void union(int p, int q) { + int rootOfP = find(p); + int rootOfQ = find(q); + if (rootOfP == rootOfQ) { + return; + } + // 修改parent时进行处理 + if (judegeParenet(rootOfP, rootOfQ)) { + parents[rootOfP] = rootOfQ; + } else { + parents[rootOfQ] = rootOfP; + } + count--; + } + + /** + * 判断两个元素谁更接近边界,如果行 列任一个在边界,优先级最高,否则以坐标绝对值差相比较 + * @param p 元素1 + * @param q 元素2 + * @return q是否比q更接近边界 + */ + private boolean judegeParenet(int p, int q) { + int dxOfP = p / col; + int dyOfP = p % col; + int dxOfQ = q / col; + int dyOfQ = q % col; + if (dxOfQ == 0 || dxOfQ == row - 1 + || dyOfQ == 0 || dyOfQ == col - 1) { + return true; + }else if (dxOfP == 0 || dxOfP == row - 1 + || dyOfP == 0 || dyOfP == col - 1) { + return false; + }else { + return (dxOfP + dyOfP) > (dxOfQ + dyOfQ); + } + } + } +} diff --git a/Week_06/G20200343030631/Leetcode_200_631.java b/Week_06/G20200343030631/Leetcode_200_631.java new file mode 100644 index 00000000..f1cbaba4 --- /dev/null +++ b/Week_06/G20200343030631/Leetcode_200_631.java @@ -0,0 +1,103 @@ +package com.dsx.twohundred.zero.zero; + +/** + * 解题思路: 并查集方式,构建并查集,连接所有连通点,最后查看有多少个区域 + * 时间复杂度: O(mn) + * 空间复杂度: O(mn),构建并查集需要的 + * 执行用时: 166 ms, 在所有 Java 提交中击败了5.11%的用户 + * 内存消耗: 43.5 MB, 在所有 Java 提交中击败了5.02%的用户 + * + * @Author: loe881@163.com + * @Date: 2020/3/19 + */ +public class Solution { + public static void main(String[] args) { + char[][] grid = new char[][]{ + {'1','1','1','1','0'}, + {'1','1','0','1','0'}, + {'1','1','0','0','0'}, + {'0','0','0','0','0'} + }; + System.out.println(numIslands(grid)); + } + + public static int numIslands(char[][] grid) { + // 边界条件 + if (null == grid || grid.length == 0 || grid[0].length == 0) { + return 0; + } + int rowCount = grid.length; + int colCount = grid[0].length; + UnionFind unionFind = new UnionFind(grid); + for (int i = 0; i < rowCount; i++) { + for (int j = 0; j < colCount; j++) { + System.out.println("row: " + i + ", col: " + j + ", count: " + unionFind.count); + if (grid[i][j] == '1') { + // 已访问的岛屿,沉没,避免回环计算 + grid[i][j] = '0'; + if (i - 1 >= 0 && grid[i - 1][j] == '1') { + unionFind.union(i * colCount + j, (i - 1) * colCount + j); + } + if (i + 1 < rowCount && grid[i + 1][j] == '1') { + unionFind.union(i * colCount + j, (i + 1) * colCount + j); + } + if (j - 1 >= 0 && grid[i][j - 1] == '1') { + unionFind.union(i * colCount + j, i * colCount + j - 1); + } + if (j + 1 < colCount && grid[i][j + 1] == '1') { + unionFind.union(i * colCount + j, i * colCount + j + 1); + } + } + } + } + return unionFind.count; + } + + static class UnionFind { + private int count = 0; + private int[] parents; + // 权重数组,用于减小生成的并查集树高 + private int[] weights; + + public UnionFind(char[][] grid) { + this.count = 0; + int rowCount = grid.length; + int colCount = grid[0].length; + this.parents = new int[rowCount * colCount]; + this.weights = new int[rowCount * colCount]; + for (int i = 0; i < rowCount; i++) { + for (int j = 0; j < colCount; j++) { + if (grid[i][j] == '1') { + parents[i * colCount + j] = i * colCount + j; + count++; + } + // 初始权重均为0 + weights[i * colCount + j] = 0; + } + } + } + + public int find(int p) { + while (p != parents[p]) { + parents[p] = parents[parents[p]]; + p = parents[p]; + } + return p; + } + + public void union(int dx, int dy) { + int rootOfDx = find(dx); + int rootOfDy = find(dy); + if (rootOfDx != rootOfDy) { + if (weights[rootOfDx] > weights[rootOfDy]) { + parents[rootOfDy] = rootOfDx; + weights[rootOfDx] += weights[rootOfDy]; + } else { + parents[rootOfDx] = rootOfDy; + weights[rootOfDy] += weights[rootOfDx]; + } + count--; + } + } + } +} diff --git a/Week_06/G20200343030631/Leetcode_208_631.java b/Week_06/G20200343030631/Leetcode_208_631.java new file mode 100644 index 00000000..8008595f --- /dev/null +++ b/Week_06/G20200343030631/Leetcode_208_631.java @@ -0,0 +1,103 @@ +package com.dsx.twohundred.zero.eight; + +/** + * 解题思路: 经典解题实现,用trienode表示trie树节点,然后逐层引用生成下一层; + * 时间复杂度: + * 空间复杂度: + * 执行用时: 48 ms, 在所有 Java 提交中击败了61.93%的用户 + * 内存消耗: 54.3 MB, 在所有 Java 提交中击败了24.88%的用户 + * @Author: loe881@163.com + * @Date: 2020/3/18 + */ +public class Solution { + public static void main(String[] args) { + Trie obj = new Trie(); + obj.insert("word"); + boolean param_2 = obj.search("word"); + System.out.println(param_2); + boolean param_3 = obj.startsWith("wo"); + System.out.println(param_3); + boolean param_4 = obj.startsWith("rd"); + System.out.println(param_4); + } + + static class Trie { + + private TrieNode root; + + /** Initialize your data structure here. */ + public Trie() { + root = new TrieNode(); + } + + /** Inserts a word into the trie. */ + public void insert(String word) { + TrieNode node = root; + for (int i = 0; i < word.length(); i++) { + char currentChar= word.charAt(i); + if (!node.containsKey(currentChar)){ + node.put(currentChar, new TrieNode()); + } + node = node.get(currentChar); + } + node.setEnd(); + } + + /** Returns if the word is in the trie. */ + public boolean search(String word) { + TrieNode node = searchInternal(word); + return null != node && node.isEnd(); + } + + private TrieNode searchInternal(String word) { + TrieNode node = root; + for (int i = 0; i < word.length(); i++) { + char currentChar = word.charAt(i); + if (node.containsKey(currentChar)){ + node = node.get(currentChar); + }else { + return null; + } + } + return node; + } + + /** Returns if there is any word in the trie that starts with the given prefix. */ + public boolean startsWith(String prefix) { + TrieNode node = searchInternal(prefix); + return null != node; + } + + class TrieNode{ + // 存储下一层指向 + private TrieNode[] nodes; + + // 存储初始容量,26个英文字母 + private final int SIZE = 26; + + // 存储是否为结束节点,即到达trie树叶子 + private boolean isEndNode; + + public TrieNode() { + this.nodes = new TrieNode[SIZE]; + } + + public boolean containsKey(char ch) { + return nodes[ch -'a'] != null; + } + public TrieNode get(char ch) { + return nodes[ch -'a']; + } + public void put(char ch, TrieNode node) { + nodes[ch -'a'] = node; + } + public void setEnd() { + isEndNode = true; + } + public boolean isEnd() { + return isEndNode; + } + } + } + +} diff --git a/Week_06/G20200343030631/Leetcode_22_631.java b/Week_06/G20200343030631/Leetcode_22_631.java new file mode 100644 index 00000000..d54c7481 --- /dev/null +++ b/Week_06/G20200343030631/Leetcode_22_631.java @@ -0,0 +1,49 @@ +import java.util.ArrayList; +import java.util.List; + +/** + * 解题思路: 动态规划思路,假定前n-1个已稳定生产,则第n对时候可考虑的位置 + * F(0) "" + * F(1) () + * F(2) ()() (()) + * F(3) ()()() (())() ()(()) (()()) ((())) + * 时间复杂度: + * 空间复杂度: + * 执行用时: 2 ms, 在所有 Java 提交中击败了54.10%的用户 + * 内存消耗: 39.5 MB, 在所有 Java 提交中击败了5.16%的用户 + * @Author: loe881@163.com + * @Date: 2020/3/22 + */ +public class Solution { + public static void main(String[] args) { + System.out.println(generateParenthesis(3)); + } + + public static List generateParenthesis(int n) { + List> result = new ArrayList<>(); + if (0 == n){ + return result.get(0); + } + List dp0 = new ArrayList<>(); + dp0.add(""); + List dp1 = new ArrayList<>(); + dp1.add("()"); + result.add(dp0); + result.add(dp1); + for (int i = 2; i <= n; i++) { + List tmpList = new ArrayList<>(); + for (int j = 0; j < i; j++) { + List dpK = result.get(j); + List dpO = result.get(i - 1 - j); + for (String dpk : dpK) { + for (String dpo : dpO) { + String tmpStr = "(".concat(dpk).concat(")").concat(dpo); + tmpList.add(tmpStr); + } + } + } + result.add(tmpList); + } + return result.get(n); + } +} diff --git a/Week_06/G20200343030631/Leetcode_36_631.java b/Week_06/G20200343030631/Leetcode_36_631.java new file mode 100644 index 00000000..c5b95bc5 --- /dev/null +++ b/Week_06/G20200343030631/Leetcode_36_631.java @@ -0,0 +1,69 @@ +package com.dsx.thirty.six; + +import java.util.HashMap; +import java.util.Map; + +/** + * 解题思路: 循环一遍,记录已存在数字到map中,判断是否重复即可; + * 时间复杂度: O(1) + * 空间复杂度: O(1) + * 执行用时: 5 ms, 在所有 Java 提交中击败了38.52%的用户 + * 内存消耗: 41.2 MB, 在所有 Java 提交中击败了96.34%的用户 + * + * @Author: loe881@163.com + * @Date: 2020/3/22 + */ +public class Solution { + public static void main(String[] args) { + char[][] board = new char[][]{ + {'8','3','.','.','7','.','.','.','.'}, + {'6','.','.','1','9','5','.','.','.'}, + {'.','9','8','.','.','.','.','6','.'}, + {'8','.','.','.','6','.','.','.','3'}, + {'4','.','.','8','.','3','.','.','1'}, + {'7','.','.','.','2','.','.','.','6'}, + {'.','6','.','.','.','.','2','8','.'}, + {'.','.','.','4','1','9','.','.','5'}, + {'.','.','.','.','8','.','.','7','9'} + }; + System.out.println(isValidSudoku(board)); + } + + public static boolean isValidSudoku(char[][] board) { + if (null == board || board.length == 0 || board[0].length == 0) { + return false; + } + + Map> rowRecords = new HashMap<>(); + Map> colRecords = new HashMap<>(); + Map> boxRecords = new HashMap<>(); + int rowCount = board.length; + int colCount = board[0].length; + + for (int row = 0; row < rowCount; row++) { + Map currentRowRecord = getCurrentRecordMap(rowRecords, row); + for (int col = 0; col < colCount; col++) { + char current = board[row][col]; + Map currentColRecord = getCurrentRecordMap(colRecords, col); + if (!('.' == current)){ + int boxIndex = (row / 3 ) * 3 + col / 3; + Map currentBoxRecord = getCurrentRecordMap(boxRecords, boxIndex); + if (currentBoxRecord.containsKey(current) || currentColRecord.containsKey(current) + || currentRowRecord.containsKey(current)){ + return false; + }else { + currentRowRecord.put(current, 1); + currentBoxRecord.put(current, 1); + currentColRecord.put(current, 1); + } + } + } + } + return true; + } + + private static Map getCurrentRecordMap(Map> recordMaps, int index) { + Map recordMap = recordMaps.computeIfAbsent(index, k -> new HashMap<>()); + return recordMap; + } +} diff --git a/Week_06/G20200343030631/Leetcode_433_631.java b/Week_06/G20200343030631/Leetcode_433_631.java new file mode 100644 index 00000000..af60b159 --- /dev/null +++ b/Week_06/G20200343030631/Leetcode_433_631.java @@ -0,0 +1,78 @@ +package com.dsx.fourhundred.thirty.three; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.Queue; + +/** + * 解题思路: 优化version1的广度优先,改为双向bfs,每次只处理量少的那个set + * 时间复杂度: O(n+m) + * 空间复杂度: O(n+m) + * 执行用时: 1 ms, 在所有 Java 提交中击败了71.52%的用户 + * 内存消耗: 37.5 MB, 在所有 Java 提交中击败了5.10%的用户 + * @Author: loe881@163.com + * @Date: 2020/2/27 + */ +public class Solution { + public static void main(String[] args) { + String start = "AAAAACCC"; + String end = "AACCCCCC"; + String[] bank = new String[]{"AAAACCCC", "AAACCCCC", "AACCCCCC"}; + System.out.println(minMutation(start, end, bank)); + } + + public static int minMutation(String start, String end, String[] bank) { + // 变化次数 + int result = 0; + // 边界条件,start、end、bank任何一个为null,或者bank中不包含end + if (null == start || null == end || null == bank + || bank.length == 0 || !Arrays.asList(bank).contains(end)){ + return -1; + } + // 边界条件,如果start、end相等,不需要变化,直接返回0 + if (start.equalsIgnoreCase(end)){ + return 0; + } + HashSet store = new HashSet<>(Arrays.asList(bank)); + char[] dict = new char[]{'A', 'C', 'G', 'T'}; + Queue possibleChangeFromStart = new LinkedList<>(); + Queue possibleChangeFromEnd = new LinkedList<>(); + possibleChangeFromStart.offer(start); + possibleChangeFromEnd.offer(end); + store.remove(start); + store.remove(end); + while (!possibleChangeFromStart.isEmpty() && !possibleChangeFromEnd.isEmpty()){ + // 每次循环,变化次数+1 + result++; + + if (possibleChangeFromStart.size() > possibleChangeFromEnd.size()){ + Queue tmpQueue = possibleChangeFromStart; + possibleChangeFromStart = possibleChangeFromEnd; + possibleChangeFromEnd = tmpQueue; + } + // 当前次合法的变化列表,循环处理合法变化列表 + for (int i = possibleChangeFromStart.size(); i > 0; i--) { + // 取出一个合法变化基因串,循环改变每一个位置的元素 + char[] tmpChars = possibleChangeFromStart.poll().toCharArray(); + for (int j = 0; j < tmpChars.length; j++) { + char oldChar = tmpChars[j]; + // 每个元素位置可选择的变化有四个,逐个循环 + for (int k = 0; k < 4; k++) { + tmpChars[j] = dict[k]; + String newGeneChange = new String(tmpChars); + if (possibleChangeFromEnd.contains(newGeneChange)){ + return result; + }else if (store.contains(newGeneChange)){ // 如果包含在基因库中,说明本次是合法的变化,从基因库移除本次变化,放入可变化队列中,继续下一次变化 + store.remove(newGeneChange); + possibleChangeFromStart.offer(newGeneChange); + } + } + tmpChars[j] = oldChar; + } + } + } + + return -1; + } +} diff --git a/Week_06/G20200343030631/Leetcode_547_631.java b/Week_06/G20200343030631/Leetcode_547_631.java new file mode 100644 index 00000000..985dcbbc --- /dev/null +++ b/Week_06/G20200343030631/Leetcode_547_631.java @@ -0,0 +1,65 @@ +package com.dsx.fivehundred.forty.seven; + +/** + * 解题思路: 并查集实现方式 + * 时间复杂度: O(n^3) + * 空间复杂度: O(n) + * 执行用时: 5 ms, 在所有 Java 提交中击败了26.45%的用户 + * 内存消耗: 41.7 MB, 在所有 Java 提交中击败了78.93%的用户 + * @Author: loe881@163.com + * @Date: 2020/3/19 + */ +public class Solution { + public static void main(String[] args) { + int[][] nums = new int[][]{ + {1,1,0}, + {1,1,1}, + {0,1,1} + }; + System.out.println(findCircleNum(nums)); + } + + public static int findCircleNum(int[][] M) { + int length = M.length; + UnionFind unionFind = new UnionFind(length); + for (int i = 0; i < length; i++) { + for (int j = 0; j < length; j++) { + if (M[i][j] == 1){ + unionFind.union(i, j); + } + } + } + return unionFind.count; + } + + static class UnionFind { + private int count = 0; + private int[] parents; + + public UnionFind(int count) { + this.count = count; + this.parents = new int[count]; + for (int i = 0; i < count; i++) { + parents[i] = i; + } + } + + public int find(int p) { + while (p != parents[p]) { + parents[p] = parents[parents[p]]; + p = parents[p]; + } + return p; + } + + public void union(int p, int q) { + int rootOfP = find(p); + int rootOfQ = find(q); + if (rootOfP == rootOfQ) { + return; + } + parents[rootOfP] = rootOfQ; + count--; + } + } +} diff --git a/Week_06/G20200343030631/Leetcode_70_631.java b/Week_06/G20200343030631/Leetcode_70_631.java new file mode 100644 index 00000000..c64216ea --- /dev/null +++ b/Week_06/G20200343030631/Leetcode_70_631.java @@ -0,0 +1,42 @@ +/** + * 暴力穷举,每次穷举,过程中记录不同目标的方法数,避免重复运算 + * 执行用时 :1 ms, 在所有 Java 提交中击败了51.10%的用户 + * 内存消耗 :34.2 MB, 在所有 Java 提交中击败了45.68%的用户 + */ +class Solution { + public static void main(String[] args) { + for (int i = 0; i < 10; i++) { + System.out.printf("Climb %s stairs hava %d ways!%n", i, climbStairs(i)); + } + } + + public static int climbStairs(int n) { + // 初始化一个历史记录数组,记录走过的不同目标的方法数 + int[] history = new int[n+1]; + return climbStair(n ,0, history); + } + + /** + * @param targetStair 要爬的楼梯数 + * @param currentStair 当前爬在第几阶楼梯 + * @param history 从不同阶梯到目标的方法数的记录数组,简化运算过程 + * @return 从当前阶楼梯到达目标楼梯的不同走法方法数 + */ + private static int climbStair(int targetStair, int currentStair, int[] history){ + // 如果已经超过目标楼梯阶数,则本次无需走 + if (currentStair > targetStair){ + return 0; + } + // 如果达到目标阶梯数,则表示需要走一步 + if (currentStair == targetStair){ + return 1; + } + // 如果从当前阶到达目标阶梯已经计算过,直接返回 + if (history[currentStair] > 0){ + return history[currentStair]; + } + // 如果没有计算过,则计算结果,并记录在记录数组中 + history[currentStair] = climbStair(targetStair, currentStair+1, history) + climbStair(targetStair, currentStair+2, history); + return history[currentStair]; + } +} \ No newline at end of file diff --git a/Week_06/G20200343030631/NOTE.md b/Week_06/G20200343030631/NOTE.md index 50de3041..794d4a91 100644 --- a/Week_06/G20200343030631/NOTE.md +++ b/Week_06/G20200343030631/NOTE.md @@ -1 +1,222 @@ -学习笔记 \ No newline at end of file +# 学习笔记 +## 第十三课 字典树和并查集 + +### Tries树 + +- 又称单词查找树或者键树 +- 核心思想是空间换时间 +- 典型应用 + + - 统计 + - 排序大量字符串(不局限于字符串) + +- 优点 + + - 减少无谓的字符串比较 + - 查询效率比哈希表高 + +- 基本性质 + + - 结点本身不存完整单词,可存储其他信息如统计次数等 + - 从根节点到某一结点,路径上经过的字符连接起来,就是该结点对应的字符串 + - 每个结点所有子节点代表的字符串不同 + +- 利用字符串的公共前缀来降低查询时间的开销以达到提高效率的目的 + +### 并查集 + +- 适用场景 + + - 组团、配对问题 + - Group or not + +- 基本操作 + + - makeSet(s) + + - 建立一个新的并查集,其中包含s个单元素集合 + + - unionSet(x, y) + + - 把元素x和元素y所在的集合合并,要求x和y所在的集合不相交,如果相交则不合并 + + - find(x) + + - 找到元素x所在的集合的代表 + - 也可以用于判断两个元素是否位于同一个集合内 + +- 模板代码 + + ```java + class UnionFind {  + private int count = 0;  + private int[] parent;  + public UnionFind(int n) {  + count = n;  + parent = new int[n];  + for (int i = 0; i < n; i++) {  + parent[i] = i; + } + }  + public int find(int p) {  + while (p != parent[p]) {  + parent[p] = parent[parent[p]];  + p = parent[p];  + } + return p;  + } + public void union(int p, int q) {  + int rootP = find(p);  + int rootQ = find(q);  + if (rootP == rootQ) return;  + parent[rootP] = rootQ;  + count--; + } + } + ``` + +## 第十四课 高级搜索 + +### 初级搜索 + +- 朴素搜索 + + - 暴力 + - 重复 + +- 优化方式 + + - 不重复运算,记忆化 + + - 斐波那契数列 + + - 剪枝 + + - 括号生成 + + - 搜索方向优化 + + - 双向搜索 + - 启发式搜索 + +### 剪枝 + +- 在预计不能达到最终目标时,提前结束本次及后续处理 +- 降低状态树复杂度 +- 括号生成 + + - 判断当前次生成括号是否合法,不合法不进行后续生成 + - 左括号始终可以放,只要小于目标 + - 右括号只有在小于左括号数目,且小于目标时才可以 + +- 数独填充问题 + + - 值得学习的实现方式 + + - 反向思维,得到数独空位可用数字,递归处理,可用数字归0即可行,没有归0说明不可行 + +### 双向BFS + +- 相对于传统BFS方式优化 +- 一侧从根节点开始,一侧从目标节点开始,直到双向相遇停止 +- 单词搜索 + + - 方向1 + + - 从beginword开始 + + - 方向2 + + - 从endword开始 + + - 两者的队列有相交元素时停止 + +### 启发式搜索 + +- 又叫A*搜索、优先级搜索、智能搜索 +- 根据某一项条件,不断优化搜索方向 +- 估价函数、优先级函数、启发式函数 + + - 用来评价哪些结点最有希望的是一个要找的结点 + - 返回一个非负实数,代表查找结点的代价 + - + +- 各种距离计算方式 + + - 坐标值之差的绝对值之和 + - 汉明距离 + - 曼哈顿距离 + +## 第十五课 红黑树和AVL树 + +### AVL树 + +- 防止二叉搜索树极端情况下退化为链表的情况 +- 保证左右子树平衡 +- 关键概念 + + - 平衡因子(Balance Factor) + + - -1 + - 0 + - 1 + + - 四种旋转操作 + +- 旋转操作 + + - 左旋 + + - 右右子树的情况 + + A + B + C + + - 右旋 + + - 左左子树的情况 + + A + B + C + + - 左右旋 + + - 左右子树的情况 + + A + B + C + + - 右左旋 + + - 右左子树的情况 + + A + B + C + +- 不足 + + - 需要存储额外信息 + - 调整次数频繁 + +### 红黑树 + +- 近似平衡的二叉搜索树,任何一个结点的左右子树的高度差小于两倍 +- 满足如下条件的二叉搜索树 + + - 每个结点要么是红色,要么是黑色 + - 根结点是黑色 + - 每个叶结点是黑色的,且是空结点 + - 不能有相邻接的两个红色结点 + - 从任一结点到其每个叶子的所有路径都包含相同数目的黑色结点 + +### 两者对比 + +- AVL树因为严格平衡,查找效率比红黑树更高一点 +- 红黑树的插入、删除速度超过AVL树,因为减少了达到平衡的旋转 +- AVL树需要存储结点额外信息,比红黑树占用多一点额外空间 +- 红黑树在多数语言中均有库实现,AVL树多用于DB中 + diff --git a/Week_06/G20200343030633/leetcode-212-word-search2.py b/Week_06/G20200343030633/leetcode-212-word-search2.py new file mode 100644 index 00000000..e3bd634a --- /dev/null +++ b/Week_06/G20200343030633/leetcode-212-word-search2.py @@ -0,0 +1,41 @@ +# 利用208的trie 同时对二维数组进行深度遍历 +import week06.leetcode_208_trie + + +class WordTrie(week06.leetcode_208_trie.Trie): + def findWords(self, board, words): + trie = {} # 构造字典树 + for word in words: + node = trie + for char in word: + node = node.setdefault(char, {}) + node['_'] = True + + def dfssearch(x, y, node, pre, visited): # (i,j)当前坐标,node当前trie树结点,pre前面的字符串,visited已访问坐标 + if '_' in node: # 已有字典树结束 + res.add(pre) # 添加答案 + for (di, dj) in ((-1, 0), (1, 0), (0, -1), (0, 1)): + _i, _j = x + di, y + dj + if -1 < _i < h and -1 < _j < w and board[_i][_j] in node and (_i, _j) not in visited: # 可继续搜索 + dfssearch(_i, _j, node[board[_i][_j]], pre + board[_i][_j], visited | {(_i, _j)}) # dfs搜索 + + res, h, w = set(), len(board), len(board[0]) + for i in range(h): + for j in range(w): + if board[i][j] in trie: # 可继续搜索 + dfssearch(i, j, trie[board[i][j]], board[i][j], {(i, j)}) # dfs搜索 + + return res + + +words = ["oath", "pea", "eat", "rain"] +board = \ + [ + ['o', 'a', 'a', 'n'], + ['e', 't', 'a', 'e'], + ['i', 'h', 'k', 'r'], + ['i', 'f', 'l', 'v'] + ] + +wt = WordTrie() +print(wt.findWords(board, words)) diff --git a/Week_06/G20200343030633/leetcode-547-friend-circle.py b/Week_06/G20200343030633/leetcode-547-friend-circle.py new file mode 100644 index 00000000..bc5b162a --- /dev/null +++ b/Week_06/G20200343030633/leetcode-547-friend-circle.py @@ -0,0 +1,21 @@ +# 并查集查找孤岛 + + +def union(p, i, j): + p1 = parent(p, i) + p2 = parent(p, j) + p[p1] = p2 + + +def parent(p, i): + root = i + while p[root] != root: + root = p[root] + + while p[i] != i: # 路径压缩 + x = i + i = p[i] + p[x] = root + + return root + diff --git a/Week_06/G20200343030633/leetcode_208_trie.py b/Week_06/G20200343030633/leetcode_208_trie.py new file mode 100644 index 00000000..9956d8bd --- /dev/null +++ b/Week_06/G20200343030633/leetcode_208_trie.py @@ -0,0 +1,27 @@ +class Trie(object): + def __init__(self): + self.trie = {} + + def insert(self, word): + t = self.trie + for c in word: + if c not in t: + t[c] = {} # 插入c 同时指向下一个字典 + t = t[c] + t["-"] = True # 这里的'-'就相当于前面声明的isEnd, 用来标记是不是结束了, 因为是用字典实现的所以可以随便声明key去标记 + + def search(self, word): + t = self.trie + for c in word: + if c not in t: + return False + t = t[c] + return "-" in t + + def startsWith(self, prefix): + t = self.trie + for c in prefix: + if c not in t: + return False + t = t[c] + return True diff --git a/Week_06/G20200343030635/id_635/208.py b/Week_06/G20200343030635/id_635/208.py new file mode 100644 index 00000000..f85f3b87 --- /dev/null +++ b/Week_06/G20200343030635/id_635/208.py @@ -0,0 +1,49 @@ +class Trie: + + def __init__(self): + """ + Initialize your data structure here. + """ + self.lookup = {} + + + def insert(self, word: str) -> None: + """ + Inserts a word into the trie. + """ + tree = self.lookup + for a in word: + if a not in tree: + tree[a] = {} + tree = tree[a] + # 单词结束标志 + tree["#"] = "#" + + + def search(self, word: str) -> bool: + """ + Returns if the word is in the trie. + """ + tree = self.lookup + for a in word: + if a not in tree: + return False + tree = tree[a] + if "#" in tree: + return True + return False + + + def startsWith(self, prefix: str) -> bool: + """ + Returns if there is any word in the trie that starts with the given prefix. + """ + tree = self.lookup + for a in prefix: + if a not in tree: + return False + tree = tree[a] + return True + + + diff --git a/Week_06/G20200343030635/id_635/547.py b/Week_06/G20200343030635/id_635/547.py new file mode 100644 index 00000000..db5645eb --- /dev/null +++ b/Week_06/G20200343030635/id_635/547.py @@ -0,0 +1,29 @@ +class Solution: + def findCircleNum(self, M: List[List[int]]) -> int: + parent = [-1 for _ in range(len(M))] + + def find(parent, i): + if parent[i] == -1: return i + return find(parent, parent[i]) + + def union(parent, x, y): + xroot = find(parent, x) + yroot = find(parent, y) + if xroot != yroot: + parent[xroot] = yroot + + def union_find(Matrix): + for i in range(len(Matrix)): + for j in range(len(Matrix)): + if Matrix[i][j] == 1 and i != j: + union(parent, i, j) + count = 0 + for i in range(len(parent)): + if parent[i] == -1: + count += 1 + return count + + return union_find(M) + + + diff --git a/Week_07/G20190282010007/NOTE.md b/Week_07/G20190282010007/NOTE.md index 50de3041..1759808a 100644 --- a/Week_07/G20190282010007/NOTE.md +++ b/Week_07/G20190282010007/NOTE.md @@ -1 +1,256 @@ -学习笔记 \ No newline at end of file +学习笔记 + + 位运算 + 或: + 符号: | + 定义:同位只要有一个为1,或后就为1 + 例子: 0011 | 1011 =》 1011 + 与: + 符号: & + 定义:同位只要有一个为0,与后就为0 + 例子: 0011 & 1011 =》 0011 + 按位取反 + 符号: ~ + 定义:就是取反 + 例子: 0011 ~ 1100 + 异或 + 符号: ^ + 定义:同位相同为0,不同则为1 + 例子: 0011 ^ 1011 =》1000 + + 十大经典排序算法: + 插入排序 + let insertionSort = function (arr) { + let len = arr.length + let preIndex, current + for (let i = 0; i < len; i++) { + preIndex = i - 1 + current = arr[i] + while(preIndex >= 0 && arr[preIndex] > current) { + arr[preIndex + 1] = arr[preIndex] + preIndex-- + } + arr[preIndex + 1] = current + } + return arr + } + 希尔排序 + let shellSort = function (arr) { + let len = arr.length + for (let gap = Math.floor(len / 2); gap > 0; gap = Math.floot(gap / 2)) { + for (let i = gap; i < len; i++) { + let j = i + let current = arr[i] + while (j - gap >=0 && current < arr[j - gap]) { + arr[j] = arr[j - gap] + j = j - gap + } + arr[j] = current + } + } + return arr + } + 选择排序 + let selectionSort = function (arr) { + let len = arr.length + let minIndex + for (let i = 0; i < len - 1; i++) { + minIndex = i; + for (let j = i + 1; j < len; j++) { + if (arr[j] < arr[minInded]) { + minIndex = j + } + } + [arr[i], arr[minIndex]] = [arr[minIndex], arr[i]] + } + return arr + } + 堆排序 + let len; + let buildMaxHeap = function (arr) { + len = arr.length + for (let i = Math.floor(len / 2); i >= 0; i--) { + heapify(arr, i) + } + } + let heapify = function (arr, i) { + let left = 2 * i + 1, + right = 2 * i + 2, + largest = i + if(left < len && arr[left] > arr[largest]) { + largest = left; + } + + if(right < len && arr[right] > arr[largest]) { + largest = right; + } + + if(largest != i) { + [arr[i], arr[largest]] = [arr[largest], arr[i]] + heapify(arr, largest); + } + } + let heapSort = function (arr) { + buildMaxHep(arr) + for (let i = arr.length - 1; i > 0; i--) { + [arr[0], arr[i]] = [arr[i], arr[0]] + len-- + heapify(arr, 0) + } + return arr + } + 冒泡排序 + let bubbleSort = function (arr) { + let len = arr.length + for (let i = 0; i < len -1; i++) { + for (let j = 0; j < len - 1 - i; j++) { + if (arr[j] > arr[j+1]) { + [arr[j], arr[j+1]] = [arr[j+1], arr[j]] + } + } + } + return arr + } + 快速排序 + let quickSort = function(arr, left, right) { + let len = arr.length, + partitionIndex, + left = typeof left != 'number' ? 0 : left, + right = typeof right != 'number' ? len - 1 : right + if (left < right) { + partitionIndex = partition(arr, left, right) + quickSort(arr, left, partitionIndex - 1) + quickSort(arr, partitionIndex + 1, right) + } + } + left partition = function (arr, left, right) { + let pivot = left, + index = pivot = 1 + for (let i = index; i <= right; i++) { + if (arr[i] < arr[pivot]) { + [arr[i], arr[index]] = [arr[index], arr[i]] + index++ + } + } + swap(arr, pivot, index-1) + [arr[pivot], arr[index - 1]] = [arr[index - 1], arr[pivot]] + return index - 1 + } + 归并排序 + let mergeSort = function (arr) { + let len = arr.length + if (let < 2) { + return arr + } + let middle = Math.floor(len / 2), + left = arr.slice(0, middle), + right = arr.slice(middle) + return merge(mergeSort(left), mergeSort(right)) + } + let merge = function (left, right) { + let result = [] + while (left.length > 0 && right.length > 0) { + if (left[0] <= right[0]) { + result.push(left.shift()) + } else { + result.push(right.shift()) + } + } + while (left.length) { + result.push(left.shift()) + } + while (right.length) { + result.push(right.shift()) + } + return result + } + + 计数排序 + function countingSort = function (arr, maxValue) { + let bucket = newArray(maxValue + 1), + sortedIndex = 0; + arrLen = arr.length, + bucketLen = maxValue + 1; + + for(let i = 0; i < arrLen; i++) { + if(!bucket[arr[i]]) { + bucket[arr[i]] = 0; + } + bucket[arr[i]]++; + } + + for(let j = 0; j < bucketLen; j++) { + while(bucket[j] > 0) { + arr[sortedIndex++] = j; + bucket[j]--; + } + } + + return arr; + } + 桶排序 + let bucketSort = function (arr, bucketSize) { + if(arr.length === 0) { + return arr; + } + + let i; + let minValue = arr[0]; + let maxValue = arr[0]; + for(i = 1; i < arr.length; i++) { + if(arr[i] < minValue) { + minValue = arr[i]; + } else if(arr[i] > maxValue) { + maxValue = arr[i]; + } + } + + + let DEFAULT_BUCKET_SIZE = 5; + bucketSize = bucketSize || DEFAULT_BUCKET_SIZE; + let bucketCount = Math.floor((maxValue - minValue) / bucketSize) + 1; + let buckets = newArray(bucketCount); + for(i = 0; i < buckets.length; i++) { + buckets[i] = []; + } + + + for(i = 0; i < arr.length; i++) { + buckets[Math.floor((arr[i] - minValue) / bucketSize)].push(arr[i]); + } + + arr.length = 0; + for(i = 0; i < buckets.length; i++) { + insertionSort(buckets[i]); + for(let j = 0; j < buckets[i].length; j++) { + arr.push(buckets[i][j]); + } + } + + return arr; + } + 基数排序 + let counter = []; + let radixSort = function (arr, maxDigit) { + let mod = 10; + let dev = 1; + for(let i = 0; i < maxDigit; i++, dev *= 10, mod *= 10) { + for(let j = 0; j < arr.length; j++) { + let bucket = parseInt((arr[j] % mod) / dev); + if(counter[bucket]==null) { + counter[bucket] = []; + } + counter[bucket].push(arr[j]); + } + let pos = 0; + for(let j = 0; j < counter.length; j++) { + let value = null; + if(counter[j]!=null) { + while((value = counter[j].shift()) != null) { + arr[pos++] = value; + } + } + } + } + return arr; + } \ No newline at end of file diff --git a/Week_07/G20190282010007/leetcode_191_007.js b/Week_07/G20190282010007/leetcode_191_007.js new file mode 100644 index 00000000..6cfc21af --- /dev/null +++ b/Week_07/G20190282010007/leetcode_191_007.js @@ -0,0 +1,23 @@ +// 题目: 位1的个数 +/** + * 题目描述: +编写一个函数,输入是一个无符号整数,返回其二进制表达式中数字位数为 ‘1’ 的个数(也被称为汉明重量)。 + + */ + + // 解题语言: javaScript + + // 解题 + + /** + * @param {number} n - a positive integer + * @return {number} + */ +var hammingWeight = function(n) { + let count = 0 + while (n !== 0) { + n = n & (n - 1) + count++ + } + return count +}; \ No newline at end of file diff --git a/Week_07/G20190282010007/leetcode_231_007.js b/Week_07/G20190282010007/leetcode_231_007.js new file mode 100644 index 00000000..2aa1ac10 --- /dev/null +++ b/Week_07/G20190282010007/leetcode_231_007.js @@ -0,0 +1,18 @@ +// 题目: 2的幂 +/** + * 题目描述: +给定一个整数,编写一个函数来判断它是否是 2 的幂次方。 + + */ + + // 解题语言: javaScript + + // 解题 + + /** + * @param {nember} n + * @return {boolean} + */ + var isPowerOfTwo = function (n) { + return n > 0 && (n & (n - 1)) == 0 + } \ No newline at end of file diff --git a/Week_07/G20190379010083/LeetCode_146_083.swift b/Week_07/G20190379010083/LeetCode_146_083.swift new file mode 100644 index 00000000..7370b1b4 --- /dev/null +++ b/Week_07/G20190379010083/LeetCode_146_083.swift @@ -0,0 +1,105 @@ +// +// 0146_LRUCache.swift +// AlgorithmPractice +// +// https://leetcode-cn.com/problems/lru-cache/ +// Created by Ryeagler on 2020/3/29. +// Copyright © 2020 Ryeagle. All rights reserved. +// + +import Foundation + +class LRUCache { + + class LinkNode { + var key: Int + var value: Int + var next: LinkNode? + var prev: LinkNode? + + init(_ key: Int, _ value: Int) { + self.key = key + self.value = value + } + } + + let capacity: Int + // The number of values currently being stored + private var usage = 0 + private var elements = [Int: LinkNode]() + // The most recently used node + private var head: LinkNode? + // The least recently used node + private var tail: LinkNode? + + init(_ capacity: Int) { + self.capacity = capacity + } + + func get(_ key: Int) -> Int { + guard let node = elements[key] else { + return -1 + } + + updateUsage(of: node) + + return node.value + } + + func put(_ key: Int, _ value: Int) { + // Key already exists + if let existing = elements[key] { + existing.value = value + updateUsage(of: existing) + } + // Add new key + else if usage < capacity { + let node = LinkNode(key, value) + elements[key] = node + if let head = self.head { + head.next = node + node.prev = head + self.head = node + } + else { + self.head = node + } + if tail == nil { + tail = node + } + usage += 1 + } + // Replace least-used key + else if let tail = self.tail { + elements[tail.key] = nil + tail.key = key + tail.value = value + elements[key] = tail + updateUsage(of: tail) + } + } + + // Moves `node` to the head of the usage list + private func updateUsage(of node: LinkNode) { + if let next = node.next { + node.next = nil + next.prev = nil + + if let prev = node.prev { + node.prev = nil + prev.next = next + next.prev = prev + } + else if self.tail === node { + self.tail = next + } + + if let head = self.head { + node.prev = head + head.next = node + } + + head = node + } + } +} diff --git a/Week_07/G20190379010083/LeetCode_191_083.swift b/Week_07/G20190379010083/LeetCode_191_083.swift new file mode 100644 index 00000000..f1dd14ce --- /dev/null +++ b/Week_07/G20190379010083/LeetCode_191_083.swift @@ -0,0 +1,32 @@ +// +// 0191_NumberOf1Bits.swift +// AlgorithmPractice +// +// https://leetcode-cn.com/problems/number-of-1-bits/ +// Created by Ryeagler on 2020/3/12. +// Copyright © 2020 Ryeagle. All rights reserved. +// + +import Foundation + +class NumberOf1Bits { + func hammingWeight(_ n: Int) -> Int { + var ones = 0, n = n + while n != 0 { + ones = ones + (n & 1) + n = n >> 1 + } + return ones + } + + // n & n - 1会把最后一位1变成0 + func hammingWeight_1(_ n: Int) -> Int { + var ones = 0, n = n + while n != 0 { + ones += 1 + n &= (n - 1); + } + return ones + + } +} diff --git a/Week_07/G20190379010083/LeetCode_242_083.swift b/Week_07/G20190379010083/LeetCode_242_083.swift new file mode 100644 index 00000000..18f4ab32 --- /dev/null +++ b/Week_07/G20190379010083/LeetCode_242_083.swift @@ -0,0 +1,44 @@ +// +// 0242_ValidAnagram.swift +// AlgorithmPractice +// +// https://leetcode-cn.com/problems/valid-anagram/ +// Created by Ryeagler on 2020/2/18. +// Copyright © 2020 Ryeagle. All rights reserved. +// + +import Foundation + +class ValidAnagram { + func isAnagramSort(_ s: String, _ t: String) -> Bool { + let sortedS = s.sorted() + let sortedT = t.sorted() + return sortedT == sortedS + } + + func isAnagram(_ s: String, _ t: String) -> Bool { + if s.count != t.count { + return false + } + var dict = [Character: Int]() + for char in s { + if let count = dict[char] { + dict[char] = count + 1 + } else { + dict[char] = 1 + } + } + + for char in t { + if dict[char] == nil { + return false + } else if dict[char]! == 0 { + return false + } + + dict[char] = dict[char]! - 1 + } + return true + } + +} diff --git a/Week_07/G20200343030001/LRUCache.java b/Week_07/G20200343030001/LRUCache.java new file mode 100644 index 00000000..b4c6bba2 --- /dev/null +++ b/Week_07/G20200343030001/LRUCache.java @@ -0,0 +1,30 @@ +package Week_07; + +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * Leetcode_146 + */ +public class LRUCache { + private int capacity; + private LinkedHashMap cache; + + public LRUCache(int capacity) { + this.capacity = capacity; + this.cache = new LinkedHashMap(capacity, 0.75f, true) { + @Override + protected boolean removeEldestEntry(Map.Entry eldest) { + return cache.size() > capacity; + } + }; + } + + public int get(int key) { + return cache.getOrDefault(key, -1); + } + + public void put(int key, int value) { + cache.put(key, value); + } +} diff --git a/Week_07/G20200343030001/Leetcode_1122_001.java b/Week_07/G20200343030001/Leetcode_1122_001.java new file mode 100644 index 00000000..f6bbee4e --- /dev/null +++ b/Week_07/G20200343030001/Leetcode_1122_001.java @@ -0,0 +1,29 @@ +package Week_07; + +public class Leetcode_1122_001 { + public int[] relativeSortArray(int[] arr1, int[] arr2) { + int[] nums = new int[1001]; + int[] res = new int[arr1.length]; + + for (int i : arr1) { + nums[i]++; + } + + int index = 0; + for (int i : arr2) { + while (nums[i]>0){ + res[index++] = i; + nums[i]--; + } + } + + for (int i = 0; i < nums.length; i++) { + while (nums[i]>0){ + res[index++] = i; + nums[i]--; + } + } + + return res; + } +} diff --git a/Week_07/G20200343030001/Leetcode_190_001.java b/Week_07/G20200343030001/Leetcode_190_001.java new file mode 100644 index 00000000..e744ea4e --- /dev/null +++ b/Week_07/G20200343030001/Leetcode_190_001.java @@ -0,0 +1,23 @@ +package Week_07; + +public class Leetcode_190_001 { + // you need treat n as an unsigned value + public int reverseBits(int n) { + int ans = 0; + + for (int bitsSize = 31; n != 0; n = n >>> 1, bitsSize--) { + ans += (n & 1) << bitsSize; + } + + return ans; + } + + public static void main(String[] args) { + int n = 43261596, result = 964176192; + + System.out.println(4 >>> 1); + System.out.println(Integer.toBinaryString(n)); + System.out.println(Integer.toBinaryString(result)); + System.out.println(new Leetcode_190_001().reverseBits(43261596) == result); + } +} diff --git a/Week_07/G20200343030001/Leetcode_191_001.java b/Week_07/G20200343030001/Leetcode_191_001.java new file mode 100644 index 00000000..4265dc30 --- /dev/null +++ b/Week_07/G20200343030001/Leetcode_191_001.java @@ -0,0 +1,15 @@ +package Week_07; + +public class Leetcode_191_001 { + // you need to treat n as an unsigned value + public int hammingWeight(int n) { + int counter = 0; + + while (n != 0) { + counter++; + n &= n - 1; + } + + return counter; + } +} diff --git a/Week_07/G20200343030001/Leetcode_231_001.java b/Week_07/G20200343030001/Leetcode_231_001.java new file mode 100644 index 00000000..4b430637 --- /dev/null +++ b/Week_07/G20200343030001/Leetcode_231_001.java @@ -0,0 +1,13 @@ +package Week_07; + +public class Leetcode_231_001 { + public boolean isPowerOfTwo(int n) { + if (n == 0) { + return false; + } + + long x = (long) n; + + return (x & (x - 1)) == 0; + } +} diff --git a/Week_07/G20200343030001/Leetcode_242_001.java b/Week_07/G20200343030001/Leetcode_242_001.java new file mode 100644 index 00000000..2846286a --- /dev/null +++ b/Week_07/G20200343030001/Leetcode_242_001.java @@ -0,0 +1,25 @@ +package Week_07; + +public class Leetcode_242_001 { + public boolean isAnagram(String s, String t) { + if (s.length() != t.length()) { + return false; + } + + int[] index = new int[26]; + + for (int i = 0; i < s.length(); i++) { + index[s.charAt(i) - 'a']++; + } + + for (int i = 0; i < t.length(); i++) { + index[t.charAt(i) - 'a']--; + + if (index[t.charAt(i) - 'a'] < 0) { + return false; + } + } + + return true; + } +} diff --git a/Week_07/G20200343030005/Leetcode_190_001.js b/Week_07/G20200343030005/Leetcode_190_001.js new file mode 100644 index 00000000..e5c054b2 --- /dev/null +++ b/Week_07/G20200343030005/Leetcode_190_001.js @@ -0,0 +1,34 @@ +// 190. 颠倒二进制位 https://leetcode-cn.com/problems/reverse-bits/ +// 颠倒给定的 32 位无符号整数的二进制位。 +/** + * @param {number} n - a positive integer + * @return {number} - a positive integer + */ +var reverseBits = function(n) { + var num = 0b0; + for (var i = 0; i <= 31; i++) { + num |= (((n >> (31 - i)) & 1) << i) >>> 0; + } + return num >>> 0; +}; +var reverseBits = function(n) { + let result = 0; + for (let i = 0; i < 32; i++) { + result = (result << 1) + (n & 1); + n >>= 1; + } + return result >>> 0; +}; +var reverseBits = function(n) { + let result = 0; + // result从右往移动空出末位 + n从左往右移动获取末位 + n次 = 倒序 + for (let i = 0; i < 32; i++) { + // 左移空出一位 + result <<= 1; + // n&1获取n的末位,result的末位换成n的末位 + result |= n & 1; + // 右移1位 + n >>= 1; + } + return result >>> 0; +}; diff --git a/Week_07/G20200343030005/Leetcode_191_001.js b/Week_07/G20200343030005/Leetcode_191_001.js new file mode 100644 index 00000000..69cd5703 --- /dev/null +++ b/Week_07/G20200343030005/Leetcode_191_001.js @@ -0,0 +1,32 @@ +// 191. 位1的个数 https://leetcode-cn.com/problems/number-of-1-bits/ +/** + * @param {number} n - a positive integer + * @return {number} + */ +var hammingWeight = function(n) { + return n + .toString(2) + .split("") + .reduce((t, n) => +t + +n); +}; + +var hammingWeight = function(n) { + return n.toString(2).replace(/0/g, "").length; +}; +var hammingWeight = function(n) { + let count = 0; + while (n) { + count += n % 2; + n = n >> 1; + // n = Math.floor(n / 2); + } + return count; +}; +var hammingWeight = function(n) { + let counts = 0; + while (n) { + counts++; + n &= n - 1; + } + return counts; +}; diff --git a/Week_07/G20200343030005/Leetcode_231_001.js b/Week_07/G20200343030005/Leetcode_231_001.js new file mode 100644 index 00000000..4b6a6e94 --- /dev/null +++ b/Week_07/G20200343030005/Leetcode_231_001.js @@ -0,0 +1,36 @@ +// 231. 2的幂 https://leetcode-cn.com/problems/power-of-two/ +/** + * @param {number} n + * @return {boolean} + */ +/* 解法一:2的幂数的数字的二进制特点 + 位操作 +2的幂数的数字的二进制有且只有一个1,其余均是0 +n & (n-1):清零最低位的1 +合起来 n & (n-1) == 0 */ + +var isPowerOfTwo = function(n) { + return n > 0 && (n & (n - 1)) == 0; +}; +// 解法二:调用函数懒蛋法 +var isPowerOfTwo = function(n) { + return Number.isInteger(Math.log2(n)); +}; +// 解法三:位运算 +var isPowerOfTwo = function(n) { + return n > 0 && (n & -n) == n; +}; +// 解法四:取模 +/** + * @param {number} n + * @return {boolean} + */ +var isPowerOfTwo = function(n) { + while (n > 1) { + n /= 2; + } + if (n == 1) { + return true; + } else { + return false; + } +}; diff --git a/Week_07/G20200343030005/NOTE.md b/Week_07/G20200343030005/NOTE.md index 50de3041..e498642a 100644 --- a/Week_07/G20200343030005/NOTE.md +++ b/Week_07/G20200343030005/NOTE.md @@ -1 +1,478 @@ -学习笔记 \ No newline at end of file +学习笔记 +线性查找: + + + +二分查找 + + + +线性——二分查找 性能对比 + + + +二叉树 bst:(Binary Search Tree) + + + +线性 二分 二叉树 【 无序 有序 二分】性能比较 + + + +//散列——hash(哈希) + +//散列 哈希 hash +function hash_add(arr,n){ + +var pos = n%arr.length; + +if(!arr[pos]){ + arr[pos] = n; + } else {// 存在了 + while(arr[pos]){ + if(arr[pos] == n){ + return ; + } + pos++; + if(pos == arr.length){ + pos = 0; + } + } + arr[pos] = n; + } +} +var arr = []; +arr.length = 10; + +function hash_find(arr,n){ + var pos = n%arr.length; + var beginIndex = pos; + var bLast = false; + +if(!arr[pos]){// 数据不存在 + return false; + } else {//有数据 + while(arr[pos]){ + if(bLast && beginIndex == pos) return false; + +if(arr[pos] == n){ + return true; + } else {// 没找到 + pos++; + if(pos == arr.length){ + pos = 0; + bLast = true; + } + } + } + return false; + } + +} + +hash_add(arr,25); +hash_add(arr,35); +hash_add(arr,28); +hash_add(arr,37); +hash_add(arr,4); +hash_add(arr,16); +hash_add(arr,5); +hash_add(arr,3); +hash_add(arr,1); +hash_add(arr,2); + +document.write(arr); +document.write(hash_find(arr,5)); + +var arr = []; +arr.length = 10; + +function hash_add(arr,n){ + //位置: + var pos = n%arr.length; + var beginIndex = pos; + var bEnd = false; + +if(!arr[pos]){//没有 + arr[pos] = n; + } else {//有值 + while(arr[pos]){ + +//判断 + if(bEnd == true && beginIndex == pos){ + return; + } + +if(arr[pos] == n){ + return;//有重复数据 + } + pos++; + if(pos == arr.length){ + pos = 0; + bEnd = true; + } + } + +arr[pos] = n; + } + +} + +hash_add(arr,12); +hash_add(arr,5); +hash_add(arr,55); +hash_add(arr,555); +hash_add(arr,102); +hash_add(arr,18); +hash_add(arr,19); +hash_add(arr,35); +hash_add(arr,1); +hash_add(arr,2); +hash_add(arr,3); + +document.write(arr + "
"); + +function hash_find(arr,n){ + +var pos = n%arr.length; + var beginIndex = pos; + var bEnd = false; + if(!arr[pos]){ + return false; + } else { + +while(arr[pos]){ + if(bEnd && beginIndex == pos){ + return false; + } + +if(arr[pos] == n){ + return true; + } + pos++; + +if(pos == arr.length){ + pos = 0; + bEnd = true; + } + } + return false; + } +} + +document.write(hash_find(arr,17)); + + diff --git a/Week_07/G20200343030007/Leetcode_007_190.java b/Week_07/G20200343030007/Leetcode_007_190.java new file mode 100644 index 00000000..69884bb5 --- /dev/null +++ b/Week_07/G20200343030007/Leetcode_007_190.java @@ -0,0 +1,11 @@ +public int reverseBits(int n) { + int res = 0; + int count = 0; + while (count < 32) { + res <<= 1; //res 左移一位空出位置 + res |= (n & 1); //得到的最低位加过来 + n >>= 1;//原数字右移一位去掉已经处理过的最低位 + count++; + } + return res; +} diff --git a/Week_07/G20200343030007/Leetcode_007_232.java b/Week_07/G20200343030007/Leetcode_007_232.java new file mode 100644 index 00000000..0393faaf --- /dev/null +++ b/Week_07/G20200343030007/Leetcode_007_232.java @@ -0,0 +1,7 @@ +class Solution { + public boolean isPowerOfTwo(int n) { + if (n == 0) return false; + while (n % 2 == 0) n /= 2; + return n == 1; + } +} \ No newline at end of file diff --git a/Week_07/G20200343030009/LeetCode_146_009.js b/Week_07/G20200343030009/LeetCode_146_009.js new file mode 100644 index 00000000..dcacdc5a --- /dev/null +++ b/Week_07/G20200343030009/LeetCode_146_009.js @@ -0,0 +1,64 @@ +/* + 146. LRU缓存机制 + 运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制。它应该支持以下操作: 获取数据 get 和 写入数据 put 。 + 获取数据 get(key) - 如果密钥 (key) 存在于缓存中,则获取密钥的值(总是正数),否则返回 -1。 + 写入数据 put(key, value) - 如果密钥不存在,则写入其数据值。当缓存容量达到上限时,它应该在写入新数据之前删除最久未使用的数据值,从而为新的数据值留出空间。 + + 进阶: + 你是否可以在 O(1) 时间复杂度内完成这两种操作? + + 示例: + LRUCache cache = new LRUCache( 2); // 缓存容量 + cache.put(1, 1); + cache.put(2, 2); + cache.get(1); // 返回 1 + cache.put(3, 3); // 该操作会使得密钥 2 作废 + cache.get(2); // 返回 -1 (未找到) + cache.put(4, 4); // 该操作会使得密钥 1 作废 + cache.get(1); // 返回 -1 (未找到) + cache.get(3); // 返回 3 + cache.get(4); // 返回 4 +*/ + +/** + * @param {number} capacity + */ +var LRUCache = function(capacity) { + this.capacity = capacity + this.map = new Map() +}; + +/** +* @param {number} key +* @return {number} +*/ +LRUCache.prototype.get = function(key) { + let val = this.map.get(key) + if (typeof val === 'undefined') return -1 + this.map.delete(key) + this.map.set(key, val) + return val +}; + +/** +* @param {number} key +* @param {number} value +* @return {void} +*/ +LRUCache.prototype.put = function(key, value) { + if (this.map.has(key)) { + this.map.delete(key) + } + this.map.set(key, value) + let keys = this.map.keys() + while (this.map.size > this.capacity) { + this.map.delete(keys.next().value) + } +}; + +/** +* Your LRUCache object will be instantiated and called as such: +* var obj = new LRUCache(capacity) +* var param_1 = obj.get(key) +* obj.put(key,value) +*/ \ No newline at end of file diff --git a/Week_07/G20200343030009/LeetCode_56_009.js b/Week_07/G20200343030009/LeetCode_56_009.js new file mode 100644 index 00000000..3fbc5ca9 --- /dev/null +++ b/Week_07/G20200343030009/LeetCode_56_009.js @@ -0,0 +1,32 @@ +/* + 56. 合并区间 + 给出一个区间的集合,请合并所有重叠的区间。 + + 示例 1: + 输入: [[1,3],[2,6],[8,10],[15,18]] + 输出: [[1,6],[8,10],[15,18]] + 解释: 区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6]. + + 示例 2: + 输入: [[1,4],[4,5]] + 输出: [[1,5]] + 解释: 区间 [1,4] 和 [4,5] 可被视为重叠区间。 +*/ +/** + * @param {number[][]} intervals + * @return {number[][]} + */ +var merge = function(intervals) { + if (!intervals || !intervals.length) return [] + intervals.sort((a, b) => a[0] - b[0]) + let ans = [intervals[0]] + for (let i = 0; i < intervals.length; i++) { + let ansLen = ans.length + if (ans[ansLen-1][1] >= intervals[i][0]) { + ans[ansLen-1][1] = Math.max(ans[ansLen-1][1], intervals[i][1]) + } else { + ans.push(intervals[i]) + } + } + return ans +}; \ No newline at end of file diff --git a/Week_07/G20200343030015/LeetCode_190_015.java b/Week_07/G20200343030015/LeetCode_190_015.java new file mode 100644 index 00000000..b5d626fe --- /dev/null +++ b/Week_07/G20200343030015/LeetCode_190_015.java @@ -0,0 +1,21 @@ +package G20200343030015.week_07; + +/** + * Created by majiancheng on 2020/3/29. + * + * 190. 颠倒二进制位 + * 颠倒给定的 32 位无符号整数的二进制位。 + */ +public class LeetCode_190_015 { + // you need treat n as an unsigned value + public int reverseBits(int n) { + int res = 0; + for(int i = 0; i < 32; i++) { + res <<= 1; + res |= (n & 1); + n >>= 1; + } + + return res; + } +} diff --git a/Week_07/G20200343030015/LeetCode_191_015.java b/Week_07/G20200343030015/LeetCode_191_015.java new file mode 100644 index 00000000..f99223c9 --- /dev/null +++ b/Week_07/G20200343030015/LeetCode_191_015.java @@ -0,0 +1,22 @@ +package G20200343030015.week_07; + +/** + * Created by majiancheng on 2020/3/29. + * + * 191. 位1的个数 + * + * 编写一个函数,输入是一个无符号整数,返回其二进制表达式中数字位数为 ‘1’ 的个数(也被称为汉明重量)。 + */ +public class LeetCode_191_015 { + // you need to treat n as an unsigned value + public int hammingWeight(int n) { + int nums = 0; + while(n != 0) { + nums ++; + + n &= (n - 1); + } + + return nums; + } +} diff --git a/Week_07/G20200343030015/LeetCode_231_015.java b/Week_07/G20200343030015/LeetCode_231_015.java new file mode 100644 index 00000000..5b7ce05c --- /dev/null +++ b/Week_07/G20200343030015/LeetCode_231_015.java @@ -0,0 +1,14 @@ +package G20200343030015.week_07; + +/** + * Created by majiancheng on 2020/3/29. + * 231. 2的幂 + * 给定一个整数,编写一个函数来判断它是否是 2 的幂次方。 + */ +public class LeetCode_231_015 { + public boolean isPowerOfTwo(int n) { + if(n <= 0) return false; + + return (n & (n - 1)) == 0; + } +} diff --git a/Week_07/G20200343030015/LeetCode_242_015.java b/Week_07/G20200343030015/LeetCode_242_015.java new file mode 100644 index 00000000..1d3b7334 --- /dev/null +++ b/Week_07/G20200343030015/LeetCode_242_015.java @@ -0,0 +1,27 @@ +package G20200343030015.week_07; + +/** + * Created by majiancheng on 2020/3/29. + * + * 242. 有效的字母异位词 + * 给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。 + * + */ +public class LeetCode_242_015 { + public boolean isAnagram(String s, String t) { + if(s.length() != t.length()) return false; + int[] nums = new int[26]; + + char[] chars = s.toCharArray(); + for(char c : chars) { + nums[c - 'a'] ++; + } + chars = t.toCharArray(); + for(char c : chars) { + nums[c - 'a'] --; + if(nums[c - 'a'] < 0) return false; + } + + return true; + } +} diff --git a/Week_07/G20200343030015/LeetCode_246_015.java b/Week_07/G20200343030015/LeetCode_246_015.java new file mode 100644 index 00000000..bb131874 --- /dev/null +++ b/Week_07/G20200343030015/LeetCode_246_015.java @@ -0,0 +1,115 @@ +package G20200343030015.week_07; + +import java.util.HashMap; +import java.util.Map; + +/** + * Created by majiancheng on 2020/3/29. + *

+ * 146. LRU缓存机制 + * 运用你所掌握的数据结构,设计和实现一个  LRU (最近最少使用) 缓存机制。它应该支持以下操作: 获取数据 get 和 写入数据 put 。 + *

+ * 获取数据 get(key) - 如果密钥 (key) 存在于缓存中,则获取密钥的值(总是正数),否则返回 -1。 + * 写入数据 put(key, value) - 如果密钥不存在,则写入其数据值。当缓存容量达到上限时,它应该在写入新数据之前删除最久未使用的数据值,从而为新的数据值留出空间。 + *

+ * 进阶: + *

+ * 你是否可以在 O(1) 时间复杂度内完成这两种操作? + *

+ * 来源:力扣(LeetCode) + * 链接:https://leetcode-cn.com/problems/lru-cache + * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + */ +public class LeetCode_246_015 { + private Map map; + + private DoubleList doubleList; + + private Integer capacity; + public LeetCode_246_015(int capacity) { + this.map = new HashMap(); + this.doubleList = new DoubleList(); + this.capacity = capacity; + } + + public int get(int key) { + if(!map.containsKey(key)) { + return -1; + } + + int val = map.get(key).val; + put(key, val); + return val; + } + + public void put(int key, int value) { + //如果包含元素 + if(map.containsKey(key)) { + doubleList.remove(map.get(key)); + } else { + if(capacity == doubleList.size()) { + Node last = doubleList.removeLast(); + map.remove(last.key); + } + } + + Node node = new Node(key, value); + doubleList.addFirst(node); + map.put(key, node); + } + + + //双端队列 + class DoubleList { + private Node head, tail; + + private int size; + + public DoubleList() { + head = new Node(0, 0); + tail = new Node(0, 0); + head.next = tail; + tail.prev = head; + size = 0; + } + + public void addFirst(Node x) { + x.next = head.next; + x.prev = head; + head.next.prev = x; + head.next = x; + size ++; + } + + public void remove(Node x) { + x.prev.next = x.next; + x.next.prev = x.prev; + size --; + } + + public Node removeLast() { + if(head.next == tail) { + return null; + } + Node node = tail.prev; + this.remove(node); + + return node; + } + + public int size() { + return this.size; + } + + } + + //队列节点 + class Node { + public int key, val; + public Node next, prev; + public Node(int k, int v) { + this.key = k; + this.val = v; + } + } +} diff --git a/Week_07/G20200343030015/LeetCode_51_015.java b/Week_07/G20200343030015/LeetCode_51_015.java new file mode 100644 index 00000000..36755f15 --- /dev/null +++ b/Week_07/G20200343030015/LeetCode_51_015.java @@ -0,0 +1,68 @@ +package G20200343030015.week_07; + +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; + +/** + * Created by majiancheng on 2020/3/29. + * + * 51. N皇后 + */ +public class LeetCode_51_015 { + List> res = new ArrayList>(); + + int flag = 0; + + public List> solveNQueens(int n) { + if(n == 0) return res; + + flag = (flag << n) - 1; + Stack stack = new Stack(); + helper(stack, 0, 0, 0, n, 0); + + return res; + } + + public void helper(Stack stack, int col, int master, int slave, int n, int row) { + if(stack.size() == n) { + res.add(generQueen(stack)); + + return; + } + + for(int i = 0; i < n; i++) { + //判断是否没有冲突 + if(((col >> i) & 1) == 0 && ((master >> (row + i)) & 1) == 0 && ((slave >> (row - i + n - 1)) & 1) == 0) { + col ^= (1 << i); + master ^= (1 << (row + i)); + slave ^= (1 << (row - i + n - 1)); + + //处理当前层逻辑 + stack.push(i); + helper(stack, col, master, slave, n, row + 1); + + col ^= (1 << i); + master ^= (1 << (row + i)); + slave ^= (1 << (row - i + n - 1)); + stack.pop(); + } + } + + } + + public List generQueen(Stack stack) { + StringBuffer sb = new StringBuffer(); + for(int i=0; i result = new ArrayList(); + String queenStr = sb.toString(); + for(int index : stack) { + result.add(sb.substring(0, index) + "Q" + sb.substring(index + 1)); + } + + return result; + } +} diff --git a/Week_07/G20200343030015/LeetCode_52_015.java b/Week_07/G20200343030015/LeetCode_52_015.java new file mode 100644 index 00000000..3ec3106b --- /dev/null +++ b/Week_07/G20200343030015/LeetCode_52_015.java @@ -0,0 +1,33 @@ +package G20200343030015.week_07; + +/** + * Created by majiancheng on 2020/3/29. + * + * 52. N皇后 II + * + * n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。 + */ +public class LeetCode_52_015 { + int count = 0; + int size = 0; + public int totalNQueens(int n) { + size = (1 << n) - 1; + dfs(0, 0, 0); + + return count; + } + + public void dfs(int row, int master, int slave) { + if(row == size) { + count ++; + return; + } + + int bits = (size & (~(row | master | slave))); + while(bits > 0) { + int pick = bits & -bits; + dfs(row | pick, (master | pick) >> 1, (slave | pick) << 1); + bits = bits & (bits - 1); + } + } +} diff --git a/Week_07/G20200343030015/NOTE.md b/Week_07/G20200343030015/NOTE.md index 50de3041..b35ee30a 100644 --- a/Week_07/G20200343030015/NOTE.md +++ b/Week_07/G20200343030015/NOTE.md @@ -1 +1,12 @@ -学习笔记 \ No newline at end of file +学习笔记 + +位运算公式 + +获取最后一位 1 + num = num & - num + +去除最后一位 1 + num = num & (num - 1) + +获取制定位数的1 + size = (1 << n) - 1 diff --git a/Week_07/G20200343030017/lru_cache/LRUCache.java b/Week_07/G20200343030017/lru_cache/LRUCache.java new file mode 100644 index 00000000..73a40689 --- /dev/null +++ b/Week_07/G20200343030017/lru_cache/LRUCache.java @@ -0,0 +1,25 @@ +package week7.lru_cache; + +import java.util.LinkedHashMap; +import java.util.Map; + +public class LRUCache extends LinkedHashMap{ + int capacity; + public LRUCache(int capacity) { + super(capacity,0.75F,true); + this.capacity = capacity; + } + + @Override + protected boolean removeEldestEntry(Map.Entry eldest) { + return size()>capacity; + } + + public int get(int key) { + return super.getOrDefault(key,-1); + } + + public void put(int key, int value) { + super.put(key,value); + } +} diff --git a/Week_07/G20200343030017/merge_intervals/Solution.java b/Week_07/G20200343030017/merge_intervals/Solution.java new file mode 100644 index 00000000..9df257f4 --- /dev/null +++ b/Week_07/G20200343030017/merge_intervals/Solution.java @@ -0,0 +1,50 @@ +package week7.merge_intervals; + +import java.util.*; + +public class Solution { + public int[][] merge(int[][] intervals) { + if (intervals.length==0){ + return new int[][]{}; + } + TreeMap map = new TreeMap<>(Comparator.naturalOrder()); + for (int n=0;nmap.get(intervals[n][0])[1]){ + map.put(intervals[n][0],intervals[n]); + } + }else{ + map.put(intervals[n][0],intervals[n]); + } + } + LinkedList list = new LinkedList<>(); + for (Integer key:map.keySet()){ + list.addLast(map.get(key)); + } + list.stream().forEach(p-> System.out.println(Arrays.toString(p))); + int t =0; + while (t+1=list.get(t+1)[0] && list.get(t)[1]=list.get(t+1)[1]){ + list.remove(t+1); + }else{ + t++; + } + } + int[][] target = new int[list.size()][2]; + for (int n=0;n0 && (a==0); + } +} diff --git a/Week_07/G20200343030017/relative_sort_array/Solution.java b/Week_07/G20200343030017/relative_sort_array/Solution.java new file mode 100644 index 00000000..daa42606 --- /dev/null +++ b/Week_07/G20200343030017/relative_sort_array/Solution.java @@ -0,0 +1,37 @@ +package week7.relative_sort_array; + +import java.util.Arrays; + +public class Solution { + public int[] relativeSortArray(int[] arr1, int[] arr2) { + int[] temp = new int[1000]; + for (int n=0;n0){ + arr1[len-1+len1]=n; + temp[n]--; + len1++; + } + } + return arr1; + } + + public static void main(String[] args) { + int[] arr1 = {2,3,1,3,2,4,6,7,9,2,19}; + int[] arr2 = {2,1,4,3,9,6}; + Solution s = new Solution(); + int[] aaa = s.relativeSortArray(arr1,arr2); + System.out.println(Arrays.toString(aaa)); + } +} diff --git a/Week_07/G20200343030017/reverse_bits/Solution.java b/Week_07/G20200343030017/reverse_bits/Solution.java new file mode 100644 index 00000000..b62f54ef --- /dev/null +++ b/Week_07/G20200343030017/reverse_bits/Solution.java @@ -0,0 +1,12 @@ +package week7.reverse_bits; + +public class Solution { + public int reverseBits(int n) { + n = ((n & 0xAAAAAAAA) >>> 1) | ((n & 0x55555555) << 1); + n = ((n & 0xCCCCCCCC) >>> 2) | ((n & 0x33333333) << 2); + n = ((n & 0xF0F0F0F0) >>> 4) | ((n & 0x0F0F0F0F) << 4); + n = ((n & 0xFF00FF00) >>> 8) | ((n & 0x00FF00FF) << 8); + n = ((n & 0xFFFF0000) >>> 16) | ((n & 0x0000FFFF) << 16); + return n; + } +} diff --git a/Week_07/G20200343030017/reverse_pairs/Solution.java b/Week_07/G20200343030017/reverse_pairs/Solution.java new file mode 100644 index 00000000..92087798 --- /dev/null +++ b/Week_07/G20200343030017/reverse_pairs/Solution.java @@ -0,0 +1,45 @@ +package week7.reverse_pairs; + +public class Solution { + public int reversePairs(int[] nums) { + int n = 0; + if (nums.length==0) return 0; + long[] nums2 = new long[nums.length]; + for (int z=0;z> 1) + (nums[i] & 1)) > nums[j]) j++; + n += (j - (mid + 1)); + } + merge(nums,left,mid,right); + return n; + } + + public void merge(long[] nums,int left,int mid,int right){ + int i = left; + int j = mid+1; + int k = 0; + long[] temp = new long[right - left + 1]; + while (i <= mid && j <= right) { + temp[k++] = (nums[i] <= nums[j]) ? nums[i++] : nums[j++]; + } + while (i <= mid) temp[k++] = nums[i++]; + while (j <= right) temp[k++] = nums[j++]; + System.arraycopy(temp, 0, nums, left, k); + } + + public static void main(String[] args) { + int[] nums = {1,3,2,3,1}; + Solution s = new Solution(); + System.out.println(s.reversePairs(nums)); + } +} diff --git a/Week_07/G20200343030017/valid_anagram/Solution.java b/Week_07/G20200343030017/valid_anagram/Solution.java new file mode 100644 index 00000000..9720180a --- /dev/null +++ b/Week_07/G20200343030017/valid_anagram/Solution.java @@ -0,0 +1,28 @@ +package week7.valid_anagram; + +import java.util.Arrays; + +public class Solution { + public boolean isAnagram(String s, String t) { + if (s.length() != t.length()) {return false;} + int [] ss = new int[27]; + int [] tt = new int[27]; + for (int n=0;n 0; arr[i] --){ + arr1[index ++] = i; + } + } + for(int i = 0; i < 1001; i ++) { + if (arr[i] > 0) + for (; arr[i] > 0; arr[i] --) { + arr1[index ++] = i; + } + } + return arr1; + } +} \ No newline at end of file diff --git a/Week_07/G20200343030019/LeetCode_190_019.java b/Week_07/G20200343030019/LeetCode_190_019.java new file mode 100644 index 00000000..cf798f9d --- /dev/null +++ b/Week_07/G20200343030019/LeetCode_190_019.java @@ -0,0 +1,15 @@ +public class Solution { + // you need treat n as an unsigned value + public int reverseBits(int n) { + int out = 0; + int index = 32; + while (index-- != 0) { + out = out << 1; + if ((n & 1) == 1) { + out++; + } + n = n >> 1; + } + return out; + } +} \ No newline at end of file diff --git a/Week_07/G20200343030019/LeetCode_191_019.java b/Week_07/G20200343030019/LeetCode_191_019.java new file mode 100644 index 00000000..4ce5cc34 --- /dev/null +++ b/Week_07/G20200343030019/LeetCode_191_019.java @@ -0,0 +1,11 @@ +public class Solution { + // you need to treat n as an unsigned value + public int hammingWeight(int n) { + int sum = 0; + while (n != 0) { + n = n & n - 1; + sum ++; + } + return sum; + } +} \ No newline at end of file diff --git a/Week_07/G20200343030019/LeetCode_231_019.java b/Week_07/G20200343030019/LeetCode_231_019.java new file mode 100644 index 00000000..0a84143c --- /dev/null +++ b/Week_07/G20200343030019/LeetCode_231_019.java @@ -0,0 +1,6 @@ +class Solution { + public boolean isPowerOfTwo(int n) { + if (n <= 0) return false; + return (n & n - 1) == 0; + } +} \ No newline at end of file diff --git a/Week_07/G20200343030019/LeetCode_242_019.java b/Week_07/G20200343030019/LeetCode_242_019.java new file mode 100644 index 00000000..483892cb --- /dev/null +++ b/Week_07/G20200343030019/LeetCode_242_019.java @@ -0,0 +1,15 @@ +class Solution { + public boolean isAnagram(String s, String t) { + int[] arr = new int[256]; + for (char c: s.toCharArray()) { + arr[c] ++; + } + for (char c: t.toCharArray()) { + arr[c] --; + } + for (int i: arr) { + if (i != 0) return false; + } + return true; + } +} \ No newline at end of file diff --git a/Week_07/G20200343030021/LeetCode_146_021.java b/Week_07/G20200343030021/LeetCode_146_021.java new file mode 100644 index 00000000..bfdf3643 --- /dev/null +++ b/Week_07/G20200343030021/LeetCode_146_021.java @@ -0,0 +1,91 @@ +package lrucache; + +//运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制。它应该支持以下操作: 获取数据 get 和 写入数据 put 。 +// +// 获取数据 get(key) - 如果密钥 (key) 存在于缓存中,则获取密钥的值(总是正数),否则返回 -1。 +//写入数据 put(key, value) - 如果密钥不存在,则写入其数据值。当缓存容量达到上限时,它应该在写入新数据之前删除最久未使用的数据值,从而为新的 +//数据值留出空间。 +// +// 进阶: +// +// 你是否可以在 O(1) 时间复杂度内完成这两种操作? +// +// 示例: +// +// LRUCache cache = new LRUCache( 2 /* 缓存容量 */ ); +// +//cache.put(1, 1); +//cache.put(2, 2); +//cache.get(1); // 返回 1 +//cache.put(3, 3); // 该操作会使得密钥 2 作废 +//cache.get(2); // 返回 -1 (未找到) +//cache.put(4, 4); // 该操作会使得密钥 1 作废 +//cache.get(1); // 返回 -1 (未找到) +//cache.get(3); // 返回 3 +//cache.get(4); // 返回 4 +// +// Related Topics 设计 + + +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * 146.lru-cache + * LRU缓存机制 + * 使用有序字典数据结构 java中 LinkedHashMap Python中 OrderedDict + */ +public class LruCache { + public static void main(String[] args) { + LruCache solution = new LruCache(); + } + + //leetcode submit region begin(Prohibit modification and deletion) + static class LRUCache extends LinkedHashMap { + private int capacity; + + public LRUCache(int capacity) { + /** + * super可以用来引用直接父类的实例变量。 + * super可以用来调用直接父类方法。 + * super()可以用于调用直接父类构造函数。 + * //原文出自【易百教程】,商业转载请联系作者获得授权,非商业请保留原文链接:https://www.yiibai.com/java/super-keyword.html + * super(capacity, 0.75F, true); LinkedHashMap(int initialCapacityfloat loadFactor, boolean accessOrder) 使用指定的初始容量,负载因子和accessOrder构造一个空的LinkedHashMap实例。 + * int initialCapacity, 初始容量 + * float loadFactor, 负载因子 + * boolean accessOrder true:表示希望根据访问顺序(而不是插入顺序)遍历条目。false:插入顺序 + * */ + super(capacity, 0.75F, true); + this.capacity = capacity; + } + + public int get(int key) { +// getOrDefault 取到返回,否则返回默认值 + return super.getOrDefault(key, -1); + } + + public void put(int key, int value) { + super.put(key, value); + } + + /** + * removeEldestEntry() 通过覆盖这个方法,加入一定的条件,满足条件返回true。当put进新的值方法返回true时,便移除该map中最老的键和值。 + * @param eldest + * @return + */ + @Override + protected boolean removeEldestEntry(Map.Entry eldest) { + return size() > capacity; + } + } + +/** + * LRUCache 对象会以如下语句构造和调用: + * Your LRUCache object will be instantiated and called as such: + * LRUCache obj = new LRUCache(capacity); + * int param_1 = obj.get(key); + * obj.put(key,value); + */ +//leetcode submit region end(Prohibit modification and deletion) + +} \ No newline at end of file diff --git a/Week_07/G20200343030021/LeetCode_242_021.java b/Week_07/G20200343030021/LeetCode_242_021.java new file mode 100644 index 00000000..2bbb0366 --- /dev/null +++ b/Week_07/G20200343030021/LeetCode_242_021.java @@ -0,0 +1,60 @@ +package recursion; + +import java.util.ArrayList; +import java.util.List; + +public class isAnagram { + + public boolean isAnagram(String s, String t) { + if (s.length() != t.length()) { + return false; + } + char[] chars = s.toCharArray(); + char[] chars2 = t.toCharArray(); + + Arrays.sort(chars); + Arrays.sort(chars2); + + return Arrays.equals(chars, chars2); + } + + public boolean isAnagram2(String s, String t) { + if (s.length() != t.length()) { + return false; + } + int[] count = new int[26]; + + for (int i = 0; i < s.length(); i++) { + count[s.charAt(i) - 'a']++; + count[t.charAt(i) - 'a']--; + } + + for (int co : count) { + if (co != 0) { + return false; + } + } + return true; + } + + public boolean isAnagram3(String s, String t) { + if (s.length() != t.length()) { + return false; + } + + + int[] count = new int[26]; + + for (int i = 0; i < s.length(); i++) { + count[s.charAt(i) - 'a']++; + } + + for (int i = 0; i < t.length(); i++) { + count[t.charAt(i) - 'a']--; + if (count[t.charAt(i) - 'a'] < 0) { + return false; + } + } + return true; + } +} diff --git a/Week_07/G20200343030025/LeetCode_1_025.java b/Week_07/G20200343030025/LeetCode_1_025.java new file mode 100644 index 00000000..77bb9405 --- /dev/null +++ b/Week_07/G20200343030025/LeetCode_1_025.java @@ -0,0 +1,140 @@ +/** + * 146. LRU缓存机制 + * 难度 + * 中等 + *

+ * 467 + *

+ * 收藏 + *

+ * 分享 + * 切换为英文 + * 关注 + * 反馈 + * 运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制。它应该支持以下操作: 获取数据 get 和 写入数据 put 。 + *

+ * 获取数据 get(key) - 如果密钥 (key) 存在于缓存中,则获取密钥的值(总是正数),否则返回 -1。 + * 写入数据 put(key, value) - 如果密钥不存在,则写入其数据值。当缓存容量达到上限时,它应该在写入新数据之前删除最久未使用的数据值,从而为新的数据值留出空间。 + *

+ * 进阶: + *

+ * 你是否可以在 O(1) 时间复杂度内完成这两种操作? + *

+ * 示例: + *

+ * LRUCache cache = new LRUCache(2); 缓存容量 + *

+ * cache.put(1,1); + * cache.put(2,2); + * cache.get(1); // 返回 1 + * cache.put(3,3); // 该操作会使得密钥 2 作废 + * cache.get(2); // 返回 -1 (未找到) + * cache.put(4,4); // 该操作会使得密钥 1 作废 + * cache.get(1); // 返回 -1 (未找到) + * cache.get(3); // 返回 3 + * cache.get(4); // 返回 4 + */ +public class LeetCode_1_025 { + + class DLinkedNode { + int key; + int value; + DLinkedNode prev; + DLinkedNode next; + } + + private void addNode(DLinkedNode node) { + /** + * Always add the new node right after head. + */ + node.prev = head; + node.next = head.next; + + head.next.prev = node; + head.next = node; + } + + private void removeNode(DLinkedNode node){ + /** + * Remove an existing node from the linked list. + */ + DLinkedNode prev = node.prev; + DLinkedNode next = node.next; + + prev.next = next; + next.prev = prev; + } + + private void moveToHead(DLinkedNode node){ + /** + * Move certain node in between to the head. + */ + removeNode(node); + addNode(node); + } + + private DLinkedNode popTail() { + /** + * Pop the current tail. + */ + DLinkedNode res = tail.prev; + removeNode(res); + return res; + } + + private Hashtable cache = + new Hashtable(); + private int size; + private int capacity; + private DLinkedNode head, tail; + + public LRUCache(int capacity) { + this.size = 0; + this.capacity = capacity; + + head = new DLinkedNode(); + // head.prev = null; + + tail = new DLinkedNode(); + // tail.next = null; + + head.next = tail; + tail.prev = head; + } + + public int get(int key) { + DLinkedNode node = cache.get(key); + if (node == null) return -1; + + // move the accessed node to the head; + moveToHead(node); + + return node.value; + } + + public void put(int key, int value) { + DLinkedNode node = cache.get(key); + + if(node == null) { + DLinkedNode newNode = new DLinkedNode(); + newNode.key = key; + newNode.value = value; + + cache.put(key, newNode); + addNode(newNode); + + ++size; + + if(size > capacity) { + // pop the tail + DLinkedNode tail = popTail(); + cache.remove(tail.key); + --size; + } + } else { + // update the value. + node.value = value; + moveToHead(node); + } + } +} \ No newline at end of file diff --git a/Week_07/G20200343030025/LeetCode_2_025.java b/Week_07/G20200343030025/LeetCode_2_025.java new file mode 100644 index 00000000..b17e24aa --- /dev/null +++ b/Week_07/G20200343030025/LeetCode_2_025.java @@ -0,0 +1,36 @@ +/** + * 56. 合并区间 + * 给出一个区间的集合,请合并所有重叠的区间。 + * + * 示例 1: + * + * 输入: [[1,3],[2,6],[8,10],[15,18]] + * 输出: [[1,6],[8,10],[15,18]] + * 解释: 区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6]. + * 示例 2: + * + * 输入: [[1,4],[4,5]] + * 输出: [[1,5]] + * 解释: 区间 [1,4] 和 [4,5] 可被视为重叠区间。 + */ +public class LeetCode_2_025 { + public int[][] merge(int[][] intervals) { + List res = new ArrayList<>(); + if (intervals == null || intervals.length == 0) { + return res.toArray(new int[0][]); + } + Arrays.sort(intervals, (a, b) -> a[0] - b[0]); + int i = 0; + while (i < intervals.length) { + int left = intervals[i][0]; + int right = intervals[i][1]; + while (i < intervals.length - 1 && intervals[i + 1][0] <= right) { + i++; + right = Math.max(right, intervals[i][1]); + } + res.add(new int[]{left, right}); + i++; + } + return res.toArray(new int[0][]); + } +} \ No newline at end of file diff --git a/Week_07/G20200343030029/LeetCode_2_029.java b/Week_07/G20200343030029/LeetCode_2_029.java new file mode 100644 index 00000000..54765e5c --- /dev/null +++ b/Week_07/G20200343030029/LeetCode_2_029.java @@ -0,0 +1,23 @@ +class LeetCode_2_029{ + public boolean isPowerOfTwo1(int n) { + if(n == 0) { + return 0; + } + + long x = (long) n; + + return (x & (x - 1)) == 0; + } + + public boolean isPowerOfTwo2(int n) { + if(n == 0) { + return false; + } + + while (n % 2 == 0) { + n = n / 2; + } + + return n == 1; + } +} diff --git a/Week_07/G20200343030029/LeetCode_7_029.java b/Week_07/G20200343030029/LeetCode_7_029.java new file mode 100644 index 00000000..1538c698 --- /dev/null +++ b/Week_07/G20200343030029/LeetCode_7_029.java @@ -0,0 +1,21 @@ +class LeetCode_7_029 extends LinkedHashMap{ + private int capacity; + + public LRUCache(int capacity) { + super(capacity, 0.75F, true); + this.capacity = capacity; + } + + public int get(int key) { + return super.getOrDefault(key, -1); + } + + public void put(int key, int value) { + super.put(key, value); + } + + @Override + protected boolean removeEldestEntry(Map.Entry eldest) { + return size() > capacity; + } +} \ No newline at end of file diff --git a/Week_07/G20200343030029/NOTE.md b/Week_07/G20200343030029/NOTE.md index 50de3041..c3aec585 100644 --- a/Week_07/G20200343030029/NOTE.md +++ b/Week_07/G20200343030029/NOTE.md @@ -1 +1,73 @@ -学习笔记 \ No newline at end of file +#排序方法整理 +*** +* 冒泡排序 + + * 比较相邻的元素。如果第一个比第二个大,就交换它们两个; + * 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对,这样在最后的元素应该会是最大的数; + * 针对所有的元素重复以上的步骤,除了最后一个; + * 重复 1 2 3步骤 + + ``` + public static int[] bubbleSort(int [] array) { + for(int i = 1; i < array.length; i++) { + for(int j = 0; j < array.length - i; j++) { + if(array[j] > array [j + 1]) { + int temp = array[j]; + array[j] = array[j + 1]; + array[j + 1] = temp; + } + } + } + return array; + } + ``` + +*** + +* 选择排序 + * 初始状态:无序区为R[1..n],有序区为空; + * 第i趟排序(i=1,2,3…n-1)开始时,当前有序区和无序区分别为R[1..i-1]和R(i..n)。该趟排序从当前无序区中-选出关键字最小的记录 R[k],将它与无序区的第1个记录R交换,使R[1..i]和R[i+1..n)分别变为记录个数增加1个的新有序区和记录个数减少1个的新无序区; + * n-1趟结束,数组有序化了。 + + ``` + public static int[] selectionSort(int[] array) { + for(int i = 0; i < array.length; i++) { + int minIndex = i; + for(int j = i; j < array.length - 1; j++) { + if(array[j] > array[j + 1]) { + minIndex = j + 1; + } + } + int temp = array[i]; + array[i] = array[minIndex]; + array[minIndex] = temp; + } + return array; + } + ``` + + *** + + * 插入排序 + * 从第一个元素开始,该元素可以认为已经被排序; + * 取出下一个元素,在已经排序的元素序列中从后向前扫描; + * 如果该元素(已排序)大于新元素,将该元素移到下一位置; + * 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置; + * 将新元素插入到该位置后; + * 重复步骤2~5。 + + ``` + public static int[] insertSort(int[] array) { + int preIndex, current; + for(int i = 1; i < array.length; i++) { + preIndex = i - 1; + current = array[i]; + while (preIndex >= 0 && array[preIndex] > current) { + array[preIndex + 1] = array[preIndex]; + preIndex--; + } + array[preIndex + 1] = current; + } + return array; + } +``` \ No newline at end of file diff --git a/Week_07/G20200343030035/LeetCode_191_035.py b/Week_07/G20200343030035/LeetCode_191_035.py new file mode 100644 index 00000000..20a58fdf --- /dev/null +++ b/Week_07/G20200343030035/LeetCode_191_035.py @@ -0,0 +1,18 @@ +''' +191. 位1的个数 +编写一个函数,输入是一个无符号整数,返回其二进制表达式中数字位数为 ‘1’ 的个数(也被称为汉明重量)。 + +提示: + +- 请注意,在某些语言(如 Java)中,没有无符号整数类型。在这种情况下,输入和输出都将被指定为有符号整数类型,并且不应影响您的实现,因为无论整数是有符号的还是无符号的,其内部的二进制表示形式都是相同的。 +- 在 Java 中,编译器使用二进制补码记法来表示有符号整数。因此,在上面的 示例 3 中,输入表示有符号整数 -3。 + +''' + +class Solution: + def hammingWeight(self, n: int) -> int: + res = 0 + while n: + res += 1 + n &= n - 1 + return res \ No newline at end of file diff --git a/Week_07/G20200343030035/LeetCode_231_035.py b/Week_07/G20200343030035/LeetCode_231_035.py new file mode 100644 index 00000000..7d443e99 --- /dev/null +++ b/Week_07/G20200343030035/LeetCode_231_035.py @@ -0,0 +1,18 @@ +''' +231. 2的幂 +给定一个整数,编写一个函数来判断它是否是 2 的幂次方。 + +''' + +class Solution: + def isPowerOfTwo(self, n: int) -> bool: + if n == 1: + return True + while n > 0: + if (n / 2) == 1: + return True + elif (n % 2) == 0: + n = n // 2 + else: + return False + return False \ No newline at end of file diff --git a/Week_07/G20200343030363/LeetCode_1122_363.java b/Week_07/G20200343030363/LeetCode_1122_363.java new file mode 100644 index 00000000..aeba69b0 --- /dev/null +++ b/Week_07/G20200343030363/LeetCode_1122_363.java @@ -0,0 +1,28 @@ +package cn.geek.week7; + +/** + * @author lemon + * @version 1.0.0 + * @Description TODO + * @createTime 2020年03月27日 21:19:00 + */ +public class LeetCode_1122_363 { + public int[] relativeSortArray(int[] arr1, int[] arr2) { + int[] bucket = new int[1001]; + for(int num:arr1){ + bucket[num]++; + } + int i = 0; + for(int num:arr2){ + while(bucket[num]-- > 0){ + arr1[i++] = num; + } + } + for(int j = 0; j < 1001; ++j){ + while(bucket[j]-- > 0){ + arr1[i++] = j; + } + } + return arr1; + } +} diff --git a/Week_07/G20200343030363/LeetCode_242_363.java b/Week_07/G20200343030363/LeetCode_242_363.java new file mode 100644 index 00000000..e77e5ea2 --- /dev/null +++ b/Week_07/G20200343030363/LeetCode_242_363.java @@ -0,0 +1,25 @@ +package cn.geek.week7; + +/** + * @author lemon + * @version 1.0.0 + * @Description TODO + * @createTime 2020年03月27日 21:18:00 + */ +public class LeetCode_242_363 { + public boolean isAnagram(String s, String t) { + int[] count = new int[26]; + for (char ch: s.toCharArray()) { + count[ch-'a']++; + } + for (char ch: t.toCharArray()) { + count[ch-'a']--; + } + for (int value : count) { + if (value != 0) { + return false; + } + } + return true; + } +} diff --git "a/Week_07/G20200343030369/190.\351\242\240\345\200\222\344\272\214\350\277\233\345\210\266\344\275\215.swift" "b/Week_07/G20200343030369/190.\351\242\240\345\200\222\344\272\214\350\277\233\345\210\266\344\275\215.swift" new file mode 100644 index 00000000..26c26d54 --- /dev/null +++ "b/Week_07/G20200343030369/190.\351\242\240\345\200\222\344\272\214\350\277\233\345\210\266\344\275\215.swift" @@ -0,0 +1,88 @@ +/* + * @lc app=leetcode.cn id=190 lang=swift + * + * [190] 颠倒二进制位 + * + * https://leetcode-cn.com/problems/reverse-bits/description/ + * + * algorithms + * Easy (54.74%) + * Likes: 143 + * Dislikes: 0 + * Total Accepted: 34.9K + * Total Submissions: 61.7K + * Testcase Example: '00000010100101000001111010011100' + * + * 颠倒给定的 32 位无符号整数的二进制位。 + * + * + * + * 示例 1: + * + * 输入: 00000010100101000001111010011100 + * 输出: 00111001011110000010100101000000 + * 解释: 输入的二进制串 00000010100101000001111010011100 表示无符号整数 43261596, + * ⁠ 因此返回 964176192,其二进制表示形式为 00111001011110000010100101000000。 + * + * 示例 2: + * + * 输入:11111111111111111111111111111101 + * 输出:10111111111111111111111111111111 + * 解释:输入的二进制串 11111111111111111111111111111101 表示无符号整数 4294967293, + * 因此返回 3221225471 其二进制表示形式为 10101111110010110010011101101001。 + * + * + * + * 提示: + * + * + * 请注意,在某些语言(如 + * Java)中,没有无符号整数类型。在这种情况下,输入和输出都将被指定为有符号整数类型,并且不应影响您的实现,因为无论整数是有符号的还是无符号的,其内部的二进制表示形式都是相同的。 + * 在 Java 中,编译器使用二进制补码记法来表示有符号整数。因此,在上面的 示例 2 中,输入表示有符号整数 -3,输出表示有符号整数 + * -1073741825。 + * + * + * + * + * 进阶: + * 如果多次调用这个函数,你将如何优化你的算法? + * + */ + +// @lc code=start +class Solution { + func reverseBits(_ n: Int) -> Int { + + } + + func reverseBitsNormal(_ n: Int) -> Int { + var n = UInt32(n), reversed = UInt32(0) + for _ in 0..<32 { + reversed = reversed * 2 + n % 2 + n /= 2 + } + return Int(reversed) + } + + func reverseBitsBits(_ n: Int) -> Int { + var n = UInt32(n), ans = UInt32(0), bitSize = 31 + while n != 0 { + ans += (n & 1) << bitSize + bitSize -= 1 + n >>= 1 + } + return Int(ans) + } + + func reverseBitsBitsOptimal(_ n: Int) -> Int { + var result = 0 + var vn = n + for i in 0...31 { + result += (vn & 1) << (31 - i) + vn >>= 1 + } + return result + } +} +// @lc code=end + diff --git "a/Week_07/G20200343030369/191.\344\275\215-1-\347\232\204\344\270\252\346\225\260.swift" "b/Week_07/G20200343030369/191.\344\275\215-1-\347\232\204\344\270\252\346\225\260.swift" new file mode 100644 index 00000000..0b61cd91 --- /dev/null +++ "b/Week_07/G20200343030369/191.\344\275\215-1-\347\232\204\344\270\252\346\225\260.swift" @@ -0,0 +1,93 @@ +/* + * @lc app=leetcode.cn id=191 lang=swift + * + * [191] 位1的个数 + * + * https://leetcode-cn.com/problems/number-of-1-bits/description/ + * + * algorithms + * Easy (64.17%) + * Likes: 148 + * Dislikes: 0 + * Total Accepted: 53.4K + * Total Submissions: 81.3K + * Testcase Example: '00000000000000000000000000001011' + * + * 编写一个函数,输入是一个无符号整数,返回其二进制表达式中数字位数为 ‘1’ 的个数(也被称为汉明重量)。 + * + * + * + * 示例 1: + * + * 输入:00000000000000000000000000001011 + * 输出:3 + * 解释:输入的二进制串 00000000000000000000000000001011 中,共有三位为 '1'。 + * + * + * 示例 2: + * + * 输入:00000000000000000000000010000000 + * 输出:1 + * 解释:输入的二进制串 00000000000000000000000010000000 中,共有一位为 '1'。 + * + * + * 示例 3: + * + * 输入:11111111111111111111111111111101 + * 输出:31 + * 解释:输入的二进制串 11111111111111111111111111111101 中,共有 31 位为 '1'。 + * + * + * + * 提示: + * + * + * 请注意,在某些语言(如 + * Java)中,没有无符号整数类型。在这种情况下,输入和输出都将被指定为有符号整数类型,并且不应影响您的实现,因为无论整数是有符号的还是无符号的,其内部的二进制表示形式都是相同的。 + * 在 Java 中,编译器使用二进制补码记法来表示有符号整数。因此,在上面的 示例 3 中,输入表示有符号整数 -3。 + * + * + * + * + * 进阶: + * 如果多次调用这个函数,你将如何优化你的算法? + * + */ + +// @lc code=start +class Solution { + func hammingWeight(_ n: Int) -> Int { + + } + + func hammingWeightBits(_ n: Int) -> Int { + var cnt = 0, mask = 1 + for _ in 0..<32 { + if n & mask != 0 { + cnt += 1 + } + mask <<= 1 + } + return cnt + } + + func hammingWeightBitsOptimal(_ n: Int) -> Int { + var cnt = 0, n = n + while n != 0 { + cnt += 1 + n &= n - 1 + } + return cnt + } + + func hammingWeightBitsOptimal2(_ n: Int) -> Int { + var bits = 0, n = n + while n != 0 { + bits += n & 1 + n >>= 1 + } + return bits + } +} +// @lc code=end + diff --git "a/Week_07/G20200343030369/231.2-\347\232\204\345\271\202.swift" "b/Week_07/G20200343030369/231.2-\347\232\204\345\271\202.swift" new file mode 100644 index 00000000..ba55bf4a --- /dev/null +++ "b/Week_07/G20200343030369/231.2-\347\232\204\345\271\202.swift" @@ -0,0 +1,70 @@ +/* + * @lc app=leetcode.cn id=231 lang=swift + * + * [231] 2的幂 + * + * https://leetcode-cn.com/problems/power-of-two/description/ + * + * algorithms + * Easy (47.53%) + * Likes: 175 + * Dislikes: 0 + * Total Accepted: 51.7K + * Total Submissions: 108K + * Testcase Example: '1' + * + * 给定一个整数,编写一个函数来判断它是否是 2 的幂次方。 + * + * 示例 1: + * + * 输入: 1 + * 输出: true + * 解释: 2^0 = 1 + * + * 示例 2: + * + * 输入: 16 + * 输出: true + * 解释: 2^4 = 16 + * + * 示例 3: + * + * 输入: 218 + * 输出: false + * + */ + +// @lc code=start +class Solution { + func isPowerOfTwo(_ n: Int) -> Bool { + + } + + func isPowerOfTwoNormal(_ n: Int) -> Bool { + guard n != 0 else {return false} + var n = n + while n % 2 == 0 { + n /= 2 + } + return n == 1 + } + + // -n = ~n+1 + // n & -n 表示获取 n 最右边的 1 + // 如果 n 是 2 的幂,那 n 中只有一位的 1 + // 则 n & (-n) 取最右边一位后应该跟 n 相等,这样才是 2 的幂 + func isPowerOfTwoBits(_ n: Int) -> Bool { + guard n != 0 else {return false} + let n = Int64(n) + return n & (-n) == n + } + + func isPowerOfTwoBits2(_ n: Int) -> Bool { + guard n != 0 else {return false} + let n = Int64(n) + return n & (n-1) == 0 + } + +} +// @lc code=end + diff --git a/Week_07/G20200343030373/LeetCode_191_373/LeetCode_191_373_test.go b/Week_07/G20200343030373/LeetCode_191_373/LeetCode_191_373_test.go new file mode 100644 index 00000000..3bb07f0f --- /dev/null +++ b/Week_07/G20200343030373/LeetCode_191_373/LeetCode_191_373_test.go @@ -0,0 +1,40 @@ +//https://leetcode-cn.com/problems/number-of-1-bits/ + +package bitwise_test + +import ( + "github.com/stretchr/testify/assert" + "testing" +) + +func TestBitwise(t *testing.T) { + assert.Equal(t, 1, hammingWeight(8)) + assert.Equal(t, 1, hammingWeightBad(8)) + assert.Equal(t, 1, hammingWeightGood(8)) +} + +func hammingWeight(num uint32) int { + return hammingWeightGood(num) +} + +//对于8而言,仅循环1次 +func hammingWeightGood(num uint32) int { + count := 0 + for num != 0 { + num = num & (num - 1) + count++ + } + return count +} + +//对于8而言,循环4次 +func hammingWeightBad(num uint32) int { + count := 0 + for num != 0 { + if num&1 == 1 { + count++ + } + num >>= 1 + } + return count +} diff --git a/Week_07/G20200343030373/LeetCode_231_373/LeetCode_231_373_test.go b/Week_07/G20200343030373/LeetCode_231_373/LeetCode_231_373_test.go new file mode 100644 index 00000000..5f88d2a5 --- /dev/null +++ b/Week_07/G20200343030373/LeetCode_231_373/LeetCode_231_373_test.go @@ -0,0 +1,17 @@ +//https://leetcode-cn.com/problems/power-of-two/ + +package bitwise_test + +import ( + "github.com/stretchr/testify/assert" + "testing" +) + +func TestBitwise(t *testing.T) { + assert.Equal(t, true, isPowerOfTwo(16)) + assert.Equal(t, false, isPowerOfTwo(9)) +} + +func isPowerOfTwo(n int) bool { + return n != 0 && n&(n-1) == 0 +} diff --git a/Week_07/G20200343030373/LeetCode_338_373/LeetCode_338_373_test.go b/Week_07/G20200343030373/LeetCode_338_373/LeetCode_338_373_test.go new file mode 100644 index 00000000..441765f5 --- /dev/null +++ b/Week_07/G20200343030373/LeetCode_338_373/LeetCode_338_373_test.go @@ -0,0 +1,20 @@ +//https://leetcode-cn.com/problems/counting-bits/ +package bitwise_test + +import ( + "github.com/stretchr/testify/assert" + "testing" +) + +func TestBitwise(t *testing.T) { + assert.Equal(t, []int{0, 1, 1}, countBits(2)) + assert.Equal(t, []int{0, 1, 1, 2, 1, 2}, countBits(5)) +} + +func countBits(num int) []int { + bits := make([]int, num+1) + for i := 1; i <= num; i++ { + bits[i] = bits[i&(i-1)] + 1 + } + return bits +} diff --git a/Week_07/G20200343030373/LeetCode_52_373/LeetCode_52_373_test.go b/Week_07/G20200343030373/LeetCode_52_373/LeetCode_52_373_test.go new file mode 100644 index 00000000..162a5f9f --- /dev/null +++ b/Week_07/G20200343030373/LeetCode_52_373/LeetCode_52_373_test.go @@ -0,0 +1,52 @@ +//https://leetcode-cn.com/problems/n-queens-ii/ + +package n_queens_2_test + +import ( + "github.com/stretchr/testify/assert" + "testing" +) + +func TestNQueens2(t *testing.T) { + t.Log("N-Queens 2: DFS Prune + Bitwise") + assert.Equal(t, 0, totalNQueens(0)) + assert.Equal(t, 2, totalNQueens(4)) +} + +//1. 递归终止条件:row行数扫描结束;则肯定找到了一个,需要加1 +//2. 得到空位:`bits := (^(col | pie | na)) & ((1<>1 +func totalNQueens(n int) int { + if n == 0 { + return 0 + } + + res := 0 + dfs(n, 0, 0, 0, 0, &res) + return res +} + +func dfs(n, row, col, pie, na int, res *int) { + if row >= n { + *res++ + return + } + + bits := (^(col | pie | na)) & ((1 << uint(n)) - 1) + for bits != 0 { + bit := bits & -bits + dfs(n, row+1, col|bit, (pie|bit)<<1, (na|bit)>>1, res) + bits = bits & (bits - 1) + } +} diff --git a/Week_07/G20200343030375/LeetCode_191_375.java b/Week_07/G20200343030375/LeetCode_191_375.java new file mode 100644 index 00000000..04ca5be5 --- /dev/null +++ b/Week_07/G20200343030375/LeetCode_191_375.java @@ -0,0 +1,15 @@ +package G20200343030375; + +public class LeetCode_191_375 { + public int hammingWeight(int n) { + int count = 0; + while(n != 0){ + n =n & (n-1); + count++; + } + return count; + } + public boolean isPowerOfTwo(int n) { + return (n>0) && (n&(n-1))==0; + } +} diff --git a/Week_07/G20200343030375/LeetCode_231_375.java b/Week_07/G20200343030375/LeetCode_231_375.java new file mode 100644 index 00000000..392ebb2a --- /dev/null +++ b/Week_07/G20200343030375/LeetCode_231_375.java @@ -0,0 +1,7 @@ +package G20200343030375; + +public class LeetCode_231_375 { + public boolean isPowerOfTwo(int n) { + return (n>0) && (n&(n-1))==0; + } +} diff --git a/Week_07/G20200343030377/LeetCode_146_377.java b/Week_07/G20200343030377/LeetCode_146_377.java new file mode 100644 index 00000000..2de52820 --- /dev/null +++ b/Week_07/G20200343030377/LeetCode_146_377.java @@ -0,0 +1,22 @@ +class LRUCache extends LinkedHashMap{ + + private int capacity; + + public LRUCache(int capacity) { + super(capacity, 0.75F, true); + this.capacity = capacity; + } + + public int get(int key) { + return super.getOrDefault(key, -1); + } + + public void put(int key, int value) { + super.put(key, value); + } + + @Override + protected boolean removeEldestEntry(Map.Entry eldest) { + return size() > capacity; + } +} diff --git a/Week_07/G20200343030377/Leetcode_493_377.java b/Week_07/G20200343030377/Leetcode_493_377.java new file mode 100644 index 00000000..0a46739d --- /dev/null +++ b/Week_07/G20200343030377/Leetcode_493_377.java @@ -0,0 +1,30 @@ +class Solution { + public int reversePairs(int[] nums) { + return mergeSort(nums, 0, nums.length-1); + } + private int mergeSort(int[] nums, int left, int right){ + if(left>=right) return 0; + int mid = left + (right-left)/2; + int cnt = mergeSort(nums, left, mid) + mergeSort(nums, mid+1, right); + + for(int i=left, j=mid+1; i<=mid; i++){ + while(j<=right && nums[i]/2.0 > nums[j]) j++; + cnt += j-(mid+1); + } + + merge(nums, left, mid, right); + return cnt; + } + private void merge(int[] nums, int left, int mid,int right){ + int[] temp = new int[right-left+1]; + int i = left, j=mid+1, k=0; + while(i<=mid && j<=right){ + temp[k++] = nums[i]<=nums[j]? nums[i++]:nums[j++]; + } + while(i<=mid) temp[k++] = nums[i++]; + while(j<=right) temp[k++] = nums[j++]; + for(int p=0; p0){ + arr1[count++]=n; + } + } + + //ʣûгarr2 + for (int i = 0; i < cnt.length; i++) { + while (cnt[i]-->0){ + arr1[count++]=i; + } + } + return arr1; + } + + +} diff --git a/Week_07/G20200343030379/LeetCode_146_379.java b/Week_07/G20200343030379/LeetCode_146_379.java new file mode 100644 index 00000000..16ff0492 --- /dev/null +++ b/Week_07/G20200343030379/LeetCode_146_379.java @@ -0,0 +1,201 @@ +package G20200343030379; + +import java.awt.*; +import java.rmi.RemoteException; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * 146. LRU + * + * յݽṹƺʵһ? LRU (ʹ) ơӦ֧² ȡ get д put + * + * ȡ get(key) - Կ (key) ڻУȡԿֵ򷵻 -1 + * д put(key, value) - ԿڣдֵﵽʱӦд֮ǰɾδʹõֵӶΪµֵռ䡣 + * + * : + * + * Ƿ?O(1) ʱ临Ӷֲ + * + * ʾ: + * + * LRUCache cache = new LRUCache( 2 ); + * + * cache.put(1,1); + * cache.put(2,2); + * cache.get(1); // 1 + * cache.put(3,3); // òʹԿ 2 + * cache.get(2); // -1 (δҵ) + * cache.put(4,4); // òʹԿ 1 + * cache.get(1); // -1 (δҵ) + * cache.get(3); // 3 + * cache.get(4); // 4 + * + * ԴۣLeetCode + * ӣhttps://leetcode-cn.com/problems/lru-cache + * ȨСҵתϵٷȨҵתע + * + * ο⣺https://leetcode-cn.com/problems/lru-cache/solution/lru-huan-cun-ji-zhi-by-leetcode/ + */ +public class LeetCode_146_379 { + + public static void main(String[] args) { + //ʮת + //String s = Integer.toBinaryString(-2147483648); + } + + /** + * ִʱ : 19 ms , Java ύл 90.06% û + * ڴ : 50.6 MB , Java ύл 89.88% û + */ + class LRUCache extends LinkedHashMap { + private int capacity; + + public LRUCache(int capacity) { + super(capacity,0.75f,true); + this.capacity=capacity; + } + + public int get(int key) { + return super.getOrDefault(key,-1); + } + + public void put(int key, int value) { + super.put(key,value); + } + + @Override + protected boolean removeEldestEntry(Map.Entry eldest) { + return size()>capacity; + } + } + + /** + * һַϣֻдͬ + * + * ִʱ : 23 ms , Java ύл 62.61% û + * ڴ : 50.7 MB , Java ύл 86.75% û + * ⣻https://leetcode.com/problems/lru-cache/discuss/46055/Probably-the-%22best%22-Java-solution-extend-LinkedHashMap + */ + class LRUCache3 { + private int capacity; + private Map map; + + public LRUCache3(int capacity) { + this.map=new LinkedHashMap(16,0.75f,true){ + @Override + protected boolean removeEldestEntry(Map.Entry eldest) { + return size()>capacity; + } + }; + this.capacity=capacity; + } + + public int get(int key) { + return map.getOrDefault(key,-1); + } + + public void put(int key, int value) { + map.put(key,value); + } + } + +/** + * Your LRUCache object will be instantiated and called as such: + * LRUCache obj = new LRUCache(capacity); + * int param_1 = obj.get(key); + * obj.put(key,value); + */ + + + class DoubleList{ + private Node head,tail; + private int size; + + DoubleList(){ + head=new Node(0,0); + tail=new Node(0,0); + head.next=tail; + tail.prev=head; + size=0; + } + + public void addFirst(Node x){ + x.next=head.next; + x.prev=head; + head.next.prev=x; + head.next=x; + size++; + } + + public void remove(Node x){ + x.prev.next=x.next; + x.next.prev=x.prev; + size--; + } + + public Node removeLast(){ + if(tail.prev==head) return null; + Node last = tail.prev; + remove(last); + return last; + } + + public int getSize() { + return size; + } +} + + class Node { + public int key,val; + public Node next,prev; + + Node(int k ,int v){ + this.key=k; + this.val=v; + } + + } + + /** + * Լһhashmap˫ + * ִʱ : 21 ms , Java ύл 71.79% û + * ڴ : 53.3 MB , Java ύл 71.50% û + */ + class LRUCache2{ + private HashMap map; + private DoubleList cache; + private int cap; + + LRUCache2(int capacity){ + this.cap=capacity; + cache=new DoubleList(); + map=new HashMap<>(); + } + + public int get(int key) { + if(map.containsKey(key)){ + Node node = map.get(key); + this.put(node.key,node.val); + return node.val; + } + return -1; + } + + public void put(int key, int value) { + Node node=new Node(key,value); + if(map.containsKey(key)){ + + cache.remove(map.get(key)); + }else{ + if(cap==cache.getSize()){ + Node last = cache.removeLast(); + map.remove(last.key); + } + } + cache.addFirst(node); + map.put(key,node); + } + } +} diff --git a/Week_07/G20200343030379/LeetCode_190_379.java b/Week_07/G20200343030379/LeetCode_190_379.java new file mode 100644 index 00000000..b0257029 --- /dev/null +++ b/Week_07/G20200343030379/LeetCode_190_379.java @@ -0,0 +1,83 @@ +package G20200343030379; + +/** + * 190. ߵλ + * + * ߵ 32 λ޷Ķλ + * + * ? + * + * ʾ 1 + * + * : 00000010100101000001111010011100 + * : 00111001011110000010100101000000 + * : Ķƴ 00000010100101000001111010011100 ʾ޷ 43261596 + * ˷ 964176192ƱʾʽΪ 00111001011110000010100101000000 + * ʾ 2 + * + * 룺11111111111111111111111111111101 + * 10111111111111111111111111111111 + * ͣĶƴ 11111111111111111111111111111101 ʾ޷ 4294967293 + * ? ˷ 3221225471 ƱʾʽΪ 10101111110010110010011101101001 + * ? + * + * ʾ + * + * ע⣬ijЩԣ JavaУû޷͡£ָΪзͣҲӦӰʵ֣ΪзŵĻ޷ŵģڲĶƱʾʽͬġ + * Java УʹöƲǷʾзˣ?ʾ 2?Уʾз -3ʾз -1073741825 + * + * ԴۣLeetCode + * ӣhttps://leetcode-cn.com/problems/reverse-bits + * ȨСҵתϵٷȨҵתע + * + * ο⣺ + */ +public class LeetCode_190_379 { + + public static void main(String[] args) { + //ʮת + //String s = Integer.toBinaryString(-2147483648); + new LeetCode_190_379().reverseBits(43261596); + } + + /** + * ִʱ : 1 ms , Java ύл 100.00% û + * ڴ : 37.9 MB , Java ύл 5.27% û + * ⣺https://leetcode-cn.com/problems/reverse-bits/solution/js-ban-shao-shao-xiu-gai-ji-ke-by-kimigao/ + * @param n + * @return + */ + public int reverseBits(int n) { + int ans=0; + for (int i = 0; i < 32; i++) { + // System.out.print("ans<<1===="+Integer.toBinaryString(ans<<1)+" ======ans "); + ans= (ans<<1) + (n&1); + // System.out.println(Integer.toBinaryString(ans)+" ======n&1 "+Integer.toBinaryString(n&1)+" ======n "+Integer.toBinaryString(n)); + n = n >>1; + } + //޷ƣ߲0߲0 + return ans >>>0; + + } + + /** + * ִʱ : 1 ms , Java ύл 100.00% û + * ڴ : 37.7 MB , Java ύл 5.27% û + * ⣺https://leetcode-cn.com/problems/reverse-bits/solution/shu-xue-si-xiang-by-lo_e-2/ + * @param n + * @return + */ + public int reverseBits2(int n) { + int reverse=0; + int i=0; + while(i<=31){ + reverse = reverse<<1; + reverse |= (n & 1); + n = n >> 1; + i++; + } + return reverse; + } + + +} diff --git a/Week_07/G20200343030379/LeetCode_191_379.java b/Week_07/G20200343030379/LeetCode_191_379.java new file mode 100644 index 00000000..3f8f7772 --- /dev/null +++ b/Week_07/G20200343030379/LeetCode_191_379.java @@ -0,0 +1,143 @@ +package G20200343030379; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; + +/** + * 191. λ1ĸ + * + * дһһ޷ƱʽλΪ 1?ĸҲΪ + * + * ? + * + * ʾ 1 + * + * 룺00000000000000000000000000001011 + * 3 + * ͣĶƴ 00000000000000000000000000001011?УλΪ '1' + * ʾ 2 + * + * 룺00000000000000000000000010000000 + * 1 + * ͣĶƴ 00000000000000000000000010000000?УһλΪ '1' + * ʾ 3 + * + * 룺11111111111111111111111111111101 + * 31 + * ͣĶƴ 11111111111111111111111111111101 У 31 λΪ '1' + * ? + * + * ʾ + * + * ע⣬ijЩԣ JavaУû޷͡£ָΪзͣҲӦӰʵ֣ΪзŵĻ޷ŵģڲĶƱʾʽͬġ + * Java УʹöƲǷʾзˣ?ʾ 3?Уʾз -3 + * ? + * + * : + * ε㽫Ż㷨 + * + * + * ԴۣLeetCode + * ӣhttps://leetcode-cn.com/problems/number-of-1-bits + * ȨСҵתϵٷȨҵתע + * + * //ⷨ + * 0תƣ + * 1뷨 + * 2&1 x = x >> 1 ; (32) + * 3whilex > 0 {count ++; x = x & (x - 1)} + * + * ο⣺ + * https://leetcode-cn.com/problems/number-of-1-bits/solution/man-hua-gan-jiu-dui-liao-ao-li-gei-by-ivan1-2/ + */ +public class LeetCode_191_379 { + + public static void main(String[] args) { + //ʮת + String s = Integer.toBinaryString(-3); + new LeetCode_191_379().hammingWeight3(-3); + } + + + // you need to treat n as an unsigned value + + /** + * + * ִʱ : 2 ms , Java ύл 7.84% û + * ڴ : 36.3 MB , Java ύл 5.58% û + * @param n + * @return + */ + public int hammingWeight0(int n) { + String s = Integer.toBinaryString(n); + int count=0; + for (int i = 0; i < s.length(); i++) { + if(s.charAt(i)=='1'){ + count++; + } + } + return count; + } + + + /** + * %2 == 1, /2 + * ִʱ : 1 ms , Java ύл 99.75% û + * ڴ : 36.5 MB , Java ύл 5.45% û + * @param n + * @return + */ + public int hammingWeight(int n) { + int count=0; + for (int i = 0; i < 32; i++) { + if((n&1)==1){ + count++; + } + //ĶƶǷ룬ҲǴ󲿷ֶ1while(n!=0) ж + n = n >> 1; + System.out.println(n); + } + return count; + } + + /** + * ִʱ : 1 ms , Java ύл 99.75% û + * ڴ : 36.4 MB , Java ύл 5.58% û + * @param n + * @return + */ + public int hammingWeight2(int n) { + int count=0; + int mask=1; + for (int i = 0; i < 32; i++) { + if((n&mask)!=0){ //DZȽʮƣǶ + count++; + } + //mask1һλ + mask = mask << 1; + //System.out.println(n); + } + return count; + } + + /** + * whilex > 0 {count ++; x = x & (x - 1)} + * ִʱ : 1 ms , Java ύл 99.75% û + * ڴ : 36.4 MB , Java ύл 5.45% û + * @param n + * @return + */ + public int hammingWeight3(int n) { + int count=0; + //ڸҪж + while(n!=0){ + n = n & (n-1); + count++; + } + return count; + } + + +} diff --git a/Week_07/G20200343030379/LeetCode_231_379.java b/Week_07/G20200343030379/LeetCode_231_379.java new file mode 100644 index 00000000..57f1eda1 --- /dev/null +++ b/Week_07/G20200343030379/LeetCode_231_379.java @@ -0,0 +1,63 @@ +package G20200343030379; + +/** + * 231. 2 + * + * һдһжǷ 2 ݴη + * + * ʾ?1: + * + * : 1 + * : true + * : 20?= 1 + * ʾ 2: + * + * : 16 + * : true + * : 24?= 16 + * ʾ 3: + * + * : 218 + * : false + * + * ԴۣLeetCode + * ӣhttps://leetcode-cn.com/problems/power-of-two + * ȨСҵתϵٷȨҵתע + * + * ο⣺ + */ +public class LeetCode_231_379 { + + public static void main(String[] args) { + //ʮת + String s = Integer.toBinaryString(-2147483648); + new LeetCode_231_379().isPowerOfTwo(-2147483648); + } + + /** + * x & x-1 λ2ݣֻλ1Ϳ֪Ƿݵֵ + * + * ִʱ : 1 ms , Java ύл 100.00%û + * ڴ : 37 MB , Java ύл 5.50% û + * @param n + * @return + */ + public boolean isPowerOfTwo(int n) { + long x = (int)n; + return x!=0 && (x & x-1)==0; + } + + /** + * x & (-x) õλ1:ֻλ1Իȡߵֵ˵ݵֵ + * ִʱ : 1 ms , Java ύл 100.00% û + * ڴ : 36.5 MB , Java ύл 5.50% û + * @param n + * @return + */ + public boolean isPowerOfTwo2(int n) { + long x = (int)n; + return x!=0 && (x & (-x))==x; + } + + +} diff --git a/Week_07/G20200343030379/LeetCode_493_379.java b/Week_07/G20200343030379/LeetCode_493_379.java new file mode 100644 index 00000000..b6d6623c --- /dev/null +++ b/Week_07/G20200343030379/LeetCode_493_379.java @@ -0,0 +1,110 @@ +package G20200343030379; + +import java.util.Arrays; + +/** + * 493. ת + * + * һ?nums??i < j??nums[i] > 2*nums[j]?Ǿͽ?(i, j)?һҪתԡ + * + * ҪظеҪתԵ + * + * ʾ 1: + * + * : [1,3,2,3,1] + * : 2 + * ʾ 2: + * + * : [2,4,3,5,1] + * : 3 + * ע: + * + * ijȲᳬ50000 + * еֶ32λıʾΧڡ + * + * ԴۣLeetCode + * ӣhttps://leetcode-cn.com/problems/reverse-pairs + * ȨСҵתϵٷȨҵתע + * + * ο⣺ + */ +public class LeetCode_493_379 { + + /** + * 鲢 + * + * ִʱ : 72 ms , Java ύл 45.87% û + * ڴ : 52.9 MB , Java ύл 16.67% û + * @param nums + * @return + */ + public int reversePairs(int[] nums) { + return merge2(nums,0,nums.length-1); + } + + /** + * 鲢 + * + * ִʱ : 72 ms , Java ύл 45.87% û + * ڴ : 52.9 MB , Java ύл 16.67% û + * @param nums + * @return + */ + public int reversePairs2(int[] nums) { + return merge2(nums,0,nums.length-1); + } + + private int merge2(int[] array, int left, int right) { + if(left>=right) return 0; + + int mid= (right + left) >>1; + int cnt=merge2(array,left,mid)+merge2(array,mid+1,right); + + for(int i=left,j=mid+1;i<=mid;i++){ + while (j<=right && array[i]/2.0 > array[j]) j++; + cnt+= j-(mid+1); + } + + //Arrays.sort(array,left,right+1); + merge(array,left,mid,right); + return cnt; + } + + public static void main(String[] args) { + /*int[] ints = new LeetCode_493_379().mergeSort(new int[]{3, 2, 34, 2}, 0, 3); + System.out.println(Arrays.toString(ints));*/ + int mid1= 2+ (2) >>1; + int mid2= 2+ (2) / 2; + System.out.println(mid1); + System.out.println(mid2); + } + + public int[] mergeSort(int[] array,int left,int right){ + if(right<=left) return array; + int mid=(left+right) >>1; + + mergeSort(array,left,mid); + mergeSort(array,mid+1,right); + return merge(array,left,mid,right); + } + + private int[] merge(int[] array, int left, int mid, int right) { + int[] temp=new int[right-left+1]; + int i = left ,j=mid+1,k=0; + + while(i<=mid && j<=right){ + temp[k++]=array[i] <=array[j] ? array[i++] :array[j++]; + } + + while (i<=mid) temp[k++] = array[i++]; + while (j<=right) temp[k++] = array[j++]; + + for (int p=0;p 2*nums[j]?Ǿͽ?(i, j)?һҪתԡ + * + * ҪظеҪתԵ + * + * ʾ 1: + * + * : [1,3,2,3,1] + * : 2 + * ʾ 2: + * + * : [2,4,3,5,1] + * : 3 + * ע: + * + * ijȲᳬ50000 + * еֶ32λıʾΧڡ + * + * ԴۣLeetCode + * ӣhttps://leetcode-cn.com/problems/reverse-pairs + * ȨСҵתϵٷȨҵתע + * + * ο⣺ʦƵվ + */ +public class LeetCode_493_379_2 { + + public static void main(String[] args) { + new LeetCode_493_379_2().reversePairs(new int[]{2147483647,2147483647,-2147483647,-2147483647,-2147483647,2147483647}); + } + + /** + * ù鲢 + * ִʱ : 88 ms , Java ύл 28.35% û + * ڴ : 49.1 MB , Java ύл 94.44% û + * @param nums + * @return + */ + public int reversePairs(int[] nums) { + return mergeSort(nums,0,nums.length-1); + } + + /** + * https://u.geekbang.org/lesson/10?article=212223 + * ʦ 17:50 ʼ + * ʱ临Ӷȣarrays.sort*ͳ n(logN) * logN + * ʱ临Ӷȣ鲢*ͳ O(N) * logN + * @param nums + * @param left + * @param right + * @return + */ + private int mergeSort(int[] nums, int left, int right) { + if(left>=right) return 0; + int mid=(left+right)/2; + + int cnt=mergeSort(nums,left,mid)+mergeSort(nums,mid+1,right); + + for(int i=left,j=mid+1;i<=mid;i++){ + while(j<=right && nums[i]/2.0>nums[j]){ + j++; + } + cnt+=j-(mid+1); + } + + //ʱ临Ӷ nlogn + Arrays.sort(nums,left,right+1); + + //ǹ鲢 O(N) + return cnt; + } + + + + /*private int mergeSort(int[] nums, int left, int right) { + if(left>=right)return 0; + int mid=(left+right)/2; + //System.out.println(Arrays.toString(nums)+"=========left:"+left+"=====mid:"+mid+"======right="+right+"===="); + int cnt=mergeSort(nums,left,mid)+mergeSort(nums,mid+1,right); + + for(int i=left,j=mid+1;i<=mid;i++){ + while (j<=right && nums[i]/2.0>nums[j]){ + j++; + } + cnt+=j-(mid+1); + } + + Arrays.sort(nums,left,right+1); + //System.out.println(""+Arrays.toString(nums)+"=========left:"+left+"=====mid:"+mid+"======right="+right+"===="); + return cnt; + }*/ + + + + /* private int mergeSort(int[] nums, int left, int right) { + if(left>=right) return 0; + int mid=(right+left)/2; + System.out.println(Arrays.toString(nums)+"=========left:"+left+"=====mid:"+mid+"======right="+right+"===="); + int cnt=mergeSort(nums,left,mid) +mergeSort(nums,mid+1,right); + + for (int i=left,j=mid+1;i<=mid;i++){ + while (j<=right && nums[i]/2.0 > nums[j]) { + j++; + } + cnt+=j-(mid+1); + } + Arrays.sort(nums,left,right+1); + System.out.println(""+Arrays.toString(nums)+"=========left:"+left+"=====mid:"+mid+"======right="+right+"===="); + return cnt; + }*/ + + +} diff --git a/Week_07/G20200343030379/LeetCode_493_379_3.java b/Week_07/G20200343030379/LeetCode_493_379_3.java new file mode 100644 index 00000000..2f3893d6 --- /dev/null +++ b/Week_07/G20200343030379/LeetCode_493_379_3.java @@ -0,0 +1,57 @@ +package G20200343030379; + +import com.sun.org.apache.regexp.internal.RE; + +import java.util.Arrays; + +/** + * 鲢ϰ + * + * + * ο⣺ʦƵվ + */ +public class LeetCode_493_379_3 { + + + public static void main(String[] args) { + int[] aaa=new int[]{44,33,3, 2, 34,33, 2}; + int[] ints = new LeetCode_493_379_3().mergeSort(aaa, 0, aaa.length-1); + System.out.println(Arrays.toString(ints)); + } + + /** + * 鲢 + */ + + private int[] mergeSort(int[] nums, int left, int right) { + if(right<=left) return nums; + + int mid =(left+right)/2; + + mergeSort(nums,left,mid); + mergeSort(nums,mid+1,right); + + merger(nums,left,mid,right); + + return nums; + } + + private void merger(int[] arr, int left, int mid, int right) { + int[] temp=new int[right-left+1]; + int i=left,j=mid+1,k=0; + + while (i<=mid && j<=right){ + temp[k++]=arr[i]<=arr[j]?arr[i++]:arr[j++]; + } + + while (i<=mid) temp[k++]=arr[i++]; + while (j<=right) temp[k++]=arr[j++]; + + for (int p=0;p> solveNQueens(int n) { + List> res=new ArrayList<>(); + if(n==0) return res; + + char board[][]=new char[n][n]; + + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + board[i][j]='.'; + } + } + dfs(board,res,new ArrayList<>(),new ArrayList<>(),new ArrayList<>(),0); + return res; + } + + private void dfs(char[][] board, List> res + , List colList + ,List na + ,List pie, int row) { + int n = board.length; + //˳ + if(row==n){ + res.add(constans(board)); + return; + } + + for (int col = 0; col < n; col++) { + if(na.contains(row+col)) continue; + if(pie.contains(row-col)) continue; + if(colList.contains(col)) continue; + + //ѡ + board[row][col]='Q'; + colList.add(col); + na.add(row+col); + pie.add(row-col); + + //ݹ + dfs(board,res,colList,na,pie,row+1); + + // + board[row][col]='.'; + colList.remove(row); + na.remove(row); + pie.remove(row); + } + } + + private boolean validate(char[][] board,int row,int col) { + //鵱 + for (int i = 0; i < row; i++) { + if(board[i][col]=='Q'){ + return false; + } + } + + //Ͻ + for(int i=row-1,j=col-1;i>=0 && j>=0;i--,j--){ + if(board[i][j]=='Q'){ + return false; + } + } + + //Ͻ + for(int i=row-1,j=col+1;i>=0 && j constans(char[][] board) { + List res=new ArrayList<>(); + for (int row = 0; row < board.length; row++) { + String sb=new String(board[row]); + res.add(sb); + } + return res; + } + + /* + ʱ临Ӷȶ࣬ʹ + private List constans(char[][] board) { + List res=new ArrayList<>(); + for (int row = 0; row < board.length; row++) { + StringBuilder sb=new StringBuilder(); + for (int j = 0; j < board.length; j++) { + sb.append(board[row][j]); + } + res.add(sb.toString()); + } + return res; + }*/ +} \ No newline at end of file diff --git a/Week_07/G20200343030379/LeetCode_51_379_3.java b/Week_07/G20200343030379/LeetCode_51_379_3.java new file mode 100644 index 00000000..f7d3d979 --- /dev/null +++ b/Week_07/G20200343030379/LeetCode_51_379_3.java @@ -0,0 +1,130 @@ +package G20200343030379; + +import java.util.ArrayList; +import java.util.List; + +/** + * 51. Nʺ + * n ʺоν n ʺ nn ϣʹʺ˴֮䲻໥ + * + * + * + * ͼΪ 8 ʺһֽⷨ + * + * һ nвͬ n ʺĽ + * + * ÿһֽⷨһȷ n ʺӷ÷÷ 'Q' '.' ֱ˻ʺͿλ + * + * ʾ: + * + * : 4 + * : [ + * [".Q..", // ⷨ 1 + * "...Q", + * "Q...", + * "..Q."], + * + * ["..Q.", // ⷨ 2 + * "Q...", + * "...Q", + * ".Q.."] + * ] + * : 4 ʺͬĽⷨ + * + * ο⣺ + */ +public class LeetCode_51_379_3 { + + + private int size; + private int count; + /** + * ִʱ : 51 ms , Java ύл 5.14% û + * ڴ : 43.6 MB , Java ύл 5.18% û + * @param n + * @return + */ + List> res=new ArrayList<>(); + public List> solveNQueens(int n) { + dfs(n,new ArrayList<>(),0,0,0,0); + conver(res); + return res; + } + + private void conver(List> res) { + for (List re : res) { + for (int i = 0; i < re.size(); i++) { + String q = String.format("%" + String.valueOf(re.size()) + "s" + // 0001001 0 滻Ϊ"." + , re.get(i)).replaceAll("[\\s|0]", ".") + .replaceAll("1", "Q"); + re.set(i,q); + } + } + } + + private void dfs(int n, List board, + int r, int c, int lr, int ll) { + if(r==n){ + res.add(new ArrayList<>(board)); + return; + } + + int bit = (~(c | lr | ll)) & ((1<>1,(ll | q)<<1); + board.remove(r); + bit = bit & (bit-1); + } + } + + private void dfs2(int n, List board, + int r, int c, int lr, int ll) { + if(r==n){ + res.add(board); + return; + } + + int bit = (~(c | lr | ll)) & ((1<(board),r+1 , c|q ,(lr | q)>>1,(ll | q)<<1); + board.remove(r); + bit = bit & (bit-1); + } + } + + public static void main(String[] args) { + String s = "000010001".replaceAll("[\\s|0]", "."); + System.out.println(s); + String.format("%"+String.valueOf(2)+"s","2312"); + + new LeetCode_51_379_3().solveNQueens(4); + } + + private void solve(int row, int ld, int rd) { + if(row==size){ + count++; + return; + } + int pos=size & (~(row | ld | rd)); + + while (pos != 0 ){ + int p=pos & (-pos); + pos -= p; + solve(row | p,(ld | p) << 1 , + (rd | p)>> 1); + } + } + +} \ No newline at end of file diff --git a/Week_07/G20200343030379/LeetCode_51_379_4.java b/Week_07/G20200343030379/LeetCode_51_379_4.java new file mode 100644 index 00000000..c2abaa0c --- /dev/null +++ b/Week_07/G20200343030379/LeetCode_51_379_4.java @@ -0,0 +1,141 @@ +package G20200343030379; + +import java.util.ArrayList; +import java.util.List; + +/** + * 51. Nʺ + * n ʺоν n ʺ nn ϣʹʺ˴֮䲻໥ + * + * + * + * ͼΪ 8 ʺһֽⷨ + * + * һ nвͬ n ʺĽ + * + * ÿһֽⷨһȷ n ʺӷ÷÷ 'Q' '.' ֱ˻ʺͿλ + * + * ʾ: + * + * : 4 + * : [ + * [".Q..", // ⷨ 1 + * "...Q", + * "Q...", + * "..Q."], + * + * ["..Q.", // ⷨ 2 + * "Q...", + * "...Q", + * ".Q.."] + * ] + * : 4 ʺͬĽⷨ + * + * ο⣺ + * https://blog.csdn.net/u011433274/article/details/52487752 + * https://github.com/1yx/leetcode.org/blob/master/solutions/51.n%E7%9A%87%E5%90%8E.java + */ +public class LeetCode_51_379_4 { + + + public static void main(String[] args) throws InterruptedException { + String s = "000010001".replaceAll("[\\s|0]", "."); + String.format("%"+String.valueOf(2)+"s","2312"); + + long start=System.currentTimeMillis(); + new LeetCode_51_379_4().solveNQueens(1); + + /*for (int i = 0; i < 1000*1000; i++) { + Integer.toBinaryString(100); + }*/ + System.out.println(new LeetCode_51_379_4().log2(8)); + + long end =System.currentTimeMillis(); + + + System.out.println(end-start); + } + + /** + * ִʱ : 1 ms , Java ύл 100.00% û + * ڴ : 41.1 MB , Java ύл 9.07% û + * @param n + * @return + */ + + public List> solveNQueens(int n) { + List> res=new ArrayList<>(); + if(n==0) return res; + + char board[][]=new char[n][n]; + + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + board[i][j]='.'; + } + } + + dfs(n,res,board,0,0,0,0); + + return res; + } + + + /** + * + * @param n + * @param board + * @param r row + * @param c col + * @param lr lright + * @param ll llfet + */ + private void dfs(int n,List> res,char[][] board, + int r, int c, int lr, int ll) { + + if(r==n){ + res.add(constans(board)); + return; + } + + int bit = (~(c | lr | ll)) & ((1<>1,(ll | q)<<1); + board[r][col] = '.'; + bit = bit & (bit-1); //Ҳд bit -= p; + } + + } + + + private List constans(char[][] board) { + List res=new ArrayList<>(); + for (int row = 0; row < board.length; row++) { + String sb=new String(board[row]); + res.add(sb); + + + } + return res; + } + + + + // 1000 ʮ8 λ2^3=8; + //ο + public double log2(double N) { + return Math.log(N)/Math.log(2);//Math.logĵΪe + } + +} \ No newline at end of file diff --git a/Week_07/G20200343030379/LeetCode_51_379_5.java b/Week_07/G20200343030379/LeetCode_51_379_5.java new file mode 100644 index 00000000..6056febd --- /dev/null +++ b/Week_07/G20200343030379/LeetCode_51_379_5.java @@ -0,0 +1,113 @@ +package G20200343030379; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * 51. Nʺ + * n ʺоν n ʺ nn ϣʹʺ˴֮䲻໥ + * + * + * + * ͼΪ 8 ʺһֽⷨ + * + * һ nвͬ n ʺĽ + * + * ÿһֽⷨһȷ n ʺӷ÷÷ 'Q' '.' ֱ˻ʺͿλ + * + * ʾ: + * + * : 4 + * : [ + * [".Q..", // ⷨ 1 + * "...Q", + * "Q...", + * "..Q."], + * + * ["..Q.", // ⷨ 2 + * "Q...", + * "...Q", + * ".Q.."] + * ] + * : 4 ʺͬĽⷨ + * + * ο⣺ + * https://blog.csdn.net/u011433274/article/details/52487752 + * https://github.com/1yx/leetcode.org/blob/master/solutions/51.n%E7%9A%87%E5%90%8E.java + */ +public class LeetCode_51_379_5 { + + + + /** + * ִʱ : 1 ms , Java ύл 100.00% û + * ڴ : 41.1 MB , Java ύл 9.07% û + * @param n + * @return + */ + + public List> solveNQueens(int n) { + List> res=new ArrayList<>(); + if(n==0) return res; + + char board[][]=new char[n][n]; + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + board[i][j]='.'; + } + } + + dfs(n,board,res,0,0,0,0); + + return res; + } + + private void dfs(int n,char[][] board, List> res, int row, int col, int lr, int ll) { + if(row==n){ + res.add(convers(board)); + return; + } + + int bit= (~(col | lr | ll)) & ((1<> 1,(ll|q) << 1); + + // + bit = bit & (bit -1); //Ҳд bit -= p; + board[row][colx]='.'; + } + + } + + private int log2(int q) { + return (int) (Math.log(q)/Math.log(2));//Math.logĵΪe + } + + private List convers(char[][] board) { + List res=new ArrayList<>(); + + /* + иЧı + for (char[] chars : board) { + StringBuilder sb=new StringBuilder(); + for (char aChar : chars) { + sb.append(aChar); + } + res.add(sb.toString()); + }*/ + + for (char[] chars : board) { + String sb=new String(chars); + res.add(sb); + } + return res; + } + + +} \ No newline at end of file diff --git a/Week_07/G20200343030379/LeetCode_52_379.java b/Week_07/G20200343030379/LeetCode_52_379.java new file mode 100644 index 00000000..c26c1fa9 --- /dev/null +++ b/Week_07/G20200343030379/LeetCode_52_379.java @@ -0,0 +1,103 @@ +package G20200343030379; + +import java.util.ArrayList; +import java.util.List; + +/** + * 52. Nʺ II + * n?ʺоν n?ʺ nn ϣʹʺ˴֮䲻໥ + * + * + * + * ͼΪ 8 ʺһֽⷨ + * + * һ n n ʺͬĽ + * + * ʾ: + * + * : 4 + * : 2 + * : 4 ʺͬĽⷨ + * [ + * ?[".Q..", ?// ⷨ 1 + * ? "...Q", + * ? "Q...", + * ? "..Q."], + * + * ?["..Q.", ?// ⷨ 2 + * ? "Q...", + * ? "...Q", + * ? ".Q.."] + * ] + * + * ԴۣLeetCode + * ӣhttps://leetcode-cn.com/problems/n-queens-ii + * ȨСҵתϵٷȨҵתע + * + * ο⣺ + * https://blog.csdn.net/u011433274/article/details/52487752 + * https://github.com/1yx/leetcode.org/blob/master/solutions/51.n%E7%9A%87%E5%90%8E.java + */ +public class LeetCode_52_379 { + + public static void main(String[] args) { + int count = Integer.highestOneBit(12); + System.out.println(count); + Integer.bitCount(12); + } + + /** + * ִʱ : 0 ms , Java ύл 100.00% û + * ڴ : 36.2 MB , Java ύл 5.35% û + * + * ο⣺ + * https://blog.csdn.net/u011433274/article/details/52487752 + * https://github.com/1yx/leetcode.org/blob/master/solutions/51.n%E7%9A%87%E5%90%8E.java + * @param n + * @return + */ + int count=0; + public int totalNQueens(int n) { + if(n==0) return 0; + + char[][] board=new char[n][n]; + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + board[i][j]='.'; + } + } + + dfs(n,board,0,0,0,0); + return count; + + } + + private void dfs(int n, char[][] board, int row, int col, int ll, int lr) { + if(n==row) { + count++; + return; + } + + int bit=(~(col|ll|lr) & (1 << n)-1); + + while (bit!=0){ + int q=bit & (-bit); //0λ + + int colx=log2(q); + board[row][colx]='Q'; + + dfs(n,board,row+1,col|q , (ll|q)<<1 , (lr|q) >>1); + + bit =bit & (bit-1); + board[row][colx]='.'; + + } + } + + private int log2(int q) { + return (int) (Math.log(q)/Math.log(2)); + } + + + +} \ No newline at end of file diff --git a/Week_07/G20200343030379/LeetCode_56_379.java b/Week_07/G20200343030379/LeetCode_56_379.java new file mode 100644 index 00000000..9547a3b3 --- /dev/null +++ b/Week_07/G20200343030379/LeetCode_56_379.java @@ -0,0 +1,95 @@ +package G20200343030379; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; +import java.util.List; + +/** + * 56. ϲ + * + * һļϣϲص䡣 + * + * ʾ 1: + * + * : [[1,3],[2,6],[8,10],[15,18]] + * : [[1,6],[8,10],[15,18]] + * : [1,3] [2,6] ص, ǺϲΪ [1,6]. + * ʾ?2: + * + * : [[1,4],[4,5]] + * : [[1,5]] + * : [1,4] [4,5] ɱΪص䡣 + * + * ԴۣLeetCode + * ӣhttps://leetcode-cn.com/problems/merge-intervals + * ȨСҵתϵٷȨҵתע + * + * ο⣺ + */ +public class LeetCode_56_379 { + + public static void main(String[] args) { + //ʮת + //String s = Integer.toBinaryString(-2147483648); + } + + /** + * 1п + * + * 2 + * + * 3ȡұ߽ + * + * 4 + * 4.1 һ߽Сڵڵǰұ߽ + * 4.1.1 һұ߽ ڵǰ߽ + * б߽ + * + * 4.2 һұ߽ڵǰұ߽ + * 4.2.1 ӵǰұ߽ + * һұ߽ + * 5 ¼ұֵ߽ + * + * + * ִʱ : 7 ms , Java ύл 86.96% û + * ڴ : 41.7 MB , Java ύл 54.96% û + * + * ⣺ + * https://leetcode-cn.com/problems/merge-intervals/solution/pai-xu-yi-ci-sao-miao-zhu-xing-jie-shi-hao-li-jie-/ + * @param intervals + * @return + */ + public int[][] merge(int[][] intervals) { + List res=new ArrayList<>(); + if(intervals.length==0) return res.toArray(new int[intervals.length][]); + + Arrays.sort(intervals, new Comparator() { + @Override + public int compare(int[] o1, int[] o2) { + return o1[0]-o2[0]; + } + }); + + + int length=intervals.length; + int left=intervals[0][0]; + int right=intervals[0][1]; + + for (int i = 1; i < length-1; i++) { + if(intervals[i][0]<=right){ + if(intervals[i][1]>right){ + right=intervals[i][1]; + } + }else{ + res.add(new int[]{left,right}); + left=intervals[i][0]; + right=intervals[i][1]; + } + + } + res.add(new int[]{left,right}); + + return res.toArray(new int[res.size()][]); + } +} \ No newline at end of file diff --git a/Week_07/G20200343030379/NOTE.md b/Week_07/G20200343030379/NOTE.md index 50de3041..9df40c5f 100644 --- a/Week_07/G20200343030379/NOTE.md +++ b/Week_07/G20200343030379/NOTE.md @@ -1 +1,9 @@ -学习笔记 \ No newline at end of file +学习笔记 + +这周但看起来感觉不是很难,但是看到位运算确实难倒我的,特别是栽倒在以前回溯那一周的N皇后,单词接龙那些题。 + +N皇后的递归回溯做法自己是理解的,但是位运算简直懵逼,花了整整一天,后来没办法,只能自己花了一个PPT的图解,类似Leetcode上面那种。 + +把每一个步骤计算结果,怎么计算的用表格写出来,慢慢的才看懂。所以最大的收获就是针对这种需要计算的题目,必须手画图解,用PPT最好, + +因为用纸画首先需要很多纸,其他你每一个步骤,都得重复上一个步骤。还不如用工具第一个环节写完,复制一个页面,改动下就行,真的很完美。 \ No newline at end of file diff --git a/Week_07/G20200343030383/LeetCode_146_383.go b/Week_07/G20200343030383/LeetCode_146_383.go new file mode 100644 index 00000000..44951386 --- /dev/null +++ b/Week_07/G20200343030383/LeetCode_146_383.go @@ -0,0 +1,81 @@ +// https://leetcode-cn.com/problems/lru-cache/ + +type LRUCache struct { + hash map[int]*node + link *dlink + size int + cap int +} +type node struct { + Key, Val int + Next, Prev *node +} + +type dlink struct { + head, rear *node +} + +func newDlink() *dlink { + head, rear := &node{}, &node{} + head.Next = rear + rear.Prev = head + return &dlink{head: head, rear: rear} +} + +func (l *dlink) remove(n *node) { + n.Prev.Next = n.Next + n.Next.Prev = n.Prev +} + +func (l *dlink) add(n *node) { + n.Next = l.head.Next + n.Prev = l.head + l.head.Next.Prev = n + l.head.Next = n +} + +func Constructor(capacity int) LRUCache { + return LRUCache{ + hash: make(map[int]*node), + cap: capacity, + link: newDlink(), + } +} + +func (this *LRUCache) Get(key int) int { + n, ok := this.hash[key] + if !ok { + return -1 + } + this.link.remove(n) + this.link.add(n) + return n.Val +} + +func (this *LRUCache) Put(key int, value int) { + n, ok := this.hash[key] + if ok { + this.link.remove(n) + this.link.add(n) + n.Val = value + return + } + if this.size == this.cap { + delete(this.hash, this.link.rear.Prev.Key) + this.link.remove(this.link.rear.Prev) + this.size-- + } + n = &node{Key: key, Val: value} + this.link.add(n) + this.hash[key] = n + this.size++ + +} + +/** + * Your LRUCache object will be instantiated and called as such: + * obj := Constructor(capacity); + * param_1 := obj.Get(key); + * obj.Put(key,value); + */ + diff --git a/Week_07/G20200343030383/LeetCode_56_383.go b/Week_07/G20200343030383/LeetCode_56_383.go new file mode 100644 index 00000000..92558075 --- /dev/null +++ b/Week_07/G20200343030383/LeetCode_56_383.go @@ -0,0 +1,50 @@ +// https://leetcode-cn.com/problems/merge-intervals/ +package leetcode + +func merge(intervals [][]int) (ret [][]int) { + sort.SliceStable(intervals, func(i, j int) bool { + return intervals[i][0] < intervals[j][0] + }) + st := new(stack) + for _, arr := range intervals { + for i, v := range arr { + switch st.size() { + case 0, 1: + st.push(v) + case 2: + if v > st.peek() { + if i == 0 { + a, b := st.pop(), st.pop() + ret = append(ret, []int{b, a}) + st.push(v) + } else { + st.pop() + st.push(v) + } + } + } + } + } + if st.size() != 0 { + a, b := st.pop(), st.pop() + ret = append(ret, []int{b, a}) + } + return +} + +type stack struct{ data []int } + +func (st *stack) peek() int { + return st.data[len(st.data)-1] +} + +func (st *stack) pop() (v int) { + size := len(st.data) + v = st.data[size-1] + st.data = st.data[:size-1] + return +} +func (st *stack) push(v int) { + st.data = append(st.data, v) +} +func (st *stack) size() int { return len(st.data) } diff --git a/Week_07/G20200343030387/LeetCode_1122_387.js b/Week_07/G20200343030387/LeetCode_1122_387.js new file mode 100644 index 00000000..23fd7e6e --- /dev/null +++ b/Week_07/G20200343030387/LeetCode_1122_387.js @@ -0,0 +1,24 @@ +/** + * @param {number[]} arr1 + * @param {number[]} arr2 + * @return {number[]} + */ +// 计数排序: +// 1. 统计arr1的元素个数,放入另外一个数组bucket中,其索引为arr1的元素值 +// 2. 遍历arr2,根据元素值找到bucket的数量值,填上相应数量的元素 +// 3. 遍历bucket,输出还有数量值的元素 +var relativeSortArray = function (arr1, arr2) { + const bucket = new Array(1001).fill(0) + for (const v of arr1) { + bucket[v]++ + } + const res = [] + for (const v of arr2) { + res.push(...(new Array(bucket[v]).fill(v))) + bucket[v] = 0 + } + for (let v = 0; v < bucket.length; v++) { + res.push(...(new Array(bucket[v]).fill(v))) + } + return res +}; \ No newline at end of file diff --git a/Week_07/G20200343030387/LeetCode_146_387.js b/Week_07/G20200343030387/LeetCode_146_387.js new file mode 100644 index 00000000..841e5fa3 --- /dev/null +++ b/Week_07/G20200343030387/LeetCode_146_387.js @@ -0,0 +1,44 @@ +/** + * @param {number} capacity + */ +// 利用Map对插入的key有顺序的特性; +// 能够通过map.keys().next().value拿到最后的元素; +// 能够模拟缓存key被重复使用后放到最前面,最少被使用的逐渐往后排,在超大小限制时,取最后的元素删除掉; +var LRUCache = function (capacity) { + this.capacity = capacity + this.map = new Map() +}; + +/** + * @param {number} key + * @return {number} + */ +LRUCache.prototype.get = function (key) { + const val = this.map.get(key) + if (typeof val === 'undefined') return -1 + this.map.delete(key) + this.map.set(key, val) + return val +}; + +/** + * @param {number} key + * @param {number} value + * @return {void} + */ +LRUCache.prototype.put = function (key, value) { + if (this.map.has(key)) { + this.map.delete(key) + } + this.map.set(key, value) + if (this.map.size > this.capacity) { + this.map.delete(this.map.keys().next().value) + } +}; + +/** + * Your LRUCache object will be instantiated and called as such: + * var obj = new LRUCache(capacity) + * var param_1 = obj.get(key) + * obj.put(key,value) + */ \ No newline at end of file diff --git a/Week_07/G20200343030387/LeetCode_190_387.js b/Week_07/G20200343030387/LeetCode_190_387.js new file mode 100644 index 00000000..2b27f011 --- /dev/null +++ b/Week_07/G20200343030387/LeetCode_190_387.js @@ -0,0 +1,14 @@ +/** + * @param {number} n - a positive integer + * @return {number} - a positive integer + */ +var reverseBits = function (n) { + let res = 0 + for (let i = 0; i < 32; i++) { + res <<= 1 + res += (n & 1) + n >>>= 1 + } + // 在js中所有的按位操作符都会会转换为补码进行,最后一位为1左移时会溢出,所有需要使用>>>变成无符号整数 + return res >>> 0 +}; \ No newline at end of file diff --git a/Week_07/G20200343030387/LeetCode_191_387.js b/Week_07/G20200343030387/LeetCode_191_387.js new file mode 100644 index 00000000..bf6dc4e2 --- /dev/null +++ b/Week_07/G20200343030387/LeetCode_191_387.js @@ -0,0 +1,14 @@ +/** + * @param {number} n - a positive integer + * @return {number} + */ +// n与n-1的与运算可以消除其二进制上的最后一位1 +// 遍历次数为bit位为1的个数 +var hammingWeight = function (n) { + let count = 0 + while (n !== 0) { + n &= n - 1 + count++ + } + return count +}; \ No newline at end of file diff --git a/Week_07/G20200343030387/LeetCode_231_387.js b/Week_07/G20200343030387/LeetCode_231_387.js new file mode 100644 index 00000000..7218b8e9 --- /dev/null +++ b/Week_07/G20200343030387/LeetCode_231_387.js @@ -0,0 +1,9 @@ +/** + * @param {number} n + * @return {boolean} + */ +// 2 的幂次方的数需要满足二进制位上只有一个1 +// 需要大于0,且消除掉一位后等于0 +var isPowerOfTwo = function (n) { + return n > 0 && (n & (n - 1)) === 0 +}; \ No newline at end of file diff --git a/Week_07/G20200343030387/LeetCode_338_387.js b/Week_07/G20200343030387/LeetCode_338_387.js new file mode 100644 index 00000000..496068a8 --- /dev/null +++ b/Week_07/G20200343030387/LeetCode_338_387.js @@ -0,0 +1,16 @@ +/** + * @param {number} num + * @return {number[]} + */ +// 动态规划 + 最低有效位 +// 任何一个数x的二进制数1的数目可以看成x右移1位的数,加上x原来的最低有效位1的数目; +// 状态:P(x)表示x的二进制数1的数目 +// DP方程:P(x) = P(x>>>1) + (x & 1) +// 注:js的 >>> 才是逻辑右移,>> 是算术右移 +var countBits = function (num) { + const res = [0] + for (let i = 0; i <= num; i++) { + res[i] = res[i >>> 1] + (i & 1) + } + return res +}; \ No newline at end of file diff --git a/Week_07/G20200343030387/LeetCode_493_387.js b/Week_07/G20200343030387/LeetCode_493_387.js new file mode 100644 index 00000000..0546a9eb --- /dev/null +++ b/Week_07/G20200343030387/LeetCode_493_387.js @@ -0,0 +1,31 @@ +/** + * @param {number[]} nums + * @return {number} + */ +// 归并排序的合并过程中,获取逆序元素个数 +var reversePairs = function (nums) { + if (!nums || nums.length === 0) return 0 + return mergeSort(nums, 0, nums.length - 1) +}; + +function mergeSort(nums, left, right) { + if (left >= right) return 0 + const mid = parseInt(left + (right - left) / 2) + return mergeSort(nums, left, mid) + mergeSort(nums, mid + 1, right) + merge(nums, left, mid, right) +} + +function merge(nums, left, mid, right) { + let i = left, l = left, count = 0, tmp = [], p = 0; + for (let j = mid + 1; j <= right; j++) { + while (i <= mid && nums[i] / 2 <= nums[j]) i++ + count += mid - i + 1 // 左边的元素比右边元素的第j个比,有mid-i+1个是大于两倍的 + + while (l <= mid && nums[l] < nums[j]) tmp[p++] = nums[l++] + tmp[p++] = nums[j] + } + while (l <= mid) tmp[p++] = nums[l++] + for (let p = 0; p < tmp.length; p++) { + nums[left + p] = tmp[p] + } + return count +} \ No newline at end of file diff --git a/Week_07/G20200343030387/LeetCode_52_387.js b/Week_07/G20200343030387/LeetCode_52_387.js new file mode 100644 index 00000000..fb25356d --- /dev/null +++ b/Week_07/G20200343030387/LeetCode_52_387.js @@ -0,0 +1,19 @@ +/** + * @param {number} n + * @return {number} + */ +// 位运算 + DFS +var totalNQueens = function (n) { + let res = 0 + const dfs = function (n, row, col, pie, na) { + if (row >= n) return res++ + let bits = ~(col | pie | na) & ((1 << n) - 1) // 当前层能放皇后的位都赋值为1 + while (bits > 0) { + let p = bits & -bits // 取最低位的1 + bits &= bits - 1 // 皇后放到最低位的1,相当于并把那一bit位赋值0 + dfs(n, row + 1, (col | p), (pie | p) << 1, (na | p) >> 1) + } + } + dfs(n, 0, 0, 0, 0) + return res +}; diff --git a/Week_07/G20200343030387/LeetCode_56_387.js b/Week_07/G20200343030387/LeetCode_56_387.js new file mode 100644 index 00000000..6523e082 --- /dev/null +++ b/Week_07/G20200343030387/LeetCode_56_387.js @@ -0,0 +1,37 @@ +/** + * @param {number[][]} intervals + * @return {number[][]} + */ +// 解法1: +// 1. intervals的每个子数组根据其第一个元素进行排序,得到连通块; +// 2. 遍历连通块,将连通块的最小区间left跟合并列表的最右区间right对比 +// a. left[0] <= right[1],则进行合并,right.end = max(right.end, left.end) +// b. 否则直接将区间加入合并列表; +var merge1 = function (intervals) { + intervals.sort((a, b) => a[0] - b[0]) + const merged = [] + for (const left of intervals) { + const mergedLast = merged[merged.length - 1] + if (!merged.length || mergedLast[1] < left[0]) { + merged.push(left) + } else { + mergedLast[1] = Math.max(left[1], mergedLast[1]) + } + } + return merged +}; + +// 解法2: +// 在解法1基础上,使用双指针对数组进行原地操作,减少了merged的空间消耗 +var merge = function (intervals) { + intervals.sort((a, b) => a[0] - b[0]) + let p = 0 // 记录合并数组的最大索引 + for (let i = 0; i < intervals.length; i++) { + if (intervals[p][1] >= intervals[i][0]) { + intervals[p][1] = Math.max(intervals[i][1], intervals[p][1]) + } else { + intervals[++p] = intervals[i] + } + } + return intervals.slice(0, p + 1) +}; \ No newline at end of file diff --git a/Week_07/G20200343030387/NOTE.md b/Week_07/G20200343030387/NOTE.md index 50de3041..6932fda9 100644 --- a/Week_07/G20200343030387/NOTE.md +++ b/Week_07/G20200343030387/NOTE.md @@ -1 +1,238 @@ -学习笔记 \ No newline at end of file +# 学习笔记 +## Bloom Filters +* 空间效率、查询性能远远超过一般算法,如hash; +* 可以判断对象是否不存在,但不能完全确定是否存在; +* 应用在数据库、分布式系统的缓存层场景; +### 代码示例 +```python +from bitarray import bitarray +import mmh3 + +class BloomFilter: + def __init__(self, size, hash_num): + self.size = size + self.hash_num = hash_num + self.bit_array = bitarray(size) + self.bit_array.setall(0) + + def add(self, s): + for seed in range(self.hash_num): + result = mmh3.hash(s, seed) % self.size + self.bit_array[result] = 1 + + def lookup(self, s): + for seed in range(self.hash_num): + result = mmh3.hash(s, seed) % self.size + if self.bit_array[result] == 0: + return "Nope" + return "Probably" + +bf = BloomFilter(500000, 7) +bf.add("dantezhao") +print (bf.lookup("dantezhao")) +print (bf.lookup("yyj")) +``` + +## LRU cache +* 最近最少使用(读或写)的就放到最后,超出缓存大小限制时,淘汰掉最后的; +* Hash Table(hash表) + Double Linkedlist(双向链表) 实现; +* 查询O(1),修改O(1) + +## 排序 +### 归并排序 +* 每次将数组分为左右两部分,分别排序后再merge; +* merge需要额外的存储空间 + +### 快速排序 +* 每次取priot,通过partition将数组分为左边小于priot的部分,右边大于priot的部分,最终整个数组有序; +* partition的空间复杂度为O(1) + +### 各个排序算法的代码 +```js + +// 选择排序 +// 每次找最小值,然后放到待排序数组的起始位置 +const selectSort = (arr) => { + const arrLen = arr.length + let minIndex, tmp + for (let i = 0; i < arrLen; i++) { + minIndex = i + for (let j = i + 1; j < arrLen; j++) { + if (arr[minIndex] >= arr[j]) { + minIndex = j + } + } + tmp = arr[i] + arr[i] = arr[minIndex] + arr[minIndex] = tmp + } + return arr +} + +// 插入排序 +// 从前往后构建序列,前面是已排序,每次拿一个未排序数据在已排序数据中从后往前找位置插入 +// 插入排序在实现上,通常采用in - place排序(即只需用到O(1)的额外空间的排序), +// 因而在从后向前扫描过程中,需要反复把已排序元素逐步向后挪位,为最新元素提供插入空间 +const insertSort = (arr) => { + let prevIndex, current + for (let i = 1; i < arr.length; i++) { + prevIndex = i - 1 + current = arr[i] + while (prevIndex >= 0 && arr[prevIndex] > current) { + arr[prevIndex + 1] = arr[prevIndex--] + } + arr[prevIndex + 1] = current + } + return arr +} + +// 冒泡排序 +// 嵌套循环,每次查看相邻元素逆序则交换位置 +// 外层循环每完成一次,会有一个大元素被排在末尾,像气泡一样往上到顶部 +const bubbleSort = (arr) => { + for (let i = 0; i < arr.length; i++) { + for (let j = i + 1; j < arr.length; j++) { + if (arr[i] > arr[j]) { + const tmp = arr[i] + arr[i] = arr[j] + arr[j] = tmp + } + } + } + return arr +} + +// 快速排序 +// 在数组任意取一标杆元素pivot,将小于pivot的元素放在其左边,大于的放右边 +// 递归上述过程,最终排序完成 +const quickSort = (arr, start, end) => { + if (start >= end) return arr + const pivot = partion(arr, start, end) + quickSort(arr, start, pivot - 1) + quickSort(arr, pivot + 1, end) + return arr +} +function partion(arr, start, end) { + let counters = start, pivot = end + // counters记录比pivot小的元素中的最大索引值+1 + for (let i = start; i < end; i++) { + if (arr[i] < arr[pivot]) { + const tmp = arr[i] + arr[i] = arr[counters] + arr[counters] = tmp + counters++ + } + } + // 最后将privot与counters所在位置交换,就达到pivot左边都是比它小的元素,右边都是比它大的 + const tmp = arr[counters] + arr[counters] = arr[pivot] + arr[pivot] = tmp + return counters +} + +// 归并排序 +// 从索引中点将数组切割两等份,递归下去,一直到不可切分 +// 逐层合并其中的子数组,最终达到有序 +const mergeSort = (arr, start, end) => { + if (start >= end) return arr + const mid = parseInt((start + end) / 2) + mergeSort(arr, start, mid) + mergeSort(arr, mid + 1, end) + merge(arr, mid, start, end) + return arr +} +function merge(arr, mid, start, end) { + let k = 0, tmp = [], i = start, j = mid + 1 + while (i <= mid && j <= end) { + tmp[k++] = arr[i] <= arr[j] ? arr[i++] : arr[j++] + } + while (i <= mid) tmp[k++] = arr[i++] + while (j <= end) tmp[k++] = arr[j++] + + for (let p = 0; p < tmp.length; p++) { + arr[start + p] = tmp[p] + } +} + +// 堆排序 +// 1. 构建大顶堆 +// 2. 不断从堆顶取出元素与堆尾互换,再排除堆尾调整堆 +// 3. 递归执行2,直到堆为空 +function heapSort(arr) { + const length = arr.length + if (length < 1) return arr + + // 构建大顶堆 + for (let i = parseInt(length / 2) - 1; i >= 0; i--) { + heapify(arr, length, i) + } + + // 步骤2,3 + for (let j = length - 1; j >= 0; j--) { + swap(arr, 0, j) + heapify(arr, j, 0) + } + return arr +} +function heapify(arr, length, i) { + let largest = i + let left = 2 * i + 1 + let right = 2 * i + 2 + if (left < length && arr[left] > arr[largest]) { + largest = left + } + if (right < length && arr[right] > arr[largest]) { + largest = right + } + if (largest !== i) { + swap(arr, i, largest) + heapify(arr, length, largest) + } +} +function swap(arr, i, j) { + const tmp = arr[i] + arr[i] = arr[j] + arr[j] = tmp +} + +const assert = require('assert') +const sortFn = [insertSort, selectSort, bubbleSort, quickSort, mergeSort, heapSort] +// const sortFn = [insertSort] +const randomArr = Array(1000).fill(0).map(i => parseInt(Math.random() * 1000)) +const testTasks = [ + { + input: [2, 3, 1, 6, 1], output: [1, 1, 2, 3, 6] + }, + { + input: [-2, 3, 1, 6], output: [-2, 1, 3, 6] + }, + { + input: [0], output: [0] + }, + { + input: [], output: [] + }, + { + input: randomArr, output: randomArr.sort((a, b) => a - b) + } +] +for (let fn of sortFn) { + console.time(`${fn.name}`) + for (let t of testTasks) { + assert.deepStrictEqual(fn(t.input.slice(0), 0, t.input.length - 1), t.output) + } + console.timeEnd(`${fn.name}`) +} + +``` + +* 日志输出 +* insertSort: 0.993ms +* selectSort: 3.574ms +* bubbleSort: 2.501ms +* quickSort: 3.911ms +* mergeSort: 1.629ms +* heapSort: 1.944ms + +这里有个不懂的地方,快排、归并居然比插入要慢不少,而且数组更长的时候,差别更明显。 +时间复杂度来看,快排、归并肯定比插入要快,但考虑js的语言动态特性,对于递归会不会消耗更多的其它资源,导致处理更慢? \ No newline at end of file diff --git a/Week_07/G20200343030391/Bloom_Filter.png b/Week_07/G20200343030391/Bloom_Filter.png new file mode 100644 index 00000000..fcb736ab Binary files /dev/null and b/Week_07/G20200343030391/Bloom_Filter.png differ diff --git a/Week_07/G20200343030391/Bloom_Filter_1.png b/Week_07/G20200343030391/Bloom_Filter_1.png new file mode 100644 index 00000000..1092e77a Binary files /dev/null and b/Week_07/G20200343030391/Bloom_Filter_1.png differ diff --git a/Week_07/G20200343030391/Bloom_Filter_2.png b/Week_07/G20200343030391/Bloom_Filter_2.png new file mode 100644 index 00000000..9df2ccf3 Binary files /dev/null and b/Week_07/G20200343030391/Bloom_Filter_2.png differ diff --git a/Week_07/G20200343030391/LeetCode_146_391.java b/Week_07/G20200343030391/LeetCode_146_391.java new file mode 100644 index 00000000..98a3b115 --- /dev/null +++ b/Week_07/G20200343030391/LeetCode_146_391.java @@ -0,0 +1,111 @@ +package G20200343030391; + +import java.util.HashMap; + +public class LeetCode_146_391 { + + public static void main(String[] args) { + + } + + public static class LRUCache { + // key -> Node(key, val) + private HashMap map; + // Node(k1, v1) <-> Node(k2, v2)... + private DoubleList cache; + // 最大容量 + private int cap; + + public LRUCache(int capacity) { + this.cap = capacity; + map = new HashMap<>(); + cache = new DoubleList(); + } + + public int get(int key) { + if (!map.containsKey(key)) + return -1; + int val = map.get(key).val; + // 利用 put 方法把该数据提前 + put(key, val); + return val; + } + + public void put(int key, int val) { + // 先把新节点 x 做出来 + Node x = new Node(key, val); + + if (map.containsKey(key)) { + // 删除旧的节点,新的插到头部 + cache.remove(map.get(key)); + cache.addFirst(x); + // 更新 map 中对应的数据 + map.put(key, x); + } else { + if (cap == cache.size()) { + // 删除链表最后一个数据 + Node last = cache.removeLast(); + map.remove(last.key); + } + // 直接添加到头部 + cache.addFirst(x); + map.put(key, x); + } + } + + class DoubleList { + private Node head, tail; // 头尾虚节点 + private int size; // 链表元素数 + + public DoubleList() { + head = new Node(0, 0); + tail = new Node(0, 0); + head.next = tail; + tail.prev = head; + size = 0; + } + + // 在链表头部添加节点 x + public void addFirst(Node x) { + x.next = head.next; + x.prev = head; + head.next.prev = x; + head.next = x; + size++; + } + + // 删除链表中的 x 节点(x 一定存在) + public void remove(Node x) { + x.prev.next = x.next; + x.next.prev = x.prev; + size--; + } + + // 删除链表中最后一个节点,并返回该节点 + public Node removeLast() { + if (tail.prev == head) + return null; + Node last = tail.prev; + remove(last); + return last; + } + + // 返回链表长度 + public int size() { + return size; + } + } + + class Node { + public int key, val; + public Node next, prev; + + public Node(int k, int v) { + this.key = k; + this.val = v; + } + } + } + + +} diff --git a/Week_07/G20200343030391/LeetCode_191_391.java b/Week_07/G20200343030391/LeetCode_191_391.java new file mode 100644 index 00000000..617e9fdf --- /dev/null +++ b/Week_07/G20200343030391/LeetCode_191_391.java @@ -0,0 +1,31 @@ +package G20200343030391; + +public class LeetCode_191_391 { + + public static void main(String[] args) { + int n = 00000000000000000000000000001011; + int i = new LeetCode_191_391().hammingWeight_2(n); + System.out.println(i); + } + + public int hammingWeight_1(int n) { + int result = 0; + int mask = 1; + for (int i = 0; i < 32; i++) { + if ((n & mask) != 0) { + result++; + } + mask = mask << 1; + } + return result; + } + + public int hammingWeight_2(int n) { + int sum = 0; + while (n != 0) { + sum++; + n &= (n - 1); + } + return sum; + } +} diff --git a/Week_07/G20200343030391/LeetCode_231_391.java b/Week_07/G20200343030391/LeetCode_231_391.java new file mode 100644 index 00000000..09136781 --- /dev/null +++ b/Week_07/G20200343030391/LeetCode_231_391.java @@ -0,0 +1,21 @@ +package G20200343030391; + +public class LeetCode_231_391 { + + public static void main(String[] args) { + int n = 00000000000000000000000000001011; + boolean value = new LeetCode_231_391().isPowerOfTwo_2(n); + System.out.println(value); + } + + public boolean isPowerOfTwo_1(int n) { + if (n == 0) return false; + while (n % 2 == 0) n /= 2; + return n == 1; + } + + public boolean isPowerOfTwo_2(int n) { + if (n == 0) return false; + return ((long) n & (-(long) n)) == (long) n; + } +} diff --git a/Week_07/G20200343030391/NOTE.md b/Week_07/G20200343030391/NOTE.md index 50de3041..657af1de 100644 --- a/Week_07/G20200343030391/NOTE.md +++ b/Week_07/G20200343030391/NOTE.md @@ -1 +1,48 @@ -学习笔记 \ No newline at end of file +学习笔记 +- 位运算符 + + | 含义 | 运算符 | 示例 | + | ---- |-------|-----| + |左移 | << | 0011 => 0110 | + |右移 | \>> | 0110 => 0011 | + |按位或 | ︳ | 0011 | 1011 = 1011 | + |按位与 | & | 0011 & 0011 = 1011 | + |按位取反 | ~ | ~0011 = 1100 + |按位异或(相同为零不同为一)| ^ |0011 ^ 1000 =1011 +- XOR -异或 + - 异或:相同为 0,不同为 1。也可用“不进位加法”来理解。 + - 异或操作的一些特点: + - x ^ 0 = x + - x ^ 1s = ~x // 注意 1s = ~0 + - x ^ (~x) = 1s + - x ^ x = 0 + - c = a ^ b => a ^ c = b, b ^ c = a // 交换两个数 + - a ^ b ^ c = a ^ (b ^ c) = (a ^ b) ^ c // associative +- 指定位置的位运算 + 1. 将 x 最右边的 n 位清零:x& (~0 << n) + 2. 获取 x 的第 n 位值(0 或者 1): (x >> n) & 1 + 3. 获取 x 的第 n 位的幂值:x& (1 < (x & 1) == 1 + - x % 2 == 0 —> (x & 1) == 0 + - x >> 1 —> x / 2. + - 即: x = x / 2; —> x = x >> 1; + - mid = (left + right) / 2; —> mid = (left + right) >> 1; + - X = X & (X-1) 清零最低位的 1 • X & -X => 得到最低位的 1 • X & ~X => 0 + +-------------------------- +- 布隆过滤器、LRU Cache + - 布隆过滤器 Bloom Filter + - HashTable + 拉链存储重复元素 + ![Bloom_Filter](Bloom_Filter.png) + - 一个很长的二进制向量和一系列随机映射函数。布隆过滤器可以用于检索一个元素是否在一个集合中。 + - 优点是空间效率和查询时间都远远超过一般的算法, + - 缺点是有一定的误识别率和删除困难。 + - 布隆过滤器示意图 + ![Bloom_Filter](Bloom_Filter_1.png) + ![Bloom_Filter](Bloom_Filter_2.png) \ No newline at end of file diff --git a/Week_07/G20200343030393/LeetCode_231_393.py b/Week_07/G20200343030393/LeetCode_231_393.py new file mode 100644 index 00000000..05ebc1de --- /dev/null +++ b/Week_07/G20200343030393/LeetCode_231_393.py @@ -0,0 +1,7 @@ +class Solution(object): + def isPowerOfTwo(self, n): + """ + :type n: int + :rtype: bool + """ + return n > 0 and n & (n - 1) == 0 \ No newline at end of file diff --git a/Week_07/G20200343030393/LeetCode_56_393.py b/Week_07/G20200343030393/LeetCode_56_393.py new file mode 100644 index 00000000..8ee780c6 --- /dev/null +++ b/Week_07/G20200343030393/LeetCode_56_393.py @@ -0,0 +1,13 @@ +class Solution(object): + def merge(self, intervals): + """ + :type intervals: List[List[int]] + :rtype: List[List[int]] + """ + out = [] + for i in sorted(intervals, key=lambda i: i.start): + if out and i.start <= out[-1].end: + out[-1].end = max(out[-1].end, i.end) + else: + out += i, + return out \ No newline at end of file diff --git a/Week_07/G20200343030395/LeetCode_1_395.java b/Week_07/G20200343030395/LeetCode_1_395.java new file mode 100644 index 00000000..d6983f1b --- /dev/null +++ b/Week_07/G20200343030395/LeetCode_1_395.java @@ -0,0 +1,18 @@ +package Week_07.G20200343030395; + +public class LeetCode_1_395 { + + public int hammingWeight(int n) { + int bits = 0; + int mask = 1; + for (int i=0; i<32; i++) { + if((n & mask) != 0) { + bits++; + } + + mask <<= 1; + } + + return bits; + } +} diff --git a/Week_07/G20200343030395/LeetCode_2_395.java b/Week_07/G20200343030395/LeetCode_2_395.java new file mode 100644 index 00000000..4b4e6156 --- /dev/null +++ b/Week_07/G20200343030395/LeetCode_2_395.java @@ -0,0 +1,7 @@ +package Week_07.G20200343030395; + +public class LeetCode_2_395 { + public boolean isPowerOfTwo(int n) { + return n>0 && (n & (n-1)) ==0; + } +} diff --git a/Week_07/G20200343030395/LeetCode_day1_395.java b/Week_07/G20200343030395/LeetCode_day1_395.java new file mode 100644 index 00000000..67cfbece --- /dev/null +++ b/Week_07/G20200343030395/LeetCode_day1_395.java @@ -0,0 +1,57 @@ +package Week_07.G20200343030395; + +import java.util.List; + +public class LeetCode_day1_395 { + public static class ListNode { + int val; + ListNode next; + ListNode(int x) { val = x; } + } + + + public static void main(String[] args) { + int[] nums = new int[]{1,2,3,4,5,6}; + + ListNode h = new ListNode(0); + ListNode x = h; + + for (int i=0; i 0) { + h = h.next; + x--; + } + + return h; + } +} diff --git a/Week_07/G20200343030395/NOTE.md b/Week_07/G20200343030395/NOTE.md index 50de3041..31317d04 100644 --- a/Week_07/G20200343030395/NOTE.md +++ b/Week_07/G20200343030395/NOTE.md @@ -1 +1,20 @@ -学习笔记 \ No newline at end of file +学习笔记 +# 2020/3/24 +指定位置的位运算 +1. 将x的最右边n位清零: x&(~0<>n)&1 +3. 获取x的第n位的幂值: x&(1<<(n-1)) +4. 仅将第n位置为1: x|(1< (x&1)==1 + 2. x%2==0 --> (x&0)==0 +* x/2 --> x>>1 +* mid=(left+right)/2 --> mid=(left+right)>>1 +* 清零最低位的1 x=x&(x-1) +* 得到最低位的1 x&-x +* x&~x diff --git a/Week_07/G20200343030401/LeetCode_191_401.java b/Week_07/G20200343030401/LeetCode_191_401.java new file mode 100644 index 00000000..67877e5d --- /dev/null +++ b/Week_07/G20200343030401/LeetCode_191_401.java @@ -0,0 +1,12 @@ +//题目链接:https://leetcode-cn.com/problems/number-of-1-bits/ +public class Solution { + // you need to treat n as an unsigned value + public int hammingWeight(int n) { + int sum = 0; + while (n != 0) { + sum++; + n &= (n - 1); + } + return sum; + } +} \ No newline at end of file diff --git a/Week_07/G20200343030401/LeetCode_56_401.java b/Week_07/G20200343030401/LeetCode_56_401.java new file mode 100644 index 00000000..1a09f489 --- /dev/null +++ b/Week_07/G20200343030401/LeetCode_56_401.java @@ -0,0 +1,29 @@ +//题目链接:https://leetcode-cn.com/problems/merge-intervals/ +class Solution { + private class IntervalComparator implements Comparator { + @Override + public int compare(Interval a, Interval b) { + return a.start < b.start ? -1 : a.start == b.start ? 0 : 1; + } + } + + public List merge(List intervals) { + Collections.sort(intervals, new IntervalComparator()); + + LinkedList merged = new LinkedList(); + for (Interval interval : intervals) { + // if the list of merged intervals is empty or if the current + // interval does not overlap with the previous, simply append it. + if (merged.isEmpty() || merged.getLast().end < interval.start) { + merged.add(interval); + } + // otherwise, there is overlap, so we merge the current and previous + // intervals. + else { + merged.getLast().end = Math.max(merged.getLast().end, interval.end); + } + } + + return merged; + } +} \ No newline at end of file diff --git a/Week_07/G20200343030409/LeetCode_146_409.java b/Week_07/G20200343030409/LeetCode_146_409.java new file mode 100644 index 00000000..d5c06ffc --- /dev/null +++ b/Week_07/G20200343030409/LeetCode_146_409.java @@ -0,0 +1,107 @@ +import java.util.*; + +class DLinkedNode { + int key; + int value; + DLinkedNode pre; + DLinkedNode post; + + DLinkedNode() { + + } + + DLinkedNode(int key, int value) { + this.key = key; + this.value = value; + } +} + +class LRUCache { + + Hashtable cache = new Hashtable<>(); + private int capacity; + private int count; + private DLinkedNode head; + private DLinkedNode tail; + + public LRUCache(int capacity) { + this.capacity = capacity; + this.count = 0; + head = new DLinkedNode(); + tail = new DLinkedNode(); + + head.pre = null; + tail.post = null; + + head.post = tail; + tail.pre = head; + } + + private void addNode(DLinkedNode node) { + + node.pre = head; + node.post = head.post; + + head.post.pre = node; + head.post = node; + + } + + private void removeNode(DLinkedNode node) { + DLinkedNode preNode = node.pre; + DLinkedNode postNode = node.post; + + preNode.post = postNode; + postNode.pre = preNode; + + } + + private void removeAndMoveToHead(DLinkedNode node) { + removeNode(node); + addNode(node); + } + + private DLinkedNode popTail() { + DLinkedNode tailRre = tail.pre; + removeNode(tailRre); + return tailRre; + } + + public int get(int key) { + DLinkedNode node = cache.get(key); + if(node == null) { + return -1; + } + removeAndMoveToHead(node); + return node.value; + } + + public void put(int key, int value) { + DLinkedNode node = cache.get(key); + + if(node == null) { + node = new DLinkedNode(key, value); + count++; + cache.put(key, node); + addNode(node); + + if(count > capacity) { + DLinkedNode tail = popTail(); + cache.remove(tail.key); + count--; + } + } else { + node.value = value; + removeAndMoveToHead(node); + + } + + } +} + +/** + * Your LRUCache object will be instantiated and called as such: + * LRUCache obj = new LRUCache(capacity); + * int param_1 = obj.get(key); + * obj.put(key,value); + */ \ No newline at end of file diff --git a/Week_07/G20200343030409/LeetCode_56_409.java b/Week_07/G20200343030409/LeetCode_56_409.java new file mode 100644 index 00000000..b60c9823 --- /dev/null +++ b/Week_07/G20200343030409/LeetCode_56_409.java @@ -0,0 +1,34 @@ +/* + time complexity: O(nlogn), space complexity: O(n) + */ +class Solution { + public int[][] merge(int intervals[][]) { + if(intervals == null || intervals.length == 0) { + return intervals; + } + + Arrays.sort(intervals, (o1,o2)->o1[0]-o2[0]); + + + int first[] = intervals[0]; + int start = first[0]; + int end = first[1]; + + List ans = new ArrayList<>(); + + for(int interval[]: intervals) { + if(end >= interval[0]) { + end = Math.max(end, interval[1]); + } else { + ans.add(new int[]{start, end}); + start = interval[0]; + end = interval[1]; + } + } + ans.add(new int[]{start, end}); + + + + return ans.toArray(new int[ans.size()][]); + } +} \ No newline at end of file diff --git a/Week_07/G20200343030415/LeetCode-190-415.java b/Week_07/G20200343030415/LeetCode-190-415.java new file mode 100644 index 00000000..1929cdf3 --- /dev/null +++ b/Week_07/G20200343030415/LeetCode-190-415.java @@ -0,0 +1,10 @@ +public class Solution { + // you need treat n as an unsigned value + public int reverseBits(int n) { + int ans = 0; + for (int bitSize = 31; n !=0; n = n >>> 1,bitSize--){ + ans += (n & 1) << bitSize; + } + return ans; + } +} \ No newline at end of file diff --git a/Week_07/G20200343030415/LeetCode-56-415.java b/Week_07/G20200343030415/LeetCode-56-415.java new file mode 100644 index 00000000..0418c174 --- /dev/null +++ b/Week_07/G20200343030415/LeetCode-56-415.java @@ -0,0 +1,22 @@ +class Solution { + + public int[][] merge(int[][] intervals) { + List res = new ArrayList<>(); + if(intervals == null || intervals.length == 0){ + return res.toArray(new int[0][]); + } + Arrays.sort(intervals,(a,b)->a[0] - b[0]); + int i = 0; + while (i < intervals.length){ + int left = intervals[i][0]; + int right = intervals[i][1]; + while (i < intervals.length - 1 && intervals[i+1][0] <= right){ + i++; + right = Math.max(right,intervals[i][1]); + } + res.add(new int[]{left,right}); + i++; + } + return res.toArray(new int[0][]); + } +} \ No newline at end of file diff --git a/Week_07/G20200343030423/LeetCode_191_423.java b/Week_07/G20200343030423/LeetCode_191_423.java new file mode 100644 index 00000000..d4f6e24b --- /dev/null +++ b/Week_07/G20200343030423/LeetCode_191_423.java @@ -0,0 +1,14 @@ +public class LeetCode_191_423 { +} + +class Solution191 { + // you need to treat n as an unsigned value + public int hammingWeight(int n) { + int sum = 0; + while (n != 0) { + sum ++; + n = n & (n-1); + } + return sum; + } +} \ No newline at end of file diff --git a/Week_07/G20200343030423/LeetCode_231_423.java b/Week_07/G20200343030423/LeetCode_231_423.java new file mode 100644 index 00000000..09ce7e2a --- /dev/null +++ b/Week_07/G20200343030423/LeetCode_231_423.java @@ -0,0 +1,14 @@ +public class LeetCode_231_423 { +} + +class Solution231 { + public boolean isPowerOfTwo(int n) { + if (n == 0) + return false; + long t = n; + if ((t & (-t)) == t) { + return true; + } + return false; + } +} \ No newline at end of file diff --git a/Week_07/G20200343030425/LeetCode_1122_425/LeetCode_1122_425.js b/Week_07/G20200343030425/LeetCode_1122_425/LeetCode_1122_425.js new file mode 100644 index 00000000..c9e84772 --- /dev/null +++ b/Week_07/G20200343030425/LeetCode_1122_425/LeetCode_1122_425.js @@ -0,0 +1,20 @@ +/* +* address : https://leetcode-cn.com/problems/relative-sort-array/ +* */ + + +const relativeSortArray = function(arr1, arr2) { + return arr1.sort((a, b) => { + let ia = arr2.indexOf(a); + let ib = arr2.indexOf(b); + if(ia === -1 && ib === -1) { + return a - b; + } else if (ia === -1) { + return 1; + } else if (ib === -1) { + return -1; + } else { + return ia-ib; + } + }); +}; diff --git a/Week_07/G20200343030425/LeetCode_231_425/LeetCode_231_425.js b/Week_07/G20200343030425/LeetCode_231_425/LeetCode_231_425.js new file mode 100644 index 00000000..3e44e7a3 --- /dev/null +++ b/Week_07/G20200343030425/LeetCode_231_425/LeetCode_231_425.js @@ -0,0 +1,6 @@ +/* +* address: https://leetcode-cn.com/problems/power-of-two/ +* */ +const isPowerOfTwo = function(n) { + return Number.isInteger(Math.log2(n)); +}; diff --git a/Week_07/G20200343030429/LeetCode_2_429.java b/Week_07/G20200343030429/LeetCode_2_429.java new file mode 100644 index 00000000..1145103a --- /dev/null +++ b/Week_07/G20200343030429/LeetCode_2_429.java @@ -0,0 +1,12 @@ +package com.study.week07; + +public class LeetCode_2_429 { + /** + * 神奇的运算 + * @param n + * @return + */ + public boolean isPowerOfTwo(int n) { + return n > 0 && (n & (n - 1)) == 0; + } +} \ No newline at end of file diff --git a/Week_07/G20200343030429/LeetCode_5_429.java b/Week_07/G20200343030429/LeetCode_5_429.java new file mode 100644 index 00000000..4cce8845 --- /dev/null +++ b/Week_07/G20200343030429/LeetCode_5_429.java @@ -0,0 +1,32 @@ +package com.study.week07; + +public class LeetCode_2_429 { + /** + * 数组相对排序 + * @param n + * @return + */ + public int[] relativeSortArray(int[] arr1, int[] arr2) { + int[] temp = new int[1001]; + for (int i : arr1) { + temp[i]++; + } + int index = 0; + for (int i : arr2) { + while (temp[i] > 0) { + arr1[index] = i; + temp[i]--; + index++; + } + } + + for (int i = 0; i < temp.length; i++) { + while (temp[i] > 0) { + arr1[index] = i; + temp[i]--; + index++; + } + } + return arr1; + } +} \ No newline at end of file diff --git a/Week_07/G20200343030431/LRU.md b/Week_07/G20200343030431/LRU.md new file mode 100644 index 00000000..f3c74c51 --- /dev/null +++ b/Week_07/G20200343030431/LRU.md @@ -0,0 +1,14 @@ +LRU全称是Least Recently Used,即最近最久未使用的意思。 + +LRU算法的设计原则是:如果一个数据在最近一段时间没有被访问到,那么在将来它被访问的可能性也很小。也就是说,当限定的空间已存满数据时,应当把最久没有被访问到的数据淘汰。 +实现LRU +      +1.用一个数组来存储数据,给每一个数据项标记一个访问时间戳,每次插入新数据项的时候,先把数组中存在的数据项的时间戳自增,并将新数据项的时间戳置为0并插入到数组中。 +每次访问数组中的数据项的时候,将被访问的数据项的时间戳置为0。当数组空间已满时,将时间戳最大的数据项淘汰。 + +2.利用一个链表来实现,每次新插入数据的时候将新数据插到链表的头部;每次缓存命中(即数据被访问), +则将数据移到链表头部;那么当链表满的时候,就将链表尾部的数据丢弃。 + +3.利用链表和hashmap。当需要插入新的数据项的时候,如果新数据项在链表中存在(一般称为命中),则把该节点移到链表头部 +,如果不存在,则新建一个节点,放到链表头部,若缓存满了,则把链表最后一个节点删除即可。在访问数据的时候,如果数据项在链表中存在,则把该节点移到链表头部,否则返回-1。 +这样一来在链表尾部的节点就是最近最久未访问的数据项。 diff --git a/Week_07/G20200343030431/LeetCode_190_431.java b/Week_07/G20200343030431/LeetCode_190_431.java new file mode 100644 index 00000000..91fc1d85 --- /dev/null +++ b/Week_07/G20200343030431/LeetCode_190_431.java @@ -0,0 +1,15 @@ +package Alogrithm0308; + +public class Solution190 { + // you need treat n as an unsigned value + public int reverseBits(int n) { + int ans = 0; + for (int bitsSize = 31; n != 0; n = n >>> 1, bitsSize--) { + ans += (n & 1) << bitsSize; + } + return ans; + } + } + + + diff --git a/Week_07/G20200343030431/LeetCode_56_431.java b/Week_07/G20200343030431/LeetCode_56_431.java new file mode 100644 index 00000000..758a2833 --- /dev/null +++ b/Week_07/G20200343030431/LeetCode_56_431.java @@ -0,0 +1,28 @@ +package Alogrithm0308; + +import java.util.Arrays; +import java.util.Comparator; +import java.util.LinkedList; + +public class Solution56 { + + public int[][] merge(int[][] arr) { + Arrays.parallelSort(arr, Comparator.comparingInt(x -> x[0])); + + LinkedList list = new LinkedList<>(); + for (int i = 0; i < arr.length; i++) { + if (list.size() == 0 || list.getLast()[1] < arr[i][0]) { + list.add(arr[i]);//集合为空,或不满足条件,向后新增 + } else {//满足条件,集合最后元素的end=最大值 + list.getLast()[1] = Math.max(list.getLast()[1], arr[i][1]); + } + } + int[][] res = new int[list.size()][2];//生成结果数组 + int index = 0; + while (!list.isEmpty()) {//遍历集合 + res[index++] = list.removeFirst();//删除集合首元素 + } + return res; + } + } + diff --git a/Week_07/G20200343030433/week7_493_433 b/Week_07/G20200343030433/week7_493_433 new file mode 100644 index 00000000..b5a5e2b2 --- /dev/null +++ b/Week_07/G20200343030433/week7_493_433 @@ -0,0 +1,19 @@ +class Solution { + int merge_sort(vector&nums,int L,int R){ + if(R-L<=1) return 0; + int mid=L+(R-L>>1); + int count=merge_sort(nums,L,mid)+merge_sort(nums,mid,R); + int right=mid; + for(int left=L;left2*(long)nums[right]) ++right; + count+=right-mid; + } + inplace_merge(nums.begin()+L,nums.begin()+mid,nums.begin()+R); + return count; + } +public: + int reversePairs(vector& nums) { + return merge_sort(nums,0,nums.size()); + } +}; + diff --git a/Week_07/G20200343030433/week7_56_433 b/Week_07/G20200343030433/week7_56_433 new file mode 100644 index 00000000..bf040135 --- /dev/null +++ b/Week_07/G20200343030433/week7_56_433 @@ -0,0 +1,18 @@ +class Solution { +public: + vector> merge(vector>& intervals) { + if (!intervals.size()) return {}; + sort(intervals.begin(), intervals.end(), less>()); + int pos = 0; + for (int i = 1; i < intervals.size(); ++i) { + if (intervals[pos][1] >= intervals[i][0]) { + intervals[pos][1] = max(intervals[pos][1], intervals[i][1]); + } else { + intervals[++pos] = intervals[i]; + } + } + intervals.resize(pos+1); + return intervals; + } +}; + diff --git a/Week_07/G20200343030435/LeetCode_56_435.js b/Week_07/G20200343030435/LeetCode_56_435.js new file mode 100644 index 00000000..4cd747c1 --- /dev/null +++ b/Week_07/G20200343030435/LeetCode_56_435.js @@ -0,0 +1,16 @@ +var merge = function(intervals) { + if (!intervals || !intervals.length) return []; + intervals.sort((a, b) => a[0] - b[0]); + let ans = [intervals[0]]; + for (let i = 1; i < intervals.length; i++) { + if (ans[ans.length - 1][1] >= intervals[i][0]) { + ans[ans.length - 1][1] = Math.max( + ans[ans.length - 1][1], + intervals[i][1] + ); + } else { + ans.push(intervals[i]); + } + } + return ans; +}; diff --git a/Week_07/G20200343030435/LeetCode_74_435.js b/Week_07/G20200343030435/LeetCode_74_435.js new file mode 100644 index 00000000..538d51fc --- /dev/null +++ b/Week_07/G20200343030435/LeetCode_74_435.js @@ -0,0 +1,11 @@ +let isAnagram = function(s, t) { + if (s.length !== t.length) { + return false; + } + for (const item of t) { + if (s.indexOf(item) !== -1) { + s = s.replace(item, ""); + } + } + return s === ""; +}; diff --git a/Week_07/G20200343030437/lru-cache b/Week_07/G20200343030437/lru-cache new file mode 100644 index 00000000..9bb295f0 --- /dev/null +++ b/Week_07/G20200343030437/lru-cache @@ -0,0 +1,27 @@ +class LRUCache { + LinkedHashMap map; + public LRUCache(int capacity) { + map = new LinkedHashMap(16,0.75f,true){ + @Override + protected boolean removeEldestEntry(Map.Entry eldest) { + return size()>capacity; + } + }; + } + + public int get(int key) { + if(map.containsKey(key)) return (Integer)map.get(key); + return -1; + } + + public void put(int key, int value) { + map.put(key,value); + } +} + +/** + * Your LRUCache object will be instantiated and called as such: + * LRUCache obj = new LRUCache(capacity); + * int param_1 = obj.get(key); + * obj.put(key,value); + */ diff --git a/Week_07/G20200343030437/merge-sort.java b/Week_07/G20200343030437/merge-sort.java new file mode 100644 index 00000000..442ec36d --- /dev/null +++ b/Week_07/G20200343030437/merge-sort.java @@ -0,0 +1,25 @@ +public static void mergeSort(int[] array, int left, int right) { + if (right <= left) return; + int mid = (left + right) >> 1; // (left + right) / 2 + + mergeSort(array, left, mid); + mergeSort(array, mid + 1, right); + merge(array, left, mid, right); +} + +public static void merge(int[] arr, int left, int mid, int right) { + int[] temp = new int[right - left + 1]; // 中间数组 + int i = left, j = mid + 1, k = 0; + + while (i <= mid && j <= right) { + temp[k++] = arr[i] <= arr[j] ? arr[i++] : arr[j++]; + } + + while (i <= mid) temp[k++] = arr[i++]; + while (j <= right) temp[k++] = arr[j++]; + + for (int p = 0; p < temp.length; p++) { + arr[left + p] = temp[p]; + } + // 也可以用 System.arraycopy(a, start1, b, start2, length) + } diff --git a/Week_07/G20200343030437/reverse-bits.java b/Week_07/G20200343030437/reverse-bits.java new file mode 100644 index 00000000..7966f1f7 --- /dev/null +++ b/Week_07/G20200343030437/reverse-bits.java @@ -0,0 +1,11 @@ +public class Solution { + // you need treat n as an unsigned value + public int reverseBits(int n) { + int result = 0; + for (int m=31; n!=0; m--) { + result += (n&1) << m; + n >>>= 1; + } + return result; + } +} diff --git a/Week_07/G20200343030439/LeetCode_190_439.java b/Week_07/G20200343030439/LeetCode_190_439.java new file mode 100644 index 00000000..5b77fa44 --- /dev/null +++ b/Week_07/G20200343030439/LeetCode_190_439.java @@ -0,0 +1,24 @@ +/* + * @lc app=leetcode.cn id=190 lang=java + * + * [190] 颠倒二进制位 + * + * https://leetcode-cn.com/problems/reverse-bits/description/ + * + */ + +// @lc code=start +class Solution { + // you need treat n as an unsigned value + public int reverseBits(int n) { + int result = 0; + for (int i = 0; i <= 32; i++) { + int tmp = n >> i; + tmp = tmp & 1; + tmp = tmp << (31 - i); + result |= tmp; + } + return result; + } +} +// @lc code=end diff --git a/Week_07/G20200343030439/LeetCode_191_439.java b/Week_07/G20200343030439/LeetCode_191_439.java new file mode 100644 index 00000000..f200d2cc --- /dev/null +++ b/Week_07/G20200343030439/LeetCode_191_439.java @@ -0,0 +1,22 @@ +/* + * @lc app=leetcode.cn id=191 lang=java + * + * [191] 位1的个数 + * + * https://leetcode-cn.com/problems/number-of-1-bits/description/ + * + */ + +// @lc code=start +class Solution { + // you need to treat n as an unsigned value + public static int hammingWeight(int n) { + int sum = 0; + while (n != 0) { + sum++; + n &= (n - 1); + } + return sum; + } +} +// @lc code=end diff --git a/Week_07/G20200343030439/LeetCode_231_439.java b/Week_07/G20200343030439/LeetCode_231_439.java new file mode 100644 index 00000000..f11b97ce --- /dev/null +++ b/Week_07/G20200343030439/LeetCode_231_439.java @@ -0,0 +1,20 @@ +/* + * @lc app=leetcode.cn id=231 lang=java + * + * [231] 2的幂 + * + * https://leetcode-cn.com/problems/power-of-two/description/ + * + */ + +// @lc code=start +class Solution { + public boolean isPowerOfTwo(int n) { + if (n == 0) + return false; + long x = (long) n; + return (x & (x - 1)) == 0; + } +} + +// @lc code=end diff --git a/Week_07/G20200343030441/LeetCode_1122_441.java b/Week_07/G20200343030441/LeetCode_1122_441.java new file mode 100644 index 00000000..724a7645 --- /dev/null +++ b/Week_07/G20200343030441/LeetCode_1122_441.java @@ -0,0 +1,61 @@ +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/* + * @lc app=leetcode.cn id=1122 lang=java + * + * [1122] 数组的相对排序 + */ + +// @lc code=start +class Solution { + public int[] relativeSortArray(int[] arr1, int[] arr2) { + // List not_in = new ArrayList<>(); + // Map arrCount = new HashMap<>(); + // for (int i : arr2) arrCount.put(i, 0); + // for (int i : arr1){ + // if (arrCount.containsKey(i)) arrCount.put(i, arrCount.get(i)+1); + // else not_in.add(i); + // } + // List res = new ArrayList<>(); + // for (int i : arr2){ + // int temp = arrCount.get(i); + // for(int j = 0; j < temp; ++j) res.add(i); + // } + + // Collections.sort(not_in); + // for (int i : not_in) res.add(i); + // int[] resArr = new int[res.size()]; + // for (int i = 0; i < res.size(); ++i) resArr[i] = res.get(i); + // return resArr; + + // 国内站牛牛的方案 + int[] nums = new int[1001]; + int[] res = new int[arr1.length]; + //遍历arr1,统计每个元素的数量 + for (int i : arr1) { + nums[i]++; + } + //遍历arr2,处理arr2中出现的元素 + int index = 0; + for (int i : arr2) { + while (nums[i]>0){ + res[index++] = i; + nums[i]--; + } + } + //遍历nums,处理剩下arr2中未出现的元素 + for (int i = 0; i < nums.length; i++) { + while (nums[i]>0){ + res[index++] = i; + nums[i]--; + } + } + return res; + } +} +// @lc code=end + diff --git a/Week_07/G20200343030441/LeetCode_190_441.java b/Week_07/G20200343030441/LeetCode_190_441.java new file mode 100644 index 00000000..3859c48e --- /dev/null +++ b/Week_07/G20200343030441/LeetCode_190_441.java @@ -0,0 +1,33 @@ +/* + * @lc app=leetcode.cn id=190 lang=java + * + * [190] 颠倒二进制位 + */ + +// @lc code=start +public class Solution { + // you need treat n as an unsigned value + public int reverseBits(int n) { + + // int ans = 0; + // int i = 32; + // while (i != 0){ + // i--; + // ans <<= 1; + // ans += n & 1; + // n >>>= 1; + // } + // return ans; + + + // java源码 Integer.reverse + n = (n & 0x55555555) << 1 | (n >>> 1) & 0x55555555; + n = (n & 0x33333333) << 2 | (n >>> 2) & 0x33333333; + n = (n & 0x0f0f0f0f) << 4 | (n >>> 4) & 0x0f0f0f0f; + n = (n << 24) | ((n & 0xff00) << 8) | + ((n >>> 8) & 0xff00) | (n >>> 24); + return n; + } +} +// @lc code=end + diff --git a/Week_07/G20200343030441/LeetCode_191_441.java b/Week_07/G20200343030441/LeetCode_191_441.java new file mode 100644 index 00000000..b463f131 --- /dev/null +++ b/Week_07/G20200343030441/LeetCode_191_441.java @@ -0,0 +1,21 @@ +/* + * @lc app=leetcode.cn id=191 lang=java + * + * [191] 位1的个数 + */ + +// @lc code=start +public class Solution { + // you need to treat n as an unsigned value + // >>> 为无符号位移,高位补 0;>> 为有符号位移,正数高位补 0,负数高位补 1; + public int hammingWeight(int n) { + int count = 0; + while(n != 0){ + if ((n & 1) == 1) count++; + n >>>= 1; + } + return count; + } +} +// @lc code=end + diff --git a/Week_07/G20200343030441/LeetCode_231_441.java b/Week_07/G20200343030441/LeetCode_231_441.java new file mode 100644 index 00000000..bf2af21c --- /dev/null +++ b/Week_07/G20200343030441/LeetCode_231_441.java @@ -0,0 +1,16 @@ +/* + * @lc app=leetcode.cn id=231 lang=java + * + * [231] 2的幂 + */ + +// @lc code=start +class Solution { + public boolean isPowerOfTwo(int n) { + if (n <= 0) return false; + if ((n & n-1) == 0) return true; + return false; + } +} +// @lc code=end + diff --git a/Week_07/G20200343030441/LeetCode_242_441.java b/Week_07/G20200343030441/LeetCode_242_441.java new file mode 100644 index 00000000..ddc7a6cb --- /dev/null +++ b/Week_07/G20200343030441/LeetCode_242_441.java @@ -0,0 +1,38 @@ +import java.util.Arrays; + +/* + * @lc app=leetcode.cn id=242 lang=java + * + * [242] 有效的字母异位词 + */ + +// @lc code=start +class Solution { + // 排序 + public boolean isAnagram(String s, String t) { + char[] c1 = s.toCharArray(); + Arrays.sort(c1); + char[] c2 = t.toCharArray(); + Arrays.sort(c2); + // if (c1.length != c2.length) return false; + // for (int i = 0; i < c1.length; ++i) if (c1[i] != c2[i]) return false; + // return true; + return String.valueOf(c1).equals(String.valueOf(c2)); + } + + // 题解的一种,效率也不高 + // public boolean isAnagram(String s, String t) { + // if (s.length() != t.length()) return false; + // int[] nums1 = new int[26]; + + // for (int i = 0; i < s.length(); ++i){ + // nums1[s.charAt(i)-'a']++; + // nums1[t.charAt(i)-'a']--; + // } + + // for (int i : nums1) if (i!=0) return false; + // return true; + // } +} +// @lc code=end + diff --git a/Week_07/G20200343030445/LeetCode_1122_445.py b/Week_07/G20200343030445/LeetCode_1122_445.py new file mode 100644 index 00000000..4deee608 --- /dev/null +++ b/Week_07/G20200343030445/LeetCode_1122_445.py @@ -0,0 +1,37 @@ +# +# @lc app=leetcode.cn id=1122 lang=python3 +# +# [1122] 数组的相对排序 +# + +# @lc code=start +class Solution: + def relativeSortArray(self, arr1: List[int], arr2: List[int]) -> List[int]: + ans = [] + for item in arr2: + ans += [item] * arr1.count(item) + left = [] + for item in arr1: + if item not in arr2: + left.append(item) + ans += sorted(left) + return ans + + # 用桶排序的答案: + # arr = [0 for _ in range(1001)] # 由于题目说arr1的范围在0-1000,所以生成一个1001大小的数组用来存放每个数出现的次数。 + # ans = [] # 储存答案的数组。 + # for i in range(len(arr1)): # 遍历arr1,把整个arr1的数的出现次数储存在arr上,arr的下标对应arr1的值,arr的值对应arr1中值出现的次数。 + # arr[arr1[i]] += 1 # 如果遇到了这个数,就把和它值一样的下标位置上+1,表示这个数在这个下标i上出现了1次。 + # for i in range(len(arr2)): # 遍历arr2,现在开始要输出答案了。 + # while arr[arr2[i]] > 0: # 如果arr2的值在arr所对应的下标位置出现次数大于0,那么就说明arr中的这个位置存在值。 + # ans.append(arr2[i]) # 如果存在值,那就把它加到ans中,因为要按arr2的顺序排序。 + # arr[arr2[i]] -= 1 # 加进去了次数 -1 ,不然就死循环了。 + # for i in range(len(arr)): # 如果arr1的值不在arr2中,那么不能就这么结束了,因为题目说了如果不在,剩下的值按照升序排序。 + # while arr[i] > 0: # 同样也是找到大于0的下标,然后一直加到ans中,直到次数为0。 + # ans.append(i) + # arr[i] -= 1 + # return ans # 返回最终答案。 + + +# @lc code=end + diff --git a/Week_07/G20200343030445/LeetCode_190_445.py b/Week_07/G20200343030445/LeetCode_190_445.py new file mode 100644 index 00000000..d4e51e30 --- /dev/null +++ b/Week_07/G20200343030445/LeetCode_190_445.py @@ -0,0 +1,20 @@ +# +# @lc app=leetcode.cn id=190 lang=python3 +# +# [190] 颠倒二进制位 +# + +# @lc code=start +class Solution: + def reverseBits(self, n: int) -> int: + ans, mask = 0, 1 + for i in range(32): + if n & mask: + ans |= 1 << (31 - i) + # bit LOOP:: 从最右边开始一个个看 + mask <<= 1 + + return ans + +# @lc code=end + diff --git a/Week_07/G20200343030445/LeetCode_56_445.py b/Week_07/G20200343030445/LeetCode_56_445.py new file mode 100644 index 00000000..69c4a6e7 --- /dev/null +++ b/Week_07/G20200343030445/LeetCode_56_445.py @@ -0,0 +1,27 @@ +# +# @lc app=leetcode.cn id=56 lang=python3 +# +# [56] 合并区间 +# + +# @lc code=start +class Solution: + def merge(self, intervals: List[List[int]]) -> List[List[int]]: + if not intervals: + return [] + output = [] + intervals.sort() + left = intervals[0][0] + right = intervals[0][1] + for i in range(len(intervals)): + if intervals[i][0] > right: + if [left, right] not in output: + output.append([left, right]) + left = intervals[i][0] + right = intervals[i][1] + if intervals[i][0] <= right and intervals[i][1] > right: + right = intervals[i][1] + output.append([left, right]) + return output +# @lc code=end + diff --git a/Week_07/G20200343030449/LeetCode_191_449.cpp b/Week_07/G20200343030449/LeetCode_191_449.cpp new file mode 100644 index 00000000..e7c5f9a6 --- /dev/null +++ b/Week_07/G20200343030449/LeetCode_191_449.cpp @@ -0,0 +1,16 @@ +class Solution { +public: + int hammingWeight(uint32_t n) { + int count = 0; + uint32_t mask = 1; + + for (int i=0;i<32;i++) { + mask = 1< &lhs, const vector &rhs) { + for (int i=0;irhs[i]) return false; + if (lhs[i]> merge(vector>& intervals) { + vector> ans; + sort(intervals.begin(),intervals.end(),internalCompare); + + vector current; + + for (int i=0;i &a, const vector &b) { + if (a[1] < b[0]) { + return false; + } + + if (a[1] < b[1]) a[1] = b[1]; + + return true; + } +}; diff --git a/Week_07/G20200343030451/LeetCode_190_451.cpp b/Week_07/G20200343030451/LeetCode_190_451.cpp new file mode 100644 index 00000000..c370d00b --- /dev/null +++ b/Week_07/G20200343030451/LeetCode_190_451.cpp @@ -0,0 +1,12 @@ +class Solution { +public: + uint32_t reverseBits(uint32_t n) { + uint32_t result = 0; + for ( int i = 0; i < 32; i++ ) { + result <<=1; + result += n & 1; + n >>=1; + } + return result; + } +}; diff --git a/Week_07/G20200343030451/LeetCode_191_451.cpp b/Week_07/G20200343030451/LeetCode_191_451.cpp new file mode 100644 index 00000000..3667beba --- /dev/null +++ b/Week_07/G20200343030451/LeetCode_191_451.cpp @@ -0,0 +1,14 @@ +class Solution { +public: + int hammingWeight(uint32_t n) { + int bits = 0; + uint32_t mask = 1; + for (int i = 0; i < 32; i++) { + if (( n & mask ) != 0) { + bits++; + } + mask = mask << 1; + } + return bits; + } +}; diff --git a/Week_07/G20200343030451/NOTE.md b/Week_07/G20200343030451/NOTE.md index 50de3041..746207e4 100644 --- a/Week_07/G20200343030451/NOTE.md +++ b/Week_07/G20200343030451/NOTE.md @@ -1 +1,36 @@ -学习笔记 \ No newline at end of file +学习笔记 + + + +介绍 + +- 程序中所有数在内存中以二进制形式储存 + +- 位运算就是直接对证书在内存中的二进制位进行操作 + +- 不需要转换成十进制,处理速度快 + + 可以应用到其中的算法的内容 + +1. 学习字典树 +2. 利用并查集解决问题 +3. AVL树的左旋、右旋、左右旋、右左旋 + + + + + + + + + + + + + + + + + + + diff --git a/Week_07/G20200343030453/LeetCode_146_453 b/Week_07/G20200343030453/LeetCode_146_453 new file mode 100755 index 00000000..f48e60d6 --- /dev/null +++ b/Week_07/G20200343030453/LeetCode_146_453 @@ -0,0 +1,56 @@ +// 146. LRU缓存机制 +// 方式一 使用C++ list 双链表实现 LRU Cache +class LRUCache { + int capacity; + struct Node { + int key; + int value; + }; + list list; +public: + LRUCache(int capacity) { + this->capacity = capacity; + } + + int get(int key) { + auto it = list.begin(); + for(; it != list.end(); it++) { + if(it->key == key) { + break; + } + } + if(it != list.end()) { + Node temp = *it; + list.erase(it); + list.push_front(temp); + return temp.value; + } + return -1; + } + + void put(int key, int value) { + Node temp; + temp.key = key; + temp.value = value; + int size = list.size(); + auto it = list.begin(); + for(; it != list.end(); it++) { + if(it->key == key) { + break; + } + } + if(it != list.end()) { + list.erase(it); + list.push_front(temp); + } + else { + if(size == capacity) { + list.pop_back(); + list.push_front(temp); + } + else { + list.push_front(temp); + } + } + } +}; \ No newline at end of file diff --git a/Week_07/G20200343030453/LeetCode_191_453 b/Week_07/G20200343030453/LeetCode_191_453 new file mode 100755 index 00000000..d7f48137 --- /dev/null +++ b/Week_07/G20200343030453/LeetCode_191_453 @@ -0,0 +1,47 @@ +// 191. 位1的个数 +// 编写一个函数,输入是一个无符号整数,返回其二进制表达式中字位数为 ‘1’ 的个数 +class Solution { +public: + // 方式一 统计 n % 2 == 1 的个数 + int hammingWeight(uint32_t n) { + int counter = 0; + while(n != 0) { + if(n % 2 == 1) { + counter++; + } + n = n >> 1; + } + return counter; + } + // 方式二 遍历每一位和位1求与,统计不为0的个数 + int hammingWeight_2(uint32_t n) { + int counter = 0; + uint32_t onebit = 1; + for(int i = 0; i < 32; i++) { + if((n & onebit) != 0) { + counter++; + } + onebit <<= 1; + } + return counter; + } + // 方式三 n & (n-1) + /* + 8 1000 + & -> 0 有1个1 + 7 0111 + + 15 01111 01110 01100 01000 + & -> 01110 & -> 01100 & -> 01000 & -> 0 有4个1 + 14 01110 01101 01011 00111 + */ + int hammingWeight_3(uint32_t n) { + int counter = 0; + while(n != 0) { + counter++; + n &= n - 1; + } + return counter; + } +}; + diff --git a/Week_07/G20200343030453/NOTE.md b/Week_07/G20200343030453/NOTE.md old mode 100644 new mode 100755 index 50de3041..5c015df2 --- a/Week_07/G20200343030453/NOTE.md +++ b/Week_07/G20200343030453/NOTE.md @@ -1 +1,3 @@ -学习笔记 \ No newline at end of file +学习笔记 + +2020-3-29 Sunday \ No newline at end of file diff --git "a/Week_07/G20200343030459/191.\344\275\215-1-\347\232\204\344\270\252\346\225\260.py" "b/Week_07/G20200343030459/191.\344\275\215-1-\347\232\204\344\270\252\346\225\260.py" new file mode 100644 index 00000000..1993506e --- /dev/null +++ "b/Week_07/G20200343030459/191.\344\275\215-1-\347\232\204\344\270\252\346\225\260.py" @@ -0,0 +1,66 @@ +# +# @lc app=leetcode.cn id=191 lang=python3 +# +# [191] 位1的个数 +# +# https://leetcode-cn.com/problems/number-of-1-bits/description/ +# +# algorithms +# Easy (65.57%) +# Likes: 148 +# Dislikes: 0 +# Total Accepted: 53.7K +# Total Submissions: 81.6K +# Testcase Example: '00000000000000000000000000001011' +# +# 编写一个函数,输入是一个无符号整数,返回其二进制表达式中数字位数为 ‘1’ 的个数(也被称为汉明重量)。 +# +# +# +# 示例 1: +# +# 输入:00000000000000000000000000001011 +# 输出:3 +# 解释:输入的二进制串 00000000000000000000000000001011 中,共有三位为 '1'。 +# +# +# 示例 2: +# +# 输入:00000000000000000000000010000000 +# 输出:1 +# 解释:输入的二进制串 00000000000000000000000010000000 中,共有一位为 '1'。 +# +# +# 示例 3: +# +# 输入:11111111111111111111111111111101 +# 输出:31 +# 解释:输入的二进制串 11111111111111111111111111111101 中,共有 31 位为 '1'。 +# +# +# +# 提示: +# +# +# 请注意,在某些语言(如 +# Java)中,没有无符号整数类型。在这种情况下,输入和输出都将被指定为有符号整数类型,并且不应影响您的实现,因为无论整数是有符号的还是无符号的,其内部的二进制表示形式都是相同的。 +# 在 Java 中,编译器使用二进制补码记法来表示有符号整数。因此,在上面的 示例 3 中,输入表示有符号整数 -3。 +# +# +# +# +# 进阶: +# 如果多次调用这个函数,你将如何优化你的算法? +# +# + +# @lc code=start +class Solution: + def hammingWeight(self, n: int) -> int: + count = 0 + while n != 0: + n = n & (n - 1) + count += 1 + return count +# @lc code=end + diff --git a/Week_07/G20200343030463/463-Week 07/LeetCode_146_463.cpp b/Week_07/G20200343030463/463-Week 07/LeetCode_146_463.cpp new file mode 100644 index 00000000..85fb5710 --- /dev/null +++ b/Week_07/G20200343030463/463-Week 07/LeetCode_146_463.cpp @@ -0,0 +1,73 @@ +学习笔记 + +class Node{ +public: + Node* pre; + Node* next; + int key, val; + Node(int key, int val):key(key),val(val){ + pre = NULL; + next = NULL; + } +}; +class LRUCache { +public: + unordered_map mp; + Node* head; + Node* tail; + int cap; + + LRUCache(int capacity) { + this->cap = capacity; + head=new Node(0,0); + tail = new Node(0,0); + head->next=tail; + tail->pre = head; + } + void addtoTail(Node* n){ + tail->pre->next=n; + n->pre=tail->pre; + n->next=tail; + tail->pre=n; + } + + int get(int key) { + if(mp.find(key)!=mp.end()){ + Node* cur = mp[key]; + if(cur){ + cur->pre->next=cur->next; + cur->next->pre=cur->pre; + addtoTail(cur); + return cur->val; + } + } + return -1; + } + + void put(int key, int value) { + if(mp.find(key)!=mp.end()){ + Node* cur = mp[key]; + if(cur){ + cur->val=value; + mp[key]=cur; + cur->pre->next=cur->next; + cur->next->pre=cur->pre; + addtoTail(cur); + return; + } + } + + if(mp.size()==cap){ + Node* tmp = head->next; + //head->next->next->pre=head; + head->next=head->next->next; + head->next->pre=head; + mp.erase(tmp->key); + } + Node* cur= new Node(key,value); + addtoTail(cur); + mp[key]=cur; + + } +}; + diff --git a/Week_07/G20200343030463/463-Week 07/LeetCode_190_463.cpp b/Week_07/G20200343030463/463-Week 07/LeetCode_190_463.cpp new file mode 100644 index 00000000..311e995e --- /dev/null +++ b/Week_07/G20200343030463/463-Week 07/LeetCode_190_463.cpp @@ -0,0 +1,28 @@ +学习笔记 +暴力求解:数组前后转换 +class Solution { +public: + uint32_t reverseBits(uint32_t n) { + bitset<32> bs{n}; + int l{0}, r{31}; + while(l < r) { + bool tmp = bs[l]; + bs[l++] = bs[r]; + bs[r--] = tmp; + } + return bs.to_ulong(); + } +}; +位运算: 获取到n的最后一位将其移动到最高位,每次n都要右移一位将最后一个数清除 最后将结果加起来 移动位数也要减一 + + +class Solution { +public: + uint32_t reverseBits(uint32_t n) { + int ans = 0; + for(int bitSize =31;n!=0;n>>=1,bitSize--){ + ans +=(n&1)<> merge(vector>& intervals) { + if (intervals.size() == 0 || intervals.size() == 1) return intervals; + + int u = 0, v = 0; + vector> ans; + + std::sort(intervals.begin(), intervals.end()); + + while (v < intervals.size()) { + if (intervals[v][0] > intervals[u][1]) { + ans.emplace_back(intervals[u]); + u = v; + } else if (intervals[v][1] <= intervals[u][1]) { + ++ v; + } else { + intervals[u][1] = intervals[v][1]; + ++ v; + } + } + + ans.emplace_back(intervals[u]); + return ans; + + } +}; diff --git a/Week_07/G20200343030463/NOTE.md b/Week_07/G20200343030463/NOTE.md index 50de3041..142f0d18 100644 --- a/Week_07/G20200343030463/NOTE.md +++ b/Week_07/G20200343030463/NOTE.md @@ -1 +1,308 @@ -学习笔记 \ No newline at end of file +学习笔记:排序算法 +001冒泡排序 +vector bubbleSort(vector arr){ +int len = arr.size(); +for(int i =0; i< len;i++){ +for (int j = 0; j < len -1; j++) +{ +int temp = arr[j+1]; +arr[j+1] = arr[j]; +arr[j+1] = temp; +} + +} +return arr; +} + +002 选择排序 +vector selectionSort(vector arr){ +int len = arr.size(); +int minIndex,temp; +for (size_t i = 0; i < len; i++) +{ +minIndex = i; +for (size_t j = 0; i len; j++) +{ +if(arr[j] insertionSort(vector arr){ +int len = arr.size(); +int preIndx,current; +for (size_t i = 1; i < len; i++) +{ +preIndex = i-1; +current = arr[i]; +while (preIndex >=0 && arr[preIndex] > current) +{ +arr[preIndex +1] = arr[preIndex]; +preIndex --; +} + +arr[preIndex +1] = current; +} + +return arr; + +} + +004 希尔排序 + +vector shellSort(vector arr){ +int len = arr.size(); +int gap = len /2; +int i,j; +for (; gap>0; gap/=2) +{ +for ( i=gap; i < len; i++) +{ +int num = arr[i]; +for ( j = i - gap; j>=0&&arr[j]>num; j-=gap) +{ +arr[j+gap] = arr[j]; +} +arr[j+gap] = num; +} + +} + +return arr; + +} + +005 归并排序 +void merge(int *A,int *L, int leftCount, int *R,int rightCount){ +int i,j,k; +i = 0;j=0,k=0; +while (i < leftCount && j < rightCount) +{ +if(L[i] < R[i]) +A[k++] = L[i++]; +else +A[k++] = L[j++]; +} +while (iarr[largest]) largest = l; + +if(r arr[largest]) largest = r; + +if(largest != i){ +swap(arr[i],arr[largest]); +heapify(arr,n,largest); +} +} + +void heapSort(int arr[],int n){ + +for (int i = n; i < n/2-1; i>=0;i--) +{ +heapify(arr,n,i); +} + +for (int i = n-1; i>=0; i--) +{ +swap(arr[0],arr[i]); +heapify(arr,i,0); +} + + +} + +008 计数排序 +#define RANGE 255 + +void countSort(char arr[]){ +char output[strlen(arr)]; +int count[RANGE +1],i; +for (int i = 0; i < arr[i]; ++i) +{ +++count[arr[i]]; +} + +for (int i = 0; i < RANGE; ++i) +{ +count[i] += count[i--]; +} + +for(i =0; arr[i];++i){ +output[count[arr[i]-1] -1] = arr[i]; +--count[arr[i]]; +} + +for (int i = 0; arr[i]; ++i) +{ +arr[i] = output[i]; +} + +} + +009 桶排序 +void bucketSort(int arr[],int n){ +// 1) Create n empty buckets +vector b[n]; +// 2) Put array elements in different buckets +for (int i = 0; i < n; i++) +{ +int bi = n*arr[i]; +b[bi].push_back(arr[i]); +} +// 3) Sort individual buckets +for (int i = 0; i < n; i++) +{ +sort(b[i].begin(),b[i].end()); +} +// 4) Concatenate all buckets into arr[] +int index = 0; +for (int i = 0; i < n; i++) +{ +for (int j = 0; j < b[i].size(); j++) +{ +arr[index++] = b[i][j]; +} + +} + +} + +010基数排序 +void radixsort(int arr[],int n){ +int m = getMax(arr,n); +for (int exp = 1; m/exp >0; exp *=10) +{ +countSort(arr,n,exp); +} + +} + +int getMax(int arr[],int n){ +int mx = arr[0]; +for (int i = 1; i < n; i++) +{ +if(arr[i]>mx){ +mx = arr[i]; +} +} +return mx; + +} + +void countSort(int arr[], int n, int exp){ +int output[n]; +int i, count[10] = {0}; + +for (int i = 0; i < n; i++) +{ +count[(arr[i]/exp)%10]++; +} + +for ( i = 1; i < 10; i++) +{ +count[i] += count[i-1]; +} + +for (int i = n-1; i >=0; i--) +{ +output[count[(arr[i]/exp) %10] -1] = arr[i]; +count[(arr[i]/exp)%10]--; +} + +for (int i = 0; i < n; i++) +{ +arr[i] = output[i]; +} +} diff --git a/Week_07/G20200343030465/LeetCode_146_465.java b/Week_07/G20200343030465/LeetCode_146_465.java new file mode 100644 index 00000000..97a9e422 --- /dev/null +++ b/Week_07/G20200343030465/LeetCode_146_465.java @@ -0,0 +1,57 @@ +class LRUCache { + + Node head = new Node(0, 0), tail = new Node(0, 0); + Map map = new HashMap(); + int capacity; + + public LRUCache(int _capacity) { + capacity = _capacity; + head.next = tail; + tail.prev = head; + } + + public int get(int key) { + if(map.containsKey(key)) { + Node node = map.get(key); + remove(node); + insert(node); + return node.value; + } else { + return -1; + } + } + + public void put(int key, int value) { + if(map.containsKey(key)) { + remove(map.get(key)); + } + if(map.size() == capacity) { + remove(tail.prev); + } + insert(new Node(key, value)); + } + + private void remove(Node node) { + map.remove(node.key); + node.prev.next = node.next; + node.next.prev = node.prev; + } + + private void insert(Node node){ + map.put(node.key, node); + Node headNext = head.next; + head.next = node; + node.prev = head; + headNext.prev = node; + node.next = headNext; + } + + class Node{ + Node prev, next; + int key, value; + Node(int _key, int _value) { + key = _key; + value = _value; + } + } +} \ No newline at end of file diff --git a/Week_07/G20200343030465/LeetCode_191_465.java b/Week_07/G20200343030465/LeetCode_191_465.java new file mode 100644 index 00000000..c5973959 --- /dev/null +++ b/Week_07/G20200343030465/LeetCode_191_465.java @@ -0,0 +1,8 @@ + public int hammingWeight(int n) { + int ones = 0; + while(n!=0) { + ones = ones + (n & 1); + n = n>>>1; + } + return ones; +} \ No newline at end of file diff --git a/Week_07/G20200343030485/LeetCode_146_485.cs b/Week_07/G20200343030485/LeetCode_146_485.cs new file mode 100644 index 00000000..a0e35dac --- /dev/null +++ b/Week_07/G20200343030485/LeetCode_146_485.cs @@ -0,0 +1,47 @@ +public class LRUCache { + Dictionary dict = new Dictionary(); + LinkedList list = new LinkedList(); + readonly int max; + + public LRUCache(int capacity) { + max = capacity; + } + + public int Get(int key) { + int result; + if (dict.TryGetValue(key, out result)) { + list.Remove(key); + list.AddFirst(key); + + return result; + } + + return -1; + } + + public void Put(int key, int value) { + int result; + if (dict.TryGetValue(key, out result)) { + list.Remove(key); + list.AddFirst(key); + dict[key] = value; + + return; + } + + if (list.Count >= max) { + dict.Remove(list.Last.Value); + list.RemoveLast(); + } + + list.AddFirst(key); + dict[key] = value; + } +} + +/** + * Your LRUCache object will be instantiated and called as such: + * LRUCache obj = new LRUCache(capacity); + * int param_1 = obj.Get(key); + * obj.Put(key,value); + */ \ No newline at end of file diff --git a/Week_07/G20200343030485/LeetCode_52_485.cs b/Week_07/G20200343030485/LeetCode_52_485.cs new file mode 100644 index 00000000..7314deec --- /dev/null +++ b/Week_07/G20200343030485/LeetCode_52_485.cs @@ -0,0 +1,22 @@ +public class Solution { + int result; + + public int TotalNQueens(int n) { + Dfs(n, 0, 0, 0, 0); + return result; + } + + public void Dfs(int n, int row, int col, int ld, int rd) { + if (row >= n) { + result++; + return; + } + + int bits = ~(col | ld | rd) & ((1 << n) - 1); + while (bits > 0) { + int pick = bits & -bits; + Dfs(n, row + 1, col | pick, (ld | pick) << 1, (rd | pick) >> 1); + bits &= bits - 1; + } + } +} \ No newline at end of file diff --git a/Week_07/G20200343030487/leetcode_1122_487.js b/Week_07/G20200343030487/leetcode_1122_487.js new file mode 100644 index 00000000..0fcb3097 --- /dev/null +++ b/Week_07/G20200343030487/leetcode_1122_487.js @@ -0,0 +1,25 @@ +/** + * @param {number[]} arr1 + * @param {number[]} arr2 + * @return {number[]} + */ +var relativeSortArray = function(arr1, arr2) { + const res = [] + const map = {} + arr1.forEach((item, index) => { + map[item] ? map[item]++ : map[item] = 1 + }) + arr2.forEach((item, index) => { + while(map[item]) { + res.push(item) + map[item]-- + } + }) + for (const o in map) { + while(map[o]) { + res.push(o) + map[o]-- + } + } + return res +}; diff --git a/Week_07/G20200343030487/leetcode_146_487.js b/Week_07/G20200343030487/leetcode_146_487.js new file mode 100644 index 00000000..7328e044 --- /dev/null +++ b/Week_07/G20200343030487/leetcode_146_487.js @@ -0,0 +1,47 @@ +/** + * @param {number} capacity + */ +var LRUCache = function (capacity) { + this.cap = capacity; + this.cache = new Map(); +}; + +/** +* @param {number} key +* @return {number} +*/ +LRUCache.prototype.get = function (key) { + let cache = this.cache; + if (cache.has(key)) { + let val = cache.get(key); + cache.delete(key); + cache.set(key, val); + return val; + } else { + return -1; + } +}; + +/** +* @param {number} key +* @param {number} value +* @return {void} +*/ +LRUCache.prototype.put = function (key, value) { + let cache = this.cache; + if (cache.has(key)) { + cache.delete(key); + } else { + if (cache.size == this.cap) { + cache.delete(cache.keys().next().value); + } + } + cache.set(key, value); +}; + +/** +* Your LRUCache object will be instantiated and called as such: +* var obj = new LRUCache(capacity) +* var param_1 = obj.get(key) +* obj.put(key,value) +*/ diff --git a/Week_07/G20200343030487/leetcode_191_487.js b/Week_07/G20200343030487/leetcode_191_487.js new file mode 100644 index 00000000..6c34d5d0 --- /dev/null +++ b/Week_07/G20200343030487/leetcode_191_487.js @@ -0,0 +1,12 @@ +/** + * @param {number} n - a positive integer + * @return {number} + */ +var hammingWeight = function(n) { + let sum = 0 + while(n !== 0) { + sum++ + n &= n - 1 + } + return sum +}; diff --git a/Week_07/G20200343030487/leetcode_231_487.js b/Week_07/G20200343030487/leetcode_231_487.js new file mode 100644 index 00000000..09d6f44b --- /dev/null +++ b/Week_07/G20200343030487/leetcode_231_487.js @@ -0,0 +1,12 @@ +/** + * @param {number} n + * @return {boolean} + */ +// var isPowerOfTwo = function(n) { +// if (n === 0) return false +// return (n & (n - 1)) === 0 +// }; +var isPowerOfTwo = function(n) { + if (n <= 0) return false + return (n & n - 1) === 0 +}; diff --git a/Week_07/G20200343030487/leetcode_242_487.js b/Week_07/G20200343030487/leetcode_242_487.js new file mode 100644 index 00000000..45ba4320 --- /dev/null +++ b/Week_07/G20200343030487/leetcode_242_487.js @@ -0,0 +1,21 @@ +/** + * @param {string} s + * @param {string} t + * @return {boolean} + */ +var isAnagram = function(s, t) { + if (s.length !== t.length) return false + const res1 = {} + const res2 = {} + for (let i = 0, len = s.length; i < len; i++) { + res1[s[i]] ? res1[s[i]]++ : res1[s[i]] = 1 + } + for (let i = 0, len = t.length; i < len; i++) { + res2[t[i]] ? res2[t[i]]++ : res2[t[i]] = 1 + } + for (const o in res1) { + if (res1[o] !== res2[o]) return false + } + + return true +}; \ No newline at end of file diff --git a/Week_07/G20200343030489/LeetCode_1122_489.cpp b/Week_07/G20200343030489/LeetCode_1122_489.cpp new file mode 100644 index 00000000..335318d0 --- /dev/null +++ b/Week_07/G20200343030489/LeetCode_1122_489.cpp @@ -0,0 +1,25 @@ +/* + * @lc app=leetcode.cn id=1122 lang=cpp + * + * [1122] 数组的相对排序 + */ + +// @lc code=start +class Solution { +public: + vector relativeSortArray(vector& arr1, vector& arr2) { + int count=0; + for(int i=0;i=0;i--) + ret=ret|(((n>>(31-i))&1)< countBits(int num) { + vector res(num+1); + for(int i=1;i<=num;i++){ + if(i&1) + res[i]=res[i-1]+1; + else + res[i]=res[i>>1]; + } + return res; + } +}; +// @lc code=end + diff --git a/Week_07/G20200343030489/LeetCode_56_489.cpp b/Week_07/G20200343030489/LeetCode_56_489.cpp new file mode 100644 index 00000000..364c5443 --- /dev/null +++ b/Week_07/G20200343030489/LeetCode_56_489.cpp @@ -0,0 +1,51 @@ +/* + * @lc app=leetcode.cn id=56 lang=cpp + * + * [56] 合并区间 + */ + +// @lc code=start +// class Solution { +// public: +// vector> merge(vector>& intervals) { +// vector> res; +// if(intervals.empty()) +// return res; +// sort(intervals.begin(),intervals.end(),[&,this](vector &v1,vector &v2){return v1.front()=intervals[i+1].front()){ +// ++i; +// tmp.back()=max(tmp.back(),intervals[i].back()); +// } +// res.push_back(tmp); +// } +// return res; +// } +// }; +class Solution { +public: + vector> merge(vector>& intervals) { + vector> res; + if(intervals.size()==0||intervals.size()==1) + return intervals; + int u=0,v=0; + sort(intervals.begin(),intervals.end()); + while(vintervals[u][1]){ + res.emplace_back(intervals[u]); + u=v; + }else if(intervals[v][1]<=intervals[u][1]) + ++v; + else{ + intervals[u][1]=intervals[v][1]; + ++v; + } + } + res.emplace_back(intervals[u]); + return res; + } +}; +// @lc code=end + diff --git a/Week_07/G20200343030491/LeetCode_1122_491.py b/Week_07/G20200343030491/LeetCode_1122_491.py new file mode 100644 index 00000000..4e2a25a1 --- /dev/null +++ b/Week_07/G20200343030491/LeetCode_1122_491.py @@ -0,0 +1,55 @@ +class Solution: + def binarySearch(self,arr,n): + if not arr: + return [n] + left, right = 0, len(arr)-1 + while left<=right: + mid = (right+left)>>1 + + if n < arr[mid]: + right = mid - 1 + else: + left = mid + 1 + + return arr[:right+1] + [n] + arr[right+1:] + + def relativeSortArray(self, arr1: List[int], arr2: List[int]) -> List[int]: + dict2 = {} + arr_last = [] + arr_first = [] + for i in arr2: + dict2[i] = [] + for i in arr1: + if i in dict2: + dict2[i] += [i] + continue + arr_last = self.binarySearch(arr_last,i) + + for i in dict2: + arr_first += dict2[i] + + return arr_first + arr_last + +class Solution: + def relativeSortArray(self, arr1: List[int], arr2: List[int]) -> List[int]: + if not arr1: + return [] + if not arr2: + return sorted(arr1) + res, temp= [], [] + dict2 = OrderedDict.fromkeys(arr2,0) + used = set() + for i in arr1: + if i in dict2: + dict2[i] += 1 + used.add(i) + for k, v in dict2.items(): + for _ in range(v): + res.append(k) + for i in arr1: + if i not in used: + temp.append(i) + if temp: + return res+sorted(temp) + else: + return res \ No newline at end of file diff --git a/Week_07/G20200343030491/LeetCode_164_491.py b/Week_07/G20200343030491/LeetCode_164_491.py new file mode 100644 index 00000000..6c6b43eb --- /dev/null +++ b/Week_07/G20200343030491/LeetCode_164_491.py @@ -0,0 +1,97 @@ +class DLinkedNode(): + def __init__(self): + self.key = 0 + self.value = 0 + self.prev = None + self.next = None + +class LRUCache(): + def _add_node(self, node): + node.prev = self.head + node.next = self.head.next + + self.head.next.prev = node + self.head.next = node + + def _remove_node(self, node): + # prev = node.prev + # next = node.next + node.prev.next, node.next.prev = node.next, node.prev + + def _move_to_head(self, node): + self._remove_node(node) + self._add_node(node) + + def _pop_tail(self): + res = self.tail.prev + self._remove_node(res) + return res + + def __init__(self, capacity): + self.cache = {} + self.size = 0 + self.capacity = capacity + self.head, self.tail = DLinkedNode(), DLinkedNode() + + self.head.next = self.tail + self.tail.prev = self.head + + + def get(self, key): + node = self.cache.get(key,None) + if not node: + return -1 + self._move_to_head(node) + + return node.value + + def put(self, key, value): + node = self.cache.get(key) + if not node: + newNode = DLinkedNode() + newNode.key = key + newNode.value = value + + self.cache[key] = newNode + self._add_node(newNode) + + self.size += 1 + + if self.size > self.capacity: + tail = self._pop_tail() + del self.cache[tail.key] + self.size -= 1 + + else: + node.value = value + self._move_to_head(node) + + +# Your LRUCache object will be instantiated and called as such: +# obj = LRUCache(capacity) +# param_1 = obj.get(key) +# obj.put(key,value) + +class LRUCache(OrderedDict): + + def __init__(self, capacity: int): + self.capacity = capacity + + def get(self, key: int) -> int: + if key not in self: + return -1 + self.move_to_end(key) + return self[key] + + def put(self, key: int, value: int) -> None: + if key in self: + self.move_to_end(key) + self[key] = value + if len(self)>self.capacity: + self.popitem(last=False) + + +# Your LRUCache object will be instantiated and called as such: +# obj = LRUCache(capacity) +# param_1 = obj.get(key) +# obj.put(key,value) \ No newline at end of file diff --git a/Week_07/G20200343030491/LeetCode_190_491.py b/Week_07/G20200343030491/LeetCode_190_491.py new file mode 100644 index 00000000..81d95df0 --- /dev/null +++ b/Week_07/G20200343030491/LeetCode_190_491.py @@ -0,0 +1,39 @@ +class Solution: + def reverseBits(self, n: int) -> int: + res = n & 1 + for _ in range(31): + res = res << 1 + n = n >> 1 + res |= (n & 1) + + return res + +class Solution: + def reverseBits(self, n: int) -> int: + res, mask = 0, 1 + for i in range(32): + if n & mask: + res = res | (1<<(31-i)) + mask = mask << 1 + + return res + +class Solution: + def reverseBits(self, n: int) -> int: + for i in range(16): + x = (n>>i) & 1 + y = (n>>(31-i)) & 1 + + if x == 0: + n = n & (~(1<<(31-i))) + if x == 1: + n = n | (1<<(31-i)) + + if y == 0: + n = n & (~(1<<(i))) + + if y == 1: + n = n | (1<<(i)) + + + return n \ No newline at end of file diff --git a/Week_07/G20200343030491/LeetCode_191_491.py b/Week_07/G20200343030491/LeetCode_191_491.py new file mode 100644 index 00000000..3e0a96a7 --- /dev/null +++ b/Week_07/G20200343030491/LeetCode_191_491.py @@ -0,0 +1,47 @@ +class Solution: + def hammingWeight(self, n: int) -> int: + count = 0 + for i in range(32): + if ((n>>i) & 1) == 1: + count += 1 + + return count + +class Solution: + def hammingWeight(self, n: int) -> int: + count = 0 + while n !=0: + if n&1 == 1: + count += 1 + n = n>>1 + + return count + + +class Solution: + def hammingWeight(self, n: int) -> int: + count = 0 + while n !=0: + if n%2 == 1: + count += 1 + n = n>>1 + + return count + +class Solution: + def hammingWeight(self, n: int) -> int: + count = 0 + while n !=0: + if n%2 == 1: + count += 1 + n = n//2 + + return count + +class Solution: + def hammingWeight(self, n: int) -> int: + count = 0 + while n != 0: + count += 1 + n = n & (n-1) + return count \ No newline at end of file diff --git a/Week_07/G20200343030491/LeetCode_231_491.py b/Week_07/G20200343030491/LeetCode_231_491.py new file mode 100644 index 00000000..5d69b980 --- /dev/null +++ b/Week_07/G20200343030491/LeetCode_231_491.py @@ -0,0 +1,33 @@ +class Solution: + def isPowerOfTwo(self, n: int) -> bool: + return n != 0 and (n & (n-1)) == 0 + +class Solution: + def isPowerOfTwo(self, n: int) -> bool: + if n<=0: return False + if n == 1: + return True + if n%2==0: + return self.isPowerOfTwo(n>>1) + +class Solution: + def isPowerOfTwo(self, n: int) -> bool: + if n<=0: return False + def rec(n): + if n==1: + return True + if n%2 == 1: + return False + return rec(n>>1) + + return rec(n) + +class Solution: + def isPowerOfTwo(self, n: int) -> bool: + if n<=0: + return False + while n != 1: + if n%2 == 1: + return False + n = n>>1 + return True \ No newline at end of file diff --git a/Week_07/G20200343030491/LeetCode_36_491.py b/Week_07/G20200343030491/LeetCode_36_491.py new file mode 100644 index 00000000..96b54d13 --- /dev/null +++ b/Week_07/G20200343030491/LeetCode_36_491.py @@ -0,0 +1,18 @@ +class Solution: + def isValidSudoku(self, board: List[List[str]]) -> bool: + rows = [[] for _ in range(9)] + cols = [[] for _ in range(9)] + boxes = [[] for _ in range(9)] + + for i in range(9): + for j in range(9): + if board[i][j] != ".": + if board[i][j] in rows[i] or board[i][j] in cols[j] or board[i][j] in boxes[i//3 * 3 + j//3]: + + return False + + rows[i].append(board[i][j]) + cols[j].append(board[i][j]) + boxes[i//3*3 + j//3].append(board[i][j]) + + return True \ No newline at end of file diff --git a/Week_07/G20200343030491/LeetCode_493_491.py b/Week_07/G20200343030491/LeetCode_493_491.py new file mode 100644 index 00000000..85548386 --- /dev/null +++ b/Week_07/G20200343030491/LeetCode_493_491.py @@ -0,0 +1,27 @@ +class Solution: + def __init__(self): + self.cnt = 0 + def mergeSort(self,nums,begin,end): + if begin>=end: return + mid = (begin+end)//2 + self.mergeSort(nums,begin,mid) + self.mergeSort(nums,mid+1,end) + self.merge(nums,begin,mid,end) + def merge(self,nums,begin,mid,end): + # + j = mid + 1 + count = 0 + i = begin + while i<=mid: + if j<=end and nums[i]>2*nums[j]: + j += 1 + count +=1 + else: + i += 1 + self.cnt += count + # + nums[begin:end+1] = sorted(nums[begin:end+1]) + + def reversePairs(self, nums: List[int]) -> int: + self.mergeSort(nums,0,len(nums)-1) + return self.cnt \ No newline at end of file diff --git a/Week_07/G20200343030491/LeetCode_56_491.py b/Week_07/G20200343030491/LeetCode_56_491.py new file mode 100644 index 00000000..98a96060 --- /dev/null +++ b/Week_07/G20200343030491/LeetCode_56_491.py @@ -0,0 +1,11 @@ +class Solution: + def merge(self, intervals: List[List[int]]) -> List[List[int]]: + intervals = sorted(intervals,key = lambda item:item[0]) + i = 1 + while i x[\cf5 0\cf3 ]))\cf4 ;\ +\ + \cf3 LinkedList\cf2 \cf3 list \cf2 = new \cf3 LinkedList\cf2 <>\cf3 ()\cf4 ;\ + \cf2 for \cf3 (\cf2 int \cf3 i \cf2 = \cf5 0\cf4 ; \cf3 i \cf2 < \cf3 arr.length\cf4 ; \cf3 i\cf2 ++\cf3 ) \{\ + \cf2 if \cf3 (list.size() \cf2 == \cf5 0 \cf2 || \cf3 list.getLast()[\cf5 1\cf3 ] \cf2 < \cf3 arr[i][\cf5 0\cf3 ]) \{\ + list.add(arr[i])\cf4 ;\cf6 // +\f1 \'bc\'af\'ba\'cf\'ce\'aa\'bf\'d5\'a3\'ac\'bb\'f2\'b2\'bb\'c2\'fa\'d7\'e3\'cc\'f5\'bc\'fe\'a3\'ac\'cf\'f2\'ba\'f3\'d0\'c2\'d4\'f6 +\f0 \ + \cf3 \} \cf2 else \cf3 \{\cf6 // +\f1 \'c2\'fa\'d7\'e3\'cc\'f5\'bc\'fe\'a3\'ac\'bc\'af\'ba\'cf\'d7\'ee\'ba\'f3\'d4\'aa\'cb\'d8\'b5\'c4 +\f0 end= +\f1 \'d7\'ee\'b4\'f3\'d6\'b5 +\f0 \ + \cf3 list.getLast()[\cf5 1\cf3 ] \cf2 = \cf3 Math.max(list.getLast()[\cf5 1\cf3 ]\cf4 , \cf3 arr[i][\cf5 1\cf3 ])\cf4 ;\ + \cf3 \}\ + \}\ + \cf2 int\cf3 [][] res \cf2 = new int\cf3 [list.size()][\cf5 2\cf3 ]\cf4 ;\cf6 // +\f1 \'c9\'fa\'b3\'c9\'bd\'e1\'b9\'fb\'ca\'fd\'d7\'e9 +\f0 \ + \cf2 int \cf3 index \cf2 = \cf5 0\cf4 ;\ + \cf2 while \cf3 (\cf2 !\cf3 list.isEmpty()) \{\cf6 // +\f1 \'b1\'e9\'c0\'fa\'bc\'af\'ba\'cf +\f0 \ + \cf3 res[index\cf2 ++\cf3 ] \cf2 = \cf3 list.removeFirst()\cf4 ;\cf6 // +\f1 \'c9\'be\'b3\'fd\'bc\'af\'ba\'cf\'ca\'d7\'d4\'aa\'cb\'d8 +\f0 \ + \cf3 \}\ + \cf2 return \cf3 res\cf4 ;\ + \cf3 \}\ +\}\ +\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardirnatural\partightenfactor0 +\cf0 \ +} \ No newline at end of file diff --git a/Week_07/G20200343030493/number_1.java b/Week_07/G20200343030493/number_1.java new file mode 100644 index 00000000..86566543 --- /dev/null +++ b/Week_07/G20200343030493/number_1.java @@ -0,0 +1,20 @@ +{\rtf1\ansi\ansicpg936\cocoartf2511 +\cocoatextscaling0\cocoaplatform0{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +{\*\expandedcolortbl;;} +\paperw11900\paperh16840\margl1440\margr1440\vieww10800\viewh8400\viewkind0 +\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardirnatural\partightenfactor0 + +\f0\fs24 \cf0 public int hammingWeight(int n) \{\ + int bits = 0;\ + int mask = 1;\ + for (int i = 0; i < 32; i++) \{\ + if ((n & mask) != 0) \{\ + bits++;\ + \}\ + mask <<= 1;\ + \}\ + return bits;\ +\}\ +\ +} \ No newline at end of file diff --git a/Week_07/G20200343030493/power_of_two.java b/Week_07/G20200343030493/power_of_two.java new file mode 100644 index 00000000..10c25bd0 --- /dev/null +++ b/Week_07/G20200343030493/power_of_two.java @@ -0,0 +1,19 @@ +{\rtf1\ansi\ansicpg936\cocoartf2511 +\cocoatextscaling0\cocoaplatform0{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;\red203\green36\blue57;\red27\green31\blue35;\red8\green68\blue184; +\red109\green109\blue109;} +{\*\expandedcolortbl;;\csgenericrgb\c79608\c14118\c22353;\csgenericrgb\c10588\c12157\c13725;\csgenericrgb\c3137\c26667\c72157; +\csgenericrgb\c42745\c42745\c42745;} +\paperw11900\paperh16840\margl1440\margr1440\vieww10800\viewh8400\viewkind0 +\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardirnatural\partightenfactor0 + +\f0\fs24 \cf2 class \cf3 Solution \{\ + \cf2 public boolean \cf3 isPowerOfTwo(\cf2 int \cf3 n) \{\ + \cf2 if \cf3 (n \cf2 == \cf4 0\cf3 ) \cf2 return false\cf5 ;\ + \cf2 long \cf3 x \cf2 = \cf3 (\cf2 long\cf3 ) n\cf5 ;\ + \cf2 return \cf3 (x \cf2 & \cf3 (\cf2 -\cf3 x)) \cf2 == \cf3 x\cf5 ;\ + \cf3 \}\ +\}\ +\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardirnatural\partightenfactor0 +\cf0 \ +} \ No newline at end of file diff --git a/Week_07/G20200343030497/LeetCode_1122_497.cpp b/Week_07/G20200343030497/LeetCode_1122_497.cpp new file mode 100644 index 00000000..6a8d8ab4 --- /dev/null +++ b/Week_07/G20200343030497/LeetCode_1122_497.cpp @@ -0,0 +1,21 @@ +class Solution { +public: + // 时间复杂度:O(mn + nlogn) + // 空间复杂度:O(nlogn) + vector relativeSortArray(vector& arr1, vector& arr2) { + int tmp = 0; + for(int i = 0; i < arr2.size(); i++){ + for(int j = 0; j < arr1.size(); j++){ + if(arr2[i] == arr1[j]){ + swap(arr1[j], arr1[tmp]); // 交换arr1中的元素 + ++tmp; // tmp之前的元素为拍好序的元素 + } + } + } + + // 对剩余元素排序 + sort(arr1.begin()+tmp, arr1.end()); + + return arr1; + } +}; diff --git a/Week_07/G20200343030497/LeetCode_190_497.cpp b/Week_07/G20200343030497/LeetCode_190_497.cpp new file mode 100644 index 00000000..fcbe3741 --- /dev/null +++ b/Week_07/G20200343030497/LeetCode_190_497.cpp @@ -0,0 +1,12 @@ +class Solution { +public: + // 时间复杂度:O(1) + // 空间复杂度:O(1) + uint32_t reverseBits(uint32_t n) { + uint32_t result= 0; + for(int i=0; i<32; i++) + result = (result << 1) + (n >> i & 1); + + return result; + } +}; diff --git a/Week_07/G20200343030497/LeetCode_242_497.cpp b/Week_07/G20200343030497/LeetCode_242_497.cpp new file mode 100644 index 00000000..9500306d --- /dev/null +++ b/Week_07/G20200343030497/LeetCode_242_497.cpp @@ -0,0 +1,23 @@ +class Solution { +public: + // 排序 + // 时间复杂度:O(nlogn) + // 空间复杂度:O(n) + vector> merge(vector>& intervals) { + if(intervals.empty()) return {}; + // 排序 + //sort(intervals.begin(), intervals.end()) + sort(intervals.begin(), intervals.end(), [&](vector& l, vector& r){return l[0] < r[0];}); + vector> res{intervals[0]}; // 将第一个数组放入结果中 + + for(int i = 1; i < intervals.size(); ++i){ + // 比较结果中最后一个区间右值的与原始区间中的左值 + if(res.back()[1] >= intervals[i][0]){ + res.back()[1] = max(res.back()[1], intervals[i][1]); // 更新结果中区间的右值 + }else{ + res.push_back(intervals[i]); + } + } + return res; + } +}; diff --git a/Week_07/G20200343030497/LeetCode_56_497.cpp b/Week_07/G20200343030497/LeetCode_56_497.cpp new file mode 100644 index 00000000..9500306d --- /dev/null +++ b/Week_07/G20200343030497/LeetCode_56_497.cpp @@ -0,0 +1,23 @@ +class Solution { +public: + // 排序 + // 时间复杂度:O(nlogn) + // 空间复杂度:O(n) + vector> merge(vector>& intervals) { + if(intervals.empty()) return {}; + // 排序 + //sort(intervals.begin(), intervals.end()) + sort(intervals.begin(), intervals.end(), [&](vector& l, vector& r){return l[0] < r[0];}); + vector> res{intervals[0]}; // 将第一个数组放入结果中 + + for(int i = 1; i < intervals.size(); ++i){ + // 比较结果中最后一个区间右值的与原始区间中的左值 + if(res.back()[1] >= intervals[i][0]){ + res.back()[1] = max(res.back()[1], intervals[i][1]); // 更新结果中区间的右值 + }else{ + res.push_back(intervals[i]); + } + } + return res; + } +}; diff --git a/Week_07/G20200343030501/LeetCode_191_501.go b/Week_07/G20200343030501/LeetCode_191_501.go new file mode 100644 index 00000000..fd41d043 --- /dev/null +++ b/Week_07/G20200343030501/LeetCode_191_501.go @@ -0,0 +1,14 @@ +package G20200343030501 + +func hammingWeight(num uint32) int { + count := 0 + for { + if num != 0 { + count++ + num = num & (num - 1) + } else { + break + } + } + return count +} \ No newline at end of file diff --git a/Week_07/G20200343030501/LeetCode_231_501.go b/Week_07/G20200343030501/LeetCode_231_501.go new file mode 100644 index 00000000..3171d547 --- /dev/null +++ b/Week_07/G20200343030501/LeetCode_231_501.go @@ -0,0 +1,8 @@ +package G20200343030501 + +func isPowerOfTwo(n int) bool { + if n == 0 { + return false + } + return 0 == n & (n - 1) +} \ No newline at end of file diff --git a/Week_07/G20200343030503/LeetCode_190_503.java b/Week_07/G20200343030503/LeetCode_190_503.java new file mode 100644 index 00000000..a41ca0b5 --- /dev/null +++ b/Week_07/G20200343030503/LeetCode_190_503.java @@ -0,0 +1,13 @@ +```java +public class Solution { + + public int reverseBits(int n) { + int ans = 0; + for (int bitsSize = 31; n != 0; n = n >>> 1, bitsSize--) { + ans += (n & 1) << bitsSize; + } + return ans; + } +} +``` + diff --git a/Week_07/G20200343030503/LeetCode_191_503.java b/Week_07/G20200343030503/LeetCode_191_503.java new file mode 100644 index 00000000..5cddfa27 --- /dev/null +++ b/Week_07/G20200343030503/LeetCode_191_503.java @@ -0,0 +1,26 @@ + +public class Solution { + // 位操作 + public int hammingWeight(int n) { + int sum = 0; + while (n != 0) { + sum++; + n &= (n - 1); + } + return sum; + } + // 循环和位移动 + public int hammingWeight(int n) { + int bits = 0; + int mask = 1; + for (int i = 0; i < 32; i++) { + if ((n & mask) != 0) { + bits++; + } + mask <<= 1; + } + return bits; + } +} +``` + diff --git a/Week_07/G20200343030503/LeetCode_231_503.java b/Week_07/G20200343030503/LeetCode_231_503.java new file mode 100644 index 00000000..d4b7a858 --- /dev/null +++ b/Week_07/G20200343030503/LeetCode_231_503.java @@ -0,0 +1,19 @@ +```java +class Solution { + // public boolean isPowerOfTwo(int n) { + // if (n == 0) return false; + // while (n % 2 == 0) + // n /= 2; + // return n==1; + // } + + public boolean isPowerOfTwo(int n) { + if (n == 0) { + return false; + } + long x = (long) n; + return (x & (x - 1)) == 0; + } +} +``` + diff --git a/Week_07/G20200343030503/NOTE.md b/Week_07/G20200343030503/NOTE.md index 50de3041..cdf6abb3 100644 --- a/Week_07/G20200343030503/NOTE.md +++ b/Week_07/G20200343030503/NOTE.md @@ -1 +1,78 @@ -学习笔记 \ No newline at end of file +学习笔记 + +**一、直接插入排序(Insertion Sort)** + +```java +// 交换次数较多的实现 +public static void insertionSort(int[] arr){ + for( int i=0; i0; j-- ) { + if( arr[j-1] <= arr[j] ) + break; + int temp = arr[j]; //交换操作 + arr[j] = arr[j-1]; + arr[j-1] = temp; + System.out.println("Sorting: " + Arrays.toString(arr)); + } + } +} +``` + + + +**二、选择排序(Insertion Sort)** + +```java +/** + * 选择排序 + * + * 1. 从待排序序列中,找到关键字最小的元素; + * 2. 如果最小元素不是待排序序列的第一个元素,将其和第一个元素互换; + * 3. 从余下的 N - 1 个元素中,找出关键字最小的元素,重复①、②步,直到排序结束。 + * 仅增量因子为1 时,整个序列作为一个表来处理,表长度即为整个序列的长度。 + * @param arr 待排序数组 + */ +public static void selectionSort(int[] arr){ + for(int i = 0; i < arr.length-1; i++){ + int min = i; + for(int j = i+1; j < arr.length; j++){ //选出之后待排序中值最小的位置 + if(arr[j] < arr[min]){ + min = j; + } + } + if(min != i){ + int temp = arr[min]; //交换操作 + arr[min] = arr[i]; + arr[i] = temp; + System.out.println("Sorting: " + Arrays.toString(arr)); + } + } +} +``` + +**三、冒泡排序(Insertion Sort)** + +```java +/** + * 冒泡排序 + * + * ①. 比较相邻的元素。如果第一个比第二个大,就交换他们两个。 + * ②. 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。 + * ③. 针对所有的元素重复以上的步骤,除了最后一个。 + * ④. 持续每次对越来越少的元素重复上面的步骤①~③,直到没有任何一对数字需要比较。 + * @param arr 待排序数组 + */ +public static void bubbleSort(int[] arr){ + for (int i = arr.length; i > 0; i--) { //外层循环移动游标 + for(int j = 0; j < i && (j+1) < i; j++){ //内层循环遍历游标及之后(或之前)的元素 + if(arr[j] > arr[j+1]){ + int temp = arr[j]; + arr[j] = arr[j+1]; + arr[j+1] = temp; + System.out.println("Sorting: " + Arrays.toString(arr)); + } + } + } +} +``` + diff --git a/Week_07/G20200343030505/LeetCode_146_505.java b/Week_07/G20200343030505/LeetCode_146_505.java new file mode 100644 index 00000000..a0232505 --- /dev/null +++ b/Week_07/G20200343030505/LeetCode_146_505.java @@ -0,0 +1,118 @@ + +class LeetCode_192_505 { + private DoubleList list; + private Map map; + private int capacity; + + public LRUCache(int capacity) { + this.capacity = capacity; + this.list = new DoubleList(); + this.map = new HashMap(); + } + + public int get(int key) { + if (!map.containsKey(key)) { + return -1; + } + int val = map.get(key).val; + //调整链表节点 先删除key节点 再放一个新的节点到头部 + list.removeNode(map.get(key)); + //下面写法是有bug的 new出来的和map里的就不同了,应该放入map里的 + //list.addFrist(new ListNode(key, val)); + list.addFrist(map.get(key)); + + return val; + } + + public void put(int key, int value) { + ListNode node = new ListNode(key, value); + if (map.containsKey(key)) { + //如果已经有该元素,调整链表 然后更新map + list.removeNode(map.get(key)); + list.addFrist(node); + map.put(key, node); + } else { + //空元素 先判断容量 如果超了就溢出头部节点 再插入 + //此处比较 链表的容量和当前容量 + if (this.capacity == this.list.size()) { + ListNode pLast = list.removeLast(); + map.remove(pLast.key); + } + + list.addFrist(node); + map.put(key, node); + } + + } +} + +//定义节点类 存储节点信息 包括前驱指针和后驱指针 +class ListNode { + public int key, val; + public ListNode pre, next; + public ListNode(int key, int val) { + this.key = key; + this.val = val; + } +} + +//定义一个双向链表 +class DoubleList { + private int size; + private ListNode head, tail; + public int size() { + return size; + } + //虚拟节点 + public DoubleList() { + head = new ListNode(0, 0); + tail = new ListNode(0, 0); + //head指向尾部节点 tail指向头部节点 + head.next = tail; + tail.pre = head; + size = 0; + } + + //头插入 + public void addFrist(ListNode node) { + node.next = head.next; + head.next.pre = node; + node.pre = head; + head.next = node; + ++size; + } + //尾插入 + public void addLast(ListNode node) { + tail.pre.next = node; + node.pre = tail.pre; + node.next = tail; + tail.pre = node; + ++size; + } + + public ListNode removeLast() { + //判断是否是空链表 + if (tail.pre == head) { + return null; + } + ListNode pLast = tail.pre; + removeNode(tail.pre); + return pLast; + } + + public void removeNode(ListNode node) { + //当前节点前驱指向节点下驱 + node.pre.next = node.next; + //当前节点下驱指向节点前驱 + node.next.pre = node.pre; + //别忘了元素减少一个 + --size; + } +} + +/** + * Your LRUCache object will be instantiated and called as such: + * LRUCache obj = new LRUCache(capacity); + * int param_1 = obj.get(key); + * obj.put(key,value); + */ \ No newline at end of file diff --git a/Week_07/G20200343030505/LeetCode_190_505.java b/Week_07/G20200343030505/LeetCode_190_505.java new file mode 100644 index 00000000..9affa609 --- /dev/null +++ b/Week_07/G20200343030505/LeetCode_190_505.java @@ -0,0 +1,14 @@ +class LeetCode_190_505 { + // you need treat n as an unsigned value + public int reverseBits(int n) { + int result = 0; + for (int i=0;i<32;++i) { + result = result<<1; + result = result | (n & 1); + n = n>>1; + } + + return result; + + } +} \ No newline at end of file diff --git a/Week_07/G20200343030505/LeetCode_191_505.java b/Week_07/G20200343030505/LeetCode_191_505.java new file mode 100644 index 00000000..085f1229 --- /dev/null +++ b/Week_07/G20200343030505/LeetCode_191_505.java @@ -0,0 +1,28 @@ + +class LeetCode_192_505 { + // you need to treat n as an unsigned value + public int hammingWeight(int n) { + int cnt = 0; + while (n != 0) { + ++cnt; + + //比如011 需要两次操作就变成0 + //比如1000 一次操作就变成了0 + //次数就是1的个数 + n = (n-1) & n; + } + return cnt; + } +} + +class LeetCode_192_505 { + // you need to treat n as an unsigned value + public int hammingWeight(int n) { + int cnt = 0; + while (n != 0) { + cnt += n & 1; + n = n >>> 1; + } + return cnt; + } +} \ No newline at end of file diff --git a/Week_07/G20200343030505/LeetCode_231_505.java b/Week_07/G20200343030505/LeetCode_231_505.java new file mode 100644 index 00000000..83d58675 --- /dev/null +++ b/Week_07/G20200343030505/LeetCode_231_505.java @@ -0,0 +1,7 @@ + +class LeetCode_192_505 { + public boolean isPowerOfTwo(int n) { + //n-1 & n 如果1的个数为1 相与的结果一定为0 + return n > 0 && (((n-1) & n) == 0); + } +} \ No newline at end of file diff --git a/Week_07/G20200343030505/LeetCode_493_505.java b/Week_07/G20200343030505/LeetCode_493_505.java new file mode 100644 index 00000000..e301fa28 --- /dev/null +++ b/Week_07/G20200343030505/LeetCode_493_505.java @@ -0,0 +1,25 @@ + +class LeetCode_493_505 { + public int reversePairs(int[] nums) { + return mergeSort(nums, 0, nums.length-1); + } + private int mergeSort(int[] nums, int s, int e){ + if(s>=e) return 0; + + int mid = s + (e-s)/2; + + //求出子数组翻转对数目 + int cnt = mergeSort(nums, s, mid) + mergeSort(nums, mid+1, e); + + //计算当前两个子数组之前的翻转对数目 + for(int i = s, j = mid+1; i<=mid; i++){ + while(j<=e && nums[i]/2.0 > nums[j]) j++; + cnt += j-(mid+1); + } + + + //调用库函数排序 + Arrays.sort(nums, s, e+1); + return cnt; + } +} \ No newline at end of file diff --git a/Week_07/G20200343030505/LeetCode_56_505.java b/Week_07/G20200343030505/LeetCode_56_505.java new file mode 100644 index 00000000..f01545ca --- /dev/null +++ b/Week_07/G20200343030505/LeetCode_56_505.java @@ -0,0 +1,41 @@ + +class LeetCode_192_505 { + public int[][] merge(int[][] intervals) { + if (intervals == null) { + return new int[0][0]; + } + + int m = intervals.length; + if (m == 0) { + return new int[0][0]; + } + int n = intervals[0].length; + //对二维数组排序 根据区间左元素大小 + Arrays.sort(intervals, new Comparator() { + public int compare(int[] o1, int[] o2) { + return o1[0] - o2[0]; + } + }); + + //依次遍历数组 如果 第一个区间right<=第二个区间left证明两个相交 + int i = 0; + //int[] 也能做泛型参数 + List result = new ArrayList(); + while (i < intervals.length) { + int left = intervals[i][0]; + int right = intervals[i][1]; + //从i开始往后查找 满足条件的所有的 + while (i < intervals.length - 1 && right >= intervals[i+1][0]) { + ++i; + //更新右边left + right = Math.max(right, intervals[i][1]); + } + //更新结果 + result.add(new int[]{left, right}); + ++i; + } + + //学习转换方法 + return result.toArray(new int[0][]); + } +} diff --git a/Week_07/G20200343030509/Solution052_509.java b/Week_07/G20200343030509/Solution052_509.java new file mode 100644 index 00000000..2cbb2cc8 --- /dev/null +++ b/Week_07/G20200343030509/Solution052_509.java @@ -0,0 +1,45 @@ +package com.leetcode.week07;/* +/* + * @lc app=leetcode.cn id=52 lang=java + * + * [52] N皇后 II + */ + +class Solution052_509 { + + private int size; + private int count; + public int totalNQueens(int n) { + count = 0; + size = (1 << n) - 1; + System.out.println("size=" + Integer.toBinaryString(size)); + solve(0, 0, 0); + return count; + } + + private void solve(int row, int left, int right) { + if (row == size) { + count++; + return; + } + int pos = size & (~(row | left | right)); + System.out.println("pos=" + Integer.toBinaryString(pos) + ", row=" + Integer.toBinaryString(row) + ", left=" + Integer.toBinaryString(left) + ", right=" + Integer.toBinaryString(right)); + while (pos != 0) { + int p = pos & (-pos); + System.out.println("p=" + Integer.toBinaryString(p) + ", pos=" + Integer.toBinaryString(pos)); + pos -= p; + System.out.println("pos=" + Integer.toBinaryString(pos)); + solve(row + p, (left + p) << 1, (right + p) >> 1); + } + } + + public static void main(String[] args) { + long startTime=System.nanoTime(); //获取开始时间 + + Solution052_509 sol = new Solution052_509(); + System.out.println(sol.totalNQueens(4)); + + long endTime=System.nanoTime(); //获取结束时间 + System.out.println( "程序运行时间: " + (endTime-startTime) + "ns"); + } +} \ No newline at end of file diff --git a/Week_07/G20200343030509/Solution190_509.java b/Week_07/G20200343030509/Solution190_509.java new file mode 100644 index 00000000..b15932ad --- /dev/null +++ b/Week_07/G20200343030509/Solution190_509.java @@ -0,0 +1,32 @@ +package com.leetcode.week07;/* +/* + * @lc app=leetcode.cn id=190 lang=java + * + * [190] 颠倒二进制位 + */ + +class Solution190_509 { + + // you need treat n as an unsigned value + public int reverseBits(int n) { + int res = 0; + for (int i = 0; i < 32; i++) { + int cur = n & 1; + res += (cur << (31 - i)); + n = n >> 1; + } + return res; + } + + public static void main(String[] args) { + long startTime=System.nanoTime(); //获取开始时间 + + Solution190_509 sol = new Solution190_509(); + int n = 6; + System.out.println(Integer.toBinaryString(n)); + System.out.println(Integer.toBinaryString(sol.reverseBits(6))); + + long endTime=System.nanoTime(); //获取结束时间 + System.out.println( "程序运行时间: " + (endTime-startTime) + "ns"); + } +} \ No newline at end of file diff --git a/Week_07/G20200343030509/Solution191_509.java b/Week_07/G20200343030509/Solution191_509.java new file mode 100644 index 00000000..7d5efed8 --- /dev/null +++ b/Week_07/G20200343030509/Solution191_509.java @@ -0,0 +1,29 @@ +package com.leetcode.week07;/* +/* + * @lc app=leetcode.cn id=191 lang=java + * + * [191] 位1的个数 + */ + +class Solution191_509 { + + // you need to treat n as an unsigned value + public int hammingWeight(int n) { + int sum = 0; + while (n != 0) { + sum++; + n = n & (n - 1); + } + return sum; + } + + public static void main(String[] args) { + long startTime=System.nanoTime(); //获取开始时间 + + Solution191_509 sol = new Solution191_509(); + System.out.println(sol.hammingWeight(4)); + + long endTime=System.nanoTime(); //获取结束时间 + System.out.println( "程序运行时间: " + (endTime-startTime) + "ns"); + } +} \ No newline at end of file diff --git a/Week_07/G20200343030509/Solution231_509.java b/Week_07/G20200343030509/Solution231_509.java new file mode 100644 index 00000000..7578927f --- /dev/null +++ b/Week_07/G20200343030509/Solution231_509.java @@ -0,0 +1,25 @@ +package com.leetcode.week07;/* +/* + * @lc app=leetcode.cn id=231 lang=java + * + * [231] 2的幂 + */ + +class Solution231_509 { + + public boolean isPowerOfTwo(int n) { + if (n == 0) return false; + long x = (long) n; + return (x & -x) == x; + } + + public static void main(String[] args) { + long startTime=System.nanoTime(); //获取开始时间 + + Solution231_509 sol = new Solution231_509(); + System.out.println(sol.isPowerOfTwo(-2147483648)); + + long endTime=System.nanoTime(); //获取结束时间 + System.out.println( "程序运行时间: " + (endTime-startTime) + "ns"); + } +} \ No newline at end of file diff --git a/Week_07/G20200343030509/Solution338_509.java b/Week_07/G20200343030509/Solution338_509.java new file mode 100644 index 00000000..96d10122 --- /dev/null +++ b/Week_07/G20200343030509/Solution338_509.java @@ -0,0 +1,31 @@ +package com.leetcode.week07;/* +/* + * @lc app=leetcode.cn id=338 lang=java + * + * [338] 比特位计数 + */ + +import java.util.Arrays; + +class Solution338_509 { + + public int[] countBits(int num) { + int[] res = new int[num + 1]; + res[0] = 0; + for (int i = 0; i <= num; i++) { + // 奇数的话比前一个数的1的数量+1,偶数的话跟前一个数的1的数量相同 + res[i] = (i & 1) == 1 ? res[i-1] + 1 : res[i>>1]; + } + return res; + } + + public static void main(String[] args) { + long startTime=System.nanoTime(); //获取开始时间 + + Solution338_509 sol = new Solution338_509(); + System.out.println(Arrays.toString(sol.countBits(4))); + + long endTime=System.nanoTime(); //获取结束时间 + System.out.println( "程序运行时间: " + (endTime-startTime) + "ns"); + } +} \ No newline at end of file diff --git a/Week_07/G20200343030509/Solution493_509.java b/Week_07/G20200343030509/Solution493_509.java new file mode 100644 index 00000000..64d3f7a1 --- /dev/null +++ b/Week_07/G20200343030509/Solution493_509.java @@ -0,0 +1,42 @@ +package com.leetcode.week07; + +/* + * @lc app=leetcode.cn id=493 lang=java + * + * [493] 翻转对 + */ + + +import java.util.Arrays; + +class Solution493_509 { + public static void main(String[] args) { + long startTime=System.nanoTime(); //获取开始时间 + + Solution493_509 sol = new Solution493_509(); + int[] numbers = {1,5,2,5,1,5}; + + System.out.println(sol.reversePairs(numbers)); + + long endTime=System.nanoTime(); //获取结束时间 + System.out.println( "程序运行时间: " + (endTime-startTime) + "ns"); + } + + public int reversePairs(int[] nums) { + if (nums == null || nums.length == 0) return 0; + return mergeSort(nums, 0, nums.length - 1); + } + + private int mergeSort(int[] nums, int left, int right) { + if (left >= right) return 0; + int mid = left + (right - left) / 2; + int count = mergeSort(nums, left, mid) + mergeSort(nums, mid + 1, right); + for (int i = left, j = mid + 1; i <= mid; i++) { + while (j <= right && nums[i]/2.0 > nums[j]) j++; + count += j - (mid + 1); + } + Arrays.sort(nums, left, right +1); + return count; + } + +} \ No newline at end of file diff --git a/Week_07/G20200343030509/sort.java b/Week_07/G20200343030509/sort.java new file mode 100644 index 00000000..52434760 --- /dev/null +++ b/Week_07/G20200343030509/sort.java @@ -0,0 +1,137 @@ +/** + * Copyright (C), 2020-2020, 孙亮 + * FileName: quickSort + * Author: sunliang + * Date: 2020/03/28 11:51 + * Description: 快速排序 + * History: + *