数组、字符串
一、合并有序数组
给你两个按 非递减顺序 排列的整数数组
nums1
和nums2
,另有两个整数m
和n
,分别表示nums1
和nums2
中的元素数目。请你 合并
nums2
到nums1
中,使合并后的数组同样按 非递减顺序 排列。注意:最终,合并后数组不应由函数返回,而是存储在数组
nums1
中。为了应对这种情况,nums1
的初始长度为m + n
,其中前m
个元素表示应合并的元素,后n
个元素为0
,应忽略。nums2
的长度为n
。
即要把nums2复制到nums1,要考虑复制速度。
最直接做法是将nums2接到后面然后快排O(nlogn);
P.S.insert不能用,因为nums1的长度已经是m+n;
O(n+m) 做法:
法1:慢一点,要交换,冒泡步骤相当于插入,后面还要复制,回溯
void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
int i=m-1,j=n-1;
while(i>=0&&j>=0){
while(j>=0&&nums1[i]<=nums2[j]){j--;}
if(j>=0)swap(nums1[i],nums2[j]);
int k=i;
while(k>0&&nums1[k-1]>nums1[k]){swap(nums1[k],nums1[k-1]);k--;}
}
for(int k=0;k<n;k++)nums1[k+m]=nums2[k];
}
法2:一遍扫描,不用回溯,且直接覆盖(最长时间k决定,m+n):
void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
int k=m+n-1;
m--;
n--;
while(n>=0){
while(n>=0&&(m<0||nums2[n]>=nums1[m]))nums1[k--]=nums2[n--];
if(n<0)break;
while(m>=0&&nums1[m]>=nums2[n])nums1[k--]=nums1[m--];
}
}
二、移除元素
给你一个数组
nums
和一个值val
,你需要 原地 移除所有数值等于val
的元素,并返回移除后数组的新长度。不要使用额外的数组空间,你必须仅使用
O(1)
额外空间并 原地 修改输入数组。元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
int removeElement(vector<int>& nums, int val) {
int j=nums.size()-1;
while(j>=0){
while(j>=0&&nums[j]==val)j--;
int i=j;
while(i>=0&&nums[i]!=val)i--;
if(i<0)break;
swap(nums[i],nums[j]);
}
return j+1;
}
三、删除数组重复项
给你一个 非严格递增排列 的数组
nums
,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。然后返回nums
中唯一元素的个数。考虑
nums
的唯一元素的数量为k
,你需要做以下事情确保你的题解可以被通过:
- 更改数组
nums
,使nums
的前k
个元素包含唯一元素,并按照它们最初在nums
中出现的顺序排列。nums
的其余元素与nums
的大小不重要。- 返回
k
。
class Solution {
public:
int removeDuplicates(vector<int>& nums) {
int i=nums.size()-1;
int len=nums.size();
int j=i;
while(i>0){
while(j>0&&nums[j]!=nums[j-1])j--;
int k=j-1;
while(k>=0&&nums[k]==nums[j])k--;
k++;
len-=(j-k);
int q=k;
while(j>0&&j<i)swap(nums[++q],nums[++j]);
i=q;
j=k;
}
return len;
}
};
四、找多数元素--投票法
给定一个大小为
n
的数组nums
,返回其中的多数元素。多数元素是指在数组中出现次数 大于⌊ n/2 ⌋
的元素。
维护目标数变量result(int),和出现次数count
遍历若当前值等于result(投给了result),count+1,否则(没投给result),若count为0,result更新(count不能为负数,或消耗完了投票),若count不为0,count-1;
int majorityElement(vector<int>& nums) {
int result=nums[0];
int count=0;
for(int i=1;i<nums.size();i++){
if(nums[i]==result)count++;
else {
if(!count)result=nums[i];
else count--;
}
}
return result;
}
五、轮转数组
给定一个整数数组
nums
,将数组中的元素向右轮转k
个位置,其中k
是非负数。
法一:逐个轮转,用零时变量存被覆盖值
void rotate(vector<int>& nums, int k) {
int n=nums.size();
k=k%n;
int count=0,tmp=0,i=0,start=0;
while(count<n){
start=i;
tmp=nums[start];
do{
i=(i+k)%n;
swap(nums[i],tmp);
count++;
}while(i!=start);
i++;
}
return;
}
法二:翻转数组
void reverse(vector<int>& nums,int begin,int end){
for(int i=begin,j=end;i<j;i++,j--)swap(nums[i],nums[j]);
}
void rotate(vector<int>& nums, int k) {
int n=nums.size();
reverse(nums,0,n-1);
reverse(nums,0,k%n-1);
reverse(nums,k%n,n-1);
return;
}