diff --git a/Leecode/src/main/java/com/markilue/leecode/stackAndDeque/TopKFrequent.java b/Leecode/src/main/java/com/markilue/leecode/stackAndDeque/T07_TopKFrequent.java similarity index 99% rename from Leecode/src/main/java/com/markilue/leecode/stackAndDeque/TopKFrequent.java rename to Leecode/src/main/java/com/markilue/leecode/stackAndDeque/T07_TopKFrequent.java index 3eae9a6..5ca1e50 100644 --- a/Leecode/src/main/java/com/markilue/leecode/stackAndDeque/TopKFrequent.java +++ b/Leecode/src/main/java/com/markilue/leecode/stackAndDeque/T07_TopKFrequent.java @@ -13,7 +13,7 @@ import java.util.*; * 给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。 * @Version: 1.0 */ -public class TopKFrequent { +public class T07_TopKFrequent { @Test diff --git a/Leecode/src/main/java/com/markilue/leecode/stackAndDeque/second/T05_EvalRPN.java b/Leecode/src/main/java/com/markilue/leecode/stackAndDeque/second/T05_EvalRPN.java index 4127a51..f0e137c 100644 --- a/Leecode/src/main/java/com/markilue/leecode/stackAndDeque/second/T05_EvalRPN.java +++ b/Leecode/src/main/java/com/markilue/leecode/stackAndDeque/second/T05_EvalRPN.java @@ -12,7 +12,7 @@ import java.util.Stack; *@Author: dingjiawen *@CreateTime: 2023-01-03 11:27 *@Description: - * TODO 力扣150题 逆波兰表达式求值: + * TODO 二刷力扣150题 逆波兰表达式求值: * 根据 逆波兰表示法,求表达式的值。 * 有效的算符包括+、-、*、/。每个运算对象可以是整数,也可以是另一个逆波兰表达式。 * 注意两个整数之间的除法只保留整数部分。 diff --git a/Leecode/src/main/java/com/markilue/leecode/stackAndDeque/second/T06_MaxSlidingWindow.java b/Leecode/src/main/java/com/markilue/leecode/stackAndDeque/second/T06_MaxSlidingWindow.java index affa70b..0bf5923 100644 --- a/Leecode/src/main/java/com/markilue/leecode/stackAndDeque/second/T06_MaxSlidingWindow.java +++ b/Leecode/src/main/java/com/markilue/leecode/stackAndDeque/second/T06_MaxSlidingWindow.java @@ -10,7 +10,7 @@ import java.util.*; *@Author: dingjiawen *@CreateTime: 2023-01-03 12:00 *@Description: - * TODO 力扣239题 滑动窗口最大值: + * TODO 二刷力扣239题 滑动窗口最大值: * 给你一个整数数组 nums,有一个大小为k的滑动窗口从数组的最左侧移动到数组的最右侧。 * 你只可以看到在滑动窗口内的 k个数字。滑动窗口每次只向右移动一位。 * 返回 滑动窗口中的最大值 。 diff --git a/Leecode/src/main/java/com/markilue/leecode/stackAndDeque/second/T07_TopKFrequent.java b/Leecode/src/main/java/com/markilue/leecode/stackAndDeque/second/T07_TopKFrequent.java new file mode 100644 index 0000000..0aa3fe2 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/stackAndDeque/second/T07_TopKFrequent.java @@ -0,0 +1,164 @@ +package com.markilue.leecode.stackAndDeque.second; + +import org.junit.Test; + +import java.util.*; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.stackAndDeque.second + *@Author: dingjiawen + *@CreateTime: 2023-01-04 10:21 + *@Description: + * TODO 二刷leecode347 前k个高频元素: + * 给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案 + *@Version: 1.0 + */ +public class T07_TopKFrequent { + + + @Test + public void test(){ + int[] nums = {1, 1, 1, 2, 2, 3}; + int k = 2; + System.out.println(Arrays.toString(topKFrequent(nums,k))); + } + + @Test + public void test2(){ + int[] nums = {3,2,3,1,2,4,5,5,6,7,7,8,2,3,1,1,1,10,11,5,6,2,4,7,8,5,6}; + int k = 10; + System.out.println(Arrays.toString(topKFrequent(nums,k))); + } + + @Test + public void test1(){ + int[] nums = {6,0,1,4,9,7,-3,1,-4,-8,4,-7,-3,3,2,-3,9,5,-4,0}; + int k = 6; + System.out.println(Arrays.toString(topKFrequent1(nums,k))); + } + + + /** + * 思路:TopK的本质还是排序后留下前K个,需要记录 + * 速度击败5.31%,内存击败5.6% 23ms + * @param nums + * @param k + * @return + */ + public int[] topKFrequent(int[] nums, int k) { + HashMap map = new HashMap<>(); + + for (int num : nums) { + map.put(num, map.getOrDefault(num, 0) + 1); + } + + int[] result = new int[k];//直接使用数组的问题就是,每插一次就要把他后面的往后挪 + Arrays.fill(result,Integer.MIN_VALUE); + if(map.size()==k){ + int i=0; + for (Integer integer : map.keySet()) { + result[i++]=integer; + } + }else { + for (Map.Entry entry : map.entrySet()) { + Integer count = entry.getValue(); + //找到第一个小于count的数 + int flag = 0; + while (flag < k && map.getOrDefault(result[flag],0) >= count) { + flag++; + } + int temp=flag; + //插入 + for (int i = 1; i < k-flag; i++) { + result[k-i] = result[k-i-1]; + } + + if(temp,使用能排序的优先队列实现 + * 时间复杂度O(nlogk) 堆化操作复杂度logk + * 速度击败90.55%,内存击败48.40% 12ms + * @param nums + * @param k + * @return + */ + public int[] topKFrequent1(int[] nums, int k) { + HashMap map = new HashMap<>(); + + for (int num : nums) { + map.put(num, map.getOrDefault(num, 0) + 1); + } + +// int[] result = new int[k];//直接使用数组的问题就是,每插一次就要把他后面的往后挪 + PriorityQueue deque = new PriorityQueue<>(new Comparator() { + @Override + public int compare(int[] o1, int[] o2) { + return o1[1]==o2[1]?o2[0]-o1[0]:o2[1]-o1[1]; + } + }); + + for (Map.Entry entry : map.entrySet()) { + + deque.offer(new int[]{entry.getKey(),entry.getValue()}); + + } + int[] result = new int[k]; + for (int i = 0; i < result.length; i++) { + result[i]=deque.poll()[0]; + } + return result; + + + } + + + /** + * 官方最快:时间复杂度降到O(N) + * 速度击败100%,内存击败24.45% 1ms + * @param nums + * @param k + * @return + */ + public int[] topKFrequent2(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/tree/PreOrderTraversal.java b/Leecode/src/main/java/com/markilue/leecode/tree/T01_PreOrderTraversal.java similarity index 99% rename from Leecode/src/main/java/com/markilue/leecode/tree/PreOrderTraversal.java rename to Leecode/src/main/java/com/markilue/leecode/tree/T01_PreOrderTraversal.java index 6bffeb5..a1cbc54 100644 --- a/Leecode/src/main/java/com/markilue/leecode/tree/PreOrderTraversal.java +++ b/Leecode/src/main/java/com/markilue/leecode/tree/T01_PreOrderTraversal.java @@ -18,7 +18,7 @@ import java.util.Stack; * 给你二叉树的根节点 root ,返回它节点值的 前序 遍历。 * @Version: 1.0 */ -public class PreOrderTraversal { +public class T01_PreOrderTraversal { @Test diff --git a/Leecode/src/main/java/com/markilue/leecode/tree/second/T01_PreOrderTraversal.java b/Leecode/src/main/java/com/markilue/leecode/tree/second/T01_PreOrderTraversal.java new file mode 100644 index 0000000..f6f24f8 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/tree/second/T01_PreOrderTraversal.java @@ -0,0 +1,178 @@ +package com.markilue.leecode.tree.second; + +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.tree.second + *@Author: dingjiawen + *@CreateTime: 2023-01-04 12:40 + *@Description: + * TODO 二刷leecode 144 二叉树的前序: + * 给你二叉树的根节点 root ,返回它节点值的 前序 遍历。 + *@Version: 1.0 + */ +public class T01_PreOrderTraversal { + + @Test + public void test() { + ArrayList list = new ArrayList<>(Arrays.asList(3,1,2,5,6,7,8,10)); + TreeNode root = TreeUtils.structureTree(list, 0); + System.out.println(preorderTraversal2(root)); + + } + + /** + * 思路:递归法 + * 速度击败100%,内存击败86.86% + */ + List result = new ArrayList<>();//记录答案 + public List preorderTraversal(TreeNode root) { + if (root == null) { + return result; + } + result.add(root.val); + preorderTraversal(root.left); + preorderTraversal(root.right); + return result; + } + + + /** + * 思路:stack迭代法 + * 速度击败100%,内存击败75.97% + * @param root + * @return + */ + public List preorderTraversal1(TreeNode root) { + List result = new ArrayList<>(); + if(root==null){ + return result; + } + + Stack stack = new Stack<>(); + stack.push(root); + + while(!stack.isEmpty()){ + TreeNode node = stack.pop(); + result.add(node.val); + if(node.right!=null){ + stack.push(node.right); + } + if(node.left!=null){ + stack.push(node.left); + } + } + return result; + } + + + /** + * 官方stack迭代法 + * @param root + * @return + */ + public List preorderTraversal3(TreeNode root) { + List res = new ArrayList(); + if (root == null) { + return res; + } + + Deque stack = new LinkedList(); + TreeNode node = root; + while (!stack.isEmpty() || node != null) { + while (node != null) { + res.add(node.val); + stack.push(node); + node = node.left; + } + node = stack.pop(); + node = node.right; + } + return res; + } + + + + + /** + * 思路:Morris遍历 + * 速度击败100%,内存击败75.97% + * @param root + * @return + */ + public List preorderTraversal2(TreeNode root) { + List result = new ArrayList<>(); + if(root==null){ + return result; + } + + while (root!=null){ + //找到上一个连接root的点(左子节点的最右节点),然后放心吧root左移 + if(root.left!=null){ + TreeNode temp=root.left; + while (temp.right!=root&&temp.right!=null){ + temp=temp.right; + } + //判断是从什么条件出来的 + if(temp.right==null){ + //第一次到这,将这与root连接 + temp.right=root; + result.add(root.val);//将其加入后就右移 + //放心将root右移 + root=root.left; + } else if(temp.right==root){ + //第二次来这,之前的都已经遍历完了 + root=root.right; + temp.right=null;//将right置空,防止下次还遍历 + } + }else { + //左边遍历完了,将它右移 + result.add(root.val); + root=root.right; + } + } + + return result; + } + + /** + * 官方morris写法 + * @param root + * @return + */ + public List preorderTraversal4(TreeNode root) { + List res = new ArrayList(); + if (root == null) { + return res; + } + + TreeNode p1 = root, p2 = null; + + while (p1 != null) { + p2 = p1.left; + if (p2 != null) { + while (p2.right != null && p2.right != p1) { + p2 = p2.right; + } + if (p2.right == null) { + res.add(p1.val); + p2.right = p1; + p1 = p1.left; + continue;//这里continue以后,后面就可以把p1 = p1.right; + } else { + p2.right = null; + } + } else { + res.add(p1.val); + } + p1 = p1.right; + } + return res; + } + +}