diff --git a/DataStructures_Algorithm/DataStructures/pom.xml b/DataStructures_Algorithm/DataStructures/pom.xml index e36fa45..ea4b98b 100644 --- a/DataStructures_Algorithm/DataStructures/pom.xml +++ b/DataStructures_Algorithm/DataStructures/pom.xml @@ -9,6 +9,33 @@ 4.0.0 + + + junit + junit + 4.13.2 + test + + + junit + junit + 4.13.2 + compile + + + org.projectlombok + lombok + RELEASE + compile + + + junit + junit + 4.13.1 + compile + + + DataStructures diff --git a/DataStructures_Algorithm/DataStructures/src/main/java/com/atguigu/sort/selftry/HeapSort.java b/DataStructures_Algorithm/DataStructures/src/main/java/com/atguigu/sort/selftry/HeapSort.java new file mode 100644 index 0000000..21d506c --- /dev/null +++ b/DataStructures_Algorithm/DataStructures/src/main/java/com/atguigu/sort/selftry/HeapSort.java @@ -0,0 +1,73 @@ +package com.atguigu.sort.selftry; + +import org.junit.Test; + +import java.util.Arrays; + +/** + *@BelongsProject: DataStructures_Algorithm + *@BelongsPackage: com.atguigu.sort.selftry + *@Author: markilue + *@CreateTime: 2023-03-31 10:26 + *@Description: TODO 尝试堆排序 + *@Version: 1.0 + */ +public class HeapSort { + + @Test + public void test(){ + int[] arr = {20, 50, 45, 40, 35,10,30,15,25}; + //测试80000个数据进行测试 +// int[] arr = new int[200]; +// for (int i = 0; i < arr.length; i++) { +// arr[i] = (int) (Math.random() * 200); //生成一个[0,80000]的数 +// } + heapSort(arr); + System.out.println(Arrays.toString(arr)); + } + + + public void heapSort(int[] arr) { + + if (arr == null) return; + //从最后一个非叶子节点开始进行堆化 + for (int i = arr.length / 2 - 1; i >= 0; i--) { + adjustHeap(arr, i, arr.length); + } + + //进行交换 + int temp; + for (int i = arr.length - 1; i > 0; i--) { + temp = arr[i]; + arr[i] = arr[0]; + arr[0] = temp; + adjustHeap(arr, 0, i);//把交换完的i放在合适的位置 + } + + + } + + public void adjustHeap(int[] arr, int i, int length) { + + int temp = arr[i];//记录下以前位置的值 + + for (int j = 2 * i + 1; j < length; j++) { + //比较左右节点哪一个更大 + if (j + 1 < length && arr[j] < arr[j + 1]) { + j++; + } + if (arr[j] > temp) { + //需要进行交换 + arr[i] = arr[j]; + i = j;//后续比较j位置的值了 + } else { + break; + } + } + arr[i] = temp;//找到合适的位置放temp + + + } + + +} diff --git a/DataStructures_Algorithm/DataStructures/src/main/java/com/atguigu/tree/HeapSort.java b/DataStructures_Algorithm/DataStructures/src/main/java/com/atguigu/tree/HeapSort.java index 2169512..8b2682a 100644 --- a/DataStructures_Algorithm/DataStructures/src/main/java/com/atguigu/tree/HeapSort.java +++ b/DataStructures_Algorithm/DataStructures/src/main/java/com/atguigu/tree/HeapSort.java @@ -1,5 +1,7 @@ package com.atguigu.tree; +import org.junit.Test; + import java.text.SimpleDateFormat; import java.util.Arrays; import java.util.Date; @@ -17,44 +19,57 @@ public class HeapSort { // System.out.println(Arrays.toString(arr)); //测试80000个数据进行测试 - int[] arr =new int[8000000]; + int[] arr = new int[8000000]; for (int i = 0; i < arr.length; i++) { - arr[i] = (int)(Math.random()*8000000); //生成一个[0,80000]的数 + arr[i] = (int) (Math.random() * 8000000); //生成一个[0,80000]的数 } Date date1 = new Date(); SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String date1Str = simpleDateFormat.format(date1); - System.out.println("排序前的时间:"+date1Str); //排序前的时间:2022-02-15 21:19:36 + System.out.println("排序前的时间:" + date1Str); //排序前的时间:2022-02-15 21:19:36 heapSort(arr); Date date2 = new Date(); String date2Str = simpleDateFormat.format(date2); - System.out.println("排序后的时间:"+date2Str); //排序后的时间:2022-02-15 21:19:40 + System.out.println("排序后的时间:" + date2Str); //排序后的时间:2022-02-15 21:19:40 } + @Test + public void test() { + int[] arr = {20, 50, 45, 40, 35,10,30,15,25}; + //测试80000个数据进行测试 +// int[] arr = new int[200]; +// for (int i = 0; i < arr.length; i++) { +// arr[i] = (int) (Math.random() * 200); //生成一个[0,80000]的数 +// } + heapSort(arr); + System.out.println(Arrays.toString(arr)); + } + /** * 编写一个堆排序的方法 */ public static void heapSort(int[] arr) { //TODO (1)将无序序列构建成一个堆,根据升序降序需求选择大顶堆或者小顶堆 - //arr.length/2-1求出来的是完全二叉树的最后一个非叶子节点 - for (int i = arr.length/2-1; i >= 0; i--) { - adjustHeap(arr,i,arr.length); + // arr.length/2-1求出来的是完全二叉树的最后一个非叶子节点; + // arr.length/2-1是关键,是adjustHeap前提的满足条件的前提 + for (int i = arr.length / 2 - 1; i >= 0; i--) { + adjustHeap(arr, i, arr.length); } - int temp=0; + int temp = 0; //TODO (2)将顶对元素与末尾元素交换,将最大元素放置在数组末尾 - //TODO (3)重新调整结构,使其满足堆定义,然后继续交换对顶元素与当前末尾元素,贩毒执行调整+交换步骤,直到整个序列有序 - for (int i = arr.length-1; i >0; i--) { + //TODO (3)重新调整结构,使其满足堆定义,然后继续交换对顶元素与当前末尾元素,反复执行调整+交换步骤,直到整个序列有序 + for (int i = arr.length - 1; i > 0; i--) { //交换 - temp=arr[i]; - arr[i]=arr[0]; - arr[0]=temp; - adjustHeap(arr,0,i); + temp = arr[i]; + arr[i] = arr[0]; + arr[0] = temp; + adjustHeap(arr, 0, i);//主要就是利用堆顶元素就是最大值来进行处理的 } @@ -62,7 +77,7 @@ public class HeapSort { } /** - * 前提:该节点的所有子节点都已经是大顶堆了 + * TODO 前提:该节点的所有子节点都已经是大顶堆了,因为这里需要break * 将以第i个位置为根节点时以下树,调整成一个大顶堆 * * @param arr 待调整的数组 @@ -76,20 +91,22 @@ public class HeapSort { //开始调整 //说明:j = i * 2 + 1 ;这里k就是i节点的左子节点 for (int j = i * 2 + 1; j < length; j = j * 2 + 1) { + //TODO 1.寻找左右节点哪一个更大 if (j + 1 < length && arr[j] < arr[j + 1]) { //左子节点的值小于右子节点的值 j++; //j指向右子节点 } + //TODO 2.用左右节点中大值去和他的父节点比较;如果小了直接将父节点变成那个最大的值 if (arr[j] > temp) { //如果子节点大于父节点 arr[i] = arr[j];//把较大的值赋给当前节点 i = j; //将i指向j,继续循环比较 - }else { - break; + } else { + break;//左右子节点都比父节点小,直接break } } //当for循环结束后,我们已经将以i为父节点的树的最大值,放在了i的位置 - arr[i]=temp; //将temp值放在调整后的位置 + arr[i] = temp; //将temp值放在调整后的位置 } diff --git a/Leecode/src/main/java/com/markilue/leecode/hot100/T55_LFUCache.java b/Leecode/src/main/java/com/markilue/leecode/hot100/T55_LFUCache.java new file mode 100644 index 0000000..e0ddc8f --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/hot100/T55_LFUCache.java @@ -0,0 +1,217 @@ +package com.markilue.leecode.hot100; + +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.hot100 + *@Author: markilue + *@CreateTime: 2023-03-13 17:13 + *@Description: + * TODO 力扣146题 LRU缓存: + * 请你为 最不经常使用(LFU)缓存算法设计并实现数据结构。 + * 实现 LFUCache 类: + * LFUCache(int capacity) - 用数据结构的容量 capacity 初始化对象 + * int get(int key) - 如果键 key 存在于缓存中,则获取键的值,否则返回 -1 。 + * void put(int key, int value) - 如果键 key 已存在,则变更其值;如果键不存在,请插入键值对。当缓存达到其容量 capacity 时,则应该在插入新项之前,移除最不经常使用的项。在此问题中,当存在平局(即两个或更多个键具有相同使用频率)时,应该去除 最近最久未使用 的键。 + * 为了确定最不常使用的键,可以为缓存中的每个键维护一个 使用计数器 。使用计数最小的键是最久未使用的键。 + * 当一个键首次插入到缓存中时,它的使用计数器被设置为 1 (由于 put 操作)。对缓存中的键执行 get 或 put 操作,使用计数器的值将会递增。 + * 函数 get 和 put 必须以 O(1) 的平均时间复杂度运行。 + *@Version: 1.0 + */ +public class T55_LFUCache { + + Map cache; + Map freqMap; + int capacity; + int min; + int size; + + + public T55_LFUCache() { + } + + + public T55_LFUCache(int capacity) { + this.capacity = capacity; + cache = new HashMap<>(); + freqMap = new HashMap<>(); + min = 0; + size = 0; + + } + + public int get(int key) { + Node node = cache.get(key); + if (node == null) { + return -1; + } + freqInc(node); + return node.value; + } + + public void put(int key, int value) { + if (capacity == 0) { + return; + } + Node node = cache.get(key); + if (node != null) { + //更新即可 + node.value = value; + freqInc(node); + } else { + if (size == capacity) { + //如果已经等于了就要进行删除 + removeNode(); + + } + Node node1 = new Node(key, value, 1); + cache.put(key, node1); + addNode(node1); + size++; + } + + } + + public void freqInc(Node node) { + int freq = node.freq; + NodeList nodeList = freqMap.get(freq); + if (nodeList != null) { + nodeList.removeNode(node); + } else { + nodeList = new NodeList(); + freqMap.put(freq, nodeList); + } + if (freq == min && nodeList.isEmpty()) { + min = freq + 1; + } + node.freq++; + NodeList nodeList1 = freqMap.get(freq + 1); + if (nodeList1 == null) { + nodeList1 = new NodeList(); + freqMap.put(freq + 1, nodeList1); + } + nodeList1.addNode(node); + + } + + public void addNode(Node node) { + int freq = node.freq; + NodeList nodeList = freqMap.get(freq); + if (nodeList == null) { + nodeList = new NodeList(); + freqMap.put(freq, nodeList); + } + nodeList.addNode(node); + min = 1; + + } + + public void removeNode() { + NodeList nodeList = freqMap.get(min); + + Node node = nodeList.removeNode(); + cache.remove(node.key); + size--; + } + + + @Test + public void test() { + T55_LFUCache lRUCache = new T55_LFUCache(2); + lRUCache.put(1, 1); // 缓存是 {1=1} + lRUCache.put(2, 2); // 缓存是 {1=1, 2=2} + System.out.println(lRUCache.get(1)); // 返回 1 + lRUCache.put(3, 3); // 该操作会使得关键字 2 作废,缓存是 {1=1, 3=3} + System.out.println(lRUCache.get(2)); // 返回 -1 (未找到) + lRUCache.put(4, 4); // 该操作会使得关键字 1 作废,缓存是 {4=4, 3=3} + System.out.println(lRUCache.get(1)); // 返回 -1 (未找到) + System.out.println(lRUCache.get(3)); // 返回 3 + System.out.println(lRUCache.get(4)); // 返回 4 + } + + public class Node { + + int key; + int value; + int freq; + Node pre; + Node next; + + + public Node() { + } + + public Node(int key, int value) { + this.key = key; + this.value = value; + this.freq = 1; + } + + public Node(int key, int value, int freq) { + this.key = key; + this.value = value; + this.freq = freq; + } + + public Node(int key, int value, int freq, Node pre, Node next) { + this.key = key; + this.value = value; + this.freq = freq; + this.pre = pre; + this.next = next; + } + + + } + + + public class NodeList { + + Node head; + Node tail; + int size; + + public NodeList() { + head = new Node(); + tail = new Node(); + head.next = tail; + tail.pre = head; + size = 0; + } + + //移除链表中的最后一个节点 + public Node removeNode() { + return removeNode(tail.pre); + } + + //移除链表指定元素 + public Node removeNode(Node node) { + node.pre.next = node.next; + node.next.pre = node.pre; + size--; + return node; + + } + + //加在链表中第一个位置 + public void addNode(Node node) { + node.next = head.next; + head.next.pre = node; + head.next = node; + node.pre = head; + size++; + } + + public boolean isEmpty() { + return size == 0; + } + + + } + + +} diff --git a/Leecode/src/main/java/com/markilue/leecode/hot100/T78_LengthOfLIS.java b/Leecode/src/main/java/com/markilue/leecode/hot100/T78_LengthOfLIS.java new file mode 100644 index 0000000..32d2281 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/hot100/T78_LengthOfLIS.java @@ -0,0 +1,72 @@ +package com.markilue.leecode.hot100; + +import org.junit.Test; + +import java.util.Arrays; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.hot100 + *@Author: markilue + *@CreateTime: 2023-03-30 10:14 + *@Description: + * TODO 力扣300 最长递增子序列: + * 给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。 + * 子序列 是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。 + *@Version: 1.0 + */ +public class T78_LengthOfLIS { + + @Test + public void test() { +// int[] nums={10,9,2,5,3,7,101,18}; + int[] nums = {1, 3, 6, 7, 9, 4, 10, 5, 6}; + System.out.println(lengthOfLIS(nums)); + } + + /** + * 思路:dp + * dp[i]表示以0开头以i结尾的数组的最长递增子序列长度 + * @param nums + * @return + */ + public int lengthOfLIS(int[] nums) { + + int[] dp = new int[nums.length]; + Arrays.fill(dp, 1); + int max = 0; + + + for (int i = 1; i < dp.length; i++) { + for (int j = 0; j < i; j++) { + if (nums[i] > nums[j]) { + dp[i] = Math.max(dp[i], dp[j] + 1); + } + if (max < dp[i]) max = dp[i]; + } + } + return max; + } + + + public int lengthOfLIS1(int[] nums) { + int N = nums.length; + //end[i]表示i+1长度的递增子序列的最小值 + int[] end = new int[N]; + end[0] = nums[0]; + int index = 0; + for(int i=1; i< N;i++){ + if(nums[i] > end[index]){ + end[++index] = nums[i]; + } else { + for (int j = 0; j <= index; j++) { + if (nums[i] <= end[j]) { + end[j] = nums[i];//替换对应的位置 + break; + } + } + } + } + return index + 1; + } +} diff --git a/Leecode/src/main/java/com/markilue/leecode/hot100/T79_RemoveInvalidParentheses.java b/Leecode/src/main/java/com/markilue/leecode/hot100/T79_RemoveInvalidParentheses.java new file mode 100644 index 0000000..165d2f9 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/hot100/T79_RemoveInvalidParentheses.java @@ -0,0 +1,241 @@ +package com.markilue.leecode.hot100; + +import org.junit.Test; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.hot100 + *@Author: markilue + *@CreateTime: 2023-03-30 10:36 + *@Description: + * TODO 力扣301 删除无效的括号: + * 给你一个由若干括号和字母组成的字符串 s ,删除最小数量的无效括号,使得输入的字符串有效。 + * 返回所有可能的结果。答案可以按 任意顺序 返回。 + *@Version: 1.0 + */ +public class T79_RemoveInvalidParentheses { + + + //不知道该怎么去重,就用set存储结果 18ms + Set set = new HashSet<>(); + StringBuilder str; + + public List removeInvalidParentheses(String s) { + int lmove = 0; + int rmove = 0; + str = new StringBuilder(s); + //遍历一遍,求出要删除左括号和右括号的数量 + for (int i = 0; i < s.length(); i++) { + if (s.charAt(i) == '(') { + lmove++; + } else if (s.charAt(i) == ')') { + //左右括号可以匹配 + if (lmove > 0) { + lmove--; + } else { + rmove++; + } + } + } + dfs(lmove, rmove, 0); + return new ArrayList<>(set); + } + + public void dfs(int lmove, int rmove, int i) { + if (lmove == 0 && rmove == 0) { + //判断字符串内括号是否有效 + if (isValid(str)) { + set.add(new String(str.toString())); + } + return; + } + //还需要删除的括号个数 小于 能过删除的字符个数 + if (lmove + rmove > str.length() - i) { + return; + } + //不删除 + dfs(lmove, rmove, i + 1); + + //删除,分左右括号考虑 + if (str.charAt(i) == '(' && lmove > 0) { + str.deleteCharAt(i);//删除 + dfs(lmove - 1, rmove, i);//进入下一层,因为删除了i处括号,所以不需要i+1 + str.insert(i, '(');//恢复现场 + } else if (str.charAt(i) == ')' && rmove > 0) { + str.deleteCharAt(i);//删除 + dfs(lmove, rmove - 1, i);//进入下一层 + str.insert(i, ')');//恢复现场 + } + } + + public boolean isValid(StringBuilder str) { + int left = 0; + for (int i = 0; i < str.length(); i++) { + if (str.charAt(i) == '(') { + left++; + } else if (str.charAt(i) == ')') { + left--; + } + if (left < 0) { + return false; + } + } + return true; + } + + + //自己去重4ms + private List res = new ArrayList(); + + public List removeInvalidParentheses1(String s) { + int lremove = 0; + int rremove = 0; + + for (int i = 0; i < s.length(); i++) { + if (s.charAt(i) == '(') { + lremove++; + } else if (s.charAt(i) == ')') { + if (lremove == 0) { + rremove++; + } else { + lremove--; + } + } + } + helper(s, 0, lremove, rremove); + + return res; + } + + private void helper(String str, int start, int lremove, int rremove) { + if (lremove == 0 && rremove == 0) { + if (isValid(str)) { + res.add(str); + } + return; + } + + for (int i = start; i < str.length(); i++) { + if (i != start && str.charAt(i) == str.charAt(i - 1)) { + continue; + } + // 如果剩余的字符无法满足去掉的数量要求,直接返回 + if (lremove + rremove > str.length() - i) { + return; + } + // 尝试去掉一个左括号 + if (lremove > 0 && str.charAt(i) == '(') { + helper(str.substring(0, i) + str.substring(i + 1), i, lremove - 1, rremove); + } + // 尝试去掉一个右括号 + if (rremove > 0 && str.charAt(i) == ')') { + helper(str.substring(0, i) + str.substring(i + 1), i, lremove, rremove - 1); + } + } + } + + private boolean isValid(String str) { + int cnt = 0; + for (int i = 0; i < str.length(); i++) { + if (str.charAt(i) == '(') { + cnt++; + } else if (str.charAt(i) == ')') { + cnt--; + if (cnt < 0) { + return false; + } + } + } + + return cnt == 0; + } + + + @Test + public void test(){ + String s ="()())()"; + System.out.println(removeInvalidParentheses2(s)); + } + + + //自己尝试一遍 + public List removeInvalidParentheses2(String s) { + + //统计需要去掉的左括号和右括号的数量 + + int left = 0; + int right = 0; + + for (char c : s.toCharArray()) { + if (c == '(') { + left++; + } else if (c == ')') { + if (left == 0) { + right++; + } else { + left--; + } + } + } + helper1(s, left, right, 0); + return res; + + } + + public void helper1(String s, int left, int right, int start) { + if (left == 0 && right == 0) { + if (isValid1(s)) { + res.add(s); + } + return; + } + + for (int i = start; i < s.length(); i++) { + //去重 + if (i != start && s.charAt(i) == s.charAt(i - 1)) continue; + + if (left + right > s.length() - i) { + //怎么删都不够了 + return; + } + + //尝试删除左括号 + if (left > 0 && s.charAt(i) == '(') { + helper1(s.substring(0, i) + s.substring(i + 1), left - 1, right, i + 1); + } + + //尝试删除右括号 + if (right > 0 && s.charAt(i) == ')') { + helper1(s.substring(0, i) + s.substring(i + 1), left, right - 1, i + 1); + } + + + } + + } + + public boolean isValid1(String s) { + int left = 0; + for (char c : s.toCharArray()) { + if (c == '(') { + left++; + } else if (c == ')') { + if (left == 0) { + return false; + } else { + left--; + } + } + } + + return left==0; + + } + + +} diff --git a/Leecode/src/main/java/com/markilue/leecode/hot100/T80_MaxProfit.java b/Leecode/src/main/java/com/markilue/leecode/hot100/T80_MaxProfit.java new file mode 100644 index 0000000..4beb134 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/hot100/T80_MaxProfit.java @@ -0,0 +1,75 @@ +package com.markilue.leecode.hot100; + +import org.junit.Test; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.hot100 + *@Author: markilue + *@CreateTime: 2023-03-31 11:13 + *@Description: + * TODO 力扣309 最佳买卖股票时机含冷冻期: + * 给定一个整数数组prices,其中第 prices[i] 表示第 i 天的股票价格 。​ + * 设计一个算法计算出最大利润。在满足以下约束条件下,你可以尽可能地完成更多的交易(多次买卖一支股票): + * 卖出股票后,你无法在第二天买入股票 (即冷冻期为 1 天)。 + * 注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。 + *@Version: 1.0 + */ +public class T80_MaxProfit { + + @Test + public void test() { + int[] prices = {1, 2, 3, 0, 2}; + System.out.println(maxProfit(prices)); + } + + + /** + * 动态dp,状态分为三种: + * 今天手里没有股票且不在冷冻期dp[i][0] + * 今天手里没有股票且在冷冻期dp[i][1] + * 今天手里有股票dp[i][2] + * @param prices + * @return + */ + public int maxProfit(int[] prices) { + if (prices.length == 1) return 0; + + int[][] dp = new int[prices.length][3]; + + dp[0][0] = 0; + dp[0][1] = 0; + dp[0][2] = -prices[0]; + + for (int i = 1; i < prices.length; i++) { + dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1]);//昨天是冷冻期;或者昨天也没买 + dp[i][1] = dp[i - 1][2] + prices[i];//必须是今天买入 + dp[i][2] = Math.max(dp[i - 1][2], dp[i - 1][0] - prices[i]);//必须是今天买入 + } + + return Math.max(dp[dp.length - 1][0], dp[dp.length - 1][1]); + + } + + //滚动数组优化 + public int maxProfit1(int[] prices) { + if (prices.length == 1) return 0; + + + int dp0 = 0; + int dp1 = 0; + int dp2 = -prices[0]; + + for (int i = 1; i < prices.length; i++) { + int temp = dp0; + dp0 = Math.max(dp0, dp1);//昨天是冷冻期;或者昨天也没买 + dp1 = dp2 + prices[i];//必须是今天买入 + dp2 = Math.max(dp2, temp - prices[i]);//必须是今天买入 + } + + return Math.max(dp0, dp1); + + } + + +} diff --git a/Leecode/src/main/java/com/markilue/leecode/hot100/T81_MaxCoins.java b/Leecode/src/main/java/com/markilue/leecode/hot100/T81_MaxCoins.java new file mode 100644 index 0000000..5f096b4 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/hot100/T81_MaxCoins.java @@ -0,0 +1,125 @@ +package com.markilue.leecode.hot100; + +import org.junit.Test; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.hot100 + *@Author: markilue + *@CreateTime: 2023-03-31 11:28 + *@Description: + * TODO 力扣312 戳气球: + * 有 n 个气球,编号为0 到 n - 1,每个气球上都标有一个数字,这些数字存在数组 nums 中。 + * 现在要求你戳破所有的气球。戳破第 i 个气球,你可以获得 nums[i - 1] * nums[i] * nums[i + 1] 枚硬币。 + * 这里的 i - 1 和 i + 1 代表和 i 相邻的两个气球的序号。如果 i - 1或 i + 1 超出了数组的边界,那么就当它是一个数字为 1 的气球。 + * 求所能获得硬币的最大数量。 + *@Version: 1.0 + */ +public class T81_MaxCoins { + + @Test + public void test() { + int[] nums = {3, 1, 5, 8}; + System.out.println(maxCoins1(nums)); + } + + + /** + * 思路:优先戳中间最小的 + * 不对 + * @param nums + * @return + */ + public int maxCoins(int[] nums) { + + int result = 0; + int count = nums.length; + + while (nums[0] != -1) { + int minIndex = 0; + int threshold = nums.length; + + if (count == 3) { + boolean flag = false; + for (int i = 0; i < nums.length; i++) { + if (nums[i] == -1) { + threshold = i; + break; + } + if (nums[i] == 1) { + minIndex = i; + flag = true; + } + + } + if (!flag) { + minIndex = 1; + } + }else { + for (int i = 1; i < nums.length; i++) { + if (nums[i] == -1) { + threshold = i; + break; + } + if (nums[minIndex] > nums[i]) { + minIndex = i; + } + } + } + + + //戳i位置 + int left; + if (minIndex - 1 < 0) { + left = 1; + } else { + left = nums[minIndex - 1]; + } + + int right; + if (minIndex + 1 >= threshold) { + right = 1; + } else { + right = nums[minIndex + 1]; + } + result += left * nums[minIndex] * right; + System.arraycopy(nums, minIndex + 1, nums, minIndex, threshold - minIndex - 1); + nums[threshold - 1] = -1; + count--; + } + + return result; + + } + + + /** + * 官方动态规划法: + * dp[i][j]表示填满开区间(i,j)能得到的最多硬币数 + * 最终答案即为 dp[0][n+1]dp[0][n+1]dp[0][n+1]。实现时要注意到动态规划的次序。 + * 动态规划: + * 速度击败27.13% 内存击败45.56% 43ms + * @param nums + * @return + */ + public int maxCoins1(int[] nums) { + int n = nums.length; + int[][] rec = new int[n + 2][n + 2]; + int[] val = new int[n + 2]; + val[0] = val[n + 1] = 1; + for (int i = 1; i <= n; i++) { + val[i] = nums[i - 1]; + } + for (int i = n - 1; i >= 0; i--) { + for (int j = i + 2; j <= n + 1; j++) { + for (int k = i + 1; k < j; k++) { + int sum = val[i] * val[k] * val[j];//计算戳当前点的sum + sum += rec[i][k] + rec[k][j];//计算不要这个点之后的左右点的戳开的和 + rec[i][j] = Math.max(rec[i][j], sum); + } + } + } + return rec[0][n + 1]; + } + +} diff --git a/Leecode/src/main/java/com/markilue/leecode/hot100/T82_CoinChange.java b/Leecode/src/main/java/com/markilue/leecode/hot100/T82_CoinChange.java new file mode 100644 index 0000000..0a52a50 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/hot100/T82_CoinChange.java @@ -0,0 +1,84 @@ +package com.markilue.leecode.hot100; + +import org.junit.Test; + +import java.util.Arrays; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.hot100 + *@Author: markilue + *@CreateTime: 2023-04-03 09:49 + *@Description: + * TODO 力扣322 零钱兑换: + * 给你一个整数数组 coins ,表示不同面额的硬币;以及一个整数 amount ,表示总金额。 + * 计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额,返回 -1 。 + * 你可以认为每种硬币的数量是无限的。 + *@Version: 1.0 + */ +public class T82_CoinChange { + + @Test + public void test() { + int[] coins = {186, 419, 83, 408}; + int amount = 6249; + System.out.println(coinChange(coins, amount)); + } + + + /** + * 思路:硬币可以使用无数次 完全背包 + * 动态DP + * @param coins + * @param amount + * @return + */ + public int coinChange(int[] coins, int amount) { + + int[][] dp = new int[coins.length][amount + 1]; + Arrays.sort(coins); + dp[0][0] = 0; + for (int i = 1; i < dp[0].length; i++) { + if (i >= coins[0] && i % coins[0] == 0) dp[0][i] = dp[0][i - coins[0]] + 1; + else dp[0][i] = Integer.MAX_VALUE; + } + + for (int i = 1; i < dp.length; i++) { + for (int j = 1; j < dp[0].length; j++) { + if (j >= coins[i] && dp[i][j - coins[i]] != Integer.MAX_VALUE) { + dp[i][j] = Math.min(dp[i][j - coins[i]] + 1, dp[i - 1][j]); + } else dp[i][j] = dp[i - 1][j];//使用哪一个 + } + } + return dp[coins.length - 1][amount] == Integer.MAX_VALUE ? -1 : dp[coins.length - 1][amount]; + } + + + /** + * 一维dp优化 + * @param coins + * @param amount + * @return + */ + public int coinChange1(int[] coins, int amount) { + + int[] dp = new int[amount + 1]; +// Arrays.sort(coins); + dp[0] = 0; + for (int i = 1; i < dp.length; i++) { + if (i >= coins[0] && i % coins[0] == 0) dp[i] = dp[i - coins[0]] + 1; + else dp[i] = Integer.MAX_VALUE; + } + + for (int i = 1; i < coins.length; i++) { + for (int j = coins[i]; j < dp.length; j++) { + if (j >= coins[i] && dp[j - coins[i]] != Integer.MAX_VALUE) { + dp[j] = Math.min(dp[j - coins[i]] + 1, dp[j]); + } + } + } + return dp[amount] == Integer.MAX_VALUE ? -1 : dp[amount]; + + + } +} diff --git a/Leecode/src/main/java/com/markilue/leecode/hot100/T83_Rob.java b/Leecode/src/main/java/com/markilue/leecode/hot100/T83_Rob.java new file mode 100644 index 0000000..1332e0c --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/hot100/T83_Rob.java @@ -0,0 +1,41 @@ +package com.markilue.leecode.hot100; + +import com.markilue.leecode.tree.TreeNode; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.hot100 + *@Author: markilue + *@CreateTime: 2023-04-03 10:24 + *@Description: + * TODO 力扣337 打家劫舍III: + * 小偷又发现了一个新的可行窃的地区。这个地区只有一个入口,我们称之为 root 。 + * 除了 root 之外,每栋房子有且只有一个“父“房子与之相连。一番侦察之后,聪明的小偷意识到“这个地方的所有房屋的排列类似于一棵二叉树”。 + * 如果 两个直接相连的房子在同一天晚上被打劫 ,房屋将自动报警。 + * 给定二叉树的 root 。返回 在不触动警报的情况下 ,小偷能够盗取的最高金额 。 + *@Version: 1.0 + */ +public class T83_Rob { + + public int rob(TreeNode root) { + + int[] dp = subRob(root); + return Math.max(dp[0],dp[1]); + + } + + public int[] subRob(TreeNode root) { + if (root == null) { + return new int[]{0, 0}; + } + + int[] left = subRob(root.left); + int[] right = subRob(root.right); + + int steal = left[0] + right[0] + root.val; + int noSteal = Math.max(left[0], left[1]) + Math.max(right[0], right[1]); + + return new int[]{noSteal, steal}; + + } +} diff --git a/Leecode/src/main/java/com/markilue/leecode/hot100/T84_CountBits.java b/Leecode/src/main/java/com/markilue/leecode/hot100/T84_CountBits.java new file mode 100644 index 0000000..39a4e5e --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/hot100/T84_CountBits.java @@ -0,0 +1,124 @@ +package com.markilue.leecode.hot100; + +import org.junit.Test; + +import java.util.Arrays; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.hot100 + *@Author: markilue + *@CreateTime: 2023-04-03 10:38 + *@Description: + * TODO 力扣338 比特位计数: + * 给你一个整数 n ,对于 0 <= i <= n 中的每个 i ,计算其二进制表示中 1 的个数 ,返回一个长度为 n + 1 的数组 ans 作为答案。 + *@Version: 1.0 + */ +public class T84_CountBits { + + @Test + public void test1() { + int n = 85723; + System.out.println(Arrays.toString(countBits(n))); + } + + /** + *思路:挨个增加,有则进位 + * 速度击败6.9% 内存击败13.58% 59ms + * @param n + * @return + */ + public int[] countBits(int n) { + + int[] nums = new int[n + 1]; + long cur = 0; + for (int i = 0; i < nums.length; i++) { + long[] check = check(cur); + cur = check[0] + 1; + nums[i] = (int)check[1]; + } + + return nums; + + } + + @Test + public void test() { + int num = 1112; + System.out.println(check(num)); + } + + public long[] check(long n) { + //int count =0; + boolean flag = false;//是否进位 + int num = 0; + int count = 0; + StringBuilder sb = new StringBuilder(); + while (n != 0 || flag) { + long cur = n % 10; + if (flag) cur += 1; + if (cur == 1) count++; + if (cur > 1) { + flag = true; + sb.append(0); + } else { + flag = false; + sb.append(cur); + } + n /= 10; + } + if (sb.length() == 0) { + sb.append(0); + } + return new long[]{Long.parseLong(sb.reverse().toString()), count}; + } + + + /** + * 官方题解:Brian Kernighan 算法 + * x=x & (x−1) 这一运算将x的二进制表示的最后一个1变成0 + * 因此重复该操作,直到x变成0,就可以得到x中1的数量 + * 速度击败41.7% 内存击败28.3% 2ms + * 时间复杂度O(nlogn) + * @param n + * @return + */ + public int[] countBits1(int n) { + int[] bits = new int[n + 1]; + for (int i = 0; i <= n; i++) { + bits[i] = countOnes(i); + } + return bits; + } + + public int countOnes(int x) { + int ones = 0; + while (x > 0) { + x &= (x - 1); + ones++; + } + return ones; + } + + + /** + * 官方题解:动态规划法:最低位有效值 + * 即如果x为偶数,bit[x]=bit[x/2] + * 如果x为奇数,bit[x]=bit[x/2]+1 + * 是否加1可以使用对2取余:x 除以 2的余数可以通过 x & 1 得到 + * @param n + * @return + */ + public int[] countBits2(int n) { + int[] bits = new int[n + 1]; + for (int i = 1; i <= n; i++) { + bits[i] = bits[i >> 1] + (i & 1); + } + return bits; + } + + + + + +} diff --git a/Leecode/src/main/java/com/markilue/leecode/hot100/T85_TopKFrequent.java b/Leecode/src/main/java/com/markilue/leecode/hot100/T85_TopKFrequent.java new file mode 100644 index 0000000..40b3efe --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/hot100/T85_TopKFrequent.java @@ -0,0 +1,98 @@ +package com.markilue.leecode.hot100; + +import org.junit.Test; + +import java.util.*; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.hot100 + *@Author: markilue + *@CreateTime: 2023-04-03 11:37 + *@Description: + * TODO 力扣347 前k个高频元素: + * 给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。 + *@Version: 1.0 + */ +public class T85_TopKFrequent { + + @Test + public void test(){ + int[] nums={4,1,-1,2,-1,2,3}; + System.out.println(topKFrequent(nums,2)); + } + + + /** + * 统计每个单词出现的次数,然后进行堆化 + * 速度击败87.71% 内存击败12.19% 12ms + * @param nums + * @param k + * @return + */ + public int[] topKFrequent(int[] nums, int k) { + + Map map = new HashMap<>();// + for (int num : nums) { + map.put(num, map.getOrDefault(num, 0) + 1); + } + + PriorityQueue queue = new PriorityQueue<>(new Comparator() { + @Override + public int compare(int[] o1, int[] o2) { + return o1[0] != o2[0] ? o2[1] - o1[1] : o2[0] - o1[0]; + } + }); + + for (Map.Entry entry : map.entrySet()) { + queue.add(new int[]{entry.getKey(), entry.getValue()}); + } + + int[] result = new int[k]; + + for (int i = 0; i < k; i++) { + if(!queue.isEmpty()) result[i] = queue.poll()[0]; + } + + return result; + + } + + + /** + * 官方最快:先计算每个数字出现的次数,使用arrayList将相同次数的数字放在一次 + * @param nums + * @param k + * @return + */ + public int[] topKFrequent1(int[] nums, int k) { + int max = Integer.MIN_VALUE,min = Integer.MAX_VALUE; + for(int i : nums){//找出最大最小值 + max = (max < i)?i:max; + min = (min > i)?i:min; + } + if(max==min)return new int[]{nums[0]}; + int times[] = new int[max-min+1];//定义桶大小 + for(int i : nums){ + times[i-min]++;//记录各个数出现的次数 + } + ArrayList count[] = new ArrayList[nums.length];//不同数量对应的数字集合 + for(int i = 0; i < times.length; i++){ + if(times[i] > 0){ + if(count[times[i]] == null){ + count[times[i]] = new ArrayList(); + } + count[times[i]].add(i+min);//相同次数的加在同一个count[i]这种 + } + } + int res[] = new int[k];//答案 + for(int i = count.length-1,j = 0; i >=0 && j < k ; i--){ + if(count[i] != null){ + while(!count[i].isEmpty()){ + res[j++] = count[i].remove(count[i].size()-1); + } + } + } + return res; + } +} diff --git a/Leecode/src/main/java/com/markilue/leecode/hot100/T86_DecodeString.java b/Leecode/src/main/java/com/markilue/leecode/hot100/T86_DecodeString.java new file mode 100644 index 0000000..0b4a6e5 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/hot100/T86_DecodeString.java @@ -0,0 +1,146 @@ +package com.markilue.leecode.hot100; + +import org.junit.Test; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.hot100 + *@Author: markilue + *@CreateTime: 2023-04-06 10:04 + *@Description: + * TODO 力扣394 字符串解码: + * 给定一个经过编码的字符串,返回它解码后的字符串。 + * 编码规则为: k[encoded_string],表示其中方括号内部的 encoded_string 正好重复 k 次。注意 k 保证为正整数。 + * 你可以认为输入字符串总是有效的;输入字符串中没有额外的空格,且输入的方括号总是符合格式要求的。 + * 此外,你可以认为原始数据不包含数字,所有的数字只表示重复的次数 k ,例如不会出现像 3a 或 2[4] 的输入。 + *@Version: 1.0 + */ +public class T86_DecodeString { + + @Test + public void test() { + String s = "3[a]2[bc]"; + System.out.println(decodeString(s)); + } + + @Test + public void test1() { + String s = "3[a2[c]]"; + System.out.println(decodeString(s)); + } + + @Test + public void test2() { + String s = "3[z]2[2[y]pq4[2[jk]e1[f]]]ef"; + System.out.println(decodeString(s)); + } + + int start = 0; + + + public String decodeString(String s) { + return decodeSubString(s.toCharArray(), 1); + } + + + public String decodeSubString(char[] chars, int count) { + if (chars[start] == '[') start++; + + StringBuilder sb = new StringBuilder(); + int sum = 0; + while (start < chars.length && Character.isDigit(chars[start])) { + sum = sum * 10 + (chars[start] - '0'); + start++; + } + //如果前面没有数字,返回1次 + if (sum == 0) { + while (start < chars.length && chars[start] >= 'a' && chars[start] <= 'z') { + sb.append(chars[start++]); + } + } else { + sb.append(decodeSubString(chars, sum)); + } + +// if (start < chars.length && Character.isDigit(chars[start])) { +// sb.append(decodeSubString(chars, 1)); +// } + + if (start < chars.length && chars[start] == ']') { + start++; + } + if (count > 1) { + String k = sb.toString(); + for (int i = 0; i < count - 1; i++) { + sb.append(k); + } + } + + if (start < chars.length && chars[start] != ']') { + sb.append(decodeSubString(chars, 1)); + } + + return sb.toString(); + + + } + + + String src; + int ptr; + + /** + * 官方递归法: + * 思路和本人一致,但是思路更清晰和简洁 + * 速度击败100% 内存击败76.28% + * @param s + * @return + */ + public String decodeString1(String s) { + src = s; + ptr = 0; + return getString(); + } + + public String getString() { + if (ptr == src.length() || src.charAt(ptr) == ']') { + // String -> EPS + return ""; + } + + char cur = src.charAt(ptr); + int repTime = 1; + StringBuilder ret = new StringBuilder(); + + if (Character.isDigit(cur)) { + // String -> Digits [ String ] String + // 解析 Digits + repTime = getDigits(); + // 过滤左括号 + ++ptr; + // 解析 String + String str = getString(); + // 过滤右括号 + ++ptr; + // 构造字符串 + while (repTime-- > 0) { + ret.append(str); + } + } else if (Character.isLetter(cur)) { + // String -> Char String + // 解析 Char + ret.append(String.valueOf(src.charAt(ptr++))); + } + ret.append(getString()); + + return ret.toString(); + } + + public int getDigits() { + int ret = 0; + while (ptr < src.length() && Character.isDigit(src.charAt(ptr))) { + ret = ret * 10 + src.charAt(ptr++) - '0'; + } + return ret; + } + +} diff --git a/Leecode/src/main/java/com/markilue/leecode/hot100/T87_CalcEquation.java b/Leecode/src/main/java/com/markilue/leecode/hot100/T87_CalcEquation.java new file mode 100644 index 0000000..b120ee0 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/hot100/T87_CalcEquation.java @@ -0,0 +1,186 @@ +package com.markilue.leecode.hot100; + +import java.util.*; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.hot100 + *@Author: markilue + *@CreateTime: 2023-04-06 11:47 + *@Description: + * TODO 力扣399 除法求值: + * 给你一个变量对数组 equations 和一个实数值数组 values 作为已知条件,其中 equations[i] = [Ai, Bi] 和 values[i] 共同表示等式 Ai / Bi = values[i] 。每个 Ai 或 Bi 是一个表示单个变量的字符串。 + * 另有一些以数组 queries 表示的问题,其中 queries[j] = [Cj, Dj] 表示第 j 个问题,请你根据已知条件找出 Cj / Dj = ? 的结果作为答案。 + * 返回 所有问题的答案 。如果存在某个无法确定的答案,则用 -1.0 替代这个答案。如果问题中出现了给定的已知条件中没有出现的字符串,也需要用 -1.0 替代这个答案。 + * 注意:输入总是有效的。你可以假设除法运算中不会出现除数为 0 的情况,且不存在任何矛盾的结果。 + *@Version: 1.0 + */ +public class T87_CalcEquation { + + /** + * 官方题解:并查集解法 + * 速度击败100% 内存击败85.81% 0ms + * @param equations + * @param values + * @param queries + * @return + */ + public double[] calcEquation(List> equations, double[] values, List> queries) { + + int equationSize = equations.size(); + UnionFind unionFind = new UnionFind(2 * equationSize); + //第一步:预处理,将变量的值与id进行映射,是的并查集的底层使用数组实现,方便编码 + HashMap hashMap = new HashMap<>(2 * equationSize); + int id = 0; + for (int i = 0; i < equationSize; i++) { + List equation = equations.get(i); + String var1 = equation.get(0); + String var2 = equation.get(1); + if (!hashMap.containsKey(var1)) { + hashMap.put(var1, id); + id++; + } + if (!hashMap.containsKey(var2)) { + hashMap.put(var2, id); + id++; + } + unionFind.union(hashMap.get(var1), hashMap.get(var2), values[i]); + } + + //第二部:做查询 + int queriesSize = queries.size(); + double[] res = new double[queriesSize]; + for (int i = 0; i < queriesSize; i++) { + String var1 = queries.get(i).get(0); + String var2 = queries.get(i).get(1); + Integer id1 = hashMap.get(var1); + Integer id2 = hashMap.get(var2); + if (id1 == null || id2 == null) { + res[i] = -1.0d; + } else { + res[i] = unionFind.isConnected(id1, id2); + } + } + return res; + + } + + + private class UnionFind { + + private int[] parent; + + private double[] weight; + + public UnionFind(int n) { + this.parent = new int[n]; + this.weight = new double[n]; + for (int i = 0; i < n; i++) { + parent[i] = i; + weight[i] = 1.0d; + } + } + + public void union(int x, int y, double value) { + int rootX = find(x); + int rootY = find(y); + if (rootX == rootY) { + return; + } + parent[rootX] = rootY; + weight[rootX] = weight[y] * value / weight[x]; + } + + + /** + * 路径压缩 + * @param x + * @return + */ + private int find(int x) { + if (x != parent[x]) {//存在引用链,至少是第一次遍历到才会不相等 + int origin = parent[x]; + parent[x] = find(parent[x]); + weight[x] *= weight[origin]; + } + return parent[x]; + } + + public double isConnected(int x, int y) { + int rootX = find(x); + int rootY = find(y); + if (rootY == rootX) { + return weight[x] / weight[y]; + } else { + return -1.0d; + } + } + + + } + + + /** + * 官方DFS法:本质上就是把数据加入子集当中,然后如果存在引用链就一定能够被连接上,则可以计算 + * 速度击败54.5% 内存击败29.67% 1ms + * @param equations + * @param values + * @param queries + * @return + */ + public double[] calcEquation1(List> equations, double[] values, List> queries) { + double[] result = new double[queries.size()]; + Map> graph = buildGraph(equations, values); + + for (int i = 0; i < queries.size(); i++) { + //dfs寻找对应的引用 + String start = queries.get(i).get(0); + String end = queries.get(i).get(1); + + if (!graph.containsKey(start) || !graph.containsKey(end)) { + result[i] = -1;//有一个没有就肯定计算不出来 + } else { + Set visited = new HashSet<>(); + result[i] = dfs(graph, start, end, visited); + } + } + + return result; + } + + //构建引用链 + private Map> buildGraph(List> equations, double[] values) { + Map> graph = new HashMap<>(); + + for (int i = 0; i < equations.size(); i++) { + String v1 = equations.get(i).get(0); + String v2 = equations.get(i).get(1); + graph.putIfAbsent(v1, new HashMap()); + graph.get(v1).put(v2, values[i]); + + graph.putIfAbsent(v2, new HashMap()); + graph.get(v2).put(v1, 1.0 / values[i]); + } + + return graph; + } + + private double dfs(Map> graph, String start, String end, Set visited) { + visited.add(start); + Map next = graph.get(start); + for (Map.Entry entry : next.entrySet()) { + if (entry.getKey().equals(end)) { + return entry.getValue(); + } + if (!visited.contains(entry.getKey())) { + double nextValue = dfs(graph, entry.getKey(), end, visited); + if (nextValue > 0) {//即不可能是-1就正常返回 + return entry.getValue() * nextValue; + } + } + } + + return -1; + } + +} diff --git a/Leecode/src/main/java/com/markilue/leecode/hot100/T88_ReconstructQueue.java b/Leecode/src/main/java/com/markilue/leecode/hot100/T88_ReconstructQueue.java new file mode 100644 index 0000000..77c27f4 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/hot100/T88_ReconstructQueue.java @@ -0,0 +1,100 @@ +package com.markilue.leecode.hot100; + +import org.junit.Test; + +import java.util.Arrays; +import java.util.Comparator; +import java.util.LinkedList; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.hot100 + *@Author: markilue + *@CreateTime: 2023-04-07 10:18 + *@Description: + * TODO 力扣406 根据身高重建队列: + * 假设有打乱顺序的一群人站成一个队列,数组 people 表示队列中一些人的属性(不一定按顺序)。 + * 每个 people[i] = [hi, ki] 表示第 i 个人的身高为 hi ,前面 正好 有 ki 个身高大于或等于 hi 的人。 + * 请你重新构造并返回输入数组 people 所表示的队列。 + * 返回的队列应该格式化为数组 queue ,其中 queue[j] = [hj, kj] 是队列中第 j 个人的属性(queue[0] 是排在队列前面的人)。 + *@Version: 1.0 + */ +public class T88_ReconstructQueue { + + @Test + public void test() { + int[][] people = {{7, 0}, {4, 4}, {7, 1}, {5, 0}, {6, 1}, {5, 2}}; +// reconstructQueue1(people); + for (int[] ints : reconstructQueue1(people)) { + System.out.println(Arrays.toString(ints)); + } + } + + + /** + * 思路:排序后使用linkedList插入 + * 速度击败26.34% 内存击败70.6% 9ms + * @param people + * @return + */ + public int[][] reconstructQueue(int[][] people) { + + Arrays.sort(people, new Comparator() { + @Override + public int compare(int[] o1, int[] o2) { + return o1[0] == o2[0] ? o1[1] - o2[1] : o2[0] - o1[0]; + } + }); + + LinkedList list = new LinkedList<>(); + + for (int[] person : people) { + list.add(person[1], person); + } + int[][] result = new int[people.length][]; + + + return list.toArray(new int[people.length][]); + + + } + + + /** + * 先排序后腾挪 + * 速度击败81.31% 内存击败17.3% 6ms + * @param people + * @return + */ + public int[][] reconstructQueue1(int[][] people) { + + Arrays.sort(people, new Comparator() { + @Override + public int compare(int[] o1, int[] o2) { + return o1[0] == o2[0] ? o1[1] - o2[1] : o1[0] - o2[0]; + } + }); + + for (int i = people.length - 1; i >= 0; i--) { + int[] person = people[i]; + + //看看前面有几个和他相等的 + int same = 0; + for (int j = i - 1; j >= 0; j--) { + if (people[j][0] == person[0]) same++; + if (people[j][0] < person[0]) break;//小了直接break + } + //不相等,需要腾挪 + if (same != person[1]) { + int length = person[1] - same; + System.arraycopy(people, i + 1, people, i, length); + people[i + length] = person; + } + } + + + return people; + + + } +} diff --git a/Leecode/src/main/java/com/markilue/leecode/hot100/T89_CanPartition.java b/Leecode/src/main/java/com/markilue/leecode/hot100/T89_CanPartition.java new file mode 100644 index 0000000..40fc5c9 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/hot100/T89_CanPartition.java @@ -0,0 +1,54 @@ +package com.markilue.leecode.hot100; + +import org.junit.Test; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.hot100 + *@Author: markilue + *@CreateTime: 2023-04-07 10:52 + *@Description: + * TODO 力扣416 分割等和数组: + * 给你一个 只包含正整数 的 非空 数组 nums 。请你判断是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。 + *@Version: 1.0 + */ +public class T89_CanPartition { + + @Test + public void test() { +// int[] nums={1,5,11,5}; + int[] nums = {1, 2, 3, 5}; + System.out.println(canPartition(nums)); + } + + /** + * 思路:本质上就是找一个总和一半的子序列 + * @param nums + * @return + */ + public boolean canPartition(int[] nums) { + + if (nums.length < 2) return false; + int sum = 0; + int max = 0; + for (int num : nums) { + sum += num; + max = Math.max(max, num); + } + + if (sum % 2 != 0) return false; + int target = sum / 2; + if (max > target) return false; + boolean[] dp = new boolean[target + 1]; + dp[0]=true; + + for (int i = 0; i < nums.length; i++) { + for (int j = dp.length - 1; j >= nums[i]; j--) { + dp[j] |= dp[j - nums[i]]; + } + } + + return dp[target]; + + } +} diff --git a/Leecode/src/main/java/com/markilue/leecode/hot100/T90_PathSum.java b/Leecode/src/main/java/com/markilue/leecode/hot100/T90_PathSum.java new file mode 100644 index 0000000..9468331 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/hot100/T90_PathSum.java @@ -0,0 +1,141 @@ +package com.markilue.leecode.hot100; + +import com.markilue.leecode.tree.TreeNode; +import com.markilue.leecode.tree.TreeUtils; +import org.junit.Test; + +import java.util.*; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.hot100 + *@Author: markilue + *@CreateTime: 2023-04-07 11:05 + *@Description: + * TODO 力扣437 路径总和III: + * 给定一个二叉树的根节点 root ,和一个整数 targetSum ,求该二叉树里节点值之和等于 targetSum 的 路径 的数目。 + * 路径 不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点)。 + *@Version: 1.0 + */ +public class T90_PathSum { + + @Test + public void test() { + TreeNode root = TreeUtils.structureTree(new ArrayList<>(Arrays.asList(10, 5, -3, 3, 2, null, 11, 3, -2, null, 1)), 0); + System.out.println(pathSum(root, 8)); + } + + + /** + * 思路:可以把return的状态分为 不要之前的左 不要之前右 都不要 + * 有问题:节点的始末不一定是终点 + * @param root + * @param targetSum + * @return + */ + public int pathSum(TreeNode root, int targetSum) { + cur.add(0); + path(root, targetSum, 0); + + return sum; + } + + int sum = 0; + List cur = new ArrayList(); + + public void path(TreeNode root, int targetSum, int last) { + if (root == null) return; + int value = root.val; + for (Integer integer : cur) { + if (integer + value == targetSum) sum++; + } + + int sum = value + last; + cur.add(value); + cur.add(sum); + + path(root.left, targetSum, sum); + cur.remove(cur.size() - 1); + path(root.right, targetSum, sum); + cur.remove(cur.size() - 1); + } + + + /** + * 分别计算节点为根的,和他为路径的之和 + * 时间复杂度为O(N^2) + * 速度击败8.17% 内存击败46.54% + * @param root + * @param targetSum + * @return + */ + public int pathSum1(TreeNode root, int targetSum) { + if (root == null) { + return 0; + } + + int ret = rootSum(root, targetSum);//计算他为根的 + ret += pathSum1(root.left, targetSum);//计算不要他的 为路径的 + ret += pathSum1(root.right, targetSum); + return ret; + } + + public int rootSum(TreeNode root, int targetSum) { + int ret = 0; + + if (root == null) { + return 0; + } + int val = root.val; + if (val == targetSum) { + ret++; + } + + ret += rootSum(root.left, targetSum - val); + ret += rootSum(root.right, targetSum - val); + return ret; + } + + + /** + * 官方前缀和解法 + * 时间复杂度O(n) + * * 前缀和的递归回溯思路 + * * 从当前节点反推到根节点(反推比较好理解,正向其实也只有一条),有且仅有一条路径,因为这是一棵树 + * * 如果此前有和为currSum-target,而当前的和又为currSum,两者的差就肯定为target了 + * * 所以前缀和对于当前路径来说是唯一的,当前记录的前缀和,在回溯结束,回到本层时去除,保证其不影响其他分支的结果 + * @param root + * @param targetSum + * @return + */ + public int pathSum2(TreeNode root, int targetSum) { + Map prefix = new HashMap(); + prefix.put(0L, 1); + return dfs(root, prefix, 0, targetSum); + } + + public int dfs(TreeNode root, Map prefix, long curr, int targetSum) { + if (root == null) { + return 0; + } + + int ret = 0; + curr += root.val; + + //---核心代码 + //看看root到当前节点这条路上是否存在节点前缀和加target为currSum的路径 + //当前节点->root节点反推,有且仅有一条路径,如果此前有和为currSum-target,而当前的和又为currSum,两者的差就肯定为target了 + //currSum-target相当于找路径的起点,起点的sum+target=currSum,当前点到起点的距离就是target + + + ret = prefix.getOrDefault(curr - targetSum, 0); + prefix.put(curr, prefix.getOrDefault(curr, 0) + 1); + ret += dfs(root.left, prefix, curr, targetSum); + ret += dfs(root.right, prefix, curr, targetSum); + prefix.put(curr, prefix.getOrDefault(curr, 0) - 1); + + return ret; + } + + +} diff --git a/Leecode/src/main/java/com/markilue/leecode/hot100/T91_FindAnagrams.java b/Leecode/src/main/java/com/markilue/leecode/hot100/T91_FindAnagrams.java new file mode 100644 index 0000000..ab5bc25 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/hot100/T91_FindAnagrams.java @@ -0,0 +1,170 @@ +package com.markilue.leecode.hot100; + +import org.junit.Test; + +import javax.print.DocFlavor; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.hot100 + *@Author: markilue + *@CreateTime: 2023-04-08 10:01 + *@Description: + * TODO 力扣438 找到字符串中所有字母异位词: + * 给定两个字符串 s 和 p,找到 s 中所有 p 的 异位词 的子串,返回这些子串的起始索引。不考虑答案输出的顺序。 + * 异位词 指由相同字母重排列形成的字符串(包括相同的字符串)。 + *@Version: 1.0 + */ +public class T91_FindAnagrams { + + @Test + public void test() { + String s = "baa", p = "aa"; + System.out.println(findAnagrams(s, p)); + } + + @Test + public void test1() { + String s = "cbaebabacd", p = "abc"; + System.out.println(findAnagrams(s, p)); + } + + @Test + public void test2() { + String s = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; + String p = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; +// String s= "aaaabaaaa"; +// String p="aaaa"; + System.out.println(s.length()); + System.out.println(p.length()); + System.out.println(findAnagrams(s, p)); + } + + + /** + * 思路:滑动窗口法:right增窗口,left减窗口,将合适的left加入result + * 速度击败20.13% 内存击败89.34% 41ms + * @param s + * @param p + * @return + */ + public List findAnagrams(String s, String p) { + HashMap need = new HashMap<>();// + int totalCount = 0; + + for (char c : p.toCharArray()) { + need.put(c, need.getOrDefault(c, 0) + 1); + totalCount++; + } + HashMap window = new HashMap<>(); + char[] chars = s.toCharArray(); + int left = 0; + int right = -1; + List result = new ArrayList<>(); + + while (right < s.length() - 1) { + right++; + + + if (need.containsKey(chars[right])) { + window.put(chars[right], window.getOrDefault(chars[right], 0) + 1); + } else { + window.clear(); + left = right + 1; + } + + + while (window.size() == need.size()) { + int length = right - left + 1; + if (length >= totalCount) { + //size相等,而且长度相等,那么就是一致的 + boolean flag = true; + for (Map.Entry entry : window.entrySet()) { + if (!entry.getValue().equals(need.get(entry.getKey())) ) { + flag = false; + break; + } + } + if (flag) { + result.add(left); + } + if (need.containsKey(chars[left])) { + Integer count = window.getOrDefault(chars[left], 0); + if (count <= 1) { + window.remove(chars[left]); + } else { + window.put(chars[left], count - 1); + } + } + left++; + } else { + break; + } + } + } + return result; + + } + + + /** + * 官方滑动窗口法: + * 只维护一个固定长度为p的窗口,判断这个窗口的s是否和p相等 + * 速度击败58.97% 内存击败29.64% 10ms + * @param s + * @param p + * @return + */ + public List findAnagrams1(String s, String p) { + int sLen = s.length(), pLen = p.length(); + + if (sLen < pLen) { + return new ArrayList(); + } + + List ans = new ArrayList(); + int[] count = new int[26]; + for (int i = 0; i < pLen; ++i) { + ++count[s.charAt(i) - 'a']; + --count[p.charAt(i) - 'a']; + } + + int differ = 0; + for (int j = 0; j < 26; ++j) { + if (count[j] != 0) { + ++differ; + } + } + + if (differ == 0) { + ans.add(0); + } + + for (int i = 0; i < sLen - pLen; ++i) { + if (count[s.charAt(i) - 'a'] == 1) { // 窗口中字母 s[i] 的数量与字符串 p 中的数量从不同变得相同 + --differ; + } else if (count[s.charAt(i) - 'a'] == 0) { // 窗口中字母 s[i] 的数量与字符串 p 中的数量从相同变得不同 + ++differ; + } + --count[s.charAt(i) - 'a']; + + if (count[s.charAt(i + pLen) - 'a'] == -1) { // 窗口中字母 s[i+pLen] 的数量与字符串 p 中的数量从不同变得相同 + --differ; + } else if (count[s.charAt(i + pLen) - 'a'] == 0) { // 窗口中字母 s[i+pLen] 的数量与字符串 p 中的数量从相同变得不同 + ++differ; + } + ++count[s.charAt(i + pLen) - 'a'];//窗口往后滑一位 + + if (differ == 0) { + ans.add(i + 1); + } + } + + return ans; + } + +} diff --git a/Leecode/src/main/java/com/markilue/leecode/hot100/T92_FindDisappearedNumbers.java b/Leecode/src/main/java/com/markilue/leecode/hot100/T92_FindDisappearedNumbers.java new file mode 100644 index 0000000..57a4ccc --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/hot100/T92_FindDisappearedNumbers.java @@ -0,0 +1,69 @@ +package com.markilue.leecode.hot100; + +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.hot100 + *@Author: markilue + *@CreateTime: 2023-04-08 11:54 + *@Description: + * TODO 力扣448 找到所有数组中的消失的数字: + * 给你一个含 n 个整数的数组 nums ,其中 nums[i] 在区间 [1, n] 内。请你找出所有在 [1, n] 范围内但没有出现在 nums 中的数字,并以数组的形式返回结果。 + *@Version: 1.0 + */ +public class T92_FindDisappearedNumbers { + + @Test + public void test(){ + int[] nums = {4, 3, 2, 7, 8, 2, 3, 1}; + System.out.println(findDisappearedNumbers(nums)); + } + + + /** + * 思路:记录各个数字出现的次数,为0则没有出现 + * 速度击败99.36% 内存击败52.21% 3ms + * @param nums + * @return + */ + public List findDisappearedNumbers(int[] nums) { + + int[] counts = new int[nums.length + 1]; + + for (int num : nums) { + counts[num]++; + } + List result = new ArrayList<>(); + for (int i = 1; i < counts.length; i++) { + if (counts[i] == 0) result.add(i); + } + return result; + + } + + /** + * 官方题解:原地+n不影响实际结果 + * 速度击败99.36% 内存击败26.85% 3ms + * @param nums + * @return + */ + public List findDisappearedNumbers1(int[] nums) { + int n = nums.length; + for (int num : nums) { + int x = (num - 1) % n; + nums[x] += n; + } + List ret = new ArrayList(); + for (int i = 0; i < n; i++) { + if (nums[i] <= n) { + ret.add(i + 1); + } + } + return ret; + } + +} diff --git a/Leecode/src/main/java/com/markilue/leecode/hot100/T93_HammingDistance.java b/Leecode/src/main/java/com/markilue/leecode/hot100/T93_HammingDistance.java new file mode 100644 index 0000000..189a7bb --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/hot100/T93_HammingDistance.java @@ -0,0 +1,40 @@ +package com.markilue.leecode.hot100; + +import org.junit.Test; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.hot100 + *@Author: markilue + *@CreateTime: 2023-04-08 13:21 + *@Description: + * TODO 力扣461 汉明距离: + * 两个整数之间的 汉明距离 指的是这两个数字对应二进制位不同的位置的数目。 + * 给你两个整数 x 和 y,计算并返回它们之间的汉明距离。 + *@Version: 1.0 + */ +public class T93_HammingDistance { + + @Test + public void test() { +// System.out.println(3^1); + System.out.println(hammingDistance(1, 3)); + } + + /** + * 思路:异或之后得到不同位为1的值 + * 然后num&(num-1)可以消除最后一个为1的值,因此可以统计有几个1 + * @param x + * @param y + * @return + */ + public int hammingDistance(int x, int y) { + int result = x ^ y; + int count = 0; + while (result != 0) { + count++; + result &= (result - 1); + } + return count; + } +} diff --git a/Leecode/src/main/java/com/markilue/leecode/hot100/T94_FindTargetSumWays.java b/Leecode/src/main/java/com/markilue/leecode/hot100/T94_FindTargetSumWays.java new file mode 100644 index 0000000..de12c41 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/hot100/T94_FindTargetSumWays.java @@ -0,0 +1,59 @@ +package com.markilue.leecode.hot100; + +import org.junit.Test; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.hot100 + *@Author: markilue + *@CreateTime: 2023-04-10 12:49 + *@Description: + * TODO 力扣494 目标和: + * 给你一个整数数组 nums 和一个整数 target 。 + * 向数组中的每个整数前添加 '+' 或 '-' ,然后串联起所有整数,可以构造一个 表达式 : + * 例如,nums = [2, 1] ,可以在 2 之前添加 '+' ,在 1 之前添加 '-' ,然后串联起来得到表达式 "+2-1" 。 + * 返回可以通过上述方法构造的、运算结果等于 target 的不同 表达式 的数目。 + *@Version: 1.0 + */ +public class T94_FindTargetSumWays { + + @Test + public void test() { + + int[] nums = {1, 1, 1, 1, 1}; + int target = 3; + System.out.println(findTargetSumWays(nums, target)); + + } + + + /** + * 思路:本质上就是一个背包问题: + * add-(sum-add)=target + * add=(sum+target)/2 + * 速度击败94.6% 内存击败50.13% 2ms + * @param nums + * @param target + * @return + */ + public int findTargetSumWays(int[] nums, int target) { + + int sum = 0; + for (int num : nums) { + sum += num; + } + if ((sum + target) % 2 != 0) return 0; + int mid = (sum + target) / 2; + if (mid < 0) return 0; + int[] dp = new int[mid + 1]; + dp[0] = 1; + + for (int i = 0; i < nums.length; i++) { + for (int j = mid; j >= nums[i]; j--) { + dp[j] += dp[j - nums[i]];//用这个数,不用这个数 + } + } + + return dp[mid]; + } +} diff --git a/Leecode/src/main/java/com/markilue/leecode/hot100/T95_ConvertBST.java b/Leecode/src/main/java/com/markilue/leecode/hot100/T95_ConvertBST.java new file mode 100644 index 0000000..07686dc --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/hot100/T95_ConvertBST.java @@ -0,0 +1,46 @@ +package com.markilue.leecode.hot100; + +import com.markilue.leecode.tree.TreeNode; +import org.junit.Test; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.hot100 + *@Author: markilue + *@CreateTime: 2023-04-10 13:02 + *@Description: + * TODO 力扣538 把二叉搜索树转换为累加树: + * 给出二叉 搜索 树的根节点,该树的节点值各不相同,请你将其转换为累加树(Greater Sum Tree),使每个节点 node 的新值等于原树中大于或等于 node.val 的值之和。 + * 提醒一下,二叉搜索树满足下列约束条件: + * 节点的左子树仅包含键 小于 节点键的节点。 + * 节点的右子树仅包含键 大于 节点键的节点。 + * 左右子树也必须是二叉搜索树。 + *@Version: 1.0 + * + */ +public class T95_ConvertBST { + + @Test + public void test() { + + } + + int sum = 0; + + /** + * 后续遍历:递归法 + * 速度击败100% 内存击败85.25% 0ms + */ + + public TreeNode convertBST(TreeNode root) { + if (root == null) { + return null; + } + convertBST(root.right); + sum += root.val; + root.val = sum; + convertBST(root.left); + return root; + + } +} diff --git a/Leecode/src/main/java/com/markilue/leecode/hot100/T96_DiameterOfBinaryTree.java b/Leecode/src/main/java/com/markilue/leecode/hot100/T96_DiameterOfBinaryTree.java new file mode 100644 index 0000000..22d34ac --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/hot100/T96_DiameterOfBinaryTree.java @@ -0,0 +1,40 @@ +package com.markilue.leecode.hot100; + +import com.markilue.leecode.tree.TreeNode; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.hot100 + *@Author: markilue + *@CreateTime: 2023-04-10 13:17 + *@Description: + * TODO 力扣543 二叉树的直径: + * 给定一棵二叉树,你需要计算它的直径长度。一棵二叉树的直径长度是任意两个结点路径长度中的最大值。这条路径可能穿过也可能不穿过根结点。 + *@Version: 1.0 + */ +public class T96_DiameterOfBinaryTree { + + + int max = 0; + + /** + * 思路:就是计算最多一条链路上的节点数目 + * 速度击败100% 内存击败79.29% 递归法 + * @param root + * @return + */ + public int diameterOfBinaryTree(TreeNode root) { + sub(root); + return max; + } + + public int sub(TreeNode root) { + if (root == null) { + return 0; + } + int left = sub(root.left); + int right = sub(root.right); + max = Math.max(max, left + right); + return Math.max(left, right) + 1; + } +} diff --git a/Leecode/src/main/java/com/markilue/leecode/hot100/T97_SubarraySum.java b/Leecode/src/main/java/com/markilue/leecode/hot100/T97_SubarraySum.java new file mode 100644 index 0000000..04bfbe2 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/hot100/T97_SubarraySum.java @@ -0,0 +1,116 @@ +package com.markilue.leecode.hot100; + +import org.junit.Test; + +import java.util.HashMap; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.hot100 + *@Author: markilue + *@CreateTime: 2023-04-10 13:28 + *@Description: + * TODO 力扣560 合为k的子数组: + * 给你一个整数数组 nums 和一个整数 k ,请你统计并返回 该数组中和为 k 的连续子数组的个数 。 + *@Version: 1.0 + */ +public class T97_SubarraySum { + + @Test + public void test() { + int[] nums = {100,1,2,3,100,1,2,3,4}; + System.out.println(subarraySum1(nums, 3)); + } + + /** + * 思路:滑动窗口法(维护一个窗口内总和为k的窗口) + * 有问题:因为数组里面有负数的情况,这个判断就是有问题的 + * @param nums + * @param k + * @return + */ + public int subarraySum(int[] nums, int k) { + if (nums.length == 1 && nums[0] == k) { + return 1; + } + + int result = 0; + int cur = nums[0]; + int left = 0; + int right = 1; + + while (left <= right && right <= nums.length) { + if (cur == k && left != right) { + result++; + } + if (left == nums.length) break; + if (right < nums.length) { + cur += nums[right++]; + } else { + cur -= nums[left++];//到终点了,直接缩小窗口 + } + + + while (left < right && cur > k) { + + cur -= nums[left++]; + } + } + + return result; + + } + + + /** + * 官方前缀和+hash优化: + * 时间复杂度O(n) + * 速度击败53.66% 内存击败29.86% 24ms + * @param nums + * @param k + * @return + */ + public int subarraySum1(int[] nums, int k) { + int count = 0, pre = 0; + HashMap mp = new HashMap<>();// + mp.put(0, 1); + for (int i = 0; i < nums.length; i++) { + pre += nums[i]; + if (mp.containsKey(pre - k)) { + count += mp.get(pre - k); + } + mp.put(pre, mp.getOrDefault(pre, 0) + 1); + } + return count; + } + + + /** + * 官方最快: + * 速度击败92.3% 内存击败40.6% 21ms + * @param nums + * @param k + * @return + */ + public int subarraySum2(int[] nums, int k) { + HashMap map = new HashMap<>(); + map.put(0,1); + int res = 0; + int sum = 0; + for(int i = 0;i < nums.length; i++){ + sum+=nums[i]; + if(map.containsKey(sum - k)){ + res+=map.get(sum - k); + + } + if(map.containsKey(sum)){ + map.put(sum,map.get(sum)+1); + }else{ + map.put(sum, 1); + } + } + return res; + } + + +} diff --git a/Leecode/src/main/java/com/markilue/leecode/hot100/T98_FindUnsortedSubarray.java b/Leecode/src/main/java/com/markilue/leecode/hot100/T98_FindUnsortedSubarray.java new file mode 100644 index 0000000..c5fc69c --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/hot100/T98_FindUnsortedSubarray.java @@ -0,0 +1,91 @@ +package com.markilue.leecode.hot100; + +import java.util.Arrays; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.hot100 + *@Author: markilue + *@CreateTime: 2023-04-11 12:47 + *@Description: + * TODO 力扣581 最短无序连续子数组: + * 给你一个整数数组 nums ,你需要找出一个 连续子数组 ,如果对这个子数组进行升序排序,那么整个数组都会变为升序排序。 + * 请你找出符合题意的 最短 子数组,并输出它的长度。 + *@Version: 1.0 + */ +public class T98_FindUnsortedSubarray { + + + /** + * 官方排序法: + * TODO 最短的思路: + * 本质上就是考虑把数组分为三段子数组:numsA,numsB,numsC ;当对numsB进行排序,整个数组就会变得有序 + * 所以要找到最短的numsB,就是找到最大的numsA和numsC的长度之和 + * 因此将数组排序与原数组对比,找到最长相同的前缀numsA和最长相同的后缀numsC,就可以最短numsB + * 时间复杂度O(nlogn) + * 时间击败36.47% 内存击败15.19% 6ms + * @param nums + * @return + */ + public int findUnsortedSubarray(int[] nums) { + if (isSorted(nums)) { + return 0; + } + int[] numsSorted = new int[nums.length]; + System.arraycopy(nums, 0, numsSorted, 0, nums.length); + Arrays.sort(numsSorted); + int left = 0; + while (nums[left] == numsSorted[left]) { + left++; + } + int right = nums.length - 1; + while (nums[right] == numsSorted[right]) { + right--; + } + return right - left + 1; + } + + public boolean isSorted(int[] nums) { + for (int i = 1; i < nums.length; i++) { + if (nums[i] < nums[i - 1]) { + return false; + } + } + return true; + } + + + /** + * 一次遍历:对于需要排序的优化: + * 时间复杂度O(n) + * 速度击败93.39% 内存击败68.96% 1ms + * @param nums + * @return + */ + public int findUnsortedSubarray1(int[] nums) { + //2,6,4,8,10,9,15 + //升序开始索引:0,2,5 + //降序开始索引:1,4 + int n = nums.length; + int maxn = Integer.MIN_VALUE, right = -1; + int minn = Integer.MAX_VALUE, left = -1; + for (int i = 0; i < n; i++) { + // 因此 从左到右 找最大值 这期间如果有值比最大值还要小 那么这个值就有可能是 中段的右边界 + //因为升序的时候(左右段) 最大值一直在替换,所以最后一个小 它就是 中段的右边界 + if (maxn > nums[i]) { + right = i; + } else { + maxn = nums[i]; + } + //因此 从右到左 找最小值 这期间如果有值比最小值还要大 那么这个值就有可能是 中段的左边界 + //因为降序的时候(左右段) 最小值一直在替换,所以最后一个大 它就是 中段的左边界 + if (minn < nums[n - i - 1]) { + left = n - i - 1; + } else { + minn = nums[n - i - 1]; + } + } + return right == -1 ? 0 : right - left + 1; + + } +} diff --git a/Leecode/src/main/java/com/markilue/leecode/hot100/T99_MergeTrees.java b/Leecode/src/main/java/com/markilue/leecode/hot100/T99_MergeTrees.java new file mode 100644 index 0000000..7c8f60e --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/hot100/T99_MergeTrees.java @@ -0,0 +1,40 @@ +package com.markilue.leecode.hot100; + +import com.markilue.leecode.tree.TreeNode; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.hot100 + *@Author: markilue + *@CreateTime: 2023-04-11 14:27 + *@Description: + * TODO 力扣617 合并二叉树: + * 给你两棵二叉树: root1 和 root2 。 + * 想象一下,当你将其中一棵覆盖到另一棵之上时,两棵树上的一些节点将会重叠(而另一些不会)。你需要将这两棵树合并成一棵新二叉树。合并的规则是:如果两个节点重叠,那么将这两个节点的值相加作为合并后节点的新值;否则,不为 null 的节点将直接作为新二叉树的节点。 + * 返回合并后的二叉树。 + * 注意: 合并过程必须从两个树的根节点开始。 + *@Version: 1.0 + */ +public class T99_MergeTrees { + + /** + * 递归法 + * @param root1 + * @param root2 + * @return + */ + public TreeNode mergeTrees(TreeNode root1, TreeNode root2) { + if (root1 == null) { + return root2; + } else if (root2 == null) { + return root1; + } + + //两者都不等于null + TreeNode root = new TreeNode(root1.val + root2.val); + root.left = mergeTrees(root1.left, root2.left); + root.right = mergeTrees(root1.right, root2.right); + return root; + + } +} diff --git a/Leecode/src/main/java/com/markilue/leecode/listnode/selftry/DeleteDuplicatesII.java b/Leecode/src/main/java/com/markilue/leecode/listnode/selftry/DeleteDuplicatesII.java index 9dbbd69..33e1c1e 100644 --- a/Leecode/src/main/java/com/markilue/leecode/listnode/selftry/DeleteDuplicatesII.java +++ b/Leecode/src/main/java/com/markilue/leecode/listnode/selftry/DeleteDuplicatesII.java @@ -16,8 +16,8 @@ import org.junit.Test; public class DeleteDuplicatesII { @Test - public void test(){ - ListNode root = ListNodeUtils.build(new int[]{1, 1, 2,2,2}); + public void test() { + ListNode root = ListNodeUtils.build(new int[]{1, 1, 2, 2, 2}); ListNodeUtils.print(deleteDuplicates(root)); } @@ -39,7 +39,7 @@ public class DeleteDuplicatesII { temp1 = temp1.next; } temp.next = temp1.next; - }else { + } else { temp = temp.next; } @@ -49,4 +49,31 @@ public class DeleteDuplicatesII { return fake.next; } + + + public ListNode deleteDuplicates1(ListNode head) { + + if (head == null) { + return head; + } + ListNode fake = new ListNode(); + fake.next = head; + ListNode temp = fake; + + while (temp.next != null) { + //存在重复 + if (temp.next.next != null && temp.next.val == temp.next.next.val) { + ListNode temp1 = temp.next.next; + while (temp1.next != null && temp1.val == temp1.next.val) { + temp1 = temp1.next; + } + temp.next = temp1.next; + } else { + temp = temp.next; + } + } + + return fake.next; + + } } diff --git a/Leecode/src/main/java/com/markilue/leecode/listnode/selftry/LRUCache.java b/Leecode/src/main/java/com/markilue/leecode/listnode/selftry/LRUCache.java new file mode 100644 index 0000000..2936326 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/listnode/selftry/LRUCache.java @@ -0,0 +1,117 @@ +package com.markilue.leecode.listnode.selftry; + +import java.util.HashMap; +import java.util.Map; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.listnode.selftry + *@Author: markilue + *@CreateTime: 2023-04-04 13:45 + *@Description: + * TODO 力扣146 LRU缓存: + * 请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。 + * 实现 LRUCache 类: + * LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化 LRU 缓存 + * int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1 。 + * void put(int key, int value) 如果关键字 key 已经存在,则变更其数据值 value ;如果不存在,则向缓存中插入该组 key-value 。如果插入操作导致关键字数量超过 capacity ,则应该 逐出 最久未使用的关键字。 + * 函数 get 和 put 必须以 O(1) 的平均时间复杂度运行。 + *@Version: 1.0 + */ +public class LRUCache { + + int size; + int capacity; + DNode head; + DNode tail; + Map map; + + + //HashMap+链表:本质上就是LinkedHashMap + public LRUCache() { + } + + public LRUCache(int capacity) { + this.capacity = capacity; + head = new DNode(); + tail = new DNode(); + map = new HashMap<>(); + size = 0; + head.next = tail; + tail.prev = head; + } + + public int get(int key) { + DNode dNode = map.get(key); + if (dNode == null) return -1; + deleteNode(dNode); + addToHead(dNode); + return dNode.value; + + } + + public void put(int key, int value) { + DNode dNode = map.get(key); + if(dNode==null){ + DNode node = new DNode(key,value); + map.put(key, node); + addToHead(node); + size++; + if (size > capacity) { + DNode dNode1 = deleteTailNode(); + map.remove(dNode1.key); + --size; + } + }else { + dNode.value=value; + deleteNode(dNode); + addToHead(dNode); + } + + + } + + public void addToHead(DNode node) { + head.next.prev = node; + node.next = head.next; + head.next = node; + node.prev = head; + } + + //自删除 + public void deleteNode(DNode node) { + node.prev.next = node.next; + node.next.prev = node.prev; + } + + //删除尾节点 + public DNode deleteTailNode() { + + DNode prev = tail.prev; + deleteNode(prev); + return prev; + } + + public class DNode { + + DNode prev; + DNode next; + int value; + int key; + + public DNode() { + } + + public DNode(int key , int value) { + this.key=key; + this.value = value; + } + + public DNode(int value, DNode prev, DNode next) { + this.value = value; + this.prev = prev; + this.next = next; + } + + } +} diff --git a/Leecode/src/main/java/com/markilue/leecode/listnode/selftry/ReorderList.java b/Leecode/src/main/java/com/markilue/leecode/listnode/selftry/ReorderList.java new file mode 100644 index 0000000..178f11b --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/listnode/selftry/ReorderList.java @@ -0,0 +1,51 @@ +package com.markilue.leecode.listnode.selftry; + +import com.markilue.leecode.listnode.ListNode; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.listnode.selftry + *@Author: markilue + *@CreateTime: 2023-04-04 12:56 + *@Description: + * TODO 力扣143 重排链表: + * 给定一个单链表 L 的头节点 head ,单链表 L 表示为: + * L0 → L1 → … → Ln - 1 → Ln + * 请将其重新排列后变为: + * L0 → Ln → L1 → Ln - 1 → L2 → Ln - 2 → … + * 不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。 + *@Version: 1.0 + */ +public class ReorderList { + + + /** + * 递归法 + * @param head + */ + ListNode p; + + public void reorderList(ListNode head) { + p = head; + recur(head); + + } + + public void recur(ListNode head) { + if (head == null) { + return; + } + + recur(head.next); + if (p.next == null || p == head || head.next == p) { + //判断当前节点是否需要合并 + p.next = null;//不需要合并了,直接把p置为null + return; + } + head.next = p.next;//把p的后面拼在head的后面 + p.next = head;//把head加在p的后面 + p = p.next.next; + + } + +} diff --git a/Leecode/src/main/java/com/markilue/leecode/listnode/selftry/reverseKGroup.java b/Leecode/src/main/java/com/markilue/leecode/listnode/selftry/reverseKGroup.java index d0a52df..b8de4a3 100644 --- a/Leecode/src/main/java/com/markilue/leecode/listnode/selftry/reverseKGroup.java +++ b/Leecode/src/main/java/com/markilue/leecode/listnode/selftry/reverseKGroup.java @@ -1,7 +1,10 @@ package com.markilue.leecode.listnode.selftry; +import com.markilue.leecode.listnode.ListNode; import com.markilue.leecode.listnode.T04_swapPairs; +import java.util.List; + public class reverseKGroup { public static void main(String[] args) { @@ -10,24 +13,53 @@ public class reverseKGroup { } public ListNode reverseKGroup(ListNode head, int k) { - + return null; } - public static class ListNode { - int val; - T04_swapPairs.ListNode next; - ListNode() { + + /** + * 反转部分链表 + * @param head + * @param k + * @return + */ + public ListNode reverseKGroup1(ListNode head, int k) { + if (head == null) { + return head; } - ListNode(int val) { - this.val = val; + ListNode temp = head; + //寻找终点 + for (int i = 0; i < k; i++) { + if (temp == null) return head;//没到k个,直接返回 + temp = temp.next; } - ListNode(int val, T04_swapPairs.ListNode next) { - this.val = val; - this.next = next; + ListNode newHead = reverse(head, temp); + head.next= reverseKGroup1(temp, k); + return newHead; + + + } + + public ListNode reverse(ListNode start, ListNode end) { + //反转部分链表 + if (start == null) return start; + + + ListNode fake = new ListNode(); + fake.next = start; + ListNode temp = start; + while (temp != end) { + ListNode tempnext = temp.next; + temp.next = fake.next; + fake.next = temp; + temp = tempnext; } + + return fake.next; + } } diff --git a/Leecode/src/main/java/com/markilue/leecode/listnode/selftry/swapPairs.java b/Leecode/src/main/java/com/markilue/leecode/listnode/selftry/swapPairs.java index 8b81157..5ca1a18 100644 --- a/Leecode/src/main/java/com/markilue/leecode/listnode/selftry/swapPairs.java +++ b/Leecode/src/main/java/com/markilue/leecode/listnode/selftry/swapPairs.java @@ -1,42 +1,45 @@ package com.markilue.leecode.listnode.selftry; +import com.markilue.leecode.listnode.ListNode; +import com.markilue.leecode.listnode.ListNodeUtils; public class swapPairs { public static void main(String[] args) { ListNode l1 = new ListNode(1); - //l1.next=new ListNode(2); - //l1.next.next=new ListNode(3); - //l1.next.next.next=new ListNode(4); + l1.next = new ListNode(2); + l1.next.next = new ListNode(3); + l1.next.next.next = new ListNode(4); - ListNode listNode = swapPairs(l1); + ListNode listNode = swapPairs1(l1); + ListNodeUtils.print(listNode); } public static ListNode swapPairs(ListNode head) { - if(head==null){ + if (head == null) { return null; } - ListNode dust=head; - ListNode swap=head.next; - int temp=0; - while (swap!=null){ - temp=swap.val; - swap.val=head.val; - head.val=temp; + ListNode dust = head; + ListNode swap = head.next; + int temp = 0; + while (swap != null) { + temp = swap.val; + swap.val = head.val; + head.val = temp; - if(swap.next!=null){ - if(swap.next.next!=null){ - swap=swap.next.next; - head=head.next.next; - }else { + if (swap.next != null) { + if (swap.next.next != null) { + swap = swap.next.next; + head = head.next.next; + } else { break; } - }else { + } else { break; } @@ -44,21 +47,30 @@ public class swapPairs { return dust; } - public static class ListNode { - int val; - ListNode next; - ListNode() { + public static ListNode swapPairs1(ListNode head) { + if (head == null || head.next == null) { + return head; + } + ListNode fake = new ListNode(); + fake.next = head; + ListNode tempcur = fake; + + while (tempcur != null && tempcur.next != null) { + ListNode temp = tempcur.next.next; + if (tempcur.next.next != null) { + tempcur.next.next = tempcur.next.next.next; + temp.next = tempcur.next; + tempcur.next=temp; + } + tempcur = tempcur.next.next; +// tempcur = temp; + } - ListNode(int val) { - this.val = val; - } + return fake.next; + - ListNode(int val, ListNode next) { - this.val = val; - this.next = next; - } } diff --git a/Leecode/src/main/java/com/markilue/leecode/sql/SQLPractice.sql b/Leecode/src/main/java/com/markilue/leecode/sql/SQLPractice.sql new file mode 100644 index 0000000..d04b973 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/sql/SQLPractice.sql @@ -0,0 +1,719 @@ +use sqlpractice; + +# 学生表Student +create table Student +( + SId varchar(10), + Sname varchar(10), + Sage datetime, + Ssex varchar(10) +); +insert into Student +values ('01', '赵雷', '1990-01-01', '男'); +insert into Student +values ('02', '钱电', '1990-12-21', '男'); +insert into Student +values ('03', '孙风', '1990-05-20', '男'); +insert into Student +values ('04', '李云', '1990-08-06', '男'); +insert into Student +values ('05', '周梅', '1991-12-01', '女'); +insert into Student +values ('06', '吴兰', '1992-03-01', '女'); +insert into Student +values ('07', '郑竹', '1989-07-01', '女'); +insert into Student +values ('09', '张三', '2017-12-20', '女'); +insert into Student +values ('10', '李四', '2017-12-25', '女'); +insert into Student +values ('11', '李四', '2017-12-30', '女'); +insert into Student +values ('12', '赵六', '2017-01-01', '女'); +insert into Student +values ('13', '孙七', '2018-01-01', '女'); + +# 科目表 +create table Course +( + CId varchar(10), + Cname nvarchar(10), + TId varchar(10) +); +insert into Course +values ('01', '语文', '02'); +insert into Course +values ('02', '数学', '01'); +insert into Course +values ('03', '英语', '03'); + +# 教师表 +create table Teacher +( + TId varchar(10), + Tname varchar(10) +); +insert into Teacher +values ('01', '张三'); +insert into Teacher +values ('02', '李四'); +insert into Teacher +values ('03', '王五'); + +# 成绩表SC +create table SC +( + SId varchar(10), + CId varchar(10), + score decimal(18, 1) +); +insert into SC +values ('01', '01', 80); +insert into SC +values ('01', '02', 90); +insert into SC +values ('01', '03', 99); +insert into SC +values ('02', '01', 70); +insert into SC +values ('02', '02', 60); +insert into SC +values ('02', '03', 80); +insert into SC +values ('03', '01', 80); +insert into SC +values ('03', '02', 80); +insert into SC +values ('03', '03', 80); +insert into SC +values ('04', '01', 50); +insert into SC +values ('04', '02', 30); +insert into SC +values ('04', '03', 20); +insert into SC +values ('05', '01', 76); +insert into SC +values ('05', '02', 87); +insert into SC +values ('06', '01', 31); +insert into SC +values ('06', '03', 34); +insert into SC +values ('07', '02', 89); +insert into SC +values ('07', '03', 98); + + +#TODO 1、查询" 01 "课程比" 02 "课程成绩高的学生的信息及课程分数 + +select Student.sid, sname, sage, Ssex, s1, s2 +from student + join + (select t1.SId, s1, s2 + from (select SId, score s1 + from sc + where CId = '01') t1 + join + (select SId, score s2 + from sc + where CId = '02') t2 on t1.SId = t2.SId and t1.s1 > t2.s2) t3 on Student.SId = t3.SId; + +#TODO 2.1、查询同时存在" 01 "课程和" 02 "课程的情况 +select t1.SId, s1, s2 +from (select SId, score s1 + from sc + where CId = '01') t1 + join + (select SId, score s2 + from sc + where CId = '02') t2 on t1.SId = t2.SId; + +#TODO 2.2、查询存在" 01 "课程但可能不存在" 02 "课程的情况(不存在时显示为 null ) +select t1.sid, s1, s2 +from (select SId, score s1 + from sc + where CId = '01') t1 + left join (select SId, score s2 + from sc + where CId = '02') t2 on t1.SId = t2.SId; + + +#TODO 2.3、查询不存在" 01 "课程但存在" 02 "课程的情况 +select t2.sid, s1, s2 +from (select SId, score s1 + from sc + where CId = '01') t1 + right join (select SId, score s2 + from sc + where CId = '02') t2 on t1.SId = t2.SId; + +#TODO 3、查询平均成绩大于等于 60 分的同学的学生编号和学生姓名和平均成绩 +-- 查询平均成绩大于等于 60 分的同学 +select SId, sum(score) / count(score) avg +from sc +group by sid +having avg > 60; + +-- 查询这些学生的相关信息 +select t1.sid, Sname, avg +from student + right join (select SId, sum(score) / count(score) avg + from sc + group by sid + having avg > 60) t1 on Student.SId = t1.SId; + +#TODO 4、查询在 SC 表存在成绩的学生信息 +-- 存在成绩+去重 +select sid +from sc +where score is not null +group by sid; +-- 查询对应的信息 +select t1.sid, Sname, Sage, Ssex +from student + right join (select sid + from sc + where score is not null + group by sid) t1 on Student.SId = t1.SId; + +#TODO 5、查询所有同学的学生编号、学生姓名、选课总数、所有课程的总成绩(没成绩的显示为 null ) +-- 查询有成绩的 +select sid, count(score) c1, sum(score) s1 +from sc +group by sid; + +select Student.sid, sname, c1, s1 +from student + left join(select sid, count(score) c1, sum(score) s1 + from sc + group by sid) t1 on Student.sid = t1.SId; + +#TODO 6、查有成绩的学生信息 +-- 有成绩的学生 +select distinct(sid) +from sc +where score is not null; +-- 查询对应的信息 +select Student.sid, Student.sname, Student.sage, ssex +from student + right join (select distinct(sid) sid + from sc + where score is not null) t1 on Student.SId = t1.SId; + +#TODO 7、查询「李」姓老师的数量 +select count(TId) +from Teacher +where Tname like '李%'; + +#TODO 8、查询学过「张三」老师授课的同学的信息 + +-- 张三老师教过的课 +select cid, t.TId +from Course + join + (select tid, tname from teacher where tname = '张三') t on Course.TId = t.TId; + +-- 张三老师教过的课的学生 +select sid, t2.CId +from sc + join (select cid, t.TId + from Course + join + (select tid, tname from teacher where tname = '张三') t on Course.TId = t.TId) t2 + on sc.CId = t2.CId; + +-- 详细信息 +select t3.sid, Sname, sage, Ssex +from student + join(select sid, t2.CId + from sc + join (select cid, t.TId + from Course + join + (select tid, tname from teacher where tname = '张三') t on Course.TId = t.TId) t2 + on sc.CId = t2.CId) t3 on Student.SId = t3.SId; + +#TODO 9、查询没有学全所有课程的同学的信息 + +-- 查询全部course的数目 +select count(cid) num +from course; + +-- 查询没有学全所有课程的同学 +select sid, count(cid) c1, num +from sc, + (select count(cid) num + from course) t2 +group by sid +having c1 < t2.num; + +-- 查询对应学生的信息 +select S.sid, sname, Sage, Ssex +from Student + right join (select sid, count(cid) c1, num + from sc, + (select count(cid) num + from course) t2 + group by sid + having c1 < t2.num) S on Student.SId = S.SId; + +#TODO 10、查询至少有一门课与学号为" 01 "的同学所学相同的同学的信息 + +-- 学号01同学所学 +SELECT CId +from sc +where SId = '01'; + +-- 所学相同 +select Student.sid, sname, Sage, Ssex +from Student +where SId in + (select distinct (sid) + from sc + join(SELECT CId + from sc + where SId = '01') t1 on sc.CId = t1.CId + where SC.SId != '01'); + +#TODO 11、查询和" 01 "号的同学学习的课程完全相同的其他同学的信息 + +-- 先join得到所有的相同的课 + +-- 计算所有课的数目和原本的数目是否相等 +select sc.sid +from sc + join(select CId + from sc + where SId = '01') t1 on sc.CId = t1.CId +where sid != '01' +group by SId +having count(sc.cid) = (select count(CId) + from sc + where SId = '01'); + +select * +from student +where Student.SId in (select sc.sid + from sc + join(select CId + from sc + where SId = '01') t1 on sc.CId = t1.CId + where sid != '01' + group by SId + having count(sc.cid) = (select count(CId) + from sc + where SId = '01')); + +#TODO 12、查询没学过"张三"老师讲授的任一门课程的学生姓名 + +-- 查询张三老师教过的课 +select cid +from course + join(select TId + from teacher + where Tname = '张三') t1 + on Course.TId = t1.TId; +-- 查询学过张三老师教过的课的学生 +select SId +from sc +where CId in (select cid + from course + join(select TId + from teacher + where Tname = '张三') t1 + on Course.TId = t1.TId); +-- 查询没有学过张三老师教过的课的学生 +select * +from student +where SId not in (select SId + from sc + where CId in (select cid + from course + where tid in (select TId + from teacher + where Tname = '张三'))); + +# TODO 13、查询两门及其以上不及格课程的同学的学号,姓名及其平均成绩 + +-- 查询两门及其以上不及格课程的同学的学号 +select sid, count(CId) c1 +from sc +where score < 60 +group by sid +having c1 >= 2; + +-- 查询这些人的平均成绩 +select sid, avg(score) avg +from sc +where SId in + (select sid + from sc + where score < 60 + group by sid + having count(CId) >= 2) +group by sid; +-- 查询全部 +select t1.sid, Sname, avg +from student + join + (select sid, avg(score) avg + from sc + where SId in + (select sid + from sc + where score < 60 + group by sid + having count(CId) >= 2) + group by sid) t1 on Student.SId = t1.SId; + +#TODO 14、检索" 01 "课程分数小于 60,按分数降序排列的学生信息 +-- 降序学生 +select sid, score +from sc +where CId = '01' + and score < 60 +order by score desc; + +select * +from Student + join + (select sid, score + from sc + where CId = '01' + and score < 60 + order by score desc) t1 on Student.SId = t1.SId; + +#TODO 15、按平均成绩从高到低显示所有学生的所有课程的成绩以及平均成绩 +select sid, CId, score, avg +from (select sid, + CId, + score, + avg(score) over (partition by sid) avg + from sc) t1 +order by avg desc; + + +#TODO 16、查询各科成绩最高分、最低分和平均分: +select cid, max(score), min(score), avg(score) +from sc +group by cid; + +#TODO 17.1、按各科成绩进行排序,并显示排名, Score 重复时保留名次空缺 + +-- 窗口函数 +select cid, sid, score, rank() over (partition by CId order by score desc) +from sc; + +-- 师兄非窗口函数法 +SELECT *, COUNT(*) +FROM sc a + LEFT JOIN + sc b + ON a.cid = b.cid AND a.score <= b.score +GROUP BY a.cid, a.sid, a.score +ORDER BY a.cid DESC, a.score DESC; + +#TODO 17.2、按各科成绩进行排序,并显示排名, Score 重复时合并名次 +-- 窗口函数 +select cid, sid, score, dense_rank() over (partition by CId order by score desc) +from sc; +-- 师兄非窗口函数法 (应该有问题) +SELECT *, COUNT(*) +FROM sc a + LEFT JOIN + sc b + ON a.cid = b.cid AND a.score < b.score +GROUP BY a.cid, a.sid, a.score +ORDER BY a.cid DESC, a.score DESC; + + +# TODO 17.3、查询学生的总成绩,并进行排名,总分重复时保留名次空缺 + +-- 非窗口函数法 +select t1.sid, t1.sum, count(*) rk +from (select sid, sum(score) sum + from sc + group by sid) t1 + left join + (select sid, sum(score) sum + from sc + group by sid) t2 on t1.sum <= t2.sum +group by t1.sid, t1.sum +order by t1.sum desc; + +-- 窗口函数法 +select sid, sum, rank() over (order by sum desc) rk +from (select sid, sum(score) sum + from sc + group by sid) t1; + +#TODO 17.4、 查询学生的总成绩,并进行排名,总分重复时不保留名次空缺 + +-- 窗口函数法 +select sid, sum, dense_rank() over (order by sum desc) rk +from (select sid, sum(score) sum + from sc + group by sid) t1; + +SET @crank = 0; +SELECT b.sid, b.a, @crank := @crank + 1 AS rank1 +FROM (SELECT sid, SUM(score) AS a FROM sc GROUP BY sid ORDER BY a DESC) b; + +#TODO 18.统计各科成绩各分数段人数:课程编号,课程名称,[100-85],[85-70],[70-60],[60-0] 及所占百分比 + +select t1.cid,cname,you,liang,zhong,cha,you/total,liang/total,zhong/total,cha/total +from course + join + ( + select cid, + sum(if(score >= 85 and score < 100, 1, 0)) you, + sum(if(score >= 70 and score < 85, 1, 0)) liang, + sum(if(score >= 60 and score < 70, 1, 0)) zhong, + sum(if(score > 0 and score < 60, 1, 0)) cha, + count(score) total + from sc + group by cid + )t1 on Course.CId=t1.CId; + +-- 师兄写法 +SELECT sc.cid,c.cname, + SUM(CASE WHEN score>85 AND score<=100 THEN 1 ELSE 0 END) AS '[100-85]', + SUM(CASE WHEN score>70 AND score<=85 THEN 1 ELSE 0 END) AS '[85-70]', + SUM(CASE WHEN score>60 AND score<=70 THEN 1 ELSE 0 END) AS '[70-60]', + SUM(CASE WHEN score<60 THEN 1 ELSE 0 END) AS '[60-0]', + SUM(CASE WHEN score>85 AND score<=100 THEN 1 ELSE 0 END)/COUNT(1) AS '[100-85]百分比', + SUM(CASE WHEN score>70 AND score<=85 THEN 1 ELSE 0 END)/COUNT(1) AS '[85-70]百分比', + SUM(CASE WHEN score>60 AND score<=70 THEN 1 ELSE 0 END)/COUNT(1) AS '[70-60]百分比', + SUM(CASE WHEN score<60 THEN 1 ELSE 0 END)/COUNT(1) AS '[60-0]百分比' +FROM sc ,course c +WHERE sc.cid=c.cid +GROUP BY sc.cid; + +# TODO 19查询各科成绩前三名的记录 + +-- 窗口函数法 +select cid,sid,score,rk +from + ( + select cid,sid,score,rank() over (partition by cid order by score desc) rk + from sc + ) t1 +where rk<=3; + +-- 师兄非窗口函数写法 +SELECT cid,sid,score FROM sc a +WHERE (SELECT COUNT(1) FROM sc b WHERE a.cid=b.cid AND a.score<=b.score)<=3 +ORDER BY cid; + +#TODO 20.查询每门课程被选修的学生数 +select Course.cid,Cname,student_num +from course +left join + ( + select cid,count(sid) student_num + from sc + group by cid + ) t1 on Course.CId=t1.CId; + +#TODO 21 查询出只选修两门课程的学生学号和姓名 +select t1.sid,Sname +from student +join + ( + select sid,count(cid) num + from sc + group by sid + having num=2 + ) t1 on Student.SId=t1.SId; + +#TODO 22.查询男生、女生人数`student` +select sum(if(Ssex='男',1,0)) '男生数量',sum(if(Ssex='女',1,0)) '女生数量' +from student; + +SELECT Ssex,COUNT(*) num FROM student GROUP BY ssex; + +#TODO 23.查询名字中含有「风」字的学生信息 +select * +from student +where Sname like '%风%'; + +#TODO 24.查询同名同姓学生名单,并统计同名人数 + +select sname ,count(sid) num +from student +group by sname +having num>1; + +#TODO 25.查询 1990 年出生的学生名单 +select sid,sname,Sage +from student +where year(Sage)='1990'; + +SELECT * FROM student WHERE sage LIKE '1990%'; + +#TODO 26.查询每门课程的平均成绩,结果按平均成绩降序排列,平均成绩相同时,按课程编号升序排列 + +select cid,avg(score) avg +from sc +group by cid +order by avg desc,cid; + +#TODO 27.查询平均成绩大于等于 85 的所有学生的学号、姓名和平均成绩 + +select t1.sid,sname,avg +from student +right join + ( + select sid,avg(score) avg + from sc + group by sid + having avg>=85 + ) t1 on Student.SId=t1.sid; + +#TODO 28.查询课程名称为「数学」,且分数低于 60 的学生姓名和分数 + +select t1.sid,Sname,score +from student +join + ( + select cid,SId,score + from sc + where cid= + ( + select cid + from Course + where Cname ='数学' + )and score<60 + ) t1 on Student.SId=t1.SId; + +#TODO 29.查询所有学生的课程及分数情况(存在学生没成绩,没选课的情况) + +select Student.sid,sname,ifnull(Cname,'无'),ifnull(score,0) +from student +left join + ( + select sid,sc.cid,cname,score + from sc,course + where sc.cid=Course.CId + )t1 on Student.SId=t1.SId; + +#TODO 30.查询任何一门课程成绩在 70 分以上的姓名、课程名称和分数 + +select sc.sid,sname,sc.cid,cname,score +from sc,course,student +where sc.CId=Course.CId and Student.SId=sc.SId and score>70; + +SELECT t3.sname,t2.cname,t1.score FROM + ( + (SELECT * FROM sc) t1 + JOIN + (SELECT cid,cname FROM course) t2 + JOIN + (SELECT sid,sname FROM student) t3 + ON t1.cid=t2.cid AND t1.sid=t3.sid + ) +WHERE t1.score > 70; + +#TODO 31.查询不及格的课程 +select sid,cid,score,(case when score<60 then 'fail' else 'success' end) result +from sc +where score<60; + +# TODO 32.查询课程编号为 01 且课程成绩在 80 分以上的学生的学号和姓名 +select sid,Sname +from Student +where sid in +(select sid +from sc +where cid='01'and score>=80); + +-- 也可以join获得具体的数 +SELECT student.`SId`,student.`Sname`,sc.`CId`,sc.`score` +FROM sc,student +WHERE sc.`SId`=student.`SId` AND sc.`CId`=01 AND sc.`score`>=80; + +#TODO 33.求每门课程的学生人数 +select cid,count(sid) num +from sc +group by cid; + +#TODO 34.成绩不重复,查询选修「张三」老师所授课程的学生中,成绩最高的学生信息及其成绩 +select student.sid, sname, sage, ssex,cid, score +from student +join + ( + select sid,cid,score + from sc + where CId + in (select CId + from course + where TId in(select TId from teacher where Tname='张三')) + having score=max(score) + ) t1 on Student.SId=t1.SId; + +SELECT t2.sid,t2.cid,MAX(t2.score) FROM + ( + (SELECT CId FROM course WHERE TId = (SELECT tid FROM teacher WHERE Tname='张三'))t1 + JOIN + (SELECT * FROM sc) t2 + ON t1.cid=t2.cid + ); + +#TODO 35.成绩有重复的情况下,查询选修「张三」老师所授课程的学生中,成绩最高的学生信息及其成绩 + +-- 本人的应该有没有重复都行 +select student.sid, sname, sage, ssex,cid, score +from student + join + ( + select sid,cid,score + from sc + where CId + in (select CId + from course + where TId in(select TId from teacher where Tname='张三')) + having score=max(score) + ) t1 on Student.SId=t1.SId; + +# TODO 36.查询不同课程成绩相同的学生的学生编号、课程编号、学生编号 +-- 窗口函数 +-- 查询不同课程成绩相同的学生的学生编号 +select sid,score,CId,num +from + ( + select sid,score,cid,count(cid) over(partition by sid,score) num + from sc + )t1 +where num>1; + +-- 师兄不用窗口函数法(有四门课及以上的应该不对) +SELECT * FROM sc a +WHERE sid IN + (SELECT sid FROM sc + GROUP BY sid + HAVING (COUNT(*)=2 AND COUNT(DISTINCT score)=1) -- 有两门课有重复的情况 + OR (COUNT(*)=3 AND COUNT(DISTINCT score)<3)); -- 有三门课有重复的情况 + +-- 根据师兄的改进(去重前后不相等则有重复) +SELECT * FROM sc a +WHERE sid IN + (SELECT sid FROM sc + GROUP BY sid + HAVING COUNT(*) != COUNT(DISTINCT score)); + +#TODO 37.查询各学生的年龄,只按年份来算 + +SELECT sid,sname, YEAR(now())-YEAR(sage) age FROM student; + +#TODO 38.按照出生日期来算,当前月日 +SELECT sid,sname,TIMESTAMPDIFF(YEAR,sage,CURDATE()) age FROM student; + +-- 自己的本办法 +-- 判断年龄是否要-1 +select sid,sname ,year(now())-year(Sage)-if(month(now())-month(Sage)>0||(month(now())=month(Sage)&&day(now())>=day(Sage)),0,1) age +from student; + +#TODO 39.查询本周过生日的学生 +SELECT * FROM student WHERE WEEKOFYEAR(sage)=WEEKOFYEAR(CURDATE()) + diff --git a/Leecode/src/main/java/com/markilue/leecode/test/ThreeSum.java b/Leecode/src/main/java/com/markilue/leecode/test/ThreeSum.java new file mode 100644 index 0000000..0138630 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/test/ThreeSum.java @@ -0,0 +1,60 @@ +package com.markilue.leecode.test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.test + *@Author: markilue + *@CreateTime: 2023-04-04 11:01 + *@Description: + * TODO 力扣15题 三数之和: + * 给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != j、i != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请 + * 你返回所有和为 0 且不重复的三元组。 + * 注意:答案中不可以包含重复的三元组。 + *@Version: 1.0 + */ +public class ThreeSum { + + + public List> threeSum(int[] nums) { + List> result = new ArrayList<>(); + if (nums.length < 3) { + return result; + } + Arrays.sort(nums); + + for (int i = 0; i < nums.length-2; i++) { + if (i != 0 && nums[i] == nums[i - 1]) { + continue; + } + if (nums[i] > 0) break; + + int left = i + 1; + int right = nums.length - 1; + + while (left < right) { + int sum = nums[i] + nums[left] + nums[right]; + + if (sum < 0) { + left++; + } else if (sum > 0) { + right--; + } else { + result.add(new ArrayList<>(Arrays.asList(nums[i], nums[left], nums[right]))); + + while (left < right && nums[left] == nums[left + 1]) left++; + while (left < right && nums[right] == nums[right - 1]) right--; + left++; + right--; + } + } + + } + + return result; + + } +} diff --git a/Leecode/src/main/java/com/markilue/leecode/test/test.java b/Leecode/src/main/java/com/markilue/leecode/test/test.java index b1e34e2..c3604b5 100644 --- a/Leecode/src/main/java/com/markilue/leecode/test/test.java +++ b/Leecode/src/main/java/com/markilue/leecode/test/test.java @@ -1,5 +1,6 @@ package com.markilue.leecode.test; +import com.markilue.leecode.hot100.T55_LFUCache; import com.markilue.leecode.tree.TreeNode; import org.junit.Test; @@ -15,6 +16,32 @@ import java.util.ArrayList; */ public class test { + @Test + public void test2(){ + T55_LFUCache lfuCache = new T55_LFUCache(2); + lfuCache.put(1,1); + lfuCache.put(2,2); + System.out.println(lfuCache.get(1)); + lfuCache.put(3,3); + System.out.println(lfuCache.get(2)); + System.out.println(lfuCache.get(3)); + lfuCache.put(4,4); + System.out.println(lfuCache.get(1)); + System.out.println(lfuCache.get(3)); + System.out.println(lfuCache.get(4)); + + } + + static { + + + System.out.println("hello sta"); + } + + public static void main(String[] args) { + System.out.println("hello world"); + } + //测试ArrayList的index是否发生变化 @Test diff --git a/Leecode/src/main/java/com/markilue/leecode/test/testAnt.java b/Leecode/src/main/java/com/markilue/leecode/test/testAnt.java index 80406a4..0e7673b 100644 --- a/Leecode/src/main/java/com/markilue/leecode/test/testAnt.java +++ b/Leecode/src/main/java/com/markilue/leecode/test/testAnt.java @@ -1,6 +1,7 @@ package com.markilue.leecode.test; -import java.util.HashMap; +import java.util.*; + import java.util.Scanner; /** @@ -14,53 +15,53 @@ import java.util.Scanner; public class testAnt { - public static void main(String[] args) { - - Scanner sc = new Scanner(System.in); - String input = sc.nextLine(); - - new testAnt().test(input); -// StringBuilder output = new StringBuilder(); -// int left = 0; +// public static void main(String[] args) { // -// //去除前面的 -// while (left < input.length() && input.charAt(left) == ' ') { -// left++; -// } +// Scanner sc = new Scanner(System.in); +// String input = sc.nextLine(); // -// boolean isCapital = true; // 首字母是否大写 -// for (int i = left; i < input.length(); i++) { -// char c = input.charAt(i); -// if (c == ' ') { -// if (i > 0 && input.charAt(i - 1) == '.') { -// output.deleteCharAt(output.length() - 1); -// } -// // 跳过多余的空格 -// while (i < input.length() - 1 && input.charAt(i + 1) == ' ') { -// i++; -// } -// if (input.charAt(i + 1) != '.') { -// output.append(' '); -// } -// } else if (c == '.') { -// // 句号后面要加一个空格 -// output.append(". "); -// isCapital = true; // 下一句话的首字母要大写 -// } else { -// if (isCapital) { -// // 首字母要大写 -// output.append(Character.toUpperCase(c)); -// isCapital = false; -// } else { -// output.append(c); -// } -// } -// } +// new testAnt().test(input); +//// StringBuilder output = new StringBuilder(); +//// int left = 0; +//// +//// //去除前面的 +//// while (left < input.length() && input.charAt(left) == ' ') { +//// left++; +//// } +//// +//// boolean isCapital = true; // 首字母是否大写 +//// for (int i = left; i < input.length(); i++) { +//// char c = input.charAt(i); +//// if (c == ' ') { +//// if (i > 0 && input.charAt(i - 1) == '.') { +//// output.deleteCharAt(output.length() - 1); +//// } +//// // 跳过多余的空格 +//// while (i < input.length() - 1 && input.charAt(i + 1) == ' ') { +//// i++; +//// } +//// if (input.charAt(i + 1) != '.') { +//// output.append(' '); +//// } +//// } else if (c == '.') { +//// // 句号后面要加一个空格 +//// output.append(". "); +//// isCapital = true; // 下一句话的首字母要大写 +//// } else { +//// if (isCapital) { +//// // 首字母要大写 +//// output.append(Character.toUpperCase(c)); +//// isCapital = false; +//// } else { +//// output.append(c); +//// } +//// } +//// } +//// +//// System.out.println(output.toString()); +// sc.close(); // -// System.out.println(output.toString()); - sc.close(); - - } +// } public void test(String str) { @@ -106,4 +107,68 @@ public class testAnt { } + + + + + +// public static void main(String[] args) { +// Scanner scanner = new Scanner(System.in); +// int k = scanner.nextInt(); +// int count = 0; +// for (int i = 0; i < 65536; i++) { +// String hex = String.format("%04x", i); // 将整数转换成长度为 4 的十六进制数 +// if (isGoodHex(hex)) { +// count++; +// if (count == k) { +// System.out.println(hex); +// break; +// } +// } +// } +// } +// +// public static boolean isGoodHex(String hex) { +// Set digits = new HashSet<>(); +// for (char c : hex.toCharArray()) { +// digits.add(c); +// } +// return digits.size() == 4; +// } + + + public static void main(String[] args) { + String s = "????(?"; // 待匹配的字符串 + int left = 0, right = 0, count = 0; // 分别记录左括号、右括号和合法的括号对的数量 + Stack stack = new Stack<>(); // 栈,用于记录左括号和 '?' 的下标 + for (int i = 0; i < s.length(); i++) { + char c = s.charAt(i); + if (c == '(' || c == '?') { + stack.push(i); + if (c == '(') { + left++; + } + } else { + if (stack.isEmpty()) { + continue; + } + stack.pop(); + if (c == ')') { + right++; + } + count++; + } + } + while (!stack.isEmpty()) { // 处理剩余的左括号或 '?' + int index = stack.pop(); + if (s.charAt(index) == '(') { + left--; + } else { + right--; + } + } + count += Math.min(left, right); // '?' 可以代替左括号或右括号,因此左右括号数量较小的值为合法的括号对数量 + System.out.println(count); + } + }