diff --git a/MCA算法突击课/第03期/mca_01/Code01_Swap.java b/MCA算法突击课/第03期/mca_01/Code01_Swap.java new file mode 100644 index 0000000..60200ad --- /dev/null +++ b/MCA算法突击课/第03期/mca_01/Code01_Swap.java @@ -0,0 +1,48 @@ +package 第03期.mca_01; + +public class Code01_Swap { + + public static void main(String[] args) { + + int a = 16; + int b = 603; + + System.out.println(a); + System.out.println(b); + + a = a ^ b; + b = a ^ b; + a = a ^ b; + + System.out.println(a); + System.out.println(b); + + int[] arr = { 3, 1, 100 }; + + int i = 0; + int j = 0; + + arr[i] = arr[i] ^ arr[j]; + arr[j] = arr[i] ^ arr[j]; + arr[i] = arr[i] ^ arr[j]; + + System.out.println(arr[i] + " , " + arr[j]); + + System.out.println(arr[0]); + System.out.println(arr[2]); + + swap(arr, 0, 0); + + System.out.println(arr[0]); + System.out.println(arr[2]); + + } + + public static void swap(int[] arr, int i, int j) { + // arr[0] = arr[0] ^ arr[0]; + arr[i] = arr[i] ^ arr[j]; + arr[j] = arr[i] ^ arr[j]; + arr[i] = arr[i] ^ arr[j]; + } + +} diff --git a/MCA算法突击课/第03期/mca_01/Code02_EvenTimesOddTimes.java b/MCA算法突击课/第03期/mca_01/Code02_EvenTimesOddTimes.java new file mode 100644 index 0000000..0eb4fe5 --- /dev/null +++ b/MCA算法突击课/第03期/mca_01/Code02_EvenTimesOddTimes.java @@ -0,0 +1,83 @@ +package 第03期.mca_01; + +public class Code02_EvenTimesOddTimes { + + // arr中,只有一种数,出现奇数次 + public static void printOddTimesNum1(int[] arr) { + int eor = 0; + for (int i = 0; i < arr.length; i++) { + eor ^= arr[i]; + } + System.out.println(eor); + } + + // arr中,有两种数,出现奇数次 + public static void printOddTimesNum2(int[] arr) { + int eor = 0; + for (int i = 0; i < arr.length; i++) { + eor ^= arr[i]; + } + // a 和 b是两种数 + // eor != 0 + // eor最右侧的1,提取出来 + // eor : 00110010110111000 + // rightOne :00000000000001000 + int rightOne = eor & (-eor); // 提取出最右的1 + + + int onlyOne = 0; // eor' + for (int i = 0 ; i < arr.length;i++) { + // arr[1] = 111100011110000 + // rightOne= 000000000010000 + if ((arr[i] & rightOne) != 0) { + onlyOne ^= arr[i]; + } + } + System.out.println(onlyOne + " " + (eor ^ onlyOne)); + } + + + public static int bit1counts(int N) { + int count = 0; + + // 011011010000 + // 000000010000 1 + + // 011011000000 + // + + + + while(N != 0) { + int rightOne = N & ((~N) + 1); + count++; + N ^= rightOne; + // N -= rightOne + } + + + return count; + + } + + + public static void main(String[] args) { + int a = 5; + int b = 7; + + a = a ^ b; + b = a ^ b; + a = a ^ b; + + System.out.println(a); + System.out.println(b); + + int[] arr1 = { 3, 3, 2, 3, 1, 1, 1, 3, 1, 1, 1 }; + printOddTimesNum1(arr1); + + int[] arr2 = { 4, 3, 4, 2, 2, 2, 4, 1, 1, 1, 3, 3, 1, 1, 1, 4, 2, 2 }; + printOddTimesNum2(arr2); + + } + +} diff --git a/MCA算法突击课/第03期/mca_01/Code03_BinarySearch.java b/MCA算法突击课/第03期/mca_01/Code03_BinarySearch.java new file mode 100644 index 0000000..02c4e2b --- /dev/null +++ b/MCA算法突击课/第03期/mca_01/Code03_BinarySearch.java @@ -0,0 +1,60 @@ +package 第03期.mca_01; + +public class Code03_BinarySearch { + + public static boolean exist(int[] sortedArr, int num) { + if (sortedArr == null || sortedArr.length == 0) { + return false; + } + int L = 0; + int R = sortedArr.length - 1; + int mid = 0; + // L..R + while (L < R) { // L..R 至少两个数的时候 + mid = L + ((R - L) >> 1); + if (sortedArr[mid] == num) { + return true; + } else if (sortedArr[mid] > num) { + R = mid - 1; + } else { + L = mid + 1; + } + } + return sortedArr[L] == num; + } + + // 在arr上,找满足>=value的最左位置 + public static int nearest1(int[] sortedArr, int value) { + int L = 0; + int R = sortedArr.length - 1; + int index = -1; // 记录最左的对号 + while (L <= R) { // 至少一个数的时候 + int mid = L + ((R - L) >> 1); + if (sortedArr[mid] >= value) { + index = mid; + R = mid - 1; + } else { + L = mid + 1; + } + } + return index; + } + + // 在arr上,找满足<=value的最右位置 + public static int nearest2(int[] sortedArr, int value) { + int L = 0; + int R = sortedArr.length - 1; + int index = -1; // 记录最右的对号 + while (L <= R) { + int mid = L + ((R - L) >> 1); + if (sortedArr[mid] <= value) { + index = mid; + L = mid + 1; + } else { + R = mid - 1; + } + } + return index; + } + +} diff --git a/MCA算法突击课/第03期/mca_01/Code04_IsStepSum.java b/MCA算法突击课/第03期/mca_01/Code04_IsStepSum.java new file mode 100644 index 0000000..fd33210 --- /dev/null +++ b/MCA算法突击课/第03期/mca_01/Code04_IsStepSum.java @@ -0,0 +1,58 @@ +package 第03期.mca_01; + +import java.util.HashMap; + +public class Code04_IsStepSum { + + public static boolean isStepSum(int stepSum) { + int L = 0; + int R = stepSum; + int M = 0; + int cur = 0; + while (L <= R) { + M = L + ((R - L) >> 1); + cur = stepSum(M); + if (cur == stepSum) { + return true; + } else if (cur < stepSum) { + L = M + 1; + } else { + R = M - 1; + } + } + return false; + } + + public static int stepSum(int num) { + int sum = 0; + while (num != 0) { + sum += num; + num /= 10; + } + return sum; + } + + // for test + public static HashMap generateStepSumNumberMap(int numMax) { + HashMap map = new HashMap<>(); + for (int i = 0; i <= numMax; i++) { + map.put(stepSum(i), i); + } + return map; + } + + // for test + public static void main(String[] args) { + int max = 1000000; + int maxStepSum = stepSum(max); + HashMap ans = generateStepSumNumberMap(max); + System.out.println("测试开始"); + for (int i = 0; i <= maxStepSum; i++) { + if (isStepSum(i) ^ ans.containsKey(i)) { + System.out.println("出错了!"); + } + } + System.out.println("测试结束"); + } + +} diff --git a/MCA算法突击课/第03期/mca_01/Code05_KokoEatingBananas.java b/MCA算法突击课/第03期/mca_01/Code05_KokoEatingBananas.java new file mode 100644 index 0000000..cf1e7c4 --- /dev/null +++ b/MCA算法突击课/第03期/mca_01/Code05_KokoEatingBananas.java @@ -0,0 +1,35 @@ +package 第03期.mca_01; + +// leetcode 875题 +public class Code05_KokoEatingBananas { + + public static int minEatingSpeed(int[] piles, int h) { + int L = 1; + int R = 0; + for (int pile : piles) { + R = Math.max(R, pile); + } + int ans = 0; + int M = 0; + while (L <= R) { + M = L + ((R - L) >> 1); + if (hours(piles, M) <= h) { + ans = M; + R = M - 1; + } else { + L = M + 1; + } + } + return ans; + } + + public static int hours(int[] piles, int speed) { + int ans = 0; + int offset = speed - 1; + for (int pile : piles) { + ans += (pile + offset) / speed; + } + return ans; + } + +} diff --git a/MCA算法突击课/第03期/mca_01/Code06_HashMapAndSortedMap.java b/MCA算法突击课/第03期/mca_01/Code06_HashMapAndSortedMap.java new file mode 100644 index 0000000..80ae9a2 --- /dev/null +++ b/MCA算法突击课/第03期/mca_01/Code06_HashMapAndSortedMap.java @@ -0,0 +1,128 @@ +package 第03期.mca_01; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.TreeMap; + +public class Code06_HashMapAndSortedMap { + + public static class Node { + public int value; + + public Node(int v) { + value = v; + } + } + + public static class Zuo { + public int value; + + public Zuo(int v) { + value = v; + } + } + + public static void main(String[] args) { + + HashMap test = new HashMap<>(); + Integer a = 19000000; + Integer b = 19000000; + System.out.println(a == b); + + test.put(a, "我是3"); + System.out.println(test.containsKey(b)); + + Zuo z1 = new Zuo(1); + Zuo z2 = new Zuo(1); + HashMap test2 = new HashMap<>(); + test2.put(z1, "我是z1"); + System.out.println(test2.containsKey(z2)); + + // UnSortedMap + HashMap map = new HashMap<>(); + map.put(1000000, "我是1000000"); + map.put(2, "我是2"); + map.put(3, "我是3"); + map.put(4, "我是4"); + map.put(5, "我是5"); + map.put(6, "我是6"); + map.put(1000000, "我是1000001"); + + System.out.println(map.containsKey(1)); + System.out.println(map.containsKey(10)); + + System.out.println(map.get(4)); + System.out.println(map.get(10)); + + map.put(4, "他是4"); + System.out.println(map.get(4)); + + map.remove(4); + System.out.println(map.get(4)); + + // key + HashSet set = new HashSet<>(); + set.add("abc"); + set.contains("abc"); + set.remove("abc"); + + // 哈希表,增、删、改、查,在使用时,O(1) + + System.out.println("====================="); + + Integer c = 100000; + Integer d = 100000; + System.out.println(c.equals(d)); + + Integer e = 127; // - 128 ~ 127 + Integer f = 127; + System.out.println(e == f); + + HashMap map2 = new HashMap<>(); + Node node1 = new Node(1); + Node node2 = node1; + map2.put(node1, "我是node1"); + map2.put(node2, "我是node1"); + System.out.println(map2.size()); + + System.out.println("======================"); + + // TreeMap 有序表:接口名 + // 红黑树、avl、sb树、跳表 + // O(logN) + System.out.println("有序表测试开始"); + TreeMap treeMap = new TreeMap<>(); + + treeMap.put(3, "我是3"); + treeMap.put(4, "我是4"); + treeMap.put(8, "我是8"); + treeMap.put(5, "我是5"); + treeMap.put(7, "我是7"); + treeMap.put(1, "我是1"); + treeMap.put(2, "我是2"); + + System.out.println(treeMap.containsKey(1)); + System.out.println(treeMap.containsKey(10)); + + System.out.println(treeMap.get(4)); + System.out.println(treeMap.get(10)); + + treeMap.put(4, "他是4"); + System.out.println(treeMap.get(4)); + + // treeMap.remove(4); + System.out.println(treeMap.get(4)); + + System.out.println("新鲜:"); + + System.out.println(treeMap.firstKey()); + System.out.println(treeMap.lastKey()); + // <= 4 + System.out.println(treeMap.floorKey(4)); + // >= 4 + System.out.println(treeMap.ceilingKey(4)); + // O(logN) + + } + +} diff --git a/MCA算法突击课/第03期/mca_01/Code07_CoverMax.java b/MCA算法突击课/第03期/mca_01/Code07_CoverMax.java new file mode 100644 index 0000000..d5e0b17 --- /dev/null +++ b/MCA算法突击课/第03期/mca_01/Code07_CoverMax.java @@ -0,0 +1,155 @@ +package 第03期.mca_01; + +import java.util.Arrays; +import java.util.Comparator; +import java.util.PriorityQueue; + +public class Code07_CoverMax { + + public static int maxCover1(int[][] lines) { + int min = Integer.MAX_VALUE; + int max = Integer.MIN_VALUE; + for (int i = 0; i < lines.length; i++) { + min = Math.min(min, lines[i][0]); + max = Math.max(max, lines[i][1]); + } + int cover = 0; + for (double p = min + 0.5; p < max; p += 1) { + int cur = 0; + for (int i = 0; i < lines.length; i++) { + if (lines[i][0] < p && lines[i][1] > p) { + cur++; + } + } + cover = Math.max(cover, cur); + } + return cover; + } + + public static int maxCover2(int[][] m) { + Line[] lines = new Line[m.length]; + for (int i = 0; i < m.length; i++) { + lines[i] = new Line(m[i][0], m[i][1]); + } + Arrays.sort(lines, new StartComparator()); + // 小根堆,每一条线段的结尾数值,使用默认的 + PriorityQueue heap = new PriorityQueue<>(); + int max = 0; + for (int i = 0; i < lines.length; i++) { + // lines[i] -> cur 在黑盒中,把<=cur.start 东西都弹出 + while (!heap.isEmpty() && heap.peek() <= lines[i].start) { + heap.poll(); + } + heap.add(lines[i].end); + max = Math.max(max, heap.size()); + } + return max; + } + + public static class Line { + public int start; + public int end; + + public Line(int s, int e) { + start = s; + end = e; + } + } + + public static class EndComparator implements Comparator { + + @Override + public int compare(Line o1, Line o2) { + return o1.end - o2.end; + } + + } + + // 和maxCover2过程是一样的 + // 只是代码更短 + // 不使用类定义的写法 + public static int maxCover3(int[][] m) { + // m是二维数组,可以认为m内部是一个一个的一维数组 + // 每一个一维数组就是一个对象,也就是线段 + // 如下的code,就是根据每一个线段的开始位置排序 + // 比如, m = { {5,7}, {1,4}, {2,6} } 跑完如下的code之后变成:{ {1,4}, {2,6}, {5,7} } + Arrays.sort(m, (a, b) -> (a[0] - b[0])); + // 准备好小根堆,和课堂的说法一样 + PriorityQueue heap = new PriorityQueue<>(); + int max = 0; + for (int[] line : m) { + while (!heap.isEmpty() && heap.peek() <= line[0]) { + heap.poll(); + } + heap.add(line[1]); + max = Math.max(max, heap.size()); + } + return max; + } + + // for test + public static int[][] generateLines(int N, int L, int R) { + int size = (int) (Math.random() * N) + 1; + int[][] ans = new int[size][2]; + for (int i = 0; i < size; i++) { + int a = L + (int) (Math.random() * (R - L + 1)); + int b = L + (int) (Math.random() * (R - L + 1)); + if (a == b) { + b = a + 1; + } + ans[i][0] = Math.min(a, b); + ans[i][1] = Math.max(a, b); + } + return ans; + } + + public static class StartComparator implements Comparator { + + @Override + public int compare(Line o1, Line o2) { + return o1.start - o2.start; + } + + } + + public static void main(String[] args) { + + Line l1 = new Line(4, 9); + Line l2 = new Line(1, 4); + Line l3 = new Line(7, 15); + Line l4 = new Line(2, 4); + Line l5 = new Line(4, 6); + Line l6 = new Line(3, 7); + + // 底层堆结构,heap + PriorityQueue heap = new PriorityQueue<>(new StartComparator()); + heap.add(l1); + heap.add(l2); + heap.add(l3); + heap.add(l4); + heap.add(l5); + heap.add(l6); + + while (!heap.isEmpty()) { + Line cur = heap.poll(); + System.out.println(cur.start + "," + cur.end); + } + + System.out.println("test begin"); + int N = 100; + int L = 0; + int R = 200; + int testTimes = 200000; + for (int i = 0; i < testTimes; i++) { + int[][] lines = generateLines(N, L, R); + int ans1 = maxCover1(lines); + int ans2 = maxCover2(lines); + int ans3 = maxCover3(lines); + if (ans1 != ans2 || ans1 != ans3) { + System.out.println("Oops!"); + } + } + System.out.println("test end"); + } + +} diff --git a/MCA算法突击课/第03期/mca_01/Code08_LessMoneySplitGold.java b/MCA算法突击课/第03期/mca_01/Code08_LessMoneySplitGold.java new file mode 100644 index 0000000..c9c38ef --- /dev/null +++ b/MCA算法突击课/第03期/mca_01/Code08_LessMoneySplitGold.java @@ -0,0 +1,79 @@ +package 第03期.mca_01; + +import java.util.PriorityQueue; + +public class Code08_LessMoneySplitGold { + + // 纯暴力! + public static int lessMoney1(int[] arr) { + if (arr == null || arr.length == 0) { + return 0; + } + return process(arr, 0); + } + + // 等待合并的数都在arr里,pre之前的合并行为产生了多少总代价 + // arr中只剩一个数字的时候,停止合并,返回最小的总代价 + public static int process(int[] arr, int pre) { + if (arr.length == 1) { + return pre; + } + int ans = Integer.MAX_VALUE; + for (int i = 0; i < arr.length; i++) { + for (int j = i + 1; j < arr.length; j++) { + ans = Math.min(ans, process(copyAndMergeTwo(arr, i, j), pre + arr[i] + arr[j])); + } + } + return ans; + } + + public static int[] copyAndMergeTwo(int[] arr, int i, int j) { + int[] ans = new int[arr.length - 1]; + int ansi = 0; + for (int arri = 0; arri < arr.length; arri++) { + if (arri != i && arri != j) { + ans[ansi++] = arr[arri]; + } + } + ans[ansi] = arr[i] + arr[j]; + return ans; + } + + public static int lessMoney2(int[] arr) { + PriorityQueue pQ = new PriorityQueue<>(); + for (int i = 0; i < arr.length; i++) { + pQ.add(arr[i]); + } + int sum = 0; + int cur = 0; + while (pQ.size() > 1) { + cur = pQ.poll() + pQ.poll(); + sum += cur; + pQ.add(cur); + } + return sum; + } + + // for test + public static int[] generateRandomArray(int maxSize, int maxValue) { + int[] arr = new int[(int) ((maxSize + 1) * Math.random())]; + for (int i = 0; i < arr.length; i++) { + arr[i] = (int) (Math.random() * (maxValue + 1)); + } + return arr; + } + + public static void main(String[] args) { + int testTime = 100000; + int maxSize = 6; + int maxValue = 1000; + for (int i = 0; i < testTime; i++) { + int[] arr = generateRandomArray(maxSize, maxValue); + if (lessMoney1(arr) != lessMoney2(arr)) { + System.out.println("Oops!"); + } + } + System.out.println("finish!"); + } + +} diff --git a/MCA算法突击课/第03期/mca_02/Code01_AddTwoNumbers.java b/MCA算法突击课/第03期/mca_02/Code01_AddTwoNumbers.java new file mode 100644 index 0000000..12998b6 --- /dev/null +++ b/MCA算法突击课/第03期/mca_02/Code01_AddTwoNumbers.java @@ -0,0 +1,62 @@ +package 第03期.mca_02; + +// 测试链接:https://leetcode.com/problems/add-two-numbers/ +public class Code01_AddTwoNumbers { + + // 不要提交这个类 + public static class ListNode { + public int val; + public ListNode next; + + public ListNode(int val) { + this.val = val; + } + + public ListNode(int val, ListNode next) { + this.val = val; + this.next = next; + } + } + + public static ListNode addTwoNumbers(ListNode head1, ListNode head2) { + int len1 = listLength(head1); + int len2 = listLength(head2); + ListNode l = len1 >= len2 ? head1 : head2; + ListNode s = l == head1 ? head2 : head1; + ListNode curL = l; + ListNode curS = s; + ListNode last = curL; + int carry = 0; + int curNum = 0; + while (curS != null) { + curNum = curL.val + curS.val + carry; + curL.val = (curNum % 10); + carry = curNum / 10; + last = curL; + curL = curL.next; + curS = curS.next; + } + while (curL != null) { + curNum = curL.val + carry; + curL.val = (curNum % 10); + carry = curNum / 10; + last = curL; + curL = curL.next; + } + if (carry != 0) { + last.next = new ListNode(1); + } + return l; + } + + // 求链表长度 + public static int listLength(ListNode head) { + int len = 0; + while (head != null) { + len++; + head = head.next; + } + return len; + } + +} diff --git a/MCA算法突击课/第03期/mca_02/Code02_IsPalindromeList.java b/MCA算法突击课/第03期/mca_02/Code02_IsPalindromeList.java new file mode 100644 index 0000000..815c245 --- /dev/null +++ b/MCA算法突击课/第03期/mca_02/Code02_IsPalindromeList.java @@ -0,0 +1,204 @@ +package 第03期.mca_02; + +import java.util.Stack; + +public class Code02_IsPalindromeList { + + public static class Node { + public int value; + public Node next; + + public Node(int data) { + this.value = data; + } + } + + // need n extra space + public static boolean isPalindrome1(Node head) { + Stack stack = new Stack(); + Node cur = head; + while (cur != null) { + stack.push(cur); + cur = cur.next; + } + while (head != null) { + if (head.value != stack.pop().value) { + return false; + } + head = head.next; + } + return true; + } + + // need n/2 extra space + public static boolean isPalindrome2(Node head) { + if (head == null || head.next == null) { + return true; + } + Node right = head.next; + Node cur = head; + while (cur.next != null && cur.next.next != null) { + right = right.next; + cur = cur.next.next; + } + Stack stack = new Stack(); + while (right != null) { + stack.push(right); + right = right.next; + } + while (!stack.isEmpty()) { + if (head.value != stack.pop().value) { + return false; + } + head = head.next; + } + return true; + } + + // need O(1) extra space + public static boolean isPalindrome3(Node head) { + if (head == null || head.next == null) { + return true; + } + Node n1 = head; + Node n2 = head; + while (n2.next != null && n2.next.next != null) { // find mid node + n1 = n1.next; // n1 -> mid + n2 = n2.next.next; // n2 -> end + } + // n1 中点 + + + n2 = n1.next; // n2 -> right part first node + n1.next = null; // mid.next -> null + Node n3 = null; + while (n2 != null) { // right part convert + n3 = n2.next; // n3 -> save next node + n2.next = n1; // next of right node convert + n1 = n2; // n1 move + n2 = n3; // n2 move + } + n3 = n1; // n3 -> save last node + n2 = head;// n2 -> left first node + boolean res = true; + while (n1 != null && n2 != null) { // check palindrome + if (n1.value != n2.value) { + res = false; + break; + } + n1 = n1.next; // left to mid + n2 = n2.next; // right to mid + } + n1 = n3.next; + n3.next = null; + while (n1 != null) { // recover list + n2 = n1.next; + n1.next = n3; + n3 = n1; + n1 = n2; + } + return res; + } + + public static void printLinkedList(Node node) { + System.out.print("Linked List: "); + while (node != null) { + System.out.print(node.value + " "); + node = node.next; + } + System.out.println(); + } + + public static void main(String[] args) { + + Node head = null; + printLinkedList(head); + System.out.print(isPalindrome1(head) + " | "); + System.out.print(isPalindrome2(head) + " | "); + System.out.println(isPalindrome3(head) + " | "); + printLinkedList(head); + System.out.println("========================="); + + head = new Node(1); + printLinkedList(head); + System.out.print(isPalindrome1(head) + " | "); + System.out.print(isPalindrome2(head) + " | "); + System.out.println(isPalindrome3(head) + " | "); + printLinkedList(head); + System.out.println("========================="); + + head = new Node(1); + head.next = new Node(2); + printLinkedList(head); + System.out.print(isPalindrome1(head) + " | "); + System.out.print(isPalindrome2(head) + " | "); + System.out.println(isPalindrome3(head) + " | "); + printLinkedList(head); + System.out.println("========================="); + + head = new Node(1); + head.next = new Node(1); + printLinkedList(head); + System.out.print(isPalindrome1(head) + " | "); + System.out.print(isPalindrome2(head) + " | "); + System.out.println(isPalindrome3(head) + " | "); + printLinkedList(head); + System.out.println("========================="); + + head = new Node(1); + head.next = new Node(2); + head.next.next = new Node(3); + printLinkedList(head); + System.out.print(isPalindrome1(head) + " | "); + System.out.print(isPalindrome2(head) + " | "); + System.out.println(isPalindrome3(head) + " | "); + printLinkedList(head); + System.out.println("========================="); + + head = new Node(1); + head.next = new Node(2); + head.next.next = new Node(1); + printLinkedList(head); + System.out.print(isPalindrome1(head) + " | "); + System.out.print(isPalindrome2(head) + " | "); + System.out.println(isPalindrome3(head) + " | "); + printLinkedList(head); + System.out.println("========================="); + + head = new Node(1); + head.next = new Node(2); + head.next.next = new Node(3); + head.next.next.next = new Node(1); + printLinkedList(head); + System.out.print(isPalindrome1(head) + " | "); + System.out.print(isPalindrome2(head) + " | "); + System.out.println(isPalindrome3(head) + " | "); + printLinkedList(head); + System.out.println("========================="); + + head = new Node(1); + head.next = new Node(2); + head.next.next = new Node(2); + head.next.next.next = new Node(1); + printLinkedList(head); + System.out.print(isPalindrome1(head) + " | "); + System.out.print(isPalindrome2(head) + " | "); + System.out.println(isPalindrome3(head) + " | "); + printLinkedList(head); + System.out.println("========================="); + + head = new Node(1); + head.next = new Node(2); + head.next.next = new Node(3); + head.next.next.next = new Node(2); + head.next.next.next.next = new Node(1); + printLinkedList(head); + System.out.print(isPalindrome1(head) + " | "); + System.out.print(isPalindrome2(head) + " | "); + System.out.println(isPalindrome3(head) + " | "); + printLinkedList(head); + System.out.println("========================="); + + } + +} diff --git a/MCA算法突击课/第03期/mca_02/Code03_SmallerEqualBigger.java b/MCA算法突击课/第03期/mca_02/Code03_SmallerEqualBigger.java new file mode 100644 index 0000000..586781f --- /dev/null +++ b/MCA算法突击课/第03期/mca_02/Code03_SmallerEqualBigger.java @@ -0,0 +1,138 @@ +package 第03期.mca_02; + +public class Code03_SmallerEqualBigger { + + public static class Node { + public int value; + public Node next; + + public Node(int data) { + this.value = data; + } + } + + public static Node listPartition1(Node head, int pivot) { + if (head == null) { + return head; + } + Node cur = head; + int i = 0; + while (cur != null) { + i++; + cur = cur.next; + } + Node[] nodeArr = new Node[i]; + i = 0; + cur = head; + for (i = 0; i != nodeArr.length; i++) { + nodeArr[i] = cur; + cur = cur.next; + } + arrPartition(nodeArr, pivot); + for (i = 1; i != nodeArr.length; i++) { + nodeArr[i - 1].next = nodeArr[i]; + } + nodeArr[i - 1].next = null; + return nodeArr[0]; + } + + public static void arrPartition(Node[] nodeArr, int pivot) { + int small = -1; + int big = nodeArr.length; + int index = 0; + while (index != big) { + if (nodeArr[index].value < pivot) { + swap(nodeArr, ++small, index++); + } else if (nodeArr[index].value == pivot) { + index++; + } else { + swap(nodeArr, --big, index); + } + } + } + + public static void swap(Node[] nodeArr, int a, int b) { + Node tmp = nodeArr[a]; + nodeArr[a] = nodeArr[b]; + nodeArr[b] = tmp; + } + + public static Node listPartition2(Node head, int pivot) { + Node sH = null; // small head + Node sT = null; // small tail + Node eH = null; // equal head + Node eT = null; // equal tail + Node mH = null; // big head + Node mT = null; // big tail + Node next = null; // save next node + // every node distributed to three lists + while (head != null) { + next = head.next; + head.next = null; + if (head.value < pivot) { + if (sH == null) { + sH = head; + sT = head; + } else { + sT.next = head; + sT = head; + } + } else if (head.value == pivot) { + if (eH == null) { + eH = head; + eT = head; + } else { + eT.next = head; + eT = head; + } + } else { + if (mH == null) { + mH = head; + mT = head; + } else { + mT.next = head; + mT = head; + } + } + head = next; + } + // 小于区域的尾巴,连等于区域的头,等于区域的尾巴连大于区域的头 + if (sT != null) { // 如果有小于区域 + sT.next = eH; + eT = eT == null ? sT : eT; // 下一步,谁去连大于区域的头,谁就变成eT + } + // 下一步,一定是需要用eT 去接 大于区域的头 + // 有等于区域,eT -> 等于区域的尾结点 + // 无等于区域,eT -> 小于区域的尾结点 + // eT 尽量不为空的尾巴节点 + if (eT != null) { // 如果小于区域和等于区域,不是都没有 + eT.next = mH; + } + return sH != null ? sH : (eH != null ? eH : mH); + } + + public static void printLinkedList(Node node) { + System.out.print("Linked List: "); + while (node != null) { + System.out.print(node.value + " "); + node = node.next; + } + System.out.println(); + } + + public static void main(String[] args) { + Node head1 = new Node(7); + head1.next = new Node(9); + head1.next.next = new Node(1); + head1.next.next.next = new Node(8); + head1.next.next.next.next = new Node(5); + head1.next.next.next.next.next = new Node(2); + head1.next.next.next.next.next.next = new Node(5); + printLinkedList(head1); + // head1 = listPartition1(head1, 4); + head1 = listPartition2(head1, 5); + printLinkedList(head1); + + } + +} diff --git a/MCA算法突击课/第03期/mca_02/Code04_CopyListWithRandom.java b/MCA算法突击课/第03期/mca_02/Code04_CopyListWithRandom.java new file mode 100644 index 0000000..ccf8664 --- /dev/null +++ b/MCA算法突击课/第03期/mca_02/Code04_CopyListWithRandom.java @@ -0,0 +1,79 @@ +package 第03期.mca_02; + +import java.util.HashMap; + +// 测试链接 : https://leetcode.com/problems/copy-list-with-random-pointer/ +public class Code04_CopyListWithRandom { + + public static class Node { + int val; + Node next; + Node random; + + public Node(int val) { + this.val = val; + this.next = null; + this.random = null; + } + } + + public static Node copyRandomList1(Node head) { + // key 老节点 + // value 新节点 + HashMap map = new HashMap(); + Node cur = head; + while (cur != null) { + map.put(cur, new Node(cur.val)); + cur = cur.next; + } + cur = head; + while (cur != null) { + // cur 老 + // map.get(cur) 新 + // 新.next -> cur.next克隆节点找到 + map.get(cur).next = map.get(cur.next); + map.get(cur).random = map.get(cur.random); + cur = cur.next; + } + return map.get(head); + } + + public static Node copyRandomList2(Node head) { + if (head == null) { + return null; + } + Node cur = head; + Node next = null; + // 1 -> 2 -> 3 -> null + // 1 -> 1' -> 2 -> 2' -> 3 -> 3' + while (cur != null) { + next = cur.next; + cur.next = new Node(cur.val); + cur.next.next = next; + cur = next; + } + cur = head; + Node copy = null; + // 1 1' 2 2' 3 3' + // 依次设置 1' 2' 3' random指针 + while (cur != null) { + next = cur.next.next; + copy = cur.next; + copy.random = cur.random != null ? cur.random.next : null; + cur = next; + } + Node res = head.next; + cur = head; + // 老 新 混在一起,next方向上,random正确 + // next方向上,把新老链表分离 + while (cur != null) { + next = cur.next.next; + copy = cur.next; + cur.next = next; + copy.next = next != null ? next.next : null; + cur = next; + } + return res; + } + +} diff --git a/MCA算法突击课/第03期/mca_02/Code05_ReverseNodesInKGroup.java b/MCA算法突击课/第03期/mca_02/Code05_ReverseNodesInKGroup.java new file mode 100644 index 0000000..f27209d --- /dev/null +++ b/MCA算法突击课/第03期/mca_02/Code05_ReverseNodesInKGroup.java @@ -0,0 +1,59 @@ + + +package 第03期.mca_02; + +// 测试链接:https://leetcode.com/problems/reverse-nodes-in-k-group/ +public class Code05_ReverseNodesInKGroup { + + // 不要提交这个类 + public static class ListNode { + public int val; + public ListNode next; + } + + public static ListNode reverseKGroup(ListNode head, int k) { + ListNode start = head; + ListNode end = getKGroupEnd(start, k); + if (end == null) { + return head; + } + // 第一组凑齐了! + head = end; + reverse(start, end); + // 上一组的结尾节点 + ListNode lastEnd = start; + while (lastEnd.next != null) { + start = lastEnd.next; + end = getKGroupEnd(start, k); + if (end == null) { + return head; + } + reverse(start, end); + lastEnd.next = end; + lastEnd = start; + } + return head; + } + + public static ListNode getKGroupEnd(ListNode start, int k) { + while (--k != 0 && start != null) { + start = start.next; + } + return start; + } + + public static void reverse(ListNode start, ListNode end) { + end = end.next; + ListNode pre = null; + ListNode cur = start; + ListNode next = null; + while (cur != end) { + next = cur.next; + cur.next = pre; + pre = cur; + cur = next; + } + start.next = end; + } + +} \ No newline at end of file diff --git a/MCA算法突击课/第03期/mca_02/Code06_MergeKSortedLists.java b/MCA算法突击课/第03期/mca_02/Code06_MergeKSortedLists.java new file mode 100644 index 0000000..14662fd --- /dev/null +++ b/MCA算法突击课/第03期/mca_02/Code06_MergeKSortedLists.java @@ -0,0 +1,52 @@ +package 第03期.mca_02; + +import java.util.Comparator; +import java.util.PriorityQueue; + +// 测试链接:https://leetcode.com/problems/merge-k-sorted-lists/ +public class Code06_MergeKSortedLists { + + public static class ListNode { + public int val; + public ListNode next; + } + + public static class ListNodeComparator implements Comparator { + + @Override + public int compare(ListNode o1, ListNode o2) { + return o1.val - o2.val; + } + + } + + public static ListNode mergeKLists(ListNode[] lists) { + if (lists == null) { + return null; + } + PriorityQueue heap = new PriorityQueue<>(new ListNodeComparator()); + for (int i = 0; i < lists.length; i++) { + if (lists[i] != null) { + heap.add(lists[i]); + } + } + if (heap.isEmpty()) { + return null; + } + ListNode head = heap.poll(); + ListNode pre = head; + if (pre.next != null) { + heap.add(pre.next); + } + while (!heap.isEmpty()) { + ListNode cur = heap.poll(); + pre.next = cur; + pre = cur; + if (cur.next != null) { + heap.add(cur.next); + } + } + return head; + } + +} diff --git a/MCA算法突击课/第03期/mca_02/Code07_FindFirstIntersectNode.java b/MCA算法突击课/第03期/mca_02/Code07_FindFirstIntersectNode.java new file mode 100644 index 0000000..0fdd8a9 --- /dev/null +++ b/MCA算法突击课/第03期/mca_02/Code07_FindFirstIntersectNode.java @@ -0,0 +1,170 @@ +package 第03期.mca_02; + +public class Code07_FindFirstIntersectNode { + + public static class Node { + public int value; + public Node next; + + public Node(int data) { + this.value = data; + } + } + + public static Node getIntersectNode(Node head1, Node head2) { + if (head1 == null || head2 == null) { + return null; + } + Node loop1 = getLoopNode(head1); + Node loop2 = getLoopNode(head2); + if (loop1 == null && loop2 == null) { + return noLoop(head1, head2); + } + if (loop1 != null && loop2 != null) { + return bothLoop(head1, loop1, head2, loop2); + } + return null; + } + + // 找到链表第一个入环节点,如果无环,返回null + public static Node getLoopNode(Node head) { + if (head == null || head.next == null || head.next.next == null) { + return null; + } + // n1 慢 n2 快 + Node slow = head.next; // n1 -> slow + Node fast = head.next.next; // n2 -> fast + while (slow != fast) { + if (fast.next == null || fast.next.next == null) { + return null; + } + fast = fast.next.next; + slow = slow.next; + } + // slow fast 相遇 + fast = head; // n2 -> walk again from head + while (slow != fast) { + slow = slow.next; + fast = fast.next; + } + return slow; + } + + // 如果两个链表都无环,返回第一个相交节点,如果不想交,返回null + public static Node noLoop(Node head1, Node head2) { + if (head1 == null || head2 == null) { + return null; + } + Node cur1 = head1; + Node cur2 = head2; + int n = 0; + while (cur1.next != null) { + n++; + cur1 = cur1.next; + } + while (cur2.next != null) { + n--; + cur2 = cur2.next; + } + if (cur1 != cur2) { + return null; + } + // n : 链表1长度减去链表2长度的值 + cur1 = n > 0 ? head1 : head2; // 谁长,谁的头变成cur1 + cur2 = cur1 == head1 ? head2 : head1; // 谁短,谁的头变成cur2 + n = Math.abs(n); + while (n != 0) { + n--; + cur1 = cur1.next; + } + while (cur1 != cur2) { + cur1 = cur1.next; + cur2 = cur2.next; + } + return cur1; + } + + // 两个有环链表,返回第一个相交节点,如果不想交返回null + public static Node bothLoop(Node head1, Node loop1, Node head2, Node loop2) { + Node cur1 = null; + Node cur2 = null; + if (loop1 == loop2) { + cur1 = head1; + cur2 = head2; + int n = 0; + while (cur1 != loop1) { + n++; + cur1 = cur1.next; + } + while (cur2 != loop2) { + n--; + cur2 = cur2.next; + } + cur1 = n > 0 ? head1 : head2; + cur2 = cur1 == head1 ? head2 : head1; + n = Math.abs(n); + while (n != 0) { + n--; + cur1 = cur1.next; + } + while (cur1 != cur2) { + cur1 = cur1.next; + cur2 = cur2.next; + } + return cur1; + } else { + cur1 = loop1.next; + while (cur1 != loop1) { + if (cur1 == loop2) { + return loop1; + } + cur1 = cur1.next; + } + return null; + } + } + + public static void main(String[] args) { + // 1->2->3->4->5->6->7->null + Node head1 = new Node(1); + head1.next = new Node(2); + head1.next.next = new Node(3); + head1.next.next.next = new Node(4); + head1.next.next.next.next = new Node(5); + head1.next.next.next.next.next = new Node(6); + head1.next.next.next.next.next.next = new Node(7); + + // 0->9->8->6->7->null + Node head2 = new Node(0); + head2.next = new Node(9); + head2.next.next = new Node(8); + head2.next.next.next = head1.next.next.next.next.next; // 8->6 + System.out.println(getIntersectNode(head1, head2).value); + + // 1->2->3->4->5->6->7->4... + head1 = new Node(1); + head1.next = new Node(2); + head1.next.next = new Node(3); + head1.next.next.next = new Node(4); + head1.next.next.next.next = new Node(5); + head1.next.next.next.next.next = new Node(6); + head1.next.next.next.next.next.next = new Node(7); + head1.next.next.next.next.next.next = head1.next.next.next; // 7->4 + + // 0->9->8->2... + head2 = new Node(0); + head2.next = new Node(9); + head2.next.next = new Node(8); + head2.next.next.next = head1.next; // 8->2 + System.out.println(getIntersectNode(head1, head2).value); + + // 0->9->8->6->4->5->6.. + head2 = new Node(0); + head2.next = new Node(9); + head2.next.next = new Node(8); + head2.next.next.next = head1.next.next.next.next.next; // 8->6 + System.out.println(getIntersectNode(head1, head2).value); + + } + +}