每日一题记录
2022/8/24-1460. 通过翻转子数组使两个数组相等 【简】
一个结论:数组的两个元素可以通过有限次翻转子数组调换位置而其他元素位置不变:
1、两个元素相邻时,显然成立
2、两个元素之间有奇数个元素,反转两次即可。如:交换以3为轴分别翻转两次[1,2,3,4,5] ->[5,4,3,2,1]->[5,2,3,4,1]。
3、两个元素之间有偶数个元素,反转三次即可。如:[1,2,3,4,5,6]->[5,4,3,2,1,6]->[5,4,3,2,6,1]->[6,1,2,3,4,5,1]
推出第二个结论:只要两个数组所包含的元素及其数量完全一样,就能通过有限次翻转互相转化。
代码很简单,判断出上面第二个结论即可。
代码1:hashmap
//时间复杂度:O(n) 用到hashmap空间复杂度O(n)
class Solution {
public:
bool canBeEqual(vector<int>& target, vector<int>& arr) {
// 长度不同
if(target.size()!=arr.size()) return false;
// 长度为1
if(target.size() == 1 && target[0] == arr[0]) return true;
// 创建两个hash map
unordered_map<int,int> hashmap1;
unordered_map<int,int> hashmap2;
// 创建两个hash map
for(int num:target){
hashmap1[num]++;
}
for(int num:arr){
hashmap2[num]++;
}
// 若有不同的数量就直false,利用了当用hashmap[num]若该key不存在,会创建新键值对,value为0的特性
for(int num:target){
if(hashmap2[num]!=hashmap1[num]) return false;
}
return true;
}
};
代码1:排序后判断
//排序时间复杂度 O(nlogn) 空间复杂度
class Solution {
public:
bool canBeEqual(vector<int>& target, vector<int>& arr) {
sort(target.begin(), target.end());
sort(arr.begin(), arr.end());
return target == arr;
}
};
另外也有一种思路:冒泡排序就是交换位置的算法,各个元素都能交换位置。
2022/8/25-658. 找到 K 个最接近的元素 【中】
我的思路:
既然数组排序好,就用折半查找定位到离x最近的那个数字作为中轴,然后以该轴左边的k和右边的k个元素组成一个2k+1长度的窗口,然后慢慢比较窗口两端的数字和x值的差而缩小窗口。
有两个需要注意的地方:
1、中轴左边或右边都可能没有k个元素,此时需要判断,若左边没有k个元素,则窗口从0开始;若后面没有k个元素,窗口以size()-1结束。
2、因为窗口两端是离x最远的元素,当窗口左边元素比窗口右边元素更远,窗口左边向右缩小一格;其他情况窗口右边向左缩小一格(即便距离相等,窗口右边也要向左缩小)。
class Solution {
public:
vector<int> findClosestElements(vector<int>& arr, int k, int x) {
// 折半查找
int low=0, high = arr.size()-1 , mid;
while(high>=low){
mid = (low+high)/2;
if(arr[mid]==x) break;
else if(arr[mid]>x) high = mid - 1;
else low = mid + 1;
}
// 窗口左边和右边位置
int left = mid-k<0?0:mid-k;
int right = mid+k>arr.size()-1?arr.size()-1:mid+k;
// 缩小窗口
while(right-left>k-1){
if(abs(arr[left]-x)>abs(arr[right]-x)) left++;
else right--;
}
// 窗口内元素写入结果
vector<int> result;
for(int i =left; i <= right; i ++){
result.push_back(arr[i]);
}
return result;
}
};