文章目录
(1)321. 拼接最大数(错1)
题解思路:
class Solution {
public int[] maxNumber(int[] nums1, int[] nums2, int k) {
int m = nums1.length, n = nums2.length;
int[] maxSubsequence = new int[k];
int start = Math.max(0, k - n), end = Math.min(k, m);
for (int i = start; i <= end; i++) {
int[] subsequence1 = maxSubsequence(nums1, i);
int[] subsequence2 = maxSubsequence(nums2, k - i);
int[] curMaxSubsequence = merge(subsequence1, subsequence2);
if (compare(curMaxSubsequence, 0, maxSubsequence, 0) > 0) {
System.arraycopy(curMaxSubsequence, 0, maxSubsequence, 0, k);
}
}
return maxSubsequence;
}
*****************************************************
public int[] maxSubsequence(int[] nums, int k) {
int length = nums.length;
int[] stack = new int[k];
int top = -1;
int remain = length - k;
for (int i = 0; i < length; i++) {
int num = nums[i];
while (top >= 0 && stack[top] < num && remain > 0) {
top--;
remain--;
}
if (top < k - 1) {
stack[++top] = num;
} else {
remain--;
}
}
return stack;
}
********************************************************
public int[] merge(int[] subsequence1, int[] subsequence2) {
int x = subsequence1.length, y = subsequence2.length;
if (x == 0) {
return subsequence2;
}
if (y == 0) {
return subsequence1;
}
int mergeLength = x + y;
int[] merged = new int[mergeLength];
int index1 = 0, index2 = 0;
for (int i = 0; i < mergeLength; i++) {
if (compare(subsequence1, index1, subsequence2, index2) > 0) {
merged[i] = subsequence1[index1++];
} else {
merged[i] = subsequence2[index2++];
}
}
return merged;
}
public int compare(int[] subsequence1, int index1, int[] subsequence2, int index2) {
int x = subsequence1.length, y = subsequence2.length;
while (index1 < x && index2 < y) {
int difference = subsequence1[index1] - subsequence2[index2];
if (difference != 0) {
return difference;
}
index1++;
index2++;
}
return (x - index1) - (y - index2);
}
}
(2)76. 最小覆盖子串(错1)
题解思路:双指针滑动窗口法,使用一个map:need来记录需要各个字符的个数;使用一个map:window记录窗口中已有的字符数,left,right是窗口起始指针,start是记录当前len最小的覆盖子串的开始位置,valid记录已经满足的字符数量;
注意:Integer会缓存频繁使用的数值,数值分为是-128-127;在范围内直接返回缓存值,超过范围new一个对象,所以需要在进行比较时,在get().intValue();
class Solution {
public String minWindow(String s, String t) {
HashMap<Character, Integer> need = new HashMap<Character, Integer>();
HashMap<Character, Integer> window = new HashMap<Character, Integer>();
for(char c : t.toCharArray()){
need.put(c, need.getOrDefault(c, 0) + 1);
}
int left = 0;
int right = 0;
int valid = 0;
int start = 0;
int len = Integer.MAX_VALUE;
while(right < s.length()){
char c = s.charAt(right);
right++;
if(need.getOrDefault(c, 0) > 0){
window.put(c, window.getOrDefault(c, 0) + 1);
if(window.getOrDefault(c, 0).intValue() == need.getOrDefault(c, 0).intValue()){
valid++;
}
}
while(valid == need.size()){
if(right - left < len){
start = left;
len = right - left;
}
char d = s.charAt(left);
left++;
if(need.getOrDefault(d, 0) > 0){
if(window.get(d).intValue() == need.get(d).intValue()){
valid--;
}
window.put(d,window.getOrDefault(d, 0) - 1);
}
}
}
return len == Integer.MAX_VALUE ? "" : s.substring(start,start+len);
}
}
python
class Solution:
def minWindow(self, s: str, t: str) -> str:
mem = defaultdict(int)
for char in t:
mem[char]+=1
t_len = len(t)
minLeft, minRight = 0,len(s)
left = 0
for right,char in enumerate(s):
if mem[char]>0:
t_len-=1
mem[char]-=1
if t_len==0:
while mem[s[left]]<0:
mem[s[left]]+=1
left+=1
if right-left<minRight-minLeft:
minLeft,minRight = left,right
mem[s[left]]+=1
t_len+=1
left+=1
return '' if minRight==len(s) else s[minLeft:minRight+1]
滑动窗口算法框架:
HashMap<Character, Integer> need = new HashMap<Character,Integer>();
HashMap<Character, Integer> window = new HashMap<Character,Integer>();
for(char c : t.toCharArray()){
need.put(c, need.getOrDefault(c, 0) + 1);
}
int left = 0;
int right = 0;
int valid = 0;
while(right < s.length()){
//要移入的字符
char c = s.charAt(right);
right++;
***一系列更新
//判断左窗口是否要收缩
while(window needs shrink){
//要移出的字符
char d = s.charAt(left);
left++;
***一系列更新
}
}
(3)567. 字符串的排列
思路:滑动窗口法,对于新加入的字符有三种情况:(1)是s1中的,且当前窗口中该字符的数量小于s1中的数量,那么添加到窗口中;(2)不是s1中的字符,从下一个字符重新搜索;(3)是s1中的字符,但当前窗口中已经有足够数量的该字符,那么先将该字符加入窗口中,再从left位置出发,将一个相同字符前出现的字符移出窗口。
class Solution {
public boolean checkInclusion(String s1, String s2) {
HashMap<Character, Integer> need = new HashMap<Character, Integer>();
HashMap<Character, Integer> window = new HashMap<Character, Integer>();
for(char c: s1.toCharArray()){
need.put(c, need.getOrDefault(c, 0) + 1);
}
int left = 0;
int right = 0;
int valid = 0;
while(right < s2.length()){
char c = s2.charAt(right);
right++;
if(window.getOrDefault(c, 0) < need.getOrDefault(c,0)){
window.put(c, window.getOrDefault(c, 0) + 1);
if(window.get(c).intValue() == need.get(c).intValue()){
valid++;
}
if(valid == need.size()){
return true;
}
}else if(need.getOrDefault(c,0) == 0){
window = new HashMap<Character, Integer>();
valid = 0;
left = right;
}else{
window.put(c, window.getOrDefault(c, 0) + 1);
while(window.get(c).intValue() > need.get(c).intValue()){
char d = s2.charAt(left);
left++;
if(window.get(d).intValue() == need.get(d).intValue()){
valid--;
}
window.put(d, window.get(d)-1);
}
}
}
return false;
}
}
(4)438. 找到字符串中所有字母异位词
思路:滑动窗口
class Solution {
public List<Integer> findAnagrams(String s, String p) {
HashMap<Character, Integer> need = new HashMap<Character,Integer>();
HashMap<Character, Integer> window = new HashMap<Character,Integer>();
for(char c: p.toCharArray()){
need.put(c, need.getOrDefault(c, 0) + 1);
}
int left = 0;
int right = 0;
int valid = 0;
List<Integer> res = new ArrayList<Integer>();
while(right < s.length()){
char c = s.charAt(right);
right++;
if(window.getOrDefault(c, 0) <= need.getOrDefault(c, 0)){
window.put(c, window.getOrDefault(c, 0) + 1);
if(window.getOrDefault(c,0).intValue() == need.getOrDefault(c,0).intValue()){
valid++;
}
while(valid == need.size()){
res.add(left);
char d = s.charAt(left);
left++;
if(window.getOrDefault(d,0).intValue() == need.getOrDefault(d,0).intValue()){
valid--;
}
window.put(d, window.get(d) - 1);
}
}else if(need.getOrDefault(c,0) == 0){
left = right;
window = new HashMap<Character,Integer>();
valid = 0;
continue;
}
while(window.getOrDefault(c,0) > need.getOrDefault(c,0)){
char d = s.charAt(left);
left++;
if(window.getOrDefault(d,0).intValue() == need.getOrDefault(d,0).intValue()){
valid--;
}
window.put(d, window.get(d) - 1);
}
}
return res;
}
}
(5)334. 递增的三元子序列(错1)
题解思路:贪心算法,用a记录当前遍历到的最小数字,b记录第二小数字,如果找到比a,b都大的数字,则返回true
class Solution {
public boolean increasingTriplet(int[] nums) {
if(nums.length < 3){
return false;
}
int a = Integer.MAX_VALUE;
int b = Integer.MAX_VALUE;
for(int i = 0; i < nums.length; i++){
if(nums[i] <= a){
a = nums[i];
}else if(nums[i] <= b){
b = nums[i];
}else{
return true;
}
}
return false;
}
}
(6)121. 买卖股票的最佳时机
class Solution {
public int maxProfit(int[] prices) {
int len = prices.length;
if(len < 2){
return 0;
}
int[][] dp = new int[len+1][2];
dp[0][0] = 0;
dp[0][1] = Integer.MIN_VALUE;
for(int i = 1; i <= len; i++){
dp[i][0] = Math.max(dp[i-1][0],dp[i-1][1]+prices[i-1]);
dp[i][1] = Math.max(dp[i-1][1],-prices[i-1]);
}
return dp[len][0];
}
}
(7)122. 买卖股票的最佳时机 II
class Solution {
public int maxProfit(int[] prices) {
int len = prices.length;
int[][] dp = new int[len+1][2];
dp[0][0] = 0;
dp[0][1] = Integer.MIN_VALUE;
for(int i = 1; i <= len; i++){
dp[i][0] = Math.max(dp[i-1][0], dp[i-1][1] + prices[i-1]);
dp[i][1] = Math.max(dp[i-1][1], dp[i-1][0] - prices[i-1]);
}
return dp[len][0];
}
}
(8)123. 买卖股票的最佳时机 III
class Solution {
public int maxProfit(int[] prices) {
int len = prices.length;
int[][][] dp = new int[len+1][3][2];
for(int i = 0; i < 3; i++){
dp[0][i][0] = 0;
dp[0][i][1] = Integer.MIN_VALUE;
}
for(int i = 0; i < len+1; i++){
dp[i][0][0] = 0;
dp[i][0][1] = Integer.MIN_VALUE;
}
for(int i = 1; i < len+1; i++){
dp[i][1][0] = Math.max(dp[i-1][1][0], dp[i-1][1][1]+prices[i-1]);
dp[i][1][1] = Math.max(dp[i-1][1][1], dp[i-1][0][0]-prices[i-1]);
dp[i][2][0] = Math.max(dp[i-1][2][0], dp[i-1][2][1]+prices[i-1]);
dp[i][2][1] = Math.max(dp[i-1][2][1], dp[i-1][1][0]-prices[i-1]);
}
return dp[len][2][0];
}
}
(9)188. 买卖股票的最佳时机 IV
class Solution {
public int maxProfit(int k, int[] prices) {
int len = prices.length;
int[][][] dp = new int[len+1][k+1][2];
for(int i = 0; i < k+1; i++){
dp[0][i][0] = 0;
dp[0][i][1] = Integer.MIN_VALUE;
}
for(int i = 0; i < len+1; i++){
dp[i][0][0] = 0;
dp[i][0][1] = Integer.MIN_VALUE;
}
for(int i = 1; i < len+1; i++){
for(int j = 1; j < k+1; j++){
dp[i][j][0] = Math.max(dp[i-1][j][0], dp[i-1][j][1]+prices[i-1]);
dp[i][j][1] = Math.max(dp[i-1][j][1], dp[i-1][j-1][0]-prices[i-1]);
}
}
return dp[len][k][0];
}
}
(10)309. 最佳买卖股票时机含冷冻期
画出状态转移图,注意初始值的设置
class Solution {
public int maxProfit(int[] prices) {
int len = prices.length;
if(len < 2){
return 0;
}
int[][] dp = new int[len+1][3];
for(int i = 0; i < 3; i++){
dp[0][1] = Integer.MIN_VALUE;
dp[0][2] = Integer.MIN_VALUE;
}
for(int i = 1; i < len+1; i++){
dp[i][0] = Math.max(dp[i-1][0], dp[i-1][2]);
dp[i][1] = Math.max(dp[i-1][1], dp[i-1][0]-prices[i-1]);
dp[i][2] = dp[i-1][1]+prices[i-1];
}
return Math.max(dp[len][0],dp[len][2]);
}
}
(11)714. 买卖股票的最佳时机含手续费
class Solution {
public int maxProfit(int[] prices, int fee) {
int len = prices.length;
if(len < 2){
return 0;
}
int[][] dp = new int[len+1][2];
dp[0][0] = 0;
dp[0][1] = Integer.MIN_VALUE;
for(int i = 1; i < len+1; i++){
dp[i][0] = Math.max(dp[i-1][0], dp[i-1][1]+prices[i-1]);
dp[i][1] = Math.max(dp[i-1][1], dp[i-1][0]-prices[i-1]-fee);
}
return dp[len][0];
}
}