9 | * 例如,给定数组 nums = [-1,2,1,-4], 和 target = 1. 10 | *
11 | * 与 target 最接近的三个数的和为 2. (-1 + 2 + 1 = 2).
12 | *
13 | * @author icecrea
14 | */
15 | public class LeetCode16_3SumClosest {
16 | /**
17 | * 3个数 问题是最接近target 最接近可以通过变量绝对值比较来判断
18 | */
19 | public int threeSumClosest(int[] nums, int target) {
20 | // 排序
21 | Arrays.sort(nums);
22 | int closestNum = nums[0] + nums[1] + nums[2];
23 | for (int i = 0; i < nums.length - 2; i++) {
24 | int l = i + 1, r = nums.length - 1;
25 | while (l < r){
26 | int threeSum = nums[l] + nums[r] + nums[i];
27 | if (Math.abs(threeSum - target) < Math.abs(closestNum - target)) {
28 | closestNum = threeSum;
29 | }
30 | if (threeSum > target) {
31 | r--;
32 | } else if (threeSum < target) {
33 | l++;
34 | } else {
35 | // 如果已经等于target的话, 肯定是最接近的
36 | return target;
37 | }
38 |
39 | }
40 |
41 | }
42 |
43 | return closestNum;
44 | }
45 |
46 | }
47 |
--------------------------------------------------------------------------------
/src/main/java/com/example/leetcode/array/LeetCode33_SearchInRotatedSortedArray.java:
--------------------------------------------------------------------------------
1 | package com.example.leetcode.array;
2 |
3 | /**
4 | * @description: 循环有序数组二分查找
5 | * 假设按照升序排序的数组在预先未知的某个点上进行了旋转。
6 | * ( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。
7 | * 搜索一个给定的目标值,如果数组中存在这个目标值,则返回它的索引,否则返回 -1 。
8 | * 你可以假设数组中不存在重复的元素。
9 | * 你的算法时间复杂度必须是 O(log n) 级别。
10 | * 示例 1:
11 | * 输入: arr = [4,5,6,7,0,1,2], target = 0
12 | * 输出: 4
13 | * 示例 2:
14 | * 输入: arr = [4,5,6,7,0,1,2], target = 3
15 | * 输出: -1
16 | * @author: icecrea
17 | * @create: 2019-10-24
18 | **/
19 | public class LeetCode33_SearchInRotatedSortedArray {
20 | /**
21 | * 中间节点小于最右节点,说明右半部分有序
22 | * 中间节点大于最右节点,说明左半部分有序
23 | */
24 | public int search(int[] arr, int target) {
25 | int low = 0, high = arr.length - 1;
26 | while (low <= high) {
27 | int mid = low + ((high - low) >> 1);
28 | if (arr[mid] == target) {
29 | return mid;
30 | } else if (arr[mid] < arr[high]) { //右侧是有序的
31 | //判断查找的数是否在右区间中
32 | if (arr[mid] < target && arr[high] >= target) {
33 | low = mid + 1;
34 | } else {
35 | high = mid - 1;
36 | }
37 | } else { //左侧是有序的
38 | //判断查找的数是否在左区间中
39 | if (arr[mid] > target && arr[low] <= target) {
40 | high = mid - 1;
41 | } else {
42 | low = mid + 1;
43 | }
44 | }
45 | }
46 | return -1;
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/main/java/com/example/leetcode/backtrack/LeetCode077_Combinations.java:
--------------------------------------------------------------------------------
1 | package com.example.leetcode.backtrack;
2 |
3 | import org.junit.Test;
4 |
5 | import java.util.ArrayList;
6 | import java.util.List;
7 |
8 | /**
9 | * @description: 组合
10 | * 给定两个整数 n 和 k,返回 1 ... n 中所有可能的 k 个数的组合。
11 | * 示例:
12 | * 输入: n = 4, k = 2
13 | * 输出:
14 | * [
15 | * [2,4],
16 | * [3,4],
17 | * [2,3],
18 | * [1,2],
19 | * [1,3],
20 | * [1,4],
21 | * ]
22 | * 来源:力扣(LeetCode)
23 | * 链接:https://leetcode-cn.com/problems/combinations
24 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
25 | * @auther: icecrea
26 | * @date: 2020/4/20
27 | */
28 | public class LeetCode077_Combinations {
29 | List
9 | * 你的 KthLargest 类需要一个同时接收整数 k 和整数数组nums 的构造器,它包含数据流中的初始元素。每次调用 KthLargest.add,返回当前数据流中第K大的元素。
10 | *
11 | * 示例:
12 | *
13 | * int k = 3;
14 | * int[] arr = [4,5,8,2];
15 | * KthLargest kthLargest = new KthLargest(3, arr);
16 | * kthLargest.add(3); // returns 4
17 | * kthLargest.add(5); // returns 5
18 | * kthLargest.add(10); // returns 5
19 | * kthLargest.add(9); // returns 8
20 | * kthLargest.add(4); // returns 8
21 | * 说明:
22 | * 你可以假设 nums 的长度≥ k-1 且k ≥ 1。
23 | * @author: icecrea
24 | * @create: 2019-04-15 13:09
25 | **/
26 | public class LeetCode703_ktLargestElementIntream {
27 |
28 | // public PriorityQueue priorityQueue = new PriorityQueue();
29 | //
30 | // public KthLargest(int k, int[] nums) {
31 | //
32 | // }
33 | //
34 | // public int add(int val) {
35 | //
36 | // }
37 | }
38 |
39 | /**
40 | * Your KthLargest object will be instantiated and called as such:
41 | * KthLargest obj = new KthLargest(k, nums);
42 | * int param_1 = obj.add(val);
43 | */
44 |
--------------------------------------------------------------------------------
/src/main/java/com/example/leetcode/heap/package-info.java:
--------------------------------------------------------------------------------
1 | package com.example.leetcode.heap;
2 |
3 | // https://leetcode-cn.com/tag/heap/
4 | // 堆 列表
--------------------------------------------------------------------------------
/src/main/java/com/example/leetcode/linkedlist/LeetCode02_AddTwoNumbers.java:
--------------------------------------------------------------------------------
1 | package com.example.leetcode.linkedlist;
2 |
3 | import com.example.leetcode.linkedlist.pojo.ListNode;
4 |
5 | /**
6 | * @description: 两数相加
7 | * 给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,
8 | * 并且它们的每个节点只能存储 一位 数字。
9 | * 如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。
10 | * 您可以假设除了数字 0 之外,这两个数都不会以 0 开头。
11 | * 示例:
12 | * 输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
13 | * 输出:7 -> 0 -> 8
14 | * 原因:342 + 465 = 807
15 | * @author: icecrea
16 | * @create: 2018-12-24 19:12
17 | **/
18 | public class LeetCode02_AddTwoNumbers {
19 |
20 | public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
21 | ListNode dummyHead = new ListNode(0);
22 | ListNode p = l1, q = l2, curr = dummyHead;
23 | int carry = 0;
24 | while (p != null || q != null) {
25 | int x = (p != null) ? p.val : 0;
26 | int y = (q != null) ? q.val : 0;
27 | int sum = carry + x + y;
28 | carry = sum / 10;
29 | curr.next = new ListNode(sum % 10);
30 | curr = curr.next;
31 | if (p != null) {
32 | p = p.next;
33 | }
34 | if (q != null) {
35 | q = q.next;
36 | }
37 | }
38 | if (carry > 0) {
39 | curr.next = new ListNode(carry);
40 | }
41 | return dummyHead.next;
42 | }
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/src/main/java/com/example/leetcode/linkedlist/LeetCode109_ConvertSortedListToBinarySearchTree.java:
--------------------------------------------------------------------------------
1 | package com.example.leetcode.linkedlist;
2 |
3 | import com.example.leetcode.linkedlist.pojo.ListNode;
4 | import com.example.leetcode.linkedlist.pojo.TreeNode;
5 |
6 | /**
7 | * @description: 有序链表转换二叉搜索树 TODO
8 | * 给定一个单链表,其中的元素按升序排序,将其转换为高度平衡的二叉搜索树。
9 | *
10 | * 本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1。
11 | *
12 | * 示例:
13 | *
14 | * 给定的有序链表: [-10, -3, 0, 5, 9],
15 | *
16 | * 一个可能的答案是:[0, -3, 9, -10, null, 5], 它可以表示下面这个高度平衡二叉搜索树:
17 | *
18 | * 0
19 | * / \
20 | * -3 9
21 | * / /
22 | * -10 5
23 | * @author: icecrea
24 | * @create: 2019-01-08 20:28
25 | **/
26 | public class LeetCode109_ConvertSortedListToBinarySearchTree {
27 |
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/java/com/example/leetcode/linkedlist/LeetCode147_InsertionSortList.java:
--------------------------------------------------------------------------------
1 | package com.example.leetcode.linkedlist;
2 |
3 | import com.example.leetcode.linkedlist.pojo.ListNode;
4 |
5 | /**
6 | * @description: 对链表进行插入排序
7 | * 插入排序的动画演示如上。从第一个元素开始,该链表可以被认为已经部分排序(用黑色表示)。
8 | * 每次迭代时,从输入数据中移除一个元素(用红色表示),并原地将其插入到已排好序的链表中。
9 | *
10 | *
11 | *
12 | * 插入排序算法:
13 | *
14 | * 插入排序是迭代的,每次只移动一个元素,直到所有元素可以形成一个有序的输出列表。
15 | * 每次迭代中,插入排序只从输入数据中移除一个待排序的元素,找到它在序列中适当的位置,并将其插入。
16 | * 重复直到所有输入数据插入完为止。
17 | *
18 | *
19 | * 示例 1:
20 | *
21 | * 输入: 4->2->1->3
22 | * 输出: 1->2->3->4
23 | * 示例 2:
24 | *
25 | * 输入: -1->5->3->4->0
26 | * 输出: -1->0->3->4->5
27 | * @author: icecrea
28 | * @create: 2019-01-03 20:57
29 | **/
30 | public class LeetCode147_InsertionSortList {
31 | public ListNode insertionSortList(ListNode head) {
32 | if (head == null) {
33 | return head;
34 | }
35 | //通过dummy节点构造链表
36 | ListNode dummy = new ListNode(0);
37 | ListNode cur = head;
38 | ListNode pre = dummy;
39 | ListNode next;
40 | while (cur != null) {
41 | next = cur.next;
42 | pre = dummy;
43 | //找到插入的位置的前一个节点pre
44 | while (pre.next != null && pre.next.val < cur.val) {
45 | pre = pre.next;
46 | }
47 | //在pre与pre.next之间插入cur
48 | cur.next = pre.next;
49 | pre.next = cur;
50 | cur = next;
51 | }
52 |
53 | //不能返回head head节点可能会被移动
54 | return dummy.next;
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/main/java/com/example/leetcode/linkedlist/LeetCode160_IntersectionOfTwoLists.java:
--------------------------------------------------------------------------------
1 | package com.example.leetcode.linkedlist;
2 |
3 | import com.example.leetcode.linkedlist.pojo.ListNode;
4 |
5 | /**
6 | * @description: 相交链表
7 | * 找到两个单链表相交的起始节点。
8 | *
9 | * 输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3
10 | * 输出:Reference of the node with value = 8
11 | * 输入解释:相交节点的值为 8 (注意,如果两个列表相交则不能为 0)。
12 | * 从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,0,1,8,4,5]。在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。
13 | *
14 | * 注意:
15 | * 如果两个链表没有交点,返回 null.
16 | * 在返回结果后,两个链表仍须保持原有的结构。
17 | * 可假定整个链表结构中没有循环。
18 | * 程序尽量满足 O(n) 时间复杂度,且仅用 O(1) 内存。
19 | * @author: icecrea
20 | * @create: 2018-12-27 11:31
21 | **/
22 | public class LeetCode160_IntersectionOfTwoLists {
23 | /**
24 | * 这个思路就是 ListA + ListB = A + intersection + Bb + intersection
25 | * ListB + ListA = Bb + intersection + A + intersection
26 | * 用大A表示ListA里面非共有 Bb表示listB里面非共有的,可以看到在第二个intersection的开头两个链表长度是一样的,必然相等
27 | * 所以我们可以遍历A再遍历B,另一个遍历B再遍历A,两个指针必定在第二个交集处相遇,没有交集就是空指针
28 | *
29 | * @param headA
30 | * @param headB
31 | * @return
32 | */
33 | public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
34 | /**
35 | 定义两个指针, 第一轮让两个到达末尾的节点指向另一个链表的头部, 最后如果相遇则为交点(在第一轮移动中恰好抹除了长度差)
36 | 两个指针等于移动了相同的距离, 有交点就返回, 无交点就是各走了两条指针的长度
37 | **/
38 | if (headA == null || headB == null) {
39 | return null;
40 | }
41 | ListNode pA = headA, pB = headB;
42 | // 在这里第一轮体现在pA和pB第一次到达尾部会移向另一链表的表头, 而第二轮体现在如果pA或pB相交就返回交点, 不相交最后就是null==null
43 | while (pA != pB) {
44 | pA = pA == null ? headB : pA.next;
45 | pB = pB == null ? headA : pB.next;
46 | }
47 | return pA;
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/main/java/com/example/leetcode/linkedlist/LeetCode19_RemoveNthNodeFromEnd.java:
--------------------------------------------------------------------------------
1 | package com.example.leetcode.linkedlist;
2 |
3 | import com.example.leetcode.linkedlist.pojo.ListNode;
4 |
5 | /**
6 | * @description: 删除链表的倒数第N个节点
7 | * 给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。
8 | *
9 | * 示例:
10 | *
11 | * 给定一个链表: 1->2->3->4->5, 和 n = 2.
12 | *
13 | * 当删除了倒数第二个节点后,链表变为 1->2->3->5.
14 | * 说明:
15 | *
16 | * 给定的 n 保证是有效的。
17 | *
18 | * 进阶:
19 | *
20 | * 你能尝试使用一趟扫描实现吗?
21 | * @author: icecrea
22 | * @create: 2018-12-24 20:39
23 | **/
24 | public class LeetCode19_RemoveNthNodeFromEnd {
25 |
26 | public ListNode removeNthFromEnd(ListNode head, int n) {
27 | ListNode d = new ListNode(0);
28 | d.next = head;
29 | ListNode fast = d, slow = d;
30 | for (int i = 0; i < n; i++) {
31 | fast = fast.next;
32 | }
33 | while (fast != null && fast.next != null) {
34 | slow = slow.next;
35 | fast = fast.next;
36 | }
37 | slow.next = slow.next.next;
38 | return d.next;
39 | }
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/src/main/java/com/example/leetcode/linkedlist/LeetCode203_RemoveLinkedListElements.java:
--------------------------------------------------------------------------------
1 | package com.example.leetcode.linkedlist;
2 |
3 | import com.example.leetcode.linkedlist.pojo.ListNode;
4 |
5 | /**
6 | * @description: 移除链表元素
7 | *
8 | * 删除链表中等于给定值 val 的所有节点。
9 | *
10 | * 示例:
11 | *
12 | * 输入: 1->2->6->3->4->5->6, val = 6
13 | * 输出: 1->2->3->4->5
14 | * @author: icecrea
15 | * @create: 2018-12-27 17:02
16 | **/
17 | public class LeetCode203_RemoveLinkedListElements {
18 | /**
19 | * 设置哑节点,next连到头节点,
20 | * 然后遍历当前节点的next值与val是否相等,便于删除
21 | * @param head
22 | * @param val
23 | * @return
24 | */
25 | public ListNode removeElements(ListNode head, int val) {
26 | if (head == null) {
27 | return null;
28 | }
29 | ListNode newHead = new ListNode(Integer.MIN_VALUE);
30 | newHead.next = head;
31 |
32 | ListNode cur = newHead;
33 | while (cur.next != null) {
34 | if (cur.next.val == val) {
35 | cur.next = cur.next.next;
36 | } else {
37 | cur = cur.next;
38 | }
39 | }
40 | return newHead.next;
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/main/java/com/example/leetcode/linkedlist/LeetCode206_ReverseLinkedList.java:
--------------------------------------------------------------------------------
1 | package com.example.leetcode.linkedlist;
2 |
3 | import com.example.leetcode.linkedlist.pojo.ListNode;
4 |
5 | /**
6 | * @description: 反转链表
7 | *
8 | * 反转一个单链表。
9 | *
10 | * 示例:
11 | *
12 | * 输入: 1->2->3->4->5->NULL
13 | * 输出: 5->4->3->2->1->NULL
14 | * 进阶:
15 | * 你可以迭代或递归地反转链表。你能否用两种方法解决这道题?
16 | * @author: icecrea
17 | * @create: 2018-12-27 11:42
18 | **/
19 | public class LeetCode206_ReverseLinkedList {
20 | /**
21 | * 非递归
22 | * @param head
23 | * @return
24 | */
25 | public ListNode reverseList(ListNode head) {
26 | if (head == null || head.next == null) {
27 | return head;
28 | }
29 |
30 | ListNode p = head;
31 | ListNode q = p.next;
32 | head.next = null;
33 | ListNode next;
34 |
35 | while (q != null) {
36 | //因为有指针反转,所以需要提前保留下一个step要处理的指针
37 | next = q.next;
38 | //指针反转
39 | q.next = p;
40 | //后移一位
41 | p = q;
42 | q = next;
43 | }
44 | return p;
45 | }
46 |
47 |
48 | /**
49 | * 递归方法
50 | * @param head
51 | * @return
52 | */
53 | public ListNode reverseListRecur(ListNode head) {
54 | //递归终止条件: 找到链表最后一个节点
55 | if (head == null || head.next == null) {
56 | return head;
57 | }
58 | ListNode newNode = reverseListRecur(head.next);
59 | //反转头节点的下一个节点的next指针 head.next对应的是 反转后链表的尾指针,而node.next是反转后的头指针的下一个节点,此处注意区分
60 | head.next.next = head;
61 | //反转头节点的next指针,将头节点作为尾节点
62 | head.next = null;
63 | return newNode;
64 | }
65 |
66 | }
67 |
--------------------------------------------------------------------------------
/src/main/java/com/example/leetcode/linkedlist/LeetCode21_MergeTwoSortedLists.java:
--------------------------------------------------------------------------------
1 | package com.example.leetcode.linkedlist;
2 |
3 | import com.example.leetcode.linkedlist.pojo.ListNode;
4 |
5 | /**
6 | * @description: 合并两个有序链表
7 | * 将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
8 | * 示例:
9 | * 输入:1->2->4, 1->3->4
10 | * 输出:1->1->2->3->4->4
11 | * @author: icecrea
12 | * @create: 2018-12-24 18:58
13 | **/
14 | public class LeetCode21_MergeTwoSortedLists {
15 | /**
16 | * 合并两个有序链表
17 | *
18 | * @param l1
19 | * @param l2
20 | * @return
21 | */
22 | public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
23 | ListNode dummy = new ListNode(Integer.MIN_VALUE);
24 | ListNode cur = dummy;
25 | while (l1 != null && l2 != null) {
26 | if (l1.val < l2.val) {
27 | cur.next = l1;
28 | l1 = l1.next;
29 | } else {
30 | cur.next = l2;
31 | l2 = l2.next;
32 | }
33 | cur = cur.next;
34 | }
35 | cur.next = l1 == null ? l2 : l1;
36 | return dummy.next;
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/main/java/com/example/leetcode/linkedlist/LeetCode234_PalindromeLinkedList.java:
--------------------------------------------------------------------------------
1 | package com.example.leetcode.linkedlist;
2 |
3 | import com.example.leetcode.linkedlist.pojo.ListNode;
4 |
5 | /**
6 | * @description: 回文链表
7 | *
8 | * 请判断一个链表是否为回文链表。
9 | *
10 | * 示例 1:
11 | *
12 | * 输入: 1->2
13 | * 输出: false
14 | * 示例 2:
15 | *
16 | * 输入: 1->2->2->1
17 | * 输出: true
18 | * 进阶:
19 | * 你能否用 O(n) 时间复杂度和 O(1) 空间复杂度解决此题?
20 | * @author: icecrea
21 | * @create: 2018-12-27 18:02
22 | **/
23 | public class LeetCode234_PalindromeLinkedList {
24 |
25 | public boolean isPalindrome(ListNode head) {
26 | // 要实现 O(n) 的时间复杂度和 O(1) 的空间复杂度,需要翻转后半部分
27 | if (head == null || head.next == null) {
28 | return true;
29 | }
30 | ListNode fast = head;
31 | ListNode slow = head;
32 | // 根据快慢指针,找到链表的中点
33 | while(fast.next != null && fast.next.next != null) {
34 | fast = fast.next.next;
35 | slow = slow.next;
36 | }
37 | slow = reverse(slow.next);
38 | while(slow != null) {
39 | if (head.val != slow.val) {
40 | return false;
41 | }
42 | head = head.next;
43 | slow = slow.next;
44 | }
45 | return true;
46 | }
47 |
48 |
49 | private ListNode reverse(ListNode head) {
50 | if (head == null || head.next == null) {
51 | return head;
52 | }
53 | ListNode newNode = reverse(head.next);
54 | head.next.next = head;
55 | head.next = null;
56 | return newNode;
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/main/java/com/example/leetcode/linkedlist/LeetCode237_DeleteNodeInLinkedList.java:
--------------------------------------------------------------------------------
1 | package com.example.leetcode.linkedlist;
2 |
3 | import com.example.leetcode.linkedlist.pojo.ListNode;
4 |
5 | /**
6 | * @description: 删除链表中的节点
7 | * 请编写一个函数,使其可以删除某个链表中给定的(非末尾)节点,你将只被给定要求被删除的节点。
8 | *
9 | * 现有一个链表 -- head = [4,5,1,9],它可以表示为:
10 | *
11 | * 4 -> 5 -> 1 -> 9
12 | * 示例 1:
13 | *
14 | * 输入: head = [4,5,1,9], node = 5
15 | * 输出: [4,1,9]
16 | * 解释: 给定你链表中值为 5 的第二个节点,那么在调用了你的函数之后,该链表应变为 4 -> 1 -> 9.
17 | * 示例 2:
18 | *
19 | * 输入: head = [4,5,1,9], node = 1
20 | * 输出: [4,5,9]
21 | * 解释: 给定你链表中值为 1 的第三个节点,那么在调用了你的函数之后,该链表应变为 4 -> 5 -> 9.
22 | * 说明:
23 | *
24 | * 链表至少包含两个节点。
25 | * 链表中所有节点的值都是唯一的。
26 | * 给定的节点为非末尾节点并且一定是链表中的一个有效节点。
27 | * 不要从你的函数中返回任何结果。
28 | * @author: icecrea
29 | * @create: 2018-12-29 00:25
30 | **/
31 | public class LeetCode237_DeleteNodeInLinkedList {
32 |
33 | /**
34 | * 我们无法访问我们想要删除的节点之前的节点,我们始终不能修改该节点的 next 指针。
35 | * 相反,我们必须将想要删除的节点的值替换为它后面节点中的值,然后删除它之后的节点。
36 | * 因为我们知道要删除的节点不是列表的末尾,所以我们可以保证这种方法是可行的。
37 | *
38 | * @param node
39 | */
40 | public void deleteNode(ListNode node) {
41 | node.val = node.next.val;
42 | node.next = node.next.next;
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/main/java/com/example/leetcode/linkedlist/LeetCode24_SwapNodesInPairs.java:
--------------------------------------------------------------------------------
1 | package com.example.leetcode.linkedlist;
2 |
3 | import com.example.leetcode.linkedlist.pojo.ListNode;
4 |
5 | /**
6 | * @description: 两两交换链表中的节点
7 | * 给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。
8 | *
9 | * 示例:
10 | *
11 | * 给定 1->2->3->4, 你应该返回 2->1->4->3.
12 | * 说明:
13 | *
14 | * 你的算法只能使用常数的额外空间。
15 | * 你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
16 | * @author: icecrea
17 | * @create: 2019-01-08 22:06
18 | **/
19 | public class LeetCode24_SwapNodesInPairs {
20 |
21 | /**
22 | *
23 | * 1->2->3->4
24 | * 2->1->4->3
25 | *
26 | * @param head
27 | * @return
28 | */
29 | public ListNode swapPairs(ListNode head) {
30 | ListNode dummy = new ListNode(0);
31 | dummy.next = head;
32 | ListNode point = dummy;
33 | while (point.next != null && point.next.next != null) {
34 | ListNode swap1 = point.next;
35 | ListNode swap2 = point.next.next;
36 | // 注意语句顺序不要变动
37 | point.next = swap2;
38 | swap1.next = swap2.next;
39 | swap2.next = swap1;
40 | point = swap1;
41 | }
42 | return dummy.next;
43 | }
44 |
45 | public ListNode swapPairsRecur(ListNode head) {
46 | if ((head == null) || (head.next == null)) {
47 | return head;
48 | }
49 | ListNode n = head.next;
50 | head.next = swapPairsRecur(head.next.next);
51 | n.next = head;
52 | return n;
53 | }
54 |
55 | }
--------------------------------------------------------------------------------
/src/main/java/com/example/leetcode/linkedlist/LeetCode328_OddEvenLinkedList.java:
--------------------------------------------------------------------------------
1 | package com.example.leetcode.linkedlist;
2 |
3 | import com.example.leetcode.linkedlist.pojo.ListNode;
4 |
5 | /**
6 | * @description: 奇偶链表
7 | * 给定一个单链表,把所有的奇数节点和偶数节点分别排在一起。请注意,这里的奇数节点和偶数节点指的是节点编号的奇偶性,而不是节点的值的奇偶性。
8 | * 请尝试使用原地算法完成。你的算法的空间复杂度应为 O(1),时间复杂度应为 O(nodes),nodes 为节点总数。
9 | * 示例 1:
10 | * 输入: 1->2->3->4->5->NULL
11 | * 输出: 1->3->5->2->4->NULL
12 | * 示例 2:
13 | * 输入: 2->1->3->5->6->4->7->NULL
14 | * 输出: 2->3->6->7->1->5->4->NULL
15 | * 说明:
16 | * 应当保持奇数节点和偶数节点的相对顺序。
17 | * 链表的第一个节点视为奇数节点,第二个节点视为偶数节点,以此类推。
18 | * @author: icecrea
19 | * @create: 2019-01-02 18:50
20 | **/
21 | public class LeetCode328_OddEvenLinkedList {
22 | /**
23 | * 限制了空间复杂度 ,则需要在链表中调整,因为每次调整会改变指针,所以我们需要在循环过程中,同时调整奇偶指针的next
24 | *
25 | * @param head
26 | * @return
27 | */
28 | public ListNode oddEvenList(ListNode head) {
29 | if (head == null || head.next == null) {
30 | return head;
31 | }
32 | ListNode oddHead = head;
33 | ListNode odd = oddHead;
34 | ListNode evenHead = head.next;
35 | ListNode even = evenHead;
36 | while (odd.next != null && even.next != null) {
37 | odd.next = odd.next.next;
38 | even.next = even.next.next;
39 |
40 | odd = odd.next;
41 | even = even.next;
42 | }
43 | odd.next = evenHead;
44 | return oddHead;
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/main/java/com/example/leetcode/linkedlist/LeetCode82_RemoveDuplicatesFromSortedList2.java:
--------------------------------------------------------------------------------
1 | package com.example.leetcode.linkedlist;
2 |
3 | import com.example.leetcode.linkedlist.pojo.ListNode;
4 |
5 | /**
6 | * @description: 删除排序链表中的重复元素 II
7 | * 给定一个排序链表,删除所有含有重复数字的节点,只保留原始链表中 没有重复出现 的数字。
8 | *
9 | * 示例 1:
10 | *
11 | * 输入: 1->2->3->3->4->4->5
12 | * 输出: 1->2->5
13 | * 示例 2:
14 | *
15 | * 输入: 1->1->1->2->3
16 | * 输出: 2->3
17 | * @author: icecrea
18 | * @create: 2019-01-07 19:46
19 | **/
20 | public class LeetCode82_RemoveDuplicatesFromSortedList2 {
21 |
22 | public ListNode deleteDuplicates(ListNode head) {
23 | ListNode dummy = new ListNode(Integer.MIN_VALUE);
24 | dummy.next = head;
25 | ListNode pre = dummy;
26 | //因为要删除所有重复的元素而并非留一个,所以要考虑头节点删除,留出pre指针,比较后两个大小是否相等
27 | while (pre.next != null && pre.next.next != null) {
28 | if (pre.next.val != pre.next.next.val) {
29 | pre = pre.next;
30 | continue;
31 | } else {
32 | ListNode lastSame = pre.next.next;
33 | while (lastSame.next != null && pre.next.val == lastSame.next.val) {
34 | lastSame = lastSame.next;
35 | }
36 | //移动指针指向,不真正移动指针,指针的移动在不同时候 比如:有可能存在54448889这种情况
37 | pre.next = lastSame.next;
38 | }
39 | }
40 | return dummy.next;
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/main/java/com/example/leetcode/linkedlist/LeetCode83_RemoveDuplicatesFromSortedList.java:
--------------------------------------------------------------------------------
1 | package com.example.leetcode.linkedlist;
2 |
3 | import com.example.leetcode.linkedlist.pojo.ListNode;
4 |
5 | /**
6 | * @description: 删除排序链表中的重复元素
7 | * 给定一个排序链表,删除所有重复的元素,使得每个元素只出现一次。
8 | *
9 | * 示例 1:
10 | *
11 | * 输入: 1->1->2
12 | * 输出: 1->2
13 | * 示例 2:
14 | *
15 | * 输入: 1->1->2->3->3
16 | * 输出: 1->2->3
17 | * @author: icecrea
18 | * @create: 2018-12-25 13:17
19 | **/
20 | public class LeetCode83_RemoveDuplicatesFromSortedList {
21 | public ListNode deleteDuplicates(ListNode head) {
22 | ListNode cur = head;
23 | while (cur != null && cur.next != null) {
24 | if (cur.val == cur.next.val) {
25 | cur.next = cur.next.next;
26 | } else {
27 | cur = cur.next;
28 | }
29 | }
30 | return head;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/java/com/example/leetcode/linkedlist/LeetCode876_MiddleOfTheLinkedList.java:
--------------------------------------------------------------------------------
1 | package com.example.leetcode.linkedlist;
2 |
3 | import com.example.leetcode.linkedlist.pojo.ListNode;
4 |
5 | /**
6 | * @description: 链表中间节点
7 | * 给定一个带有头结点 head 的非空单链表,返回链表的中间结点。
8 | *
9 | * 如果有两个中间结点,则返回第二个中间结点。
10 | *
11 | * 示例 1:
12 | *
13 | * 输入:[1,2,3,4,5]
14 | * 输出:此列表中的结点 3 (序列化形式:[3,4,5])
15 | * 返回的结点值为 3 。 (测评系统对该结点序列化表述是 [3,4,5])。
16 | * 注意,我们返回了一个 ListNode 类型的对象 ans,这样:
17 | * ans.val = 3, ans.next.val = 4, ans.next.next.val = 5, 以及 ans.next.next.next = NULL.
18 | * 示例 2:
19 | *
20 | * 输入:[1,2,3,4,5,6]
21 | * 输出:此列表中的结点 4 (序列化形式:[4,5,6])
22 | * 由于该列表有两个中间结点,值分别为 3 和 4,我们返回第二个结点。
23 | * @author: icecrea
24 | * @create: 2018-12-25 13:06
25 | **/
26 | public class LeetCode876_MiddleOfTheLinkedList {
27 |
28 | public ListNode middleNode(ListNode head) {
29 | ListNode fast = head;
30 | ListNode low = head;
31 | while (fast != null && fast.next != null) {
32 | fast = fast.next.next;
33 | low = low.next;
34 | }
35 | return low;
36 | }
37 |
38 | public ListNode middleNode2(ListNode head) {
39 | ListNode[] A = new ListNode[100];
40 | int t = 0;
41 | while (head.next != null) {
42 | A[t++] = head;
43 | head = head.next;
44 | }
45 | return A[t / 2];
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/main/java/com/example/leetcode/linkedlist/README.md:
--------------------------------------------------------------------------------
1 | ## LeetCode链表类型题目
2 |
3 | - [02.两数相加](./LeetCode02_AddTwoNumbers.java)
4 | - [19.删除链表的倒数第N个节点](./LeetCode19_RemoveNthNodeFromEnd.java)
5 | - [21.合并两个有序链表](./LeetCode21_MergeTwoSortedLists.java)
6 | - [23.合并k个排序链表](./LeetCode23_MergeKSortedLists.java)
7 | - [24.两两交换链表中的节点](./LeetCode24_SwapNodesInPairs.java)
8 | - [61.旋转链表](./LeetCode61_RotateList.java)
9 | - [82.删除排序链表中的重复元素2](./LeetCode82_RemoveDuplicatesFromSortedList2.java)
10 | - [83.删除排序链表中的重复元素](./LeetCode83_RemoveDuplicatesFromSortedList.java)
11 | - [86.分隔链表](./LeetCode86_PartitionList.java)
12 | - [92.反转链表2](./LeetCode92_ReverseLinkedList2.java)
13 | - [109.有序链表转换二叉搜索树](./LeetCode109_ConvertSortedListToBinarySearchTree.java)
14 | - [138.复制带随机指针的链表](./LeetCode138_CopyListWithRandomPointer.java)
15 | - [141.环形链表](./LeetCode141_LinkedListCycle.java)
16 | - [142.环形链表2](./LeetCode142_LinkedListCycle2.java)
17 | - [143.重排链表](./LeetCode143_ReorderList.java)
18 | - [147.对链表进行插入排序](./LeetCode147_InsertionSortList.java)
19 | - [148.排序链表](./LeetCode148_SortList.java)
20 | - [160.相交链表](./LeetCode160_IntersectionOfTwoLists.java)
21 | - [203.移除链表元素](./LeetCode203_RemoveLinkedListElements.java)
22 | - [206.反转链表](./LeetCode206_ReverseLinkedList.java)
23 | - [234.回文链表](./LeetCode234_PalindromeLinkedList.java)
24 | - [237.删除链表中的节点](./LeetCode237_DeleteNodeInLinkedList.java)
25 | - [328.奇偶链表](./LeetCode328_OddEvenLinkedList.java)
26 | - [445.两数相加2](./LeetCode445_AddTwoNumbers2.java)
27 | - [725.分隔链表](./LeetCode725_SplitLinkedListInParts.java)
28 | - [876.链表中间节点](./LeetCode876_MiddleOfTheLinkedList.java)
--------------------------------------------------------------------------------
/src/main/java/com/example/leetcode/linkedlist/pojo/ListNode.java:
--------------------------------------------------------------------------------
1 | package com.example.leetcode.linkedlist.pojo;
2 |
3 | /**
4 | * @description: 方便起见,设置Public
5 | * @author: icecrea
6 | * @create: 2018-12-18 17:44
7 | **/
8 | public class ListNode {
9 | public int val;
10 | public ListNode next;
11 |
12 | public ListNode(int x) {
13 | val = x;
14 | next = null;
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/main/java/com/example/leetcode/linkedlist/pojo/RandomListNode.java:
--------------------------------------------------------------------------------
1 | package com.example.leetcode.linkedlist.pojo;
2 |
3 | /**
4 | * @description:
5 | * @author: icecrea
6 | * @create: 2019-01-10 11:21
7 | **/
8 | public class RandomListNode {
9 | public int label;
10 | public RandomListNode next, random;
11 |
12 | public RandomListNode(int x) {
13 | this.label = x;
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/main/java/com/example/leetcode/linkedlist/pojo/TreeNode.java:
--------------------------------------------------------------------------------
1 | package com.example.leetcode.linkedlist.pojo;
2 |
3 | /**
4 | * @description:
5 | * @author: icecrea
6 | * @create: 2019-01-08 20:29
7 | **/
8 | public class TreeNode {
9 | public int val;
10 | public TreeNode left;
11 | public TreeNode right;
12 |
13 | public TreeNode(int x) {
14 | val = x;
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/main/java/com/example/leetcode/other/LeetCode007_ReverseInteger.java:
--------------------------------------------------------------------------------
1 | package com.example.leetcode.other;
2 |
3 | import org.junit.Test;
4 |
5 | /**
6 | * @description: 整数反转
7 | * 给出一个 32 位的有符号整数,你需要将这个整数中每位上的数字进行反转。
8 | *
9 | * 示例 1:
10 | *
11 | * 输入: 123
12 | * 输出: 321
13 | * 示例 2:
14 | *
15 | * 输入: -123
16 | * 输出: -321
17 | * 示例 3:
18 | *
19 | * 输入: 120
20 | * 输出: 21
21 | * 注意:
22 | *
23 | * 假设我们的环境只能存储得下 32 位的有符号整数,则其数值范围为 [−231, 231 − 1]。请根据这个假设,如果反转后整数溢出那么就返回 0。
24 | *
25 | * 来源:力扣(LeetCode)
26 | * 链接:https://leetcode-cn.com/problems/reverse-integer
27 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
28 | * @author: icecrea
29 | * @create: 2020-05-01
30 | **/
31 | public class LeetCode007_ReverseInteger {
32 |
33 | public int reverse(int x) {
34 | int ans = 0;
35 | while (x != 0) {
36 | int pop = x % 10;
37 | if (ans > Integer.MAX_VALUE / 10 || (ans == Integer.MAX_VALUE / 10 && pop > Integer.MAX_VALUE % 10)) {
38 | return 0;
39 | }
40 | if (ans < Integer.MIN_VALUE / 10 || (ans == Integer.MIN_VALUE / 10 && pop < Integer.MIN_VALUE % 10)) {
41 | return 0;
42 | }
43 | ans = ans * 10 + pop;
44 | x /= 10;
45 | }
46 | return ans;
47 | }
48 |
49 | @Test
50 | public void test() {
51 | System.out.println(Integer.MAX_VALUE);
52 | System.out.println(Integer.MIN_VALUE % 10);
53 | System.out.println(reverse(-1234));
54 | System.out.println(-1 / 10);
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/main/java/com/example/leetcode/other/LeetCode014_LongestCommonPrefix.java:
--------------------------------------------------------------------------------
1 | package com.example.leetcode.other;
2 |
3 | /**
4 | * @description: 字符串数组最长公共前缀
5 | * 编写一个函数来查找字符串数组中的最长公共前缀。
6 | *
7 | * 如果不存在公共前缀,返回空字符串 ""。
8 | *
9 | * 示例 1:
10 | *
11 | * 输入: ["flower","flow","flight"]
12 | * 输出: "fl"
13 | * 示例 2:
14 | *
15 | * 输入: ["dog","racecar","car"]
16 | * 输出: ""
17 | * 解释: 输入不存在公共前缀。
18 | * 说明:
19 | *
20 | * 所有输入只包含小写字母 a-z 。
21 | *
22 | * 来源:力扣(LeetCode)
23 | * 链接:https://leetcode-cn.com/problems/longest-common-prefix
24 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
25 | * @author: icecrea
26 | * @create: 2020-05-01
27 | **/
28 | public class LeetCode014_LongestCommonPrefix {
29 |
30 | public String longestCommonPrefix(String[] strs) {
31 | if (strs.length == 0) {
32 | return "";
33 | }
34 | String ans = strs[0];
35 | for (int i = 1; i < strs.length; i++) {
36 | int j = 0;
37 | for (; j < ans.length() && j < strs[i].length(); j++) {
38 | if (ans.charAt(j) != strs[i].charAt(j)) {
39 | break;
40 | }
41 | }
42 | ans = ans.substring(0, j);
43 | if (ans.equals("")) {
44 | return ans;
45 | }
46 | }
47 | return ans;
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/main/java/com/example/leetcode/other/LeetCode038_CountAndSay.java:
--------------------------------------------------------------------------------
1 | package com.example.leetcode.other;
2 |
3 | /**
4 | * @description: 外观数列
5 | *
6 | * 「外观数列」是一个整数序列,从数字 1 开始,序列中的每一项都是对前一项的描述。前五项如下:
7 | *
8 | * 1. 1
9 | * 2. 11
10 | * 3. 21
11 | * 4. 1211
12 | * 5. 111221
13 | * 1 被读作 "one 1" ("一个一") , 即 11。
14 | * 11 被读作 "two 1s" ("两个一"), 即 21。
15 | * 21 被读作 "one 2", "one 1" ("一个二" , "一个一") , 即 1211。
16 | *
17 | * 给定一个正整数 n(1 ≤ n ≤ 30),输出外观数列的第 n 项。
18 | *
19 | * 注意:整数序列中的每一项将表示为一个字符串。
20 | *
21 | *
22 | *
23 | * 示例 1:
24 | *
25 | * 输入: 1
26 | * 输出: "1"
27 | * 解释:这是一个基本样例。
28 | * 示例 2:
29 | *
30 | * 输入: 4
31 | * 输出: "1211"
32 | * 解释:当 n = 3 时,序列是 "21",其中我们有 "2" 和 "1" 两组,"2" 可以读作 "12",也就是出现频次 = 1 而 值 = 2;类似 "1" 可以读作 "11"。所以答案是 "12" 和 "11" 组合在一起,也就是 "1211"。
33 | * @author: icecrea
34 | * @create: 2020-05-01
35 | **/
36 | public class LeetCode038_CountAndSay {
37 |
38 | public String countAndSay(int n) {
39 | String s = "1";
40 | int k;
41 | for (int i = 1; i < n; i++) {
42 | StringBuilder t = new StringBuilder();
43 | for (int j = 0; j < s.length(); j = k) {
44 | k = j;
45 | //找有几个相同的.
46 | while(k < s.length() && s.charAt(k) == s.charAt(j)) {
47 | k++;
48 | }
49 | t.append(k - j).append(s.charAt(j));
50 | }
51 | s = t.toString();
52 | }
53 | return s;
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/main/java/com/example/leetcode/other/LeetCode050_Powx.java:
--------------------------------------------------------------------------------
1 | package com.example.leetcode.other;
2 |
3 | import com.example.swordoffer.Sword12_Power;
4 | import org.junit.Test;
5 |
6 | /**
7 | * @description: Pow(x, n)
8 | * 实现 pow(x, n) ,即计算 x 的 n 次幂函数。
9 | *
10 | * 示例 1:
11 | *
12 | * 输入: 2.00000, 10
13 | * 输出: 1024.00000
14 | * 示例 2:
15 | *
16 | * 输入: 2.10000, 3
17 | * 输出: 9.26100
18 | * 示例 3:
19 | *
20 | * 输入: 2.00000, -2
21 | * 输出: 0.25000
22 | * 解释: 2-2 = 1/22 = 1/4 = 0.25
23 | * 说明:
24 | *
25 | * -100.0 < x < 100.0
26 | * n 是 32 位有符号整数,其数值范围是 [−231, 231 − 1] 。
27 | *
28 | * 来源:力扣(LeetCode)
29 | * 链接:https://leetcode-cn.com/problems/powx-n
30 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
31 | * @author: icecrea
32 | * @create: 2020-05-03
33 | **/
34 | public class LeetCode050_Powx {
35 |
36 | /**
37 | * @see Sword12_Power
38 | * 11的二进制是1011
39 | * 11 = 2³×1 + 2²×0 + 2¹×1 + 2º×1 = 2³+2¹+2º
40 | * a¹¹= a^2³ * a ^2¹ * a^2º
41 | */
42 | public double myPow(double x, int n) {
43 | int sign = n;
44 | double res = 1;
45 | n = Math.abs(n);
46 | while (n != 0) {
47 | if ((n & 1) == 1) {//和1与取末尾
48 | res *= x;
49 | }
50 | x *= x;
51 | n = n >>> 1;//注意此处>>>
52 | }
53 | return sign >= 0 ? res : 1 / res;
54 | }
55 |
56 | @Test
57 | public void test() {
58 | System.out.println(myPow(2.0, -2));
59 | System.out.println(Math.abs(-2147483648));
60 | System.out.println(myPow(1.0, -2147483648));
61 |
62 | }
63 |
64 | }
65 |
--------------------------------------------------------------------------------
/src/main/java/com/example/leetcode/other/LeetCode059_SpiralMatrix2.java:
--------------------------------------------------------------------------------
1 | package com.example.leetcode.other;
2 |
3 | /**
4 | * @description: 螺旋矩阵2
5 | * 给定一个正整数 n,生成一个包含 1 到 n2 所有元素,且元素按顺时针顺序螺旋排列的正方形矩阵。
6 | * 示例:
7 | * 输入: 3
8 | * 输出:
9 | * [
10 | * [ 1, 2, 3 ],
11 | * [ 8, 9, 4 ],
12 | * [ 7, 6, 5 ]
13 | * ]
14 | * 来源:力扣(LeetCode)
15 | * 链接:https://leetcode-cn.com/problems/spiral-matrix-ii
16 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
17 | * @author: icecrea
18 | * @create: 2020-05-01
19 | **/
20 | public class LeetCode059_SpiralMatrix2 {
21 |
22 | public int[][] generateMatrix(int n) {
23 | int left = 0, right = n - 1, top = 0, bottom = n - 1;
24 | int[][] mat = new int[n][n];
25 | int num = 1, end = n * n;
26 | while (num <= end) {
27 | for (int i = left; i <= right; i++) {
28 | mat[top][i] = num++; // left to right.
29 | }
30 | top++;
31 | for (int i = top; i <= bottom; i++) {
32 | mat[i][right] = num++; // top to bottom.
33 | }
34 | right--;
35 | for (int i = right; i >= left; i--) {
36 | mat[bottom][i] = num++; // right to left.
37 | }
38 | bottom--;
39 | for (int i = bottom; i >= top; i--) {
40 | mat[i][left] = num++; // bottom to top.
41 | }
42 | left++;
43 | }
44 | return mat;
45 | }
46 |
47 |
48 | }
49 |
--------------------------------------------------------------------------------
/src/main/java/com/example/leetcode/other/LeetCode11_ContainerWithMostWater.java:
--------------------------------------------------------------------------------
1 | package com.example.leetcode.other;
2 |
3 | /**
4 | * @description:
5 | * @author: icecrea
6 | * @create: 2018-12-24 17:48
7 | **/
8 | public class LeetCode11_ContainerWithMostWater {
9 |
10 | /**
11 | * leetcode 11 盛水最多的容器
12 | * https://leetcode-cn.com/problems/container-with-most-water/
13 | * 给定 n 个非负整数 a1,a2,...,an,每个数代表坐标中的一个点 (i, ai) 。
14 | * 在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0)。
15 | * 找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
16 | *
17 | * 示例
18 | * 输入: [1,8,6,2,5,4,8,3,7]
19 | * 输出: 49
20 | *
21 | * @return
22 | */
23 | public int maxArea(int[] height) {
24 | int maxarea = 0;
25 | for (int i = 0; i < height.length; i++) {
26 | for (int j = i + 1; j < height.length; j++) {
27 | maxarea = Math.max(maxarea, Math.min(height[i], height[j]) * (j - i));
28 | }
29 | }
30 | return maxarea;
31 | }
32 |
33 | /**
34 | * 使用两个指针,一个放在开始,一个置于末尾。
35 | * 此外,我们会使用变量 maxareamaxarea 来持续存储到目前为止所获得的最大面积。
36 | * 在每一步中,我们会找出指针所指向的两条线段形成的区域,更新 maxareamaxarea,
37 | * 并将指向较短线段的指针向较长线段那端移动一步。
38 | *
39 | * @param height
40 | * @return
41 | */
42 | public int maxArea2(int[] height) {
43 | int i = 0;
44 | int j = height.length - 1;
45 | int maxArea = 0;
46 | while (i < j) {
47 | int area = (j - i) * Math.min(height[i], height[j]);
48 | if (area > maxArea) {
49 | maxArea = area;
50 | }
51 | if (height[i] < height[j]) {
52 | i++;
53 | } else {
54 | j--;
55 | }
56 | }
57 | return maxArea;
58 | }
59 |
60 | }
61 |
--------------------------------------------------------------------------------
/src/main/java/com/example/leetcode/other/LeetCode202_HappyNumber.java:
--------------------------------------------------------------------------------
1 | package com.example.leetcode.other;
2 |
3 | import java.util.HashSet;
4 | import java.util.Set;
5 |
6 | /**
7 | * @description: 快乐数
8 | * 编写一个算法来判断一个数 n 是不是快乐数。
9 | *
10 | * 「快乐数」定义为:对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和,然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。如果 可以变为 1,那么这个数就是快乐数。
11 | *
12 | * 如果 n 是快乐数就返回 True ;不是,则返回 False 。
13 | *
14 | *
15 | *
16 | * 示例:
17 | *
18 | * 输入:19
19 | * 输出:true
20 | * 解释:
21 | * 12 + 92 = 82
22 | * 82 + 22 = 68
23 | * 62 + 82 = 100
24 | * 12 + 02 + 02 = 1
25 | *
26 | * 来源:力扣(LeetCode)
27 | * 链接:https://leetcode-cn.com/problems/happy-number
28 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
29 | * @author: icecrea
30 | * @create: 2020-04-30
31 | **/
32 | public class LeetCode202_HappyNumber {
33 |
34 | public boolean isHappy(int n) {
35 | Set
10 | * 示例 1:
11 | *
12 | * 输入: [10,2]
13 | * 输出: 210
14 | * 示例 2:
15 | *
16 | * 输入: [3,30,34,5,9]
17 | * 输出: 9534330
18 | * 说明: 输出结果可能非常大,所以你需要返回一个字符串而不是整数。
19 | * @author: icecrea
20 | * @create: 2019-03-27 10:21
21 | **/
22 | public class LeetCode179_LargestNumber {
23 |
24 | public String largestNumber(int[] num) {
25 |
26 | if (num == null || num.length == 0) {
27 | return "";
28 | }
29 |
30 | String[] numStr = new String[num.length];
31 | for (int i = 0; i < num.length; i++) {
32 | numStr[i] = String.valueOf(num[i]);
33 | }
34 |
35 | Comparator
10 | * 示例 1:
11 | *
12 | * 输入: nums1 = [1,2,2,1], nums2 = [2,2]
13 | * 输出: [2]
14 | * 示例 2:
15 | *
16 | * 输入: nums1 = [4,9,5], nums2 = [9,4,9,8,4]
17 | * 输出: [9,4]
18 | * 说明:
19 | *
20 | * 输出结果中的每个元素一定是唯一的。
21 | * 我们可以不考虑输出结果的顺序。
22 | * @author: icecrea
23 | * @create: 2019-03-28 09:54
24 | **/
25 | public class LeetCode349_IntersectionOfTwoArrays {
26 |
27 | public int[] intersection(int[] nums1, int[] nums2) {
28 | HashSet
9 | * 如果不能形成任何面积不为零的三角形,返回 0。
10 | *
11 | *
12 | *
13 | * 示例 1:
14 | *
15 | * 输入:[2,1,2]
16 | * 输出:5
17 | * 示例 2:
18 | *
19 | * 输入:[1,2,1]
20 | * 输出:0
21 | * 示例 3:
22 | *
23 | * 输入:[3,2,3,4]
24 | * 输出:10
25 | * 示例 4:
26 | *
27 | * 输入:[3,6,2,3]
28 | * 输出:8
29 | *
30 | *
31 | * 提示:
32 | *
33 | * 3 <= A.length <= 10000
34 | * 1 <= A[i] <= 10^6
35 | * @author: icecrea
36 | * @create: 2019-04-02 10:08
37 | **/
38 | public class LeetCode976_LargestTriangle {
39 |
40 | /**
41 | * 排序之后从后往前 尽量找最大
42 | * @param A
43 | * @return
44 | */
45 | public int largestPerimeter(int[] A) {
46 | Arrays.sort(A);
47 | for (int i = A.length - 3; i >= 0; --i) {
48 | if (A[i] + A[i + 1] > A[i + 2]) {
49 | return A[i] + A[i + 1] + A[i + 2];
50 | }
51 | }
52 | return 0;
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/main/java/com/example/leetcode/sort/README.md:
--------------------------------------------------------------------------------
1 | ## 排序专题
2 |
3 | - [56.合并区间](./LeetCode56_MergeIntervals.java)
4 | - [57.插入区间](./LeetCode57_InsertInterval.java)
5 | - [75.颜色分类](./LeetCode75_SortColors.java)
6 | - [147.链表插入排序](./LeetCode147_InsertionSortList.java)
7 | - [148.排序链表](./LeetCode148_SortList.java)
8 | - [164.最大间距](./LeetCode164_MaximumGap.java)
9 | - [179.最大数](./LeetCode179_LargestNumber.java)
10 | - [215.数组中第K个最大元素](./LeetCode215_KthLargestElementInAnArray.java)
11 | - [274.H指数](./LeetCode274_HIndex.java)
12 | - [324.摆动排序2](./LeetCode324_WiggleSort2.java)
13 | - [349.两个数组交集](./LeetCode349_IntersectionOfTwoArrays.java)
14 | - [524.通过删除字母匹配到字典里最长单词](./LeetCode524_LongestWordInDictionaryThroughDeleting.java)
15 | - [710.黑名单中随机数](./LeetCode710_RandomPickWithBlackList.java)
16 | - [767.重构字符串](./LeetCode767_ReorganizeString.java)
17 | - [922.按奇偶排序数组2](./LeetCode922_sortArrayByParity2.java)
18 | - [969.煎饼排序](./LeetCode969_PancakeSorting.java)
19 | - [973.最接近原点的K个点](./LeetCode973_KClosestPointsToOrigin.java)
20 | - [976.三角形最大周长](./LeetCode976_LargestTriangle.java)
--------------------------------------------------------------------------------
/src/main/java/com/example/leetcode/sort/SortStackByStack.java:
--------------------------------------------------------------------------------
1 | package com.example.leetcode.sort;
2 |
3 | import org.junit.Test;
4 |
5 | import java.util.Stack;
6 |
7 | /**
8 | * @description: 用一个栈排序另一个栈
9 | * @auther: icecrea
10 | * @date: 2020/4/24
11 | */
12 | public class SortStackByStack {
13 | public static void sortStackByStack(Stack
20 | * 对应输出应该为:
21 | *
22 | * 1,2,3,4,5
23 | *
24 | *
25 | *
26 | * @param node
27 | */
28 | public void push(int node) {
29 | stack1.push(node);
30 | }
31 |
32 | public int pop() {
33 | //当stack2为空时,一次压入stack1中全部全元素。 即栈1每次出栈时,弹出所有元素
34 | if (stack2.empty()) {
35 | while (!stack1.empty()) {
36 | stack2.push(stack1.pop());
37 | }
38 | }
39 | //不为空时,弹出栈顶元素
40 | return stack2.pop();
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/main/java/com/example/swordoffer/Sword07_Fibonacci.java:
--------------------------------------------------------------------------------
1 | package com.example.swordoffer;
2 |
3 | /**
4 | * @description:斐波那契数列
5 | * 大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项(从0开始,第0项为0)。n<=39
6 | * @author: icecrea
7 | * @create: 2019-04-17 23:54
8 | **/
9 | public class Sword07_Fibonacci {
10 |
11 | public int Fibonacci(int n) {
12 | if (n == 0) {
13 | return 0;
14 | }
15 | int[] a = new int[n + 1];
16 | a[0] = 0;
17 | a[1] = 1;
18 | for (int i = 2; i <= n; i++) {
19 | a[i] = a[i - 1] + a[i - 2];
20 | }
21 | return a[n];
22 | }
23 |
24 | public int Fibonacci2(int n) {
25 | if (n == 1) {
26 | return 1;
27 | }
28 | int p = 0;
29 | int q = 1;
30 | int ans = 0;
31 | for (int i = 2; i <= n; i++) {
32 | ans = p + q;
33 | p = q;
34 | q = ans;
35 | }
36 | return ans;
37 | }
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/src/main/java/com/example/swordoffer/Sword08_JumpFloor.java:
--------------------------------------------------------------------------------
1 | package com.example.swordoffer;
2 |
3 | /**
4 | * @description: 青蛙跳台阶
5 | * 一只青蛙一次可以跳上1级台阶,也可以跳上2级。
6 | * 求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果)。
7 | * @author: icecrea
8 | * @create: 2019-04-18 00:10
9 | **/
10 | public class Sword08_JumpFloor {
11 | public int JumpFloor(int target) {
12 | if (target == 1) {
13 | return 1;
14 | }
15 | if (target == 2) {
16 | return 2;
17 | }
18 | return JumpFloor(target - 1) + JumpFloor(target - 2);
19 | }
20 |
21 | public int JumpFloor2(int target) {
22 | if (target == 1) {
23 | return 1;
24 | }
25 | if (target == 2) {
26 | return 2;
27 | }
28 | int p = 1;
29 | int q = 2;
30 | int sum = 0;
31 | for (int i = 3; i <= target; i++) {
32 | sum = p + q;
33 | p = q;
34 | q = sum;
35 | }
36 | return sum;
37 | }
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/src/main/java/com/example/swordoffer/Sword09_JumpFloorII.java:
--------------------------------------------------------------------------------
1 | package com.example.swordoffer;
2 |
3 | /**
4 | * @description: 变态跳台阶
5 | * 一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。
6 | * @author: icecrea
7 | * @create: 2019-04-18 00:15
8 | **/
9 | public class Sword09_JumpFloorII {
10 | /**
11 | * 1 1 1
12 | * 2 2 11/2
13 | * 3 4 111/21/12/3
14 | * 4 8 1111/121/211/112/31/13/4/22
15 | * 5 16 11111/1112/1121/1211/2111/311/131/113/14/41/5/221/122/212/32/23
16 | *
17 | *
18 | *
19 | *
20 | * 因为n级台阶,第一步有n种跳法:跳1级、跳2级、到跳n级
21 | * 跳1级,剩下n-1级,则剩下跳法是f(n-1)
22 | * 跳2级,剩下n-2级,则剩下跳法是f(n-2)
23 | * 所以f(n)=f(n-1)+f(n-2)+...+f(1)
24 | * 因为f(n-1)=f(n-2)+f(n-3)+...+f(1)
25 | * 所以f(n)=2*f(n-1)
26 | *
27 | * @param target
28 | * @return
29 | */
30 | public int JumpFloorII(int target) {
31 | return 1 << (target - 1);
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/java/com/example/swordoffer/Sword10_RectCover.java:
--------------------------------------------------------------------------------
1 | package com.example.swordoffer;
2 |
3 | /**
4 | * @description: 矩形覆盖
5 | * 我们可以用2*1的小矩形横着或者竖着去覆盖更大的矩形。
6 | * 请问用n个2*1的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法?
7 | * @author: icecrea
8 | * @create: 2019-04-18 00:42
9 | **/
10 | public class Sword10_RectCover {
11 |
12 | /**
13 | * 1 1
14 | * 2 2
15 | * 3 3
16 | * 4 5
17 | * target = 1大矩形为2*1,只有一种摆放方法,return1;
18 | * target = 2 大矩形为2*2,有两种摆放方法,return2;
19 | * target = n 分为两步考虑:
20 | * 1.第一次摆放一块 2*1 的小矩阵,则摆放方法总共为f(target - 1)
21 | * 2.第一次摆放一块1*2的小矩阵,则摆放方法总共为f(target-2)
22 | *
23 | * @param target
24 | * @return
25 | */
26 | public int RectCover(int target) {
27 | if (target == 1) {
28 | return 1;
29 | }
30 | if (target == 2) {
31 | return 2;
32 | }
33 | int p = 1;
34 | int q = 2;
35 | int sum = 0;
36 | for (int i = 3; i <= target; i++) {
37 | sum = p + q;
38 | p = q;
39 | q = sum;
40 | }
41 | return sum;
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/main/java/com/example/swordoffer/Sword11_NumberOf1.java:
--------------------------------------------------------------------------------
1 | package com.example.swordoffer;
2 |
3 | /**
4 | * @description: 二进制中1的个数
5 | * 输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。
6 | * @author: icecrea
7 | * @create: 2019-04-18 09:02
8 | **/
9 | public class Sword11_NumberOf1 {
10 |
11 | public int NumberOf1(int n) {
12 | int size = 0;
13 | while (n != 0) {
14 | size += n & 1;
15 | n = n >>> 1;
16 | }
17 | return size;
18 | }
19 |
20 |
21 | /**
22 | * 如果一个整数不为0,那么这个整数至少有一位是1(二进制)。如果我们把这个整数减1,那么原来处在整数最右边的1就会变为0,
23 | * 原来在1后面的所有的0都会变成1(如果最右边的1后面还有0的话)。其余所有位将不会受到影响。
24 | * 举个例子:一个二进制数1100,从右边数起第三位是处于最右边的一个1。减去1后,第三位变成0,它后面的两位0变成了1
25 | * ,而前面的1保持不变,因此得到的结果是1011.我们发现减1的结果是把最右边的一个1开始的所有位都取反了。
26 | * 这个时候如果我们再把原来的整数和减去1之后的结果做与运算,从原来整数最右边一个1那一位开始所有位都会变成0。
27 | * 如1100&1011=1000.也就是说,把一个整数减去1,再和原整数做与运算,会把该整数最右边一个1变成0.
28 | * 那么一个整数的二进制有多少个1,就可以进行多少次这样的操作。
29 | *
30 | * @param n
31 | * @return
32 | */
33 | public int NumberOf1II(int n) {
34 | int count = 0;
35 | while (n != 0) {
36 | count++;
37 | n = n & (n - 1);
38 | }
39 | return count;
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/main/java/com/example/swordoffer/Sword12_Power.java:
--------------------------------------------------------------------------------
1 | package com.example.swordoffer;
2 |
3 | /**
4 | * @description: 给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。
5 | * @author: icecrea
6 | * @create: 2019-04-18 09:03
7 | **/
8 | public class Sword12_Power {
9 | public double Power(double base, int exponent) {
10 | double result = 1;
11 | for (int i = 0; i < Math.abs(exponent); i++) {
12 | result *= base;
13 | }
14 | if (exponent < 0) {
15 | result = 1 / result;
16 | }
17 | return result;
18 | }
19 |
20 |
21 | /**
22 | * 2^11 = 2^1 * 2^2 * 2^8
23 | * 2^1011 = 2^0001 * 2^0010 * 2^1000
24 | *
25 | * 写出指数的二进制表达,例如13表达为二进制1101。
26 | * 举例:10^1101 = 10^0001* 10^0100 * 10^1000。
27 | * 通过&1和>>1来逐位读取1101,为1时将该位代表的乘数累乘到最终结果。
28 | */
29 | public double Power2(double base, int n) {
30 | double res = 1;
31 | int exponent;
32 | if (n > 0) {
33 | exponent = n;
34 | } else if (n < 0) {
35 | exponent = -n;
36 | } else {
37 | // 0次方
38 | return 1;
39 | }
40 |
41 | while (exponent != 0) {
42 | if ((exponent & 1) == 1) {
43 | res *= base;
44 | }
45 | // 翻倍
46 | base *= base;
47 | // 右移一位
48 | exponent >>= 1;
49 | }
50 | return n >= 0 ? res : (1 / res);
51 | }
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/src/main/java/com/example/swordoffer/Sword14_FindKthToTail.java:
--------------------------------------------------------------------------------
1 | package com.example.swordoffer;
2 |
3 | import com.example.leetcode.linkedlist.pojo.ListNode;
4 |
5 | /**
6 | * @description: 链表中倒数第k个节点
7 | * 输入一个链表,输出该链表中倒数第k个结点。
8 | * @author: icecrea
9 | * @create: 2019-04-18 13:26
10 | **/
11 | public class Sword14_FindKthToTail {
12 |
13 | /**
14 | * 用例:
15 | * 6,{1,2,3,4,5}
16 | *
17 | * 对应输出应该为:
18 | *
19 | * {}
20 | *
21 | * 你的输出为:
22 | *
23 | * {1,2,3,4,5}
24 | *
25 | * @param head
26 | * @param k
27 | * @return
28 | */
29 | public ListNode FindKthToTail(ListNode head, int k) {
30 | int len = 0;
31 | ListNode cur = head;
32 | while (cur != null) {
33 | len++;
34 | cur = cur.next;
35 | }
36 | if (len < k) {
37 | return null;
38 | }
39 | for (int i = 0; i < len - k; i++) {
40 | head = head.next;
41 | }
42 | return head;
43 | }
44 |
45 | /**
46 | * 倒数第k个订单,快指针先走k-1步
47 | * 注意终止条件是 fast.next !=null
48 | *
49 | * @param head
50 | * @param k
51 | * @return
52 | */
53 | public ListNode FindKthToTail2(ListNode head, int k) {
54 | if (head == null || k <= 0) {
55 | return null;
56 | }
57 | ListNode fast = head;
58 | ListNode slow = head;
59 | for (int i = 0; i < k - 1; i++) {
60 | if (fast.next != null) {
61 | fast = fast.next;
62 | } else {
63 | return null;
64 | }
65 | }
66 | while (fast.next != null) {
67 | fast = fast.next;
68 | slow = slow.next;
69 | }
70 | return slow;
71 | }
72 |
73 |
74 | }
75 |
--------------------------------------------------------------------------------
/src/main/java/com/example/swordoffer/Sword15_ReverseList.java:
--------------------------------------------------------------------------------
1 | package com.example.swordoffer;
2 |
3 | import com.example.leetcode.linkedlist.pojo.ListNode;
4 |
5 | /**
6 | * @description: 反转链表
7 | * 输入一个链表,反转链表后,输出新链表的表头。
8 | * @author: icecrea
9 | * @create: 2019-04-18 18:39
10 | **/
11 | public class Sword15_ReverseList {
12 | public ListNode ReverseList(ListNode head) {
13 | ListNode pre = null;
14 | ListNode next;
15 | while (head != null) {
16 | next = head.next;
17 | head.next = pre;
18 | pre = head;
19 | head = next;
20 | }
21 | return pre;
22 | }
23 |
24 | private ListNode reverse(ListNode head) {
25 | //递归终止条件: 找到链表最后一个节点 注意空链表
26 | if (head == null || head.next == null) {
27 | return head;
28 | }
29 | ListNode newNode = reverse(head.next);
30 | head.next.next = head;
31 | //反转头节点的next指针,将头节点作为尾节点
32 | head.next = null;
33 | return newNode;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/main/java/com/example/swordoffer/Sword16_MergeSortedLinkedList.java:
--------------------------------------------------------------------------------
1 | package com.example.swordoffer;
2 |
3 | import com.example.leetcode.linkedlist.pojo.ListNode;
4 |
5 | /**
6 | * @description: 合并两个排序的链表
7 | * @author: icecrea
8 | * @create: 2019-11-07
9 | **/
10 | public class Sword16_MergeSortedLinkedList {
11 |
12 | public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
13 | ListNode dummy = new ListNode(Integer.MIN_VALUE);
14 | ListNode cur = dummy;
15 | while (l1 != null && l2 != null) {
16 | if (l1.val < l2.val) {
17 | cur.next = l1;
18 | l1 = l1.next;
19 | } else {
20 | cur.next = l2;
21 | l2 = l2.next;
22 | }
23 | cur = cur.next;
24 | }
25 | cur.next = l1 == null ? l2 : l1;
26 | return dummy.next;
27 | }
28 |
29 |
30 | /**
31 | * 合并k个排序链表 分治成n个再2个合并
32 | * @param lists
33 | * @return
34 | */
35 | public ListNode mergeKLists(ListNode[] lists) {
36 | return partion(lists, 0, lists.length - 1);
37 | }
38 |
39 | public ListNode partion(ListNode[] lists, int start, int end) {
40 | //终止条件
41 | if (start == end) {
42 | return lists[start];
43 | }
44 | int mid = start + ((end - start) >> 1);
45 | ListNode l1 = partion(lists, start, mid);
46 | ListNode l2 = partion(lists, mid + 1, end);
47 | return mergeTwoLists(l1, l2);
48 | }
49 |
50 | }
51 |
--------------------------------------------------------------------------------
/src/main/java/com/example/swordoffer/Sword17_HasSubtree.java:
--------------------------------------------------------------------------------
1 | package com.example.swordoffer;
2 |
3 | import com.example.leetcode.linkedlist.pojo.TreeNode;
4 |
5 |
6 | /**
7 | * @description: 树的子结构
8 | * 输入两棵二叉树A,B,判断B是不是A的子结构。(ps:我们约定空树不是任意一个树的子结构)
9 | * @author: icecrea
10 | * @create: 2019-04-18 19:25
11 | **/
12 | public class Sword17_HasSubtree {
13 |
14 | public boolean HasSubtree(TreeNode root1, TreeNode root2) {
15 | boolean result = false;
16 | //当Tree1和Tree2都不为零的时候,才进行比较。否则直接返回false
17 | if (root2 == null || root1 == null) {
18 | return false;
19 | }
20 | //如果找到了对应Tree2的根节点的点
21 | if (root1.val == root2.val) {
22 | //以这个根节点为为起点判断是否包含Tree2
23 | result = isSameTree(root1, root2);
24 | }
25 | //如果找不到,那么就再去root的左儿子当作起点,去判断时候包含Tree2
26 | if (!result) {
27 | result = HasSubtree(root1.left, root2);
28 | }
29 |
30 | //如果还找不到,那么就再去root的右儿子当作起点,去判断时候包含Tree2
31 | if (!result) {
32 | result = HasSubtree(root1.right, root2);
33 | }
34 | //返回结果
35 | return result;
36 | }
37 |
38 | /**
39 | * 比较两颗树是否完全相同
40 | */
41 | public boolean isSameTree(TreeNode root1, TreeNode root2) {
42 | // 都为空的话,显然相同
43 | if (root1 == null && root2 == null) {
44 | return true;
45 | }
46 | // 一个为空,一个非空,显然不同
47 | if (root1 == null || root2 == null) {
48 | return false;
49 | }
50 | // 两个都非空,但 val 不一样也不行
51 | if (root1.val != root2.val) {
52 | return false;
53 | }
54 | // root1 和 root2 该比的都比完了
55 | return isSameTree(root1.left, root2.left) && isSameTree(root1.right, root2.right);
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/main/java/com/example/swordoffer/Sword20_StackWithMin.java:
--------------------------------------------------------------------------------
1 | package com.example.swordoffer;
2 |
3 | import java.util.Stack;
4 |
5 | /**
6 | * @description: 包含Min的栈
7 | * 定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min函数(时间复杂度应为O(1))。
8 | * @author: icecrea
9 | * @create: 2019-04-18 23:37
10 | **/
11 | public class Sword20_StackWithMin {
12 |
13 | /**
14 | * 注意需要初始化
15 | */
16 | private Stack
16 | * 先全部异或,再按照亦或后某一位不为0,分成两个子数组异或
17 | * [2,4,3,6,3,2,5,5]
18 | *
19 | * @param array
20 | * @param num1
21 | * @param num2
22 | */
23 | public void FindNumsAppearOnce(int[] array, int num1[], int num2[]) {
24 | int sum = 0;
25 | for (int a : array) {
26 | sum ^= a;
27 | }
28 | int firstBit1 = findFirstBit1(sum);
29 | //按照某一位是不是1来划分成两个数组(保证只出现一次的两个数在两个数组)
30 | for (int i = 0; i < array.length; i++) {
31 | if (isBit1(array[i], firstBit1)) {
32 | num1[0] ^= array[i];
33 | } else {
34 | num2[0] ^= array[i];
35 | }
36 | }
37 | }
38 |
39 | public int findFirstBit1(int a) {
40 | int indexBit = 0;
41 | while (((a & 1) == 0) && indexBit < 32) {
42 | a = a >> 1;
43 | ++indexBit;
44 | }
45 | return indexBit;
46 | }
47 |
48 | public boolean isBit1(int num, int indexBit) {
49 | num = num >> indexBit;
50 | return (num & 1) == 1;
51 | }
52 |
53 | @Test
54 | public void test() {
55 | int[] a = new int[]{2, 4, 3, 6, 3, 2, 5, 5};
56 | int[] num1 = new int[1];
57 | int[] num2 = new int[1];
58 | FindNumsAppearOnce(a, num1, num2);
59 |
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/main/java/com/example/swordoffer/Sword41_ConitunuousSequence.java:
--------------------------------------------------------------------------------
1 | package com.example.swordoffer;
2 |
3 | import java.util.ArrayList;
4 |
5 | /**
6 | * @description: 和为S的连续正数序列
7 | * 小明很喜欢数学,有一天他在做数学作业时,要求计算出9~16的和,他马上就写出了正确答案是100。
8 | * 但是他并不满足于此,他在想究竟有多少种连续的正数序列的和为100(至少包括两个数)。
9 | * 没多久,他就得到另一组连续正数和为100的序列:18,19,20,21,22。
10 | * 现在把问题交给你,你能不能也很快的找出所有和为S的连续正数序列? Good Luck!
11 | * 输出描述:
12 | * 输出所有和为S的连续正数序列。序列内按照从小至大的顺序,序列间按照开始数字从小到大的顺序
13 | * @author: icecrea
14 | * @create: 2019-05-09 13:07
15 | **/
16 | public class Sword41_ConitunuousSequence {
17 |
18 | public ArrayList
6 | * 求1+2+3+...+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。
7 | * @author: icecrea
8 | * @create: 2019-09-05 00:11
9 | **/
10 | public class Sword47_Sum {
11 |
12 |
13 | /**
14 | * 利用短路与的特性,弥补无法使用if else,实现递归的终止条件(n=0的计算)
15 | *
16 | * 当n=0时候,不执行n += Sum_Solution(n - 1),直接返回0
17 | * 当n>0时,递归执行Sum_Solution
18 | *
19 | * @param n
20 | * @return
21 | */
22 | int Sum_Solution(int n) {
23 | boolean flag = (n > 0) && ((n += Sum_Solution(n - 1)) > 0);
24 | return n;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/main/java/com/example/swordoffer/Sword48_Add.java:
--------------------------------------------------------------------------------
1 | package com.example.swordoffer;
2 |
3 | import org.junit.Test;
4 |
5 | /**
6 | * @description: 不用加减乘除做加法
7 | * 写一个函数,求两个整数之和,要求在函数体内不得使用+、-、*、/四则运算符号。
8 | * @author: icecrea
9 | * @create: 2019-11-07
10 | **/
11 | public class Sword48_Add {
12 | /**
13 | * 1.两个数异或:相当于每一位相加,而不考虑进位;
14 | * 2.两个数相与,并左移一位:相当于求得进位;
15 | * 3.将上述两步的结果相加
16 | */
17 | public int Add(int num1, int num2) {
18 | while (num2 != 0) {
19 | //求和
20 | int sum = num1 ^ num2;
21 | //求进位
22 | int carray = (num1 & num2) << 1;
23 | num1 = sum;
24 | num2 = carray;
25 | }
26 | return num1;
27 | }
28 |
29 | @Test
30 | public void test() {
31 | int a = 5;
32 | int b = 7;
33 | System.out.println(Add(a, b));
34 | //circle0: num1 5 num2 7 | 101 111
35 | //circle1: sum 2 carry 10 | 010 1010
36 | //circle2: sum 8 carry 4 | 1000 100
37 | //circle3: sum 12 carry 0 | 1100 0
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/main/java/com/example/swordoffer/Sword54_FirstAppearingOnce.java:
--------------------------------------------------------------------------------
1 | package com.example.swordoffer;
2 |
3 | /**
4 | * @description: 字符流中第一个不重复的数字、
5 | *
6 | * 题目描述
7 | * 请实现一个函数用来找出字符流中第一个只出现一次的字符。例如,当从字符流中只读出前两个字符"go"时,第一个只出现一次的字符是"g"。当从该字符流中读出前六个字符“google"时,第一个只出现一次的字符是"l"。
8 | * 输出描述:
9 | * 如果当前字符流没有存在出现一次的字符,返回#字符。
10 | * @author: icecrea
11 | * @create: 2019-09-11 12:57
12 | **/
13 | public class Sword54_FirstAppearingOnce {
14 |
15 | /**
16 | * 一个字符8位,使用256数组足够
17 | */
18 | int[] hashtable = new int[256];
19 | StringBuffer s = new StringBuffer();
20 |
21 | //Insert one char from stringstream
22 | public void Insert(char ch) {
23 | s.append(ch);
24 | if (hashtable[ch] == 0) {
25 | hashtable[ch] = 1;
26 | } else {
27 | hashtable[ch] += 1;
28 | }
29 | }
30 |
31 | //return the first appearence once char in current stringstream
32 | public char FirstAppearingOnce() {
33 | char[] str = s.toString().toCharArray();
34 | for (char c : str) {
35 | if (hashtable[c] == 1) {
36 | return c;
37 | }
38 | }
39 | return '#';
40 | }
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/src/main/java/com/example/swordoffer/Sword55_EntryNodeOfLoop.java:
--------------------------------------------------------------------------------
1 | package com.example.swordoffer;
2 |
3 | import com.example.leetcode.linkedlist.LeetCode142_LinkedListCycle2;
4 | import com.example.leetcode.linkedlist.pojo.ListNode;
5 |
6 | /**
7 | * @description: 链表中环的入口结点
8 | * 给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null。
9 | * @author: icecrea
10 | * @create: 2019-09-11 12:58
11 | **/
12 | public class Sword55_EntryNodeOfLoop {
13 |
14 | /**
15 | * 思路参考 LEETCODE142题
16 | * @see LeetCode142_LinkedListCycle2
17 | * @param pHead
18 | * @return
19 | */
20 | public ListNode EntryNodeOfLoop(ListNode pHead) {
21 | if (pHead == null) {
22 | return null;
23 | }
24 | ListNode fast = pHead;
25 | ListNode slow = pHead;
26 |
27 | boolean isCycle = false;
28 | while (fast.next != null && fast.next.next != null) {
29 | fast = fast.next.next;
30 | slow = slow.next;
31 | if (fast == slow) {
32 | isCycle = true;
33 | break;
34 | }
35 | }
36 |
37 | if (isCycle) {
38 | ListNode p = pHead;
39 | while (p != slow) {
40 | p = p.next;
41 | slow = slow.next;
42 | }
43 | }
44 |
45 | return slow;
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/main/java/com/example/swordoffer/Sword56_DeleteDuplication.java:
--------------------------------------------------------------------------------
1 | package com.example.swordoffer;
2 |
3 | import com.example.leetcode.linkedlist.LeetCode82_RemoveDuplicatesFromSortedList2;
4 | import com.example.leetcode.linkedlist.pojo.ListNode;
5 |
6 | /**
7 | * @description: 删除链表中重复的节点
8 | * 在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5
9 | * @author: icecrea
10 | * @create: 2019-09-11 12:58
11 | **/
12 | public class Sword56_DeleteDuplication {
13 |
14 | /**
15 | * 参考leetcode 82题
16 | *
17 | * @param pHead
18 | * @return
19 | * @see LeetCode82_RemoveDuplicatesFromSortedList2
20 | * 难点在
21 | * 1.多个重复节点的删除
22 | * 2.删除节点前一个指针的保存
23 | *
24 | * 因为要删除所有重复的元素而并非留一个,所以要考虑头节点删除,留出pre指针,比较后两个大小是否相等
25 | */
26 | public ListNode deleteDuplication(ListNode pHead) {
27 | ListNode dummy = new ListNode(Integer.MIN_VALUE);
28 | dummy.next = pHead;
29 | ListNode pre = dummy;
30 | //因为要删除所有重复的元素而并非留一个,所以要考虑头节点删除,留出pre指针,比较后两个大小是否相等
31 | while (pre.next != null && pre.next.next != null) {
32 | if (pre.next.val != pre.next.next.val) {
33 | pre = pre.next;
34 | continue;
35 | } else {
36 | ListNode lastSame = pre.next.next;
37 | while (lastSame.next != null && pre.next.val == lastSame.next.val) {
38 | lastSame = lastSame.next;
39 | }
40 | //移动指针指向,不真正移动指针,指针的移动在不同时候
41 | pre.next = lastSame.next;
42 | }
43 | }
44 | return dummy.next;
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/main/java/com/example/swordoffer/Sword57_GetNext.java:
--------------------------------------------------------------------------------
1 | package com.example.swordoffer;
2 |
3 | /**
4 | * @description: 二叉树中序遍历下一个节点
5 | * 给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。
6 | * @author: icecrea
7 | * @create: 2019-09-11 12:59
8 | **/
9 | public class Sword57_GetNext {
10 |
11 | /**
12 | * A
13 | * B C
14 | * D E F G
15 | * H I
16 | * 思路:
17 | * (1) 若该节点存在右子树:则下一个节点为右子树最左子节点(如图节点 B )
18 | * (2) 若该节点不存在右子树:这时分两种情况:
19 | * 2.1 该节点为父节点的左子节点,则下一个节点为其父节点(如图节点 D )
20 | * 2.2 该节点为父节点的右子节点,则沿着父节点向上遍历,直到找到一个节点的父节点的左子节点为该节点,则该节点的父节点下一个节点(如图节点 I ,沿着父节点一直向上查找找到 B ( B 为其父节点的左子节点),则 B 的父节点 A 为下一个节点)
21 | *
22 | * @param node
23 | * @return
24 | */
25 | public TreeLinkNode GetNext(TreeLinkNode node) {
26 | if (node == null) {
27 | return null;
28 | }
29 | //如果有右子树,则找右子树的最左节点
30 | if (node.right != null) {
31 | node = node.right;
32 | while (node.left != null) {
33 | node = node.left;
34 | }
35 | return node;
36 | }
37 | //没右子树,则找第一个当前节点是父节点左孩子的节点
38 | while (node.next != null) {
39 | if (node.next.left == node) {
40 | return node.next;
41 | }
42 | node = node.next;
43 | }
44 | //退到了根节点仍没找到,则返回null
45 | return null;
46 | }
47 |
48 | public class TreeLinkNode {
49 | int val;
50 | TreeLinkNode left = null;
51 | TreeLinkNode right = null;
52 | TreeLinkNode next = null;
53 |
54 | TreeLinkNode(int val) {
55 | this.val = val;
56 | }
57 | }
58 | }
59 |
60 |
--------------------------------------------------------------------------------
/src/main/java/com/example/swordoffer/Sword61_SerializeTreeNode.java:
--------------------------------------------------------------------------------
1 | package com.example.swordoffer;
2 |
3 | import com.example.leetcode.linkedlist.pojo.TreeNode;
4 |
5 | /**
6 | * @description: 序列化二叉树
7 | * 请实现两个函数,分别用来序列化和反序列化二叉树
8 | * 二叉树的序列化是指:把一棵二叉树按照某种遍历方式的结果以某种格式保存为字符串,从而使得内存中建立起来的二叉树可以持久保存。
9 | * 序列化可以基于先序、中序、后序、层序的二叉树遍历方式来进行修改,序列化的结果是一个字符串,序列化时通过 某种符号表示空节点(#),以,表示一个结点值的结束(value,)。
10 | * 二叉树的反序列化是指:根据某种遍历顺序得到的序列化字符串结果str,重构二叉树。
11 | * @author: icecrea
12 | * @create: 2019-09-11 22:47
13 | **/
14 | public class Sword61_SerializeTreeNode {
15 | public int index = -1;
16 |
17 | String Serialize(TreeNode root) {
18 | StringBuffer sb = new StringBuffer();
19 | if (root == null) {
20 | sb.append("#,");
21 | return sb.toString();
22 | }
23 | sb.append(root.val + ",");
24 | sb.append(Serialize(root.left));
25 | sb.append(Serialize(root.right));
26 | return sb.toString();
27 | }
28 |
29 | TreeNode Deserialize(String str) {
30 | index++;
31 | TreeNode node = null;
32 | String[] strr = str.split(",");
33 | if (!strr[index].equals("#")) {
34 | node = new TreeNode(Integer.valueOf(strr[index]));
35 | node.left = Deserialize(str);
36 | node.right = Deserialize(str);
37 | }
38 | return node;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/main/java/com/example/swordoffer/Sword66_MovingCount.java:
--------------------------------------------------------------------------------
1 | package com.example.swordoffer;
2 |
3 | import org.junit.Test;
4 |
5 | /**
6 | * @description: 机器人的运动范围
7 | * 地上有一个m行和n列的方格。一个机器人从坐标0,0的格子开始移动,每一次只能向左,右,上,下四个方向移动一格,但是不能进入行坐标和列坐标的数位之和大于k的格子。
8 | * 例如,当k为18时,机器人能够进入方格(35,37),因为3+5+3+7 = 18。但是,它不能进入方格(35,38),因为3+5+3+8 = 19。请问该机器人能够达到多少个格子?
9 | * @author: icecrea
10 | * @create: 2019-11-07
11 | **/
12 | public class Sword66_MovingCount {
13 | public int movingCount(int threshold, int rows, int cols) {
14 | int flag[][] = new int[rows][cols];
15 | return dfs(0, 0, rows, cols, flag, threshold);
16 | }
17 |
18 | private int dfs(int i, int j, int rows, int cols, int[][] flag, int threshold) {
19 | if (i < 0 || i >= rows || j < 0 || j >= cols || numSum(i) + numSum(j) > threshold || flag[i][j] == 1) {
20 | return 0;
21 | }
22 | flag[i][j] = 1;
23 | return dfs(i - 1, j, rows, cols, flag, threshold)
24 | + dfs(i + 1, j, rows, cols, flag, threshold)
25 | + dfs(i, j - 1, rows, cols, flag, threshold)
26 | + dfs(i, j + 1, rows, cols, flag, threshold)
27 | + 1;
28 | }
29 |
30 | private int numSum(int i) {
31 | int sum = 0;
32 | do {
33 | sum += i % 10;
34 | } while ((i = i / 10) > 0);
35 | return sum;
36 | }
37 |
38 | @Test
39 | public void test() {
40 | System.out.println(movingCount(18, 5, 5));
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/main/java/com/example/swordoffer/Sword68_MaxGift.java:
--------------------------------------------------------------------------------
1 | package com.example.swordoffer;
2 |
3 | import org.junit.Test;
4 |
5 | /**
6 | * @description: 礼物的最大价值
7 | * (剑指offer题目,牛客网剑指offer在线变成没有该题,手动补充)
8 | * 在一个 m*n 的棋盘的每一格都放有一个礼物,每个礼物都有一定的价值(价值大于 0)。你可以从棋盘的左上角开始拿格子里的礼物,并每次向右或者向下移动一格、直到到达棋盘的右下角。给定一个棋盘及其上面的礼物的价值,请计算你最多能拿到多少价值的礼物?
9 | *
10 | * 示例 1:
11 | *
12 | * 输入:
13 | * [
14 | * [1,3,1],
15 | * [1,5,1],
16 | * [4,2,1]
17 | * ]
18 | * 输出: 12
19 | * 解释: 路径 1→3→5→2→1 可以拿到最多价值的礼物
20 | *
21 | *
22 | * 提示:
23 | *
24 | * 0 < grid.length <= 200
25 | * 0 < grid[0].length <= 200
26 | *
27 | * 来源:力扣(LeetCode)
28 | * 链接:https://leetcode-cn.com/problems/li-wu-de-zui-da-jie-zhi-lcof
29 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
30 | * @author: icecrea
31 | * @create: 2020-04-23
32 | **/
33 | public class Sword68_MaxGift {
34 |
35 | /**
36 | * dp - 到该位置能拿到的最大价值
37 | */
38 | public int maxValue(int[][] grid) {
39 | int[][] dp = new int[grid.length][grid[0].length];
40 | dp[0][0] = grid[0][0];
41 | for (int i = 1; i < dp.length; i++) {
42 | dp[i][0] = dp[i - 1][0] + grid[i][0];
43 | }
44 | for (int i = 1; i < dp[0].length; i++) {
45 | dp[0][i] = dp[0][i - 1] + grid[0][i];
46 | }
47 | for (int i = 1; i < dp.length; i++) {
48 | for (int j = 1; j < dp[0].length; j++) {
49 | dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]) + grid[i][j];
50 | }
51 | }
52 | return dp[grid.length - 1][grid[0].length - 1];
53 | }
54 |
55 | @Test
56 | public void test(){
57 | System.out.println(maxValue(new int[][]{{1,3,1},{1,5,1},{4,2,1}}));
58 | }
59 |
60 | }
61 |
--------------------------------------------------------------------------------
/src/main/java/com/example/topinterview/README.md:
--------------------------------------------------------------------------------
1 | # 高频算法题目清单
2 |
3 | 这是由LeetCode官方推出的的经典面试题目清单,将题目重新整理规划,从而为大家提供更好的练习体验和帮助大家找到理想的工作。 我们将题目分为以下三个部分:
4 |
5 | - 初级算法 - 帮助入门
6 | - 中级算法 - 巩固训练
7 | - 高级算法 - 提升进阶
8 |
9 | - [初级算法原地址](https://leetcode-cn.com/explore/interview/card/top-interview-questions-easy/)
10 | - [中级算法原地址](https://leetcode-cn.com/explore/interview/card/top-interview-questions-medium/)
11 | - [高级算法原地址](https://leetcode-cn.com/explore/interview/card/top-interview-questions-hard/)
12 |
--------------------------------------------------------------------------------
/src/main/java/com/example/topinterview/easy/array/array21_removeDuplicates.java:
--------------------------------------------------------------------------------
1 | package com.example.topinterview.easy.array;
2 |
3 | import org.junit.Test;
4 |
5 | /**
6 | * @description: 从排序数组中删除重复项
7 | *
8 | * 给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。
9 | *
10 | * 不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。
11 | *
12 | * 示例 1:
13 | * 给定数组 nums = [1,1,2],
14 | * 函数应该返回新的长度 2, 并且原数组 nums 的前两个元素被修改为 1, 2。
15 | * 你不需要考虑数组中超出新长度后面的元素。
16 | *
17 | * 示例 2:
18 | * 给定 nums = [0,0,1,1,1,2,2,3,3,4],
19 | * 函数应该返回新的长度 5, 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4。
20 | * 你不需要考虑数组中超出新长度后面的元素。
21 | *
22 | * 说明:
23 | * 为什么返回数值是整数,但输出的答案是数组呢?
24 | * 请注意,输入数组是以“引用”方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。
25 | *
26 | * 你可以想象内部操作如下:
27 | *
28 | * // nums 是以“引用”方式传递的。也就是说,不对实参做任何拷贝
29 | * int len = removeDuplicates(nums);
30 | *
31 | * // 在函数里修改输入数组对于调用者是可见的。
32 | * // 根据你的函数返回的长度, 它会打印出数组中该长度范围内的所有元素。
33 | * for (int i = 0; i < len; i++) {
34 | * print(nums[i]);
35 | * }
36 | * @author: icecrea
37 | * @create: 2019-02-19 09:18
38 | **/
39 | public class array21_removeDuplicates {
40 | public int removeDuplicates(int[] nums) {
41 | //两个指针 一个不断向后遍历,记录值不同的位置。一个记录需要替换的位置
42 | //数组新赋值的下标
43 | int index = 0;
44 | for (int i = index + 1; i < nums.length; i++) {
45 | if (nums[i] != nums[index]) {
46 | nums[++index] = nums[i];
47 | }
48 | }
49 | return index + 1;
50 | }
51 |
52 | @Test
53 | public void test() {
54 | int[] a = new int[]{0, 0, 1, 1, 1, 2, 2, 3, 3, 4};
55 | System.out.println(removeDuplicates(a));
56 | for (int i : a) {
57 | System.out.println(i);
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/main/java/com/example/topinterview/easy/array/array23_reverse.java:
--------------------------------------------------------------------------------
1 | package com.example.topinterview.easy.array;
2 |
3 | /**
4 | * @description: 旋转数组
5 | * 给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数。
6 | *
7 | * 示例 1:
8 | *
9 | * 输入: [1,2,3,4,5,6,7] 和 k = 3
10 | * 输出: [5,6,7,1,2,3,4]
11 | * 解释:
12 | * 向右旋转 1 步: [7,1,2,3,4,5,6]
13 | * 向右旋转 2 步: [6,7,1,2,3,4,5]
14 | * 向右旋转 3 步: [5,6,7,1,2,3,4]
15 | * 示例 2:
16 | *
17 | * 输入: [-1,-100,3,99] 和 k = 2
18 | * 输出: [3,99,-1,-100]
19 | * 解释:
20 | * 向右旋转 1 步: [99,-1,-100,3]
21 | * 向右旋转 2 步: [3,99,-1,-100]
22 | * 说明:
23 | *
24 | * 尽可能想出更多的解决方案,至少有三种不同的方法可以解决这个问题。
25 | * 要求使用空间复杂度为 O(1) 的原地算法。
26 | * @author: icecrea
27 | * @create: 2019-02-20 09:06
28 | **/
29 | public class array23_reverse {
30 | /**
31 | * 可以先整体反序,然后以k下标处分割,两部分再次反序
32 | *
33 | * @param nums
34 | * @param k
35 | */
36 | public void rotate(int[] nums, int k) {
37 | k = k % nums.length;
38 | reverse(nums, 0, nums.length - 1);
39 | reverse(nums, 0, k - 1);
40 | reverse(nums, k, nums.length - 1);
41 | }
42 |
43 | /**
44 | * @param nums
45 | * @param p
46 | * @param q
47 | */
48 | public void reverse(int[] nums, int p, int q) {
49 | while (p <= q) {
50 | int tmp = nums[p];
51 | nums[p] = nums[q];
52 | nums[q] = tmp;
53 | p++;
54 | q--;
55 | }
56 | }
57 |
58 | }
59 |
--------------------------------------------------------------------------------
/src/main/java/com/example/topinterview/easy/array/array24_containsDuplicate.java:
--------------------------------------------------------------------------------
1 | package com.example.topinterview.easy.array;
2 |
3 | import org.junit.Test;
4 |
5 | import java.util.HashMap;
6 | import java.util.HashSet;
7 | import java.util.Set;
8 |
9 | /**
10 | * @description: 存在重复
11 | * 给定一个整数数组,判断是否存在重复元素。
12 | *
13 | * 如果任何值在数组中出现至少两次,函数返回 true。如果数组中每个元素都不相同,则返回 false。
14 | *
15 | * 示例 1:
16 | * 输入: [1,2,3,1]
17 | * 输出: true
18 | *
19 | * 示例 2:
20 | * 输入: [1,2,3,4]
21 | * 输出: false
22 | * 示例 3:
23 | *
24 | * 输入: [1,1,1,3,3,4,3,2,4,2]
25 | * 输出: true
26 | * @author: icecrea
27 | * @create: 2019-02-20 09:44
28 | **/
29 | public class array24_containsDuplicate {
30 |
31 | public boolean containsDuplicate(int[] nums) {
32 | Set
10 | * 给定一个代表每个房屋存放金额的非负整数数组,计算你在不触动警报装置的情况下,能够偷窃到的最高金额。
11 | *
12 | * 示例 1:
13 | * 1 2 4 3
14 | * 输入: [1,2,3,1]
15 | * 输出: 4
16 | * 解释: 偷窃 1 号房屋 (金额 = 1) ,然后偷窃 3 号房屋 (金额 = 3)。
17 | * 偷窃到的最高金额 = 1 + 3 = 4 。
18 | * 示例 2:
19 | * 2 7 11 10 12
20 | * 输入: [2,7,9,3,1]
21 | * 输出: 12
22 | * 解释: 偷窃 1 号房屋 (金额 = 2), 偷窃 3 号房屋 (金额 = 9),接着偷窃 5 号房屋 (金额 = 1)。
23 | * 偷窃到的最高金额 = 2 + 9 + 1 = 12 。
24 | * @author: icecrea
25 | * @create: 2019-03-18 20:04
26 | **/
27 | public class array57_rob {
28 | public int rob(int[] nums) {
29 | if (nums == null || nums.length == 0) {
30 | return 0;
31 | }
32 | if (nums.length == 1) {
33 | return nums[0];
34 | }
35 | int[] dp = new int[nums.length];
36 | dp[0] = nums[0];
37 | dp[1] = Math.max(nums[0], nums[1]);
38 | for (int i = 2; i < nums.length; i++) {
39 | dp[i] = Math.max(dp[i - 2] + nums[i], dp[i - 1]);
40 | }
41 | return dp[nums.length - 1];
42 | }
43 |
44 | @Test
45 | public void test() {
46 | // 1 2 4 4
47 | // int rob = rob(new int[]{1, 2, 3, 1});
48 | // 2 2 3 4
49 | int rob = rob(new int[]{2, 1, 1, 2});
50 | System.out.println(rob);
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/main/java/com/example/topinterview/easy/linkedlist/array41_deleteNode.java:
--------------------------------------------------------------------------------
1 | package com.example.topinterview.easy.linkedlist;
2 |
3 | import com.example.leetcode.linkedlist.pojo.ListNode;
4 |
5 | /**
6 | * @description: 删除链表节点
7 | * 请编写一个函数,使其可以删除某个链表中给定的(非末尾)节点,你将只被给定要求被删除的节点。
8 | *
9 | * 现有一个链表 -- head = [4,5,1,9],它可以表示为:
10 | *
11 | *
12 | * 示例 1:
13 | *
14 | * 输入: head = [4,5,1,9], node = 5
15 | * 输出: [4,1,9]
16 | * 解释: 给定你链表中值为 5 的第二个节点,那么在调用了你的函数之后,该链表应变为 4 -> 1 -> 9.
17 | * 示例 2:
18 | *
19 | * 输入: head = [4,5,1,9], node = 1
20 | * 输出: [4,5,9]
21 | * 解释: 给定你链表中值为 1 的第三个节点,那么在调用了你的函数之后,该链表应变为 4 -> 5 -> 9.
22 | *
23 | *
24 | * 说明:
25 | *
26 | * 链表至少包含两个节点。
27 | * 链表中所有节点的值都是唯一的。
28 | * 给定的节点为非末尾节点并且一定是链表中的一个有效节点。
29 | * 不要从你的函数中返回任何结果。
30 | * @author: icecrea
31 | * @create: 2019-03-17 23:29
32 | **/
33 | public class array41_deleteNode {
34 | /**
35 | * 要删除一个节点 通常需要前一个节点 但本体给的是需要删除的节点
36 | * 所以通过值替换,删除下一个节点 移花接木
37 | * @param node
38 | */
39 | public void deleteNode(ListNode node) {
40 | node.val = node.next.val;
41 | node.next = node.next.next;
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/main/java/com/example/topinterview/easy/linkedlist/array42_removeNthFromEnd.java:
--------------------------------------------------------------------------------
1 | package com.example.topinterview.easy.linkedlist;
2 |
3 | import com.example.leetcode.linkedlist.pojo.ListNode;
4 |
5 | /**
6 | * @description: 删除链表倒数第n个节点
7 | * 给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。
8 | *
9 | * 示例:
10 | *
11 | * 给定一个链表: 1->2->3->4->5, 和 n = 2.
12 | *
13 | * 当删除了倒数第二个节点后,链表变为 1->2->3->5.
14 | * 说明:
15 | *
16 | * 给定的 n 保证是有效的。
17 | *
18 | * 进阶:
19 | *
20 | * 你能尝试使用一趟扫描实现吗?
21 | * @author: icecrea
22 | * @create: 2019-03-06 20:29
23 | **/
24 | public class array42_removeNthFromEnd {
25 | /**
26 | * 删除从列表开头数起的第 (L - n + 1)个结点,其中 L 是列表的长度
27 | *
28 | * @param head
29 | * @param n
30 | * @return
31 | */
32 | public ListNode removeNthFromEnd(ListNode head, int n) {
33 | int len = 0;
34 | ListNode dummy = new ListNode(0);
35 | dummy.next = head;
36 | ListNode node = dummy;
37 | while (node.next != null) {
38 | len++;
39 | node = node.next;
40 | }
41 | node = dummy;
42 | len = len - n;
43 | for (int i = 0; i < len; i++) {
44 | node = node.next;
45 | }
46 | node.next = node.next.next;
47 | return dummy.next;
48 | }
49 |
50 | }
51 |
--------------------------------------------------------------------------------
/src/main/java/com/example/topinterview/easy/linkedlist/array43_reverseList.java:
--------------------------------------------------------------------------------
1 | package com.example.topinterview.easy.linkedlist;
2 |
3 | import com.example.leetcode.linkedlist.pojo.ListNode;
4 | import org.junit.Test;
5 |
6 | /**
7 | * @description: 反转链表
8 | * 反转一个单链表。
9 | *
10 | * 示例:
11 | *
12 | * 输入: 1->2->3->4->5->NULL
13 | * 输出: 5->4->3->2->1->NULL
14 | * 进阶:
15 | * 你可以迭代或递归地反转链表。你能否用两种方法解决这道题?
16 | * @author: icecrea
17 | * @create: 2019-03-17 22:47
18 | **/
19 | public class array43_reverseList {
20 | /**
21 | * 非递归
22 | *
23 | * @param head
24 | * @return
25 | */
26 | public ListNode reverseList(ListNode head) {
27 | ListNode pre = null;
28 | ListNode next;
29 |
30 | while (head != null) {
31 | next = head.next;
32 | head.next = pre;
33 | pre = head;
34 | head = next;
35 | }
36 | return pre;
37 | }
38 |
39 | /**
40 | * 递归方法
41 | *
42 | * @param head
43 | * @return
44 | */
45 | public ListNode reverseListRecur(ListNode head) {
46 | //递归终止条件: 找到链表最后一个节点
47 | if (head == null || head.next == null) {
48 | return head;
49 | }
50 | ListNode newNode = reverseListRecur(head.next);
51 | //反转头节点的下一个节点的next指针 head.next对应的是 反转后链表的尾指针,而node.next是反转后的头指针的下一个节点,此处注意区分
52 | head.next.next = head;
53 | //反转头节点的next指针,将头节点作为尾节点
54 | head.next = null;
55 | return newNode;
56 | }
57 |
58 |
59 | @Test
60 | public void test() {
61 | ListNode a = new ListNode(1);
62 | ListNode b = new ListNode(2);
63 | ListNode c = new ListNode(3);
64 | a.next = b;
65 | b.next = c;
66 | c.next = null;
67 | reverseListRecur(a);
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/src/main/java/com/example/topinterview/easy/linkedlist/array44_mergeTwoLists.java:
--------------------------------------------------------------------------------
1 | package com.example.topinterview.easy.linkedlist;
2 |
3 | import com.example.leetcode.linkedlist.pojo.ListNode;
4 | import org.junit.Test;
5 |
6 | /**
7 | * @description: 合并两个有序链表
8 | * 将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
9 | *
10 | * 示例:
11 | *
12 | * 输入:1->2->4, 1->3->4
13 | * 输出:1->1->2->3->4->4
14 | * @author: icecrea
15 | * @create: 2019-03-18 09:28
16 | **/
17 | public class array44_mergeTwoLists {
18 | public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
19 | ListNode dummy = new ListNode(0);
20 | ListNode cur = dummy;
21 | while (l1 != null && l2 != null) {
22 | if (l1.val <= l2.val) {
23 | cur.next = l1;
24 | l1 = l1.next;
25 | } else {
26 | cur.next = l2;
27 | l2 = l2.next;
28 | }
29 | cur = cur.next;
30 | }
31 | if (l1 != null) {
32 | cur.next = l1;
33 | }
34 | if (l2 != null) {
35 | cur.next = l2;
36 | }
37 | return dummy.next;
38 | }
39 |
40 | @Test
41 | public void test() {
42 | ListNode a = new ListNode(1);
43 | ListNode b = new ListNode(2);
44 | ListNode c = new ListNode(3);
45 | a.next = b;
46 | b.next = c;
47 | c.next = null;
48 |
49 | ListNode a2 = new ListNode(1);
50 | ListNode b2 = new ListNode(2);
51 | ListNode c2 = new ListNode(3);
52 | a2.next = b2;
53 | b2.next = c2;
54 | c2.next = null;
55 | mergeTwoLists(a, a2);
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/main/java/com/example/topinterview/easy/linkedlist/array45_isPalindrome.java:
--------------------------------------------------------------------------------
1 | package com.example.topinterview.easy.linkedlist;
2 |
3 | import com.example.leetcode.linkedlist.pojo.ListNode;
4 | import org.junit.Test;
5 |
6 | /**
7 | * @description: 回文链表
8 | * 请判断一个链表是否为回文链表。
9 | *
10 | * 示例 1:
11 | *
12 | * 输入: 1->2
13 | * 输出: false
14 | * 示例 2:
15 | *
16 | * 输入: 1->2->2->1
17 | * 输出: true
18 | * 进阶:
19 | * 你能否用 O(n) 时间复杂度和 O(1) 空间复杂度解决此题?
20 | * @author: icecrea
21 | * @create: 2019-03-18 09:37
22 | **/
23 | public class array45_isPalindrome {
24 | /**
25 | * 对链表后半部分反转
26 | *
27 | * @param head
28 | * @return
29 | */
30 | public boolean isPalindrome(ListNode head) {
31 | // 要实现 O(n) 的时间复杂度和 O(1) 的空间复杂度,需要翻转后半部分
32 | if (head == null || head.next == null) {
33 | return true;
34 | }
35 | ListNode fast = head;
36 | ListNode slow = head;
37 | // 根据快慢指针,找到链表的中点 快指针的下个和下下个均不能为空
38 | while (fast.next != null && fast.next.next != null) {
39 | fast = fast.next.next;
40 | slow = slow.next;
41 | }
42 | //注意反转后半部分
43 | slow = reverse(slow.next);
44 | while (slow != null) {
45 | if (head.val != slow.val) {
46 | return false;
47 | }
48 | head = head.next;
49 | slow = slow.next;
50 | }
51 | return true;
52 | }
53 |
54 | private ListNode reverse(ListNode head) {
55 | if (head == null || head.next == null) {
56 | return head;
57 | }
58 | ListNode newNode = reverse(head.next);
59 | head.next.next = head;
60 | head.next = null;
61 | return newNode;
62 | }
63 |
64 |
65 | }
66 |
--------------------------------------------------------------------------------
/src/main/java/com/example/topinterview/easy/math/array61_countPrimes.java:
--------------------------------------------------------------------------------
1 | package com.example.topinterview.easy.math;
2 |
3 | import org.junit.Test;
4 |
5 | import java.util.Arrays;
6 |
7 | /**
8 | * @description: 计数质数
9 | * 统计所有小于非负整数 n 的质数的数量。
10 | *
11 | * 示例:
12 | *
13 | * 输入: 10
14 | * 输出: 4
15 | * 解释: 小于 10 的质数一共有 4 个, 它们是 2, 3, 5, 7 。
16 | * @author: icecrea
17 | * @create: 2019-03-19 10:42
18 | **/
19 | public class array61_countPrimes {
20 | /**
21 | * 从 2 开始,2 是一个素数,那么 2 × 2 = 4, 3 × 2 = 6, 4 × 2 = 8... 不可能是素数。
22 | * 3 也是素数,那么 3 × 2 = 6, 3 × 3 = 9, 3 × 4 = 12... 不可能是素数。
23 | */
24 | public int countPrimes(int n) {
25 | boolean[] isPrime = new boolean[n];
26 | Arrays.fill(isPrime, true);
27 | int count = 0;
28 | //对于i 判断素数 只需要遍历到sqrt(i)即可
29 | for (int i = 2; i * i < n; i++) {
30 | if (isPrime[i]) {
31 | for (int j = 2 * i; j < n; j += i) {
32 | isPrime[j] = false;
33 | }
34 | }
35 | }
36 | for (int i = 2; i < n; i++)
37 | if (isPrime[i]) {
38 | count++;
39 | }
40 | return count;
41 | }
42 |
43 | @Test
44 | public void test() {
45 | System.out.println(countPrimes(10));
46 | }
47 |
48 | }
49 |
--------------------------------------------------------------------------------
/src/main/java/com/example/topinterview/easy/math/array62_isPowerOfThree.java:
--------------------------------------------------------------------------------
1 | package com.example.topinterview.easy.math;
2 |
3 | import org.junit.Test;
4 |
5 | /**
6 | * @description: 3的幂
7 | * 给定一个整数,写一个函数来判断它是否是 3 的幂次方。
8 | *
9 | * 示例 1:
10 | *
11 | * 输入: 27
12 | * 输出: true
13 | * 示例 2:
14 | *
15 | * 输入: 0
16 | * 输出: false
17 | * 示例 3:
18 | *
19 | * 输入: 9
20 | * 输出: true
21 | * 示例 4:
22 | *
23 | * 输入: 45
24 | * 输出: false
25 | * 进阶:
26 | * 你能不使用循环或者递归来完成本题吗?
27 | * @author: icecrea
28 | * @create: 2019-03-19 12:07
29 | **/
30 | public class array62_isPowerOfThree {
31 | /**
32 | * 超时
33 | *
34 | * @param n
35 | * @return
36 | */
37 | public boolean isPowerOfThree(int n) {
38 | if (n < 1) {
39 | return false;
40 | }
41 | while (n % 3 == 0) {
42 | n /= 3;
43 | }
44 | return n == 1;
45 | }
46 |
47 | public boolean isPowerOfThree2(int n) {
48 | // 1162261467 is 3^19, 3^20 is bigger than int
49 | return n > 0 && (1162261467 % n == 0);
50 | }
51 |
52 | /**
53 | * @param n
54 | * @return
55 | */
56 | public boolean isPowerOfThree3(int n) {
57 | return (n > 0) && (Math.log10(n) / Math.log10(3) % 1 == 0);
58 | }
59 |
60 | @Test
61 | public void test() {
62 | System.out.println(isPowerOfThree(1162261468 * 3));
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/src/main/java/com/example/topinterview/easy/other/array64_hammingWeight.java:
--------------------------------------------------------------------------------
1 | package com.example.topinterview.easy.other;
2 |
3 | /**
4 | * @description: 位1的个数
5 | *
6 | * 编写一个函数,输入是一个无符号整数,返回其二进制表达式中数字位数为 ‘1’ 的个数(也被称为汉明重量)。
7 | *
8 | * 示例 1:
9 | * 输入:00000000000000000000000000001011
10 | * 输出:3
11 | * 解释:输入的二进制串 00000000000000000000000000001011 中,共有三位为 '1'。
12 | *
13 | * 示例 2:
14 | * 输入:00000000000000000000000010000000
15 | * 输出:1
16 | * 解释:输入的二进制串 00000000000000000000000010000000 中,共有一位为 '1'。
17 | *
18 | * 示例 3:
19 | * 输入:11111111111111111111111111111101
20 | * 输出:31
21 | * 解释:输入的二进制串 11111111111111111111111111111101 中,共有 31 位为 '1'。
22 | *
23 | * 提示:
24 | *
25 | * 请注意,在某些语言(如 Java)中,没有无符号整数类型。在这种情况下,输入和输出都将被指定为有符号整数类型,并且不应影响您的实现,因为无论整数是有符号的还是无符号的,其内部的二进制表示形式都是相同的。
26 | * 在 Java 中,编译器使用二进制补码记法来表示有符号整数。因此,在上面的 示例 3 中,输入表示有符号整数 -3。
27 | *
28 | *
29 | * 进阶:
30 | * 如果多次调用这个函数,你将如何优化你的算法?
31 | * @author: icecrea
32 | * @create: 2019-03-19 16:34
33 | **/
34 | public class array64_hammingWeight {
35 | /**
36 | * 注意
37 | * 1.使用>>> 而不是>>
38 | * 2.n&1加括号
39 | *
40 | * @param n
41 | * @return
42 | */
43 | public int hammingWeight(int n) {
44 | int count = 0;
45 | while (n != 0) {
46 | count = count + (n & 1);
47 | n = n >>> 1;
48 | }
49 | return count;
50 | }
51 |
52 | public int hammingWeight2(int n) {
53 | return Integer.bitCount(n);
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/main/java/com/example/topinterview/easy/other/array65_hammingDistance.java:
--------------------------------------------------------------------------------
1 | package com.example.topinterview.easy.other;
2 |
3 | /**
4 | * @description: 汉明距离
5 | * 两个整数之间的汉明距离指的是这两个数字对应二进制位不同的位置的数目。
6 | *
7 | * 给出两个整数 x 和 y,计算它们之间的汉明距离。
8 | *
9 | * 注意:
10 | * 0 ≤ x, y < 231.
11 | *
12 | * 示例:
13 | *
14 | * 输入: x = 1, y = 4
15 | *
16 | * 输出: 2
17 | *
18 | * 解释:
19 | * 1 (0 0 0 1)
20 | * 4 (0 1 0 0)
21 | * ↑ ↑
22 | *
23 | * 上面的箭头指出了对应二进制位不同的位置。
24 | * @author: icecrea
25 | * @create: 2019-03-19 22:04
26 | **/
27 | public class array65_hammingDistance {
28 | /**
29 | * 利用亦或 不同为1 相同为0
30 | * @param x
31 | * @param y
32 | * @return
33 | */
34 | public int hammingDistance(int x, int y) {
35 | int xor = x ^ y, count = 0;
36 | for (int i = 0; i < 32; i++) {
37 | count += (xor >> i) & 1;
38 | }
39 | return count;
40 | }
41 |
42 | public int hammingDistance1(int x, int y) {
43 | return Integer.bitCount(x ^ y);
44 | }
45 |
46 |
47 | }
48 |
--------------------------------------------------------------------------------
/src/main/java/com/example/topinterview/easy/other/array67_pascalTriangle.java:
--------------------------------------------------------------------------------
1 | package com.example.topinterview.easy.other;
2 |
3 | import org.junit.Test;
4 |
5 | import java.util.ArrayList;
6 | import java.util.List;
7 |
8 | /**
9 | * @description: 帕斯卡三角形
10 | * 定一个非负整数 numRows,生成杨辉三角的前 numRows 行。
11 | * 在杨辉三角中,每个数是它左上方和右上方的数的和。
12 | *
13 | * 示例:
14 | * 输入: 5
15 | * 输出:
16 | * [
17 | * [1],
18 | * [1,1],
19 | * [1,2,1],
20 | * [1,3,3,1],
21 | * [1,4,6,4,1]
22 | * ]
23 | * @author: icecrea
24 | * @create: 2019-03-22 15:51
25 | **/
26 | public class array67_pascalTriangle {
27 | public List> res = new ArrayList<>();
30 |
31 | public List
> combine(int n, int k) {
32 | List
> triangle) {
40 | int row = triangle.size();
41 | List
> list = new ArrayList();
54 | list.add(Lists.newArrayList(2));
55 | list.add(Lists.newArrayList(3, 4));
56 | list.add(Lists.newArrayList(6, 5, 7));
57 | list.add(Lists.newArrayList(4, 1, 8, 3));
58 | int i = minimumTotal(list);
59 | System.out.println(i);
60 |
61 | }
62 |
63 | }
64 |
--------------------------------------------------------------------------------
/src/main/java/com/example/leetcode/dp/LeetCode300_LIS.java:
--------------------------------------------------------------------------------
1 | package com.example.leetcode.dp;
2 |
3 | import org.junit.Test;
4 |
5 | import java.util.ArrayList;
6 | import java.util.Arrays;
7 | import java.util.List;
8 | import java.util.Stack;
9 |
10 | /**
11 | * 最长上升子序列
12 | * LIS问题 LongestIncreasingSubsequence
13 | * 给定一个无序的整数数组,找到其中最长上升子序列的长度。
14 | * 示例:
15 | * 输入: [10,9,2,5,3,7,101,18]
16 | * 输出: 4
17 | * 解释: 最长的上升子序列是 [2,3,7,101],它的长度是 4。
18 | * 说明:
19 | * 可能会有多种最长上升子序列的组合,你只需要输出对应的长度即可。
20 | * 你算法的时间复杂度应该为 O(n2) 。
21 | * 进阶: 你能将算法的时间复杂度降低到 O(n log n) 吗?
22 | */
23 | public class LeetCode300_LIS {
24 |
25 | /**
26 | * dp[i]: 以i结尾的最长递增子序列长度 O(N^2)
27 | * 问题在于如何根据已知的dp[0]...dp[i-1],来推导dp[i]
28 | * 10,9,2,5,3,7,101,18
29 | * 1 ,1,1,2,2,3,4, 4
30 | */
31 | public int lengthOfLIS(int[] a) {
32 | if (a == null || a.length == 0) {
33 | return 0;
34 | }
35 | //dp[i] 以i结尾的最长递增子序列长度
36 | int dp[] = new int[a.length];
37 | Arrays.fill(dp, 1);
38 | int max = Integer.MIN_VALUE;
39 | for (int j = 1; j < a.length; j++) {
40 | for (int i = 0; i < j; i++) {
41 | if (a[j] > a[i]) {
42 | dp[j] = Math.max(dp[j], dp[i] + 1);
43 | }
44 | }
45 | max = Math.max(max, dp[j]);
46 | }
47 | return max;
48 | }
49 |
50 | @Test
51 | public void test() {
52 | System.out.println(lengthOfLIS(new int[]{10, 9, 2, 5, 3, 7, 101, 18}));
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/main/java/com/example/leetcode/dp/LeetCode53_MaximumSubarray.java:
--------------------------------------------------------------------------------
1 | package com.example.leetcode.dp;
2 |
3 | import org.junit.Test;
4 |
5 | /**
6 | * 最大连续子序列和
7 | * 给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
8 | *
9 | * 示例:
10 | *
11 | * 输入: [-2,1,-3,4,-1,2,1,-5,4],
12 | * 输出: 6
13 | * 解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。
14 | * 进阶:
15 | *
16 | * 如果你已经实现复杂度为 O(n) 的解法,尝试使用更为精妙的分治法求解。
17 | */
18 | public class LeetCode53_MaximumSubarray {
19 |
20 | /**
21 | * -2,1,-3,4,-1,2,1,-5,4
22 | * -2,1,-2,4,3,5,6,1,5
23 | * -2,1, 1,4,4,5,6,6,6
24 | *
25 | * @param nums
26 | * @return
27 | */
28 | public int maxSubArray(int[] nums) {
29 | int maxToCur = Integer.MIN_VALUE;
30 | int max = Integer.MIN_VALUE;
31 | for (int i = 0; i < nums.length; i++) {
32 | if (maxToCur >= 0) {
33 | maxToCur += nums[i];
34 | } else {
35 | maxToCur = nums[i];
36 | }
37 | max = Math.max(maxToCur, max);
38 | }
39 | return max;
40 | }
41 |
42 | @Test
43 | public void test() {
44 | // int max = maxSubArray(new int[]{-2, 1, -3, 4, -1, 2, 1, -5, 4});
45 | int max = maxSubArray(new int[]{-1});
46 | System.out.println(max);
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/main/java/com/example/leetcode/dp/LeetCode55_JumpGame.java:
--------------------------------------------------------------------------------
1 | package com.example.leetcode.dp;
2 |
3 | /**
4 | * @description: 跳跃游戏
5 | * 给定一个非负整数数组,你最初位于数组的第一个位置。
6 | * 数组中的每个元素代表你在该位置可以跳跃的最大长度。
7 | * 判断你是否能够到达最后一个位置。
8 | * 示例 1:
9 | * 输入: [2,3,1,1,4]
10 | * 输出: true
11 | * 解释: 我们可以先跳 1 步,从位置 0 到达 位置 1, 然后再从位置 1 跳 3 步到达最后一个位置。
12 | * 示例 2:
13 | * 输入: [3,2,1,0,4]
14 | * 输出: false
15 | * 解释: 无论怎样,你总会到达索引为 3 的位置。但该位置的最大跳跃长度是 0 , 所以你永远不可能到达最后一个位置。
16 | * 来源:力扣(LeetCode)
17 | * 链接:https://leetcode-cn.com/problems/jump-game
18 | * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
19 | * @auther: icecrea
20 | * @date: 2020/4/22
21 | */
22 | public class LeetCode55_JumpGame {
23 |
24 | /**
25 | * 2 3 1 1 4
26 | * 2 4 4 4
27 | * 3 2 1 0 4
28 | * 3 3 3 3
29 | *
30 | * @param nums
31 | * @return
32 | */
33 | public boolean canJump(int[] nums) {
34 | int max = 0;
35 | for (int i = 0; i < nums.length - 1; i++) {
36 | // 计算从0到i为止能跳到的最远距离
37 | max = Math.max(max, i + nums[i]);
38 | if (max <= i) {
39 | return false;
40 | }
41 | }
42 | return true;
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/main/java/com/example/leetcode/dp/LeetCode70_ClimbingStairs.java:
--------------------------------------------------------------------------------
1 | package com.example.leetcode.dp;
2 |
3 | import org.junit.Test;
4 |
5 | /**
6 | * 爬楼梯
7 | * 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
8 | *
9 | * 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
10 | *
11 | * 注意:给定 n 是一个正整数。
12 | *
13 | * 示例 1:
14 | *
15 | * 输入: 2
16 | * 输出: 2
17 | * 解释: 有两种方法可以爬到楼顶。
18 | * 1. 1 阶 + 1 阶
19 | * 2. 2 阶
20 | * 示例 2:
21 | *
22 | * 输入: 3
23 | * 输出: 3
24 | * 解释: 有三种方法可以爬到楼顶。
25 | * 1. 1 阶 + 1 阶 + 1 阶
26 | * 2. 1 阶 + 2 阶
27 | * 3. 2 阶 + 1 阶
28 | */
29 | public class LeetCode70_ClimbingStairs {
30 |
31 | /**
32 | * f(n) = f(n-1) + f(n-2)
33 | * 11 22 33 45 58
34 | * @param n
35 | * @return
36 | */
37 | public int climbStairs(int n) {
38 | if (n == 1) {
39 | return 1;
40 | }
41 | if (n == 2) {
42 | return 2;
43 | }
44 | int l = 1;
45 | int r = 2;
46 | int res = 0;
47 | for (int i = 3; i <= n; i++) {
48 | res = l + r;
49 | l = r;
50 | r = res;
51 | }
52 | return res;
53 | }
54 |
55 | @Test
56 | public void test(){
57 | System.out.println(climbStairs(3));
58 | System.out.println(climbStairs(4));
59 | System.out.println(climbStairs(5));
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/main/java/com/example/leetcode/dp/LeetCode87_ScrambleString.java:
--------------------------------------------------------------------------------
1 | package com.example.leetcode.dp;
2 |
3 | /**
4 | * 扰乱字符串
5 | * 给定一个字符串 s1,我们可以把它递归地分割成两个非空子字符串,从而将其表示为二叉树。
6 | *
7 | * 下图是字符串 s1 = "great" 的一种可能的表示形式。
8 | *
9 | * great
10 | * / \
11 | * gr eat
12 | * / \ / \
13 | * g r e at
14 | * / \
15 | * a t
16 | * 在扰乱这个字符串的过程中,我们可以挑选任何一个非叶节点,然后交换它的两个子节点。
17 | *
18 | * 例如,如果我们挑选非叶节点 "gr" ,交换它的两个子节点,将会产生扰乱字符串 "rgeat" 。
19 | *
20 | * rgeat
21 | * / \
22 | * rg eat
23 | * / \ / \
24 | * r g e at
25 | * / \
26 | * a t
27 | * 我们将 "rgeat” 称作 "great" 的一个扰乱字符串。
28 | *
29 | * 同样地,如果我们继续交换节点 "eat" 和 "at" 的子节点,将会产生另一个新的扰乱字符串 "rgtae" 。
30 | *
31 | * rgtae
32 | * / \
33 | * rg tae
34 | * / \ / \
35 | * r g ta e
36 | * / \
37 | * t a
38 | * 我们将 "rgtae” 称作 "great" 的一个扰乱字符串。
39 | *
40 | * 给出两个长度相等的字符串 s1 和 s2,判断 s2 是否是 s1 的扰乱字符串。
41 | *
42 | * 示例 1:
43 | *
44 | * 输入: s1 = "great", s2 = "rgeat"
45 | * 输出: true
46 | * 示例 2:
47 | *
48 | * 输入: s1 = "abcde", s2 = "caebd"
49 | * 输出: false
50 | *
51 | */
52 | public class LeetCode87_ScrambleString {
53 |
54 | // public boolean isScramble(String s1, String s2) {
55 | //
56 | // }
57 | }
58 |
--------------------------------------------------------------------------------
/src/main/java/com/example/leetcode/dp/README.md:
--------------------------------------------------------------------------------
1 | ## 动态规划专题 Leetcode
2 | - [05.最长回文子串](./LeetCode05_LongestPalindromicSubstring.java)
3 | - [10.正则表达式匹配](./LeetCode10_RegularExpressionMatching.java)
4 | - [32.最长有效括号](./LeetCode32_LongestValidParantheses.java)
5 | - [53.最大连续子序列和](./LeetCode53_MaximumSubarray.java)
6 | - [62.不同路径](./LeetCode62_UniquePaths.java)
7 | - [63.不同路径2](./LeetCode63_UniquePaths2.java)
8 | - [64.最小路径和](./LeetCode64_MinimumPathSum.java)
9 | - [70.爬楼梯](./LeetCode70_ClimbingStairs.java)
10 | - [72.编辑距离](./LeetCode72_EditDistance.java)
11 | - [79.单词搜索](./LeetCode79_SearchWord.java)
12 | - [84.柱状图中最大的矩形](./LeetCode84_LargestRectangleInHistogram.java)
13 | - [85.最大矩形](./LeetCode85_MaximalRectangle.java)
14 | - [87.扰乱字符串](./LeetCode87_ScrambleString.java)
15 | - [95.不同的二叉搜索树2](./LeetCode95_UniqueBST2.java)
16 | - [96.不同的二叉搜索树](./LeetCode96_UniqueBST.java)
17 | - [120.三角形最小路径和](./LeetCode120_TriangleMinPath.java)
18 | - [121.买卖股票的最佳时机](./LeetCode121_BestTimeToBuyAndSellStock.java)
19 | - [122.买卖股票的最佳时机2](./LeetCode122_BestTimeToBuyAndSellStock2.java)
20 | - [123.买卖股票的最佳时机3](./LeetCode123_BestTimeToBuyAndSellStock3.java)
21 | - [198.打家劫舍](./LeetCode198_HouseRobber.java)
22 | - [213.打家劫舍2](./LeetCode213_HouseRobber2.java)
23 | - [300.最长上升子序列LIS](./LeetCode300_LIS.java)
24 | - [322.零钱兑换](./LeetCode322_CoinChange.java)
25 | - [474.一和零](./LeetCode474_OnesAndZeros.java)
26 | - [516.最长回文子序列](./LeetCode516_LongestPalindromicSubsequence.java)
27 | - [651.四键键盘](./LeetCode651_4KeysKeyboard.java)
28 | - [673.最长递增子序列的个数](./LeetCode673_NumberOfLIS.java)
29 | - [1143.最长公共子序列LCS](./LeetCode1143_LCS.java)
--------------------------------------------------------------------------------
/src/main/java/com/example/leetcode/dp/palindrome/LeetCode516_LongestPalindromicSubsequence.java:
--------------------------------------------------------------------------------
1 | package com.example.leetcode.dp.palindrome;
2 |
3 | import org.junit.Test;
4 |
5 | /**
6 | * 最长回文子序列
7 | * 给定一个字符串s,找到其中最长的回文子序列。可以假设s的最大长度为1000。
8 | *
9 | * 示例 1:
10 | * 输入:
11 | * "bbbab"
12 | * 输出:
13 | * 4
14 | * 一个可能的最长回文子序列为 "bbbb"。
15 | *
16 | * 示例 2:
17 | * 输入:
18 | * "cbbd"
19 | * 输出:
20 | *
21 | * 2
22 | * 一个可能的最长回文子序列为 "bb"。
23 | */
24 | public class LeetCode516_LongestPalindromicSubsequence {
25 |
26 | /**
27 | * dp[i][j] : 在子串 s[i..j] 中,最长回文子序列的长度
28 | * 我们需要的是 dp[0][n - 1]
29 | * 注意遍历顺序,i 从最后一个字符开始往前遍历,j 从 i + 1 开始往后遍历,这样可以保证每个子问题都已经算好了。
30 | */
31 | public int longestPalindromeSubseq(String s) {
32 | int n = s.length();
33 | int[][] dp = new int[s.length()][s.length()];
34 | for (int i = n - 1; i >= 0; i--) {
35 | //单个字符初始化 回文为1
36 | dp[i][i] = 1;
37 | for (int j = i + 1; j < n; j++) {
38 | if (s.charAt(i) == s.charAt(j)) {
39 | dp[i][j] = dp[i + 1][j - 1] + 2;
40 | } else {
41 | dp[i][j] = Math.max(dp[i + 1][j], dp[i][j - 1]);
42 | }
43 | }
44 | }
45 | return dp[0][n - 1];
46 | }
47 |
48 | @Test
49 | public void test(){
50 |
51 | /**
52 | *
53 | * b b b a b
54 | * b 1
55 | * b 1
56 | * b 1
57 | * a 1
58 | * b 1
59 | */
60 |
61 | System.out.println(longestPalindromeSubseq("bbbab"));
62 | }
63 |
64 | }
65 |
--------------------------------------------------------------------------------
/src/main/java/com/example/leetcode/dp/palindrome/LeetCode647_PalindromicSubstrings.java:
--------------------------------------------------------------------------------
1 | package com.example.leetcode.dp.palindrome;
2 |
3 | import org.junit.Test;
4 |
5 | /**
6 | * @description: 回文子串个数
7 | * 给定一个字符串,你的任务是计算这个字符串中有多少个回文子串。
8 | * 具有不同开始位置或结束位置的子串,即使是由相同的字符组成,也会被计为是不同的子串。
9 | * 示例 1:
10 | * 输入: "abc"
11 | * 输出: 3
12 | * 解释: 三个回文子串: "a", "b", "c".
13 | * 示例 2:
14 | * 输入: "aaa"
15 | * 输出: 6
16 | * 说明: 6个回文子串: "a", "a", "a", "aa", "aa", "aaa".
17 | * 注意:
18 | * 输入的字符串长度不会超过1000。
19 | * @auther: icecrea
20 | * @date: 2019/12/16
21 | */
22 | public class LeetCode647_PalindromicSubstrings {
23 | /**
24 | * 动态规划
25 | * dp[i][j] 代表str[i] - str[j]是否是回文子串
26 | * 考虑单字符和双字符的特殊情况
27 | * 状态转移方程:dp[i][j] = dp[i+1][j-1] && str[i]==str[j]
28 | * 可以类比
29 | * @see LeetCode05_LongestPalindromicSubstring
30 | */
31 | public int countSubstrings(String s) {
32 | int res = 0;
33 | boolean dp[][] = new boolean[s.length()][s.length()];
34 | for (int j = 0; j < s.length(); j++) {
35 | for (int i = j; i >= 0; i--) {
36 | if (s.charAt(i) == s.charAt(j) && ((j - i < 2) || dp[i + 1][j - 1])) {
37 | dp[i][j] = true;
38 | res++;
39 | }
40 | }
41 | }
42 | return res;
43 | }
44 |
45 | @Test
46 | public void test() {
47 | System.out.println(countSubstrings("aaa"));
48 | System.out.println(countSubstrings("abc"));
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/main/java/com/example/leetcode/heap/LeetCode703_ktLargestElementIntream.java:
--------------------------------------------------------------------------------
1 | package com.example.leetcode.heap;
2 |
3 | import java.util.PriorityQueue;
4 |
5 | /**
6 | * @description: 数据流中的第K大元素
7 | * 设计一个找到数据流中第K大元素的类(class)。注意是排序后的第K大元素,不是第K个不同的元素。
8 | *
> generate(int numRows) {
28 | List
> allrows = new ArrayList<>();
29 | ArrayList