class Solution {
public List<List<Integer>> findDifference(int[] nums1, int[] nums2) {
Set<Integer> l1 = new HashSet<>();
Set<Integer> l2 = new HashSet<>();
Map<Integer,Integer> m1 = new HashMap<>();
Map<Integer,Integer> m2 = new HashMap<>();
for(int i:nums1)
m1.put(i,0);
for(int i:nums2)
m2.put(i,0);
for(int i:nums1)
if(!m2.containsKey(i))
l1.add(i);
for(int i:nums2)
if(!m1.containsKey(i))
l2.add(i);
List<List<Integer>> l = new ArrayList<>();
l.add(new ArrayList<>(l1));
l.add(new ArrayList<>(l2));
return l;
}
}
贪心。遍历数组的过程中记录在到达此下标前已经删除了多少个数。
显而易见,如果遍历到 i 时,nums[i] == nums[i + 1] ,并且 i 为偶数那么必定要删除 i(删 i 和 i + 1是一样的)或者 i 之前的一个数(令 i 变为奇数)。如果我们选择删除 i 之前的一个数,那么这个数有两种可能,一是它本来不用删,而是他本来就要删。如果它本来不用删,我们额外增加一次删数的机会把他删了来使得当前的 i 满足要求,那为什么不把这次机会放在 删除 i 上呢? 如果它本来就要删,那么我们只要在遍历数组的过程中记录在到达此下标前已经删除了多少个数,如果已经删除了奇数个数,那么 i 就会变得满足条件(此时 i 的下标变成了奇数,而我们只需要讨论偶数下标)
class Solution {
public int minDeletion(int[] nums) {
int ans = 0;
for(int i = 0; i < nums.length - 1; i++){
if(ans % 2 == i % 2){
if(nums[i] == nums[i + 1]){
ans ++;
}
}
}
if((nums.length - ans) % 2 != 0)
ans ++;
return ans;
}
}
class Solution {
public long[] kthPalindrome(int[] queries, int intLength) {
long[] ans = new long[queries.length];
if(intLength % 2 == 0)
for(int i = 0; i < queries.length; i++){
if(queries[i] - 1 >= 9 * Math.pow(10,intLength / 2 - 1)){
ans[i] = -1;
continue;
}
long t = (long)Math.pow(10,intLength / 2 - 1) + queries[i] - 1;
long k = 0;
for(int j = 0; j < intLength / 2; j++){
k *= 10;
k += t % 10;
t /= 10;
}
ans[i] = k + (long)(Math.pow(10,intLength / 2 - 1) + queries[i] - 1) * (long)Math.pow(10,intLength / 2);
}
else
for(int i = 0; i < queries.length; i++){
if(queries[i] - 1 >= 9 * Math.pow(10,intLength / 2)){
ans[i] = -1;
continue;
}
long t = (long)Math.pow(10,intLength / 2) + queries[i] - 1;
long k = 0;
for(int j = 0; j < intLength / 2; j++){
t /= 10;
k *= 10;
k += t % 10;
}
ans[i] = k + (long)(Math.pow(10,intLength / 2) + queries[i] - 1) * (long)Math.pow(10,intLength / 2);
}
return ans;
}
}
经典动态规划问题,
转移方程很容易想到 f[i][j]=max(f[i][j],f[i−1][j−w]+v)
f[i]f[i] 表示从前 i 个组取 j 枚硬币时,物品价值之和的最大值。
枚举第 i 个组的所有物品,设当前取 w 枚硬币,价值为 v
这里有一个超时的坑,对于这道题,我们每次都需要把每一个栈中的硬币取出来求和才能得到 v,而这一步骤存在于一个二重循环内,放大了这一步产生的时间复杂度,因此我们需要提前利用前缀和的思想,把每一个栈中取 n 枚硬币的价值计算好,省去每一次重复计算
class Solution {
public int maxValueOfCoins(List<List<Integer>> piles, int k) {
int[][] dp = new int[piles.size()][k + 1];
for(int i = 1; i < k+ 1 && i <= piles.get(0).size(); i++)
dp[0][i] = dp[0][i - 1] + piles.get(0).get(i - 1);
for(int i = piles.get(0).size() + 1; i < k + 1; i++)
dp[0][i] = dp[0][i - 1];
for(int i = 1; i < piles.size(); i++){
int m = piles.get(i).size();
for(int j = 1 ; j < piles.get(i).size(); j++)
piles.get(i).set(j,piles.get(i).get(j) + piles.get(i).get(j - 1));
for(int j = 1; j < k + 1; j++){
dp[i][j] = dp[i - 1][j];
for(int n = 1; n <= j && n - 1 < m; n++){
dp[i][j] = Math.max(dp[i][j],piles.get(i).get(n - 1) + dp[i - 1][j - n]);
}
}
}
return dp[piles.size() - 1][k];
}
}