2021-10-19
一本通 1264:【例9.8】合唱队形
一本通的题,想明白了很简单,想不明白比较复杂。就是从左到右是升序子序列,而从右边到左也是升序子序列。两个dp数组,一个从左到右计算最大升序子序列。一个从右往左计算最大升序子序列。最后做一个合并。看每个位置dp1[i]+dp2[i] 的最大值,减去重复的i位置的值,就是最大值了。
public int res(int[] t) {
int dp1[] = new int[t.length];
int dp2[] = new int[t.length];
for (int i = 0; i < t.length; i++) {
dp1[i] = 1;
for (int j = 0; j < 1; j++) {
if (t[i] > t[j]) {
dp1[i] = Math.max(dp1[j] + 1, dp1[i]);
}
}
}
for (int i = t.length - 1; i >= 0; i--) {
dp2[i] = 1;
for (int j = t.length - 1; j > i; j--) {
if (t[i] > t[j]) {
dp2[i] = Math.max(dp2[j] + 1, dp2[i]);
}
}
}
int max = 1;
for (int i = 0; i < t.length; i++) {
max = Math.max(dp1[i] + dp2[i], max);
}
System.out.println(max-1);
return max - 1;
}
2021-10-20
516. 最长回文子序列
这题是非常经典的动态规划题,详细解析,后面补充。
回文串、序列 的题,通常你要先定义两个指针,一个是指向起始位置,一个指向结束位置。所以都是二位dp数组
- 1.dp[i][j]代表从索引 i到j位置的最长回文序列长度。则我们最终要求得最长回文序列为 dp[0][len-1]
- 2.回文特点是对称。则dp[i][j]和dp[i+1][j-1]产生递推关系
- 3.当i位置字符和j位置字符相同则 dp[i][j]=dp[i+1][j-1]+2,因为长度是在原来基础上增加2的
- 3.当i位置字符和j位置字符不同则 dp[i][j]这个的最大值与下面两个位置产生的最长回文相同,因为i和j无效,位置一:i+1到j,位置二:i~j-1位置
- 4.i如果从0开始遍历,则j在遍历过程中,比如i=0,j=3,则此时状态转移为 i=2,而此时i=2的dp我们还没计算出来,所以无法算得,所以i需要从len-1开始
class Solution {
public int longestPalindromeSubseq(String s) {
if (s == null) {
return 0;
}
int len = s.length();
char[] cs = s.toCharArray();
//状态转义方程式 当cs[i]==cs[j]
// 则有dp[i][j]= dp[i+1][j-1]。
// 否则dp[i][j] = Max(dp[i+1][j],dp[i][j-1])
int[][] dp = new int[len][len];
for (int i = len - 1; i >= 0; i--) {
dp[i][i]=1;
for (int j = i + 1; j < len; j++) {
if (cs[i] == cs[j]) {
dp[i][j] = dp[i + 1][j - 1]+2;
} else {
dp[i][j] = Math.max(dp[i + 1][j], dp[i][j - 1]);
}
}
}
return dp[0][len - 1];
}
}
2021-10-26
首先说这两天的纪念意义,2020年10月27日是我在力扣上提交通过的第一道题,知道今天我通过了刚好350题
P496. 下一个更大元素 I
P496. 下一个更大元素 I
这题暴力解法时间复杂度O(n2),这里使用单调栈和map来降低时间复杂度
- 1.求得nums2每个位置上比当前位置大的元素的索引,并放入map
- 1.1 倒序遍历(必须倒序),把元素索引放入栈,使得栈索引对应值保持单调递减的,也就是当前的元素的下一个元素一定在栈顶。如果不满足单调,就一直弹栈,直到拿到比当前更大的元素
- 2.遍历nums1,找到其在map中对应的索引,去nums2取出来
public int[] nextGreaterElement(int[] nums1, int[] nums2) {
//i - index ,i表示元素,index表示下一个比i大的数
//[1,3,4,2,5]
//用一个栈找到下一个比自己大的元素
//栈里面保持逐渐增大的
Map<Integer, Integer> map = new HashMap<>();
Stack<Integer> stack = new Stack<>();
for (int i = nums2.length - 1; i >= 0; i--) {
if (stack.isEmpty() || nums2[i] < nums2[stack.peek()]) {
map.put(nums2[i], stack.isEmpty() ? -1 : stack.peek());
stack.add(i);
} else {
while (!stack.isEmpty() && nums2[i] > nums2[stack.peek()]) {
stack.pop();
}
map.put(nums2[i], stack.isEmpty() ? -1 : stack.peek());
stack.add(i);
}
}
int res[] = new int[nums1.length];
for (int i = 0; i < nums1.length; i++) {
res[i] = map.get(nums1[i]) == -1 ? -1 : nums2[map.get(nums1[i])];
}
return res;
}
P503. 下一个更大元素 II
P503. 下一个更大元素 II
这题要注意一些细节,使用的元素的索引去映射,因为元素可能重复,这样map会被覆盖。这题在原来基础上,首先要构造一个nums2数组,循环数组直接拼接两个数组能达到循环数组的效果
class Solution {
public int[] nextGreaterElements(int[] nums) {
int nums2[] = new int[nums.length * 2];
System.arraycopy(nums, 0, nums2, 0, nums.length);
System.arraycopy(nums, 0, nums2, nums.length, nums.length);
Map<Integer, Integer> map = new HashMap<>();
Stack<Integer> stack = new Stack<>();
for (int i = nums2.length - 1; i >= 0; i--) {
if (stack.isEmpty() || nums2[i] < nums2[stack.peek()]) {
map.put(i, stack.isEmpty() ? -1 : stack.peek());
stack.add(i);
} else {
while (!stack.isEmpty() && nums2[i] >= nums2[stack.peek()]) {
stack.pop();
}
map.put(i, stack.isEmpty() ? -1 : stack.peek());
stack.add(i);
}
}
int res[] = new int[nums.length];
for (int i = 0; i < nums.length; i++) {
res[i] = map.get(i) == -1 ? -1 : nums2[map.get(i)];
}
return res;
}
}