一、数组种的k个最强值
给你一个整数数组 arr
和一个整数 k
。设 m
为数组的中位数,只要满足下述两个前提之一,就可以判定 arr[i]
的值比 arr[j]
的值更强:
-
|arr[i] - m| > |arr[j] - m|
-
|arr[i] - m| == |arr[j] - m|
,且arr[i] > arr[j]
请返回由数组中最强的 k
个值组成的列表。答案可以以 任意顺序 返回。
思路:
最强值比较的规则为:和中位数的差值越大的最强。如果差值相同,大于中位数的强。
我们可以先排序,然后相向双指针,依次和中位数进行比较。
mid-nums[left] nums[right]-mid 比较这两个数字的大小
代码:
class Solution {
public int[] getStrongest(int[] arr, int k) {
Arrays.sort(arr);
int[] res = new int[k];
int left = 0;
int right = arr.length - 1;
int mid = arr[right / 2];
while (k>0) {
if (mid - arr[left] > arr[right] - mid)
res[--k] = arr[left++];
else if (mid - arr[left] <= arr[right] - mid)
res[--k] = arr[right--];
}
return res;
}
}
二、找到k个最接近的元素(相向双指针/固定长度的滑动窗口)
相向双指针(删除法):
思路:
因为要找到k个最接近的元素,所以要删除掉len-k个,那么删除掉哪些元素呢?
又因为数组是一个非递减的。
如果目标值x更接近左边,那么右边就要多删除一点;
如果目标值x更接近右边,那么左边就要多删除一点。
直到删除后的right-left+1==k
代码:
class Solution {
public List<Integer> findClosestElements(int[] arr, int k, int x) {
int left=0;
int right=arr.length-1;
List<Integer> res=new ArrayList<>();
while(right-left+1!=k){
if(Math.abs(arr[left]-x)<=Math.abs(arr[right]-x)){
right--;
}else{
left++;
}
}
for(int i=left;i<=right;i++){
res.add(arr[i]);
}
return res;
}
}
固定长度的滑动窗口:
思路:
因为元素的数目是固定的,所以滑动窗口的长度也是固定的。
从左往右遍历数组,当滑动窗口的长度==k的时候,如果此时相差值的和是更小的。那么就更新l,l,r。
代码:
class Solution {
public List<Integer> findClosestElements(int[] arr, int k, int x) {
//最接近的k个元素一定是一个连续子数组 所以也是一个滑动窗口
int left=0;
int right=0;
int sum=0;
int l=0;
int r=0;
int res=Integer.MAX_VALUE;
while(right<arr.length){
sum+=Math.abs(arr[right]-x);
if(right-left+1==k){
if(sum<res){
res=sum;
l=left;
r=right;
}
sum-=Math.abs(arr[left]-x);
left++;
}
right++;
}
List<Integer> ans=new ArrayList<>();
for(int i=l;i<=r;i++){
ans.add(arr[i]);
}
return ans;
}
}
三、数的平方等于两数乘积的方法数
题意:
给你两个整数数组 nums1
和 nums2
,请你返回根据以下规则形成的三元组的数目(类型 1 和类型 2 ):
- 类型 1:三元组
(i, j, k)
,如果nums1[i]2 == nums2[j] * nums2[k]
其中0 <= i < nums1.length
且0 <= j < k < nums2.length
- 类型 2:三元组
(i, j, k)
,如果nums2[i]2 == nums1[j] * nums1[k]
其中0 <= i < nums2.length
且0 <= j < k < nums1.length
代码:
class Solution {
public int numTriplets(int[] nums1, int[] nums2) {
return calCount(nums1, nums2) + calCount(nums2, nums1);
}
public int calCount(int[] nums1, int[] nums2) {
int res = 0;
for (int num : nums1) {
long square = (long) num * num;
Map<Long, Integer> productMap = new HashMap<>();
// 遍历 nums2 中的每对元素,寻找满足条件的三元组
for (int j = 0; j < nums2.length; j++) {
if (square % nums2[j] == 0) {
long complement = square / nums2[j];
res += productMap.getOrDefault(complement, 0);
}
// 更新当前 nums2[j] 的频次
productMap.put((long) nums2[j], productMap.getOrDefault((long) nums2[j], 0) + 1);
}
}
return res;
}
}