- 找出两数组的不同
第一遍建立哈希表存值方便查找
第二遍寻找不同的数
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;
}
}
- 找到指定长度的回文数
观察每一个回文数,因为他们长度一样,所以我们只需要比较前一半的大小就可以知道两个回文数的大小。
因为第一位数不能为 0 ,所以我们可以给出第 n 小的数的前半部分为 10… + n - 1(有多少个0取决于intLength的大小),接下来只需要依据前半部分把数字补充完整就可以了
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;
}
}
- 从栈中取出 K 个硬币的最大面值和
经典动态规划问题,
转移方程很容易想到 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];
}
}