leecode更新
This commit is contained in:
parent
89885c0e53
commit
4d659677a1
|
|
@ -3,6 +3,7 @@ package com.markilue.leecode.hot100;
|
|||
import org.junit.Test;
|
||||
import org.omg.CORBA.PUBLIC_MEMBER;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,150 @@
|
|||
package com.markilue.leecode.hot100;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
*@BelongsProject: Leecode
|
||||
*@BelongsPackage: com.markilue.leecode.hot100
|
||||
*@Author: markilue
|
||||
*@CreateTime: 2023-03-16 09:54
|
||||
*@Description:
|
||||
* TODO 力扣207题 课程表:
|
||||
* 你这个学期必须选修 numCourses 门课程,记为 0 到 numCourses - 1 。
|
||||
* 在选修某些课程之前需要一些先修课程。 先修课程按数组 prerequisites 给出,其中 prerequisites[i] = [ai, bi] ,表示如果要学习课程 ai 则 必须 先学习课程 bi 。
|
||||
* 例如,先修课程对 [0, 1] 表示:想要学习课程 0 ,你需要先完成课程 1 。
|
||||
* 请你判断是否可能完成所有课程的学习?如果可以,返回 true ;否则,返回 false 。
|
||||
*@Version: 1.0
|
||||
*/
|
||||
public class T64_CanFinish {
|
||||
|
||||
@Test
|
||||
public void test(){
|
||||
int numCourses = 3;
|
||||
int[][] prerequisites = {{1,0},{0,2},{2,1}};
|
||||
System.out.println(canFinish(numCourses,prerequisites));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 思路:使用一个Map<Integer,List> 数字,需要在他后面学的东西
|
||||
* 有问题 当处于一个循环的时候,后面没有办法再重新监测前面的内容
|
||||
* 过了42个用例
|
||||
* @param numCourses
|
||||
* @param prerequisites
|
||||
* @return
|
||||
*/
|
||||
public boolean canFinish(int numCourses, int[][] prerequisites) {
|
||||
|
||||
HashMap<Integer, HashSet<Integer>> map = new HashMap<Integer, HashSet<Integer>>();
|
||||
// HashSet<Integer> set1 = new HashSet<>();
|
||||
|
||||
|
||||
for (int[] prerequisite : prerequisites) {
|
||||
// set1.add(prerequisite[0]);
|
||||
// set1.add(prerequisite[1]);
|
||||
if (!map.containsKey(prerequisite[1])) {
|
||||
HashSet<Integer> set = new HashSet<>();
|
||||
set.add(prerequisite[0]);
|
||||
map.put(prerequisite[1], set);
|
||||
}else {
|
||||
HashSet<Integer> set = map.get(prerequisite[1]);
|
||||
set.add(prerequisite[0]);
|
||||
}
|
||||
|
||||
if(map.containsKey(prerequisite[0])){
|
||||
//看看必须在他后面完成的里面有没有prerequisite[1]
|
||||
if(map.get(prerequisite[0]).contains(prerequisite[1])){//1必须在0之前完成
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// if(set1.size()<numCourses){//课程数不够
|
||||
// return false;
|
||||
// }
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 官方深度优先算法:
|
||||
* 时间复杂度O(N+M)
|
||||
* 速度击败92..85% 内存击败38.86% 3ms
|
||||
*/
|
||||
List<List<Integer>> edges;
|
||||
int[] visited;
|
||||
boolean valid = true;
|
||||
|
||||
public boolean canFinish1(int numCourses, int[][] prerequisites) {
|
||||
edges = new ArrayList<List<Integer>>();
|
||||
for (int i = 0; i < numCourses; ++i) {
|
||||
edges.add(new ArrayList<Integer>());
|
||||
}
|
||||
visited = new int[numCourses];
|
||||
for (int[] info : prerequisites) {
|
||||
edges.get(info[1]).add(info[0]);
|
||||
}
|
||||
for (int i = 0; i < numCourses && valid; ++i) {
|
||||
if (visited[i] == 0) {
|
||||
dfs(i);
|
||||
}
|
||||
}
|
||||
return valid;
|
||||
}
|
||||
|
||||
public void dfs(int u) {
|
||||
visited[u] = 1;//搜索中
|
||||
for (int v: edges.get(u)) {
|
||||
if (visited[v] == 0) {
|
||||
dfs(v);
|
||||
if (!valid) {
|
||||
return;
|
||||
}
|
||||
} else if (visited[v] == 1) {//肯定要在当前节点之后进行遍历到才行
|
||||
valid = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
visited[u] = 2;//已完成
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 官方最快:
|
||||
* 速度击败100% 内存击败93.16% 1ms
|
||||
* @param numCourses
|
||||
* @param prerequisites
|
||||
* @return
|
||||
*/
|
||||
public boolean canFinish2(int numCourses, int[][] prerequisites) {
|
||||
int len = prerequisites.length;
|
||||
if (len == 0) return true;
|
||||
int[] pointer = new int[numCourses];// 每个课程被指向的次数
|
||||
for (int[] p : prerequisites) ++pointer[p[1]];
|
||||
boolean[] removed = new boolean[len];// 标记prerequisites中的元素是否被移除
|
||||
int remove = 0;// 移除的元素数量
|
||||
while (remove < len) {
|
||||
int currRemove = 0;// 本轮移除的元素数量
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (removed[i]) continue;// 被移除的元素跳过
|
||||
int[] p = prerequisites[i];
|
||||
if (pointer[p[0]] == 0) {// 如果被安全课程指向
|
||||
--pointer[p[1]];// 被指向次数减1
|
||||
removed[i] = true;
|
||||
++currRemove;
|
||||
}
|
||||
}
|
||||
if (currRemove == 0) return false;// 如果一轮跑下来一个元素都没移除,则没必要进行下一轮
|
||||
remove += currRemove;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,124 @@
|
|||
package com.markilue.leecode.hot100;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
*@BelongsProject: Leecode
|
||||
*@BelongsPackage: com.markilue.leecode.hot100
|
||||
*@Author: markilue
|
||||
*@CreateTime: 2023-03-16 11:09
|
||||
*@Description:
|
||||
* TODO 力扣215 数组中的第K个最大元素:
|
||||
* 给定整数数组 nums 和整数 k,请返回数组中第 k 个最大的元素。
|
||||
* 请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。
|
||||
* 你必须设计并实现时间复杂度为 O(n) 的算法解决此问题。
|
||||
*@Version: 1.0
|
||||
*/
|
||||
public class T66_FindKthLargest {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
int[] nums = {3, 2, 1, 5, 6, 4};
|
||||
int k = 2;
|
||||
System.out.println(findKthLargest(nums, k));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test1() {
|
||||
int[] nums = {2, 1};
|
||||
int k = 1;
|
||||
System.out.println(findKthLargest(nums, k));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 快排的思路:通过partition找到对应的位置,然后抛弃另一半
|
||||
* 速度击败64.38% 内存击败78.98% 14ms
|
||||
* @param nums
|
||||
* @param k
|
||||
* @return
|
||||
*/
|
||||
public int findKthLargest(int[] nums, int k) {
|
||||
return partition(nums, 0, nums.length - 1, nums.length - k);
|
||||
}
|
||||
|
||||
|
||||
public int partition(int[] nums, int start, int end, int k) {
|
||||
if (start == end) {
|
||||
return nums[start];
|
||||
}
|
||||
|
||||
int index = sort(nums, start, end);
|
||||
|
||||
if (index < k) return partition(nums, index + 1, end, k);
|
||||
else if (index > k) return partition(nums, start, index - 1, k);
|
||||
else return nums[index];
|
||||
}
|
||||
|
||||
public int sort(int[] nums, int start, int end) {
|
||||
|
||||
int left = start;
|
||||
int right = end + 1;
|
||||
int compare = nums[start];
|
||||
|
||||
while (left <= right) {
|
||||
|
||||
while (++left < nums.length && nums[left] < compare) {
|
||||
continue;
|
||||
}
|
||||
|
||||
while (--right >= 0 && nums[right] > compare) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (left > right) break;
|
||||
swap(nums, left, right);
|
||||
}
|
||||
swap(nums, start, right);
|
||||
return right;
|
||||
}
|
||||
|
||||
public void swap(int[] nums, int left, int right) {
|
||||
int temp = nums[left];
|
||||
nums[left] = nums[right];
|
||||
nums[right] = temp;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 官方最快:记录每个数出现的次数,然后进行相减,当k<=0就是所需要的那个数
|
||||
* 速度击败100% 内存击败5% 1ms
|
||||
* @param nums
|
||||
* @param k
|
||||
* @return
|
||||
*/
|
||||
public int findKthLargest1(int[] nums, int k) {
|
||||
|
||||
int max = nums[0];
|
||||
int min = nums[0];
|
||||
//寻找最大值和最小值
|
||||
for (int num : nums) {
|
||||
if (max < num) {
|
||||
max = num;
|
||||
}
|
||||
if (min > num) {
|
||||
min = num;
|
||||
}
|
||||
}
|
||||
|
||||
int[] allnums = new int[max - min + 1];
|
||||
|
||||
for (int num : nums) {
|
||||
allnums[num - min]++;//记录每个数出现的次数
|
||||
}
|
||||
|
||||
for (int i = max - min; i >= 0; i--) {
|
||||
k = k - allnums[i];//次数相减
|
||||
if (k <= 0) {
|
||||
return i + min;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,120 @@
|
|||
package com.markilue.leecode.hot100;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
*@BelongsProject: Leecode
|
||||
*@BelongsPackage: com.markilue.leecode.hot100
|
||||
*@Author: markilue
|
||||
*@CreateTime: 2023-03-16 11:48
|
||||
*@Description:
|
||||
* TODO 力扣221 最大正方形:
|
||||
* 在一个由 '0' 和 '1' 组成的二维矩阵内,找到只包含 '1' 的最大正方形,并返回其面积。
|
||||
*@Version: 1.0
|
||||
*/
|
||||
public class T67_MaximalSquare {
|
||||
|
||||
@Test
|
||||
public void test(){
|
||||
char[][] matrix={
|
||||
{'1', '1', '1', '1', '0'},
|
||||
{'1', '1', '1', '1', '0'},
|
||||
{'1', '1', '1', '1', '1'},
|
||||
{'1', '1', '1', '1', '1'},
|
||||
{'0', '0', '1', '1', '1'}
|
||||
};
|
||||
maximalSquare1(matrix);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 思路:动态规划法:
|
||||
* TODO DP五部曲:
|
||||
* 1.dp定义: dp[i][j]表示位于nums[i][j]位置的最大正方形面积
|
||||
* 2.dp状态转移方程:
|
||||
* if(nums[i][j]==1){
|
||||
* if(dp[i-1][j]!=0&&dp[i][j-1]==dp[i-1][j]){
|
||||
* dp[i][j]=(sqrt(dp[i-1][j-1])+1)*
|
||||
* }
|
||||
* }
|
||||
* 3.dp初始化:
|
||||
* 4.dp遍历顺序:
|
||||
* 5.dp举例推导:
|
||||
* 通过63个用例test用例无法过
|
||||
* @param matrix
|
||||
* @return
|
||||
*/
|
||||
public int maximalSquare(char[][] matrix) {
|
||||
|
||||
int[][] dp = new int[matrix.length][matrix[0].length];
|
||||
|
||||
int result = 0;
|
||||
|
||||
for (int i = 0; i < dp.length; i++) {
|
||||
if (matrix[i][0] == '1') {
|
||||
dp[i][0] =1;
|
||||
result=1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for (int i = 0; i < dp[0].length; i++) {
|
||||
if (matrix[0][i] == '1') {
|
||||
dp[0][i] =1;
|
||||
result=1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
for (int i = 1; i < matrix.length; i++) {
|
||||
for (int j = 1; j < matrix[0].length; j++) {
|
||||
if (matrix[i][j] == '1') {
|
||||
if (dp[i - 1][j] != 0 && dp[i][j - 1] == dp[i - 1][j]) {
|
||||
dp[i][j] = (int) Math.pow((Math.sqrt(dp[i - 1][j - 1]) + 1), 2);
|
||||
} else {
|
||||
dp[i][j] = 1;
|
||||
}
|
||||
}
|
||||
if (result < dp[i][j]) result = dp[i][j];
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 官方动态规划法:
|
||||
* TODO
|
||||
* DP定义:我们用 dp(i,j) 表示以 (i,j) 为右下角,且只包含 1 的正方形的边长最大值。
|
||||
* 如果我们能计算出所有 dp(i,j) 的值,那么其中的最大值即为矩阵中只包含 1的正方形的边长最大值,其平方即为最大正方形的面积。
|
||||
* 速度击败89.83% 内存击败34.75% 6ms
|
||||
* @param matrix
|
||||
* @return
|
||||
*/
|
||||
public int maximalSquare1(char[][] matrix) {
|
||||
int maxSide = 0;
|
||||
if (matrix == null || matrix.length == 0 || matrix[0].length == 0) {
|
||||
return maxSide;
|
||||
}
|
||||
int rows = matrix.length, columns = matrix[0].length;
|
||||
int[][] dp = new int[rows][columns];
|
||||
for (int i = 0; i < rows; i++) {
|
||||
for (int j = 0; j < columns; j++) {
|
||||
if (matrix[i][j] == '1') {
|
||||
if (i == 0 || j == 0) {
|
||||
dp[i][j] = 1;
|
||||
} else {
|
||||
dp[i][j] = Math.min(Math.min(dp[i - 1][j], dp[i][j - 1]), dp[i - 1][j - 1]) + 1;
|
||||
}
|
||||
maxSide = Math.max(maxSide, dp[i][j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
int maxSquare = maxSide * maxSide;
|
||||
return maxSquare;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
package com.markilue.leecode.hot100;
|
||||
|
||||
import com.markilue.leecode.tree.TreeNode;
|
||||
|
||||
/**
|
||||
*@BelongsProject: Leecode
|
||||
*@BelongsPackage: com.markilue.leecode.hot100
|
||||
*@Author: markilue
|
||||
*@CreateTime: 2023-03-16 12:42
|
||||
*@Description:
|
||||
* TODO 力扣226题 翻转二叉树:
|
||||
* 给你一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点。
|
||||
*@Version: 1.0
|
||||
*/
|
||||
public class T68_InvertTree {
|
||||
|
||||
|
||||
/**
|
||||
* 优先深度或者优先广度都行
|
||||
* 速度击败100% 内存击败55.93%
|
||||
* @param root
|
||||
* @return
|
||||
*/
|
||||
public TreeNode invertTree(TreeNode root) {
|
||||
if(root==null)return null;
|
||||
|
||||
TreeNode temp=root.left;
|
||||
root.left=invertTree(root.right);
|
||||
root.right=invertTree(temp);
|
||||
|
||||
return root;
|
||||
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue