1. 统计三元组
按照题意写就行
class Solution {
// 题意:i和j的差距小于a,j和k的差距小于b,i和k的差距小于c
public int countGoodTriplets(int[] arr, int a, int b, int c) {
int res = 0;
int length = arr.length;
for (int i = 0; i < length - 2; i++) {
for (int j = i+1; j < length - 1; j++) {
for (int k = j+1; k < length; k++) {
if (Math.abs(arr[i] - arr[j]) <= a && Math.abs(arr[j] - arr[k]) <= b && Math.abs(arr[i] - arr[k]) <= c) {
res++;
}
}
}
}
return res;
}
}
2.找游戏的赢家
// 比赛中提交的代码
class Solution {
public int getWinner(int[] arr, int k) {
int length = arr.length;
// -----------------------------
// 如果k大于(数组长度-1)也就是说最终的结果至少需要大于(数组长度-1)个不同的数。所以直接返回最大值。
if(k>=length-1) {
Arrays.sort(arr);
return arr[length-1];
}
// --------------------------------
// 按照题意不断向后遍历寻找,
// cur为当前最大的值,count为当前最大值比过的次数。
// 如果满足题意,直接返回即可
int count = 0;
int cur = arr[0];
for(int i=1;i<arr.length;i++) {
if(cur>arr[i]) {
count++;
} else {
cur = arr[i];
count = 1;
}
if(count==k) return cur;
}
// 如果没有在上述操作中返回,可知已经遍历完整个数组了。此时cur就是数组的最大值,
// 接下来无论如何比较,cur是最大,cur的值不会改变,所以直接返回即可。
return cur;
}
}
// 实际上k>length-1并不需要单独讨论。
3. 二进制网格的最小交换次数
// 比赛中提交的代码
class Solution {
private void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
public int minSwaps(int[][] grid) {
int n = grid.length;
int[] arr = new int[n];
// 获取每一行的从右到左连续的0的个数
for (int i = 0; i < n; i++) {
//
int temp = 0;
for (int j = n - 1; j > 0; j--) {
if (grid[i][j] == 0) {
temp++;
} else {
break;
}
}
arr[i] = temp;
}
int index = 0;
int res = 0;
for (int i = n - 1; i > 0; i--) {
if (arr[index] < i) {
// 该行不满足条件,往后找满足条件的那一行
for (int j = index + 1; j < n; j++) {
if (arr[j] >= i) {
res = res + (j - index);
for(int k=j;k>index;k--) {
swap(arr, k, k-1);
}
break;
}
}
if(arr[index]<i) return -1;
}
index++;
}
// // 判断最终是否会成功
// Arrays.sort(arr);
// for (int i = 0; i < arr.length; i++) {
// if (arr[i] < i) return -1;
// }
return res;
}
}
- 本题思路:
- 统计每一行,从右向左的连续为0的个数。保存到一个数组中
- 模拟交换,使得该数组对应的矩阵满足题目条件,返回交换的次数。
- 注意只能相邻两行交换,也就是数组的相邻两个数交换。比如1 2 3 4, 将4换到1,交换后结果为4 1 2 3
- 发现不满足条件的数时,向后查找,发现查找数满足条件,即可将该数交换到不满足位置。因为遍历的顺序是从要求连续0的个数最大到最小,所以后面有更能满足的,也不需要考虑。并且这样能使交换次数最少。
- 例如要求 第一位大于3,第二位大于2,第三位大于1,第四位大于0.
- 对于1 0 3 4(只是对问题的抽象)3换到1即可,不用考虑4的问题。4放到条件更宽松的后面位置也不会对是否能成功产生影响。
4. 最大得分
- 这题还是被大于10_0000_0007需要取余坑了,练的太少…在中间过程也不断取余,结果在最后比较之前取余了,导致结果错误,而且错误的版本数组太大也debug不了没发现错误。
- Java中long的范围(-2的63次方)-(2的63次方-1)9223372036854775807:十九位
- 这道题中1 <= nums1[i], nums2[i] <= 10^7
- 这道题中1 <= nums1/2.length <= 10^5
- 和最多也是12位,所以使用long是满足要求的。只需要在末尾取余即可。int的范围是(-2的31次方)-(2的31次方-1)2147483647十位显然不满足。
- 模拟大佬C++的Java版本。
class Solution {
public int maxSum(int[] nums1, int[] nums2) {
int m = nums1.length;
int n = nums2.length;
long t1 = 0, t2 = 0;
int i = 0, j = 0;
while (i < m || j < n) {
if (i < m && j < n) {
if (nums1[i] < nums2[j]) {
t1 += nums1[i++];
} else if (nums1[i] > nums2[j]) {
t2 += nums2[j++];
} else {
long best = Math.max(t1, t2) + nums1[i];
t1 = t2 = best;
++i;
++j;
}
} else if (i < m) {
t1 += nums1[i++];
} else if (j < n) {
t2 += nums2[j++];
}
}
return (int) (Math.max(t1, t2) % 1000000007);
}
}
- 自己的最终代码修改正确后
class Solution {
public static int maxSum(int[] nums1, int[] nums2) {
Set<Integer> set = new HashSet<>();
int index = 0;
for (int i = 0; i < nums1.length; i++) {
for (int j = index; j < nums2.length; j++) {
if (nums1[i] == nums2[j]) {
set.add(nums1[i]);
index = j + 1;
break;
} else if (nums1[i] < nums2[j]) {
index = j;
break;
}
}
}
long sum1 = 0;
long sum2 = 0;
int index2 = 0;
for (int i = 0; i < nums1.length; i++) {
sum1 += nums1[i];
if (set.contains(nums1[i])) {
while (nums2[index2] != nums1[i]) {
sum2 += nums2[index2];
index2++;
}
sum2 += nums2[index2];
index2++;
long max = Math.max(sum1, sum2);
sum1 = max;
sum2 = max;
}
}
while (index2<nums2.length) {
sum2+=nums2[index2];
index2++;
}
return (int)(Math.max(sum1,sum2)%10_0000_0007);// 这里注意顺序,如果不加后面的括号会先执行int强转,然后取余。这就错了(越界得话丢弃)。必须先取余再强转。
}
}
-
自己的思路就是首先找到所有相同的元素,放到一个set中。
-
从左到右遍历一个数组,一旦发现当前元素在set中,则将比较两个数组前面所有数的最大值,最为两个数组当前的最大值。(类似于动态规划。)
-
大佬的代码为什么那么简洁呢?大佬的代码每次只比较一位,每次索引只向后移动一位,开始没想到这种写法,导致写得复杂了。