leecode更新
This commit is contained in:
parent
c2963545b3
commit
013a1161d1
|
|
@ -0,0 +1,134 @@
|
||||||
|
package com.markilue.leecode.dynamic;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*@BelongsProject: Leecode
|
||||||
|
*@BelongsPackage: com.markilue.leecode.dynamic
|
||||||
|
*@Author: dingjiawen
|
||||||
|
*@CreateTime: 2022-12-15 09:48
|
||||||
|
*@Description:
|
||||||
|
* TODO 力扣300题 最长递增子序列:
|
||||||
|
* 给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。
|
||||||
|
* 子序列 是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。
|
||||||
|
*@Version: 1.0
|
||||||
|
*/
|
||||||
|
public class T27_LengthOfLIS {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test() {
|
||||||
|
int[] nums = {0, 5,8, 4,6,7, 12, 2};
|
||||||
|
System.out.println(lengthOfLIS1(nums));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 代码随想录思路:
|
||||||
|
* TODO 动态规划五部曲:
|
||||||
|
* (1)dp定义:dp[i]表示i之前包括i的以nums[i]结尾最长上升子序列的长度
|
||||||
|
* (2)dp状态转移方程:if (nums[i] > nums[j]) dp[i] = max(dp[i], dp[j] + 1);
|
||||||
|
* 注意这里不是要dp[i] 与 dp[j] + 1进行比较,而是我们要取dp[j] + 1的最大值。
|
||||||
|
* (3)dp初始化:dp[0]=1
|
||||||
|
* (4)dp遍历顺序:从前往后
|
||||||
|
* (5)dp举例推导:以[0,1,0,3,2]为例:
|
||||||
|
* [0 1 2 3 4]
|
||||||
|
* i=1 1 2 1 1 1
|
||||||
|
* i=2 1 2 1 1 1
|
||||||
|
* i=3 1 2 1 3 1
|
||||||
|
* i=4 1 2 1 3 3
|
||||||
|
* 感觉本质上还是暴力解法,与常规两次for一致 时间复杂度O(n^2)
|
||||||
|
* 速度击败72.45%,内存击败46.73%
|
||||||
|
* @param nums
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int lengthOfLIS(int[] nums) {
|
||||||
|
|
||||||
|
int[] dp = new int[nums.length];
|
||||||
|
Arrays.fill(dp, 1);
|
||||||
|
int result = 0;
|
||||||
|
for (int i = 0; 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 (dp[i] > result) result = dp[i]; // 取长的子序列
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 官方贪心+二分查找法:本质上是我们希望每次在上升子序列最后加上的那个数尽可能的小。
|
||||||
|
* 时间复杂度O(nlog(n)) 遍历数组复杂度n,二分查找插入dp数组复杂度log(n)
|
||||||
|
* 速度击败99.63%,内存击败15.78% 2ms
|
||||||
|
* 以{0, 5, 8, 4, 6, 7, 12, 2}为例:
|
||||||
|
* i=1:d={0}
|
||||||
|
* i=2:d={0,5}
|
||||||
|
* i=3:d={0,5,8}
|
||||||
|
* i=4:d={0,4,8}
|
||||||
|
* i=5:d={0,4,6}
|
||||||
|
* i=6:d={0,4,6,7}
|
||||||
|
* i=7:d={0,4,6,7,12}
|
||||||
|
* i=8:d={0,2,6,7,12}
|
||||||
|
* @param nums
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int lengthOfLIS1(int[] nums) {
|
||||||
|
int len = 1, n = nums.length;
|
||||||
|
if (n == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int[] d = new int[n + 1];
|
||||||
|
d[len] = nums[0];
|
||||||
|
for (int i = 1; i < n; ++i) {
|
||||||
|
if (nums[i] > d[len]) {
|
||||||
|
d[++len] = nums[i];
|
||||||
|
} else {
|
||||||
|
int l = 1, r = len, pos = 0; // 如果找不到说明所有的数都比 nums[i] 大,此时要更新 d[1],所以这里将 pos 设为 0
|
||||||
|
while (l <= r) {//寻找最后一个比num[i]小的数
|
||||||
|
int mid = (l + r) >> 1;
|
||||||
|
if (d[mid] < nums[i]) {
|
||||||
|
pos = mid;
|
||||||
|
l = mid + 1;
|
||||||
|
} else {
|
||||||
|
r = mid - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
d[pos + 1] = nums[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 题解1ms法:本质上还是贪心,甚至没有用二分查找
|
||||||
|
* 速度击败99.93%,内存击败5.8% 1ms
|
||||||
|
* @param nums
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int lengthOfLIS2(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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,164 @@
|
||||||
|
package com.markilue.leecode.dynamic;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*@BelongsProject: Leecode
|
||||||
|
*@BelongsPackage: com.markilue.leecode.dynamic
|
||||||
|
*@Author: dingjiawen
|
||||||
|
*@CreateTime: 2022-12-15 11:58
|
||||||
|
*@Description:
|
||||||
|
* TODO leetcode674题 最长连续递增序列:
|
||||||
|
* 给定一个未经排序的整数数组,找到最长且 连续递增的子序列,并返回该序列的长度。
|
||||||
|
* 连续递增的子序列 可以由两个下标 l 和 r(l < r)确定
|
||||||
|
* 如果对于每个 l <= i < r,都有 nums[i] < nums[i + 1]
|
||||||
|
* 那么子序列 [nums[l], nums[l + 1], ..., nums[r - 1], nums[r]] 就是连续递增子序列。
|
||||||
|
*@Version: 1.0
|
||||||
|
*/
|
||||||
|
public class T28_FindLengthOfLCIS {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test(){
|
||||||
|
int[] nums = {1, 3, 5,5,6, 4, 7};
|
||||||
|
System.out.println(findLengthOfLCIS2(nums));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 思路:核心在于连续递增,所以甚至比T27更简单,更好找规律
|
||||||
|
* 这里先直接使用贪心,一次遍历
|
||||||
|
* 速度击败99.96%,内存击败51.38% 1ms
|
||||||
|
* @param nums
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int findLengthOfLCIS(int[] nums) {
|
||||||
|
|
||||||
|
int min = nums[0];
|
||||||
|
int nowLength=1;
|
||||||
|
int maxLength = 1;
|
||||||
|
|
||||||
|
for (int i = 1; i < nums.length; i++) {
|
||||||
|
if (nums[i] <= min) {
|
||||||
|
nowLength=1;
|
||||||
|
}else {
|
||||||
|
nowLength+=1;
|
||||||
|
maxLength=Math.max(maxLength,nowLength);
|
||||||
|
}
|
||||||
|
min = nums[i];
|
||||||
|
}
|
||||||
|
return maxLength;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 思路:核心在于连续递增,所以甚至比T27更简单,更好找规律
|
||||||
|
* 这里尝试动归,一次遍历
|
||||||
|
* TODO 动归五部曲:
|
||||||
|
* (1)dp定义:dp[i]表示使用num[0-i]得到的最长连续子序列
|
||||||
|
* (2)dp状态转移方程:dp[i]=num[i]>num[i-1]?max(dp[i-1],now+1),max(dp[i-1],now)
|
||||||
|
* (3)dp初始化:dp[0]=1
|
||||||
|
* (4)dp遍历顺序:从前往后
|
||||||
|
* (5)dp举例推导:以{1, 3, 5,5,6, 4, 7}为例:
|
||||||
|
* dp=[1,2,3,3,3,3,3]
|
||||||
|
* 速度击败99.96%,内存击败32.74% 1ms
|
||||||
|
* @param nums
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int findLengthOfLCIS1(int[] nums) {
|
||||||
|
|
||||||
|
int nowLength=1;
|
||||||
|
int[] dp = new int[nums.length];
|
||||||
|
dp[0]=1;
|
||||||
|
|
||||||
|
for (int i = 1; i < nums.length; i++) {
|
||||||
|
if (nums[i] > nums[i-1]) {
|
||||||
|
nowLength+=1;
|
||||||
|
}else {
|
||||||
|
nowLength=1;
|
||||||
|
}
|
||||||
|
dp[i]=Math.max(dp[i-1],nowLength);
|
||||||
|
}
|
||||||
|
return dp[nums.length-1];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 代码随想录思路:自己的思路还是有点贪心的意思,代码随想录不会
|
||||||
|
*速度击败99.96%,内存击败42.32% 1ms
|
||||||
|
* @param nums
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int findLengthOfLCIS2(int[] nums) {
|
||||||
|
|
||||||
|
int[] dp = new int[nums.length];
|
||||||
|
Arrays.fill(dp,1);
|
||||||
|
int result=1;
|
||||||
|
|
||||||
|
for (int i = 1; i < nums.length; i++) {
|
||||||
|
if (nums[i] > nums[i-1]) {
|
||||||
|
dp[i]=dp[i-1]+1;
|
||||||
|
}
|
||||||
|
if (dp[i] > result) result = dp[i];
|
||||||
|
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 思路:动态规划滚动数组优化
|
||||||
|
* TODO 动归五部曲:
|
||||||
|
* (1)dp定义:dp[i]表示以num[i]结尾得到的最长连续子序列
|
||||||
|
* (2)dp状态转移方程:if nums[i + 1] > nums[i] 得到dp[i]=dp[i-1]+1
|
||||||
|
* (3)dp初始化:dp[i]=1
|
||||||
|
* (4)dp遍历顺序:从前往后
|
||||||
|
* (5)dp举例推导:以{1, 3, 5,5,6, 4, 7}为例:
|
||||||
|
* dp=[1,2,3,1,2,1,2]
|
||||||
|
* 速度击败99.96%,内存击败32.74% 1ms
|
||||||
|
* @param nums
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int findLengthOfLCIS3(int[] nums) {
|
||||||
|
|
||||||
|
int nowLength=1;
|
||||||
|
int dp0=1;
|
||||||
|
|
||||||
|
for (int i = 1; i < nums.length; i++) {
|
||||||
|
if (nums[i] > nums[i-1]) {
|
||||||
|
nowLength+=1;
|
||||||
|
}else {
|
||||||
|
nowLength=1;
|
||||||
|
}
|
||||||
|
dp0=Math.max(dp0,nowLength);
|
||||||
|
}
|
||||||
|
return dp0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 题解中0ms方法:比之前的快在count=1不需要在判断一次if(count>max)
|
||||||
|
* 速度击败100%,内存击败38.73%
|
||||||
|
* @param nums
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int findLengthOfLCIS5(int[] nums) {
|
||||||
|
int left=0,right,count=1,max=1;
|
||||||
|
for (right = 1; right < nums.length; right++,left++) {
|
||||||
|
if(nums[left]<nums[right]){
|
||||||
|
count++;
|
||||||
|
if(count>max){
|
||||||
|
max=count;
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
count=1;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return max;
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue