leecode更新
This commit is contained in:
parent
ee4c7618f8
commit
776e572905
|
|
@ -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<int[]>() {
|
||||||
|
@Override
|
||||||
|
public int compare(int[] o1, int[] o2) {
|
||||||
|
return o1[0] == o2[0] ? o1[1] - o2[1] : o2[0] - o1[0];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
LinkedList<int[]> 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<int[]>() {
|
||||||
|
@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;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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];
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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<Integer> cur = new ArrayList<Integer>();
|
||||||
|
|
||||||
|
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<Long, Integer> prefix = new HashMap<Long, Integer>();
|
||||||
|
prefix.put(0L, 1);
|
||||||
|
return dfs(root, prefix, 0, targetSum);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int dfs(TreeNode root, Map<Long, Integer> 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue