顺序表应用题
1. 删除返回最小值并由最后元素填补
bool Del_Min(vector<int>& nums,int &val) {
if(nums.size()==0) return false;
int pos = 0;//假定0号元素最小
for(int i=1;i<nums.size();i++)
if(nums[i]<nums[pos])
pos = i;//找最小值下标
val = nums[pos];//返回最小值
nums[pos] = nums.back();//替换删除值
nums.pop_back();//长度减一
return true;
}
2. 逆置所有元素
void Reverse(vector<int>& nums) {
int n = nums.size();
for(int i=0;i<nums.size()/2;i++)
swap(nums[i],nums[n-1-i]);
}
3. 删除所有指定值
void del_x(vector<int>& nums,int val) {
//本质上是重新更改映射
int k =0;//记录不等于val的个数
for(int i=0;i<nums.size();i++)
if(nums[i]!=val)
nums[k++] = nums[i];
//修改数组长度为k
}
4. 有序表中删除所有指定范围值
//与题3解法相同,由于是有序表,也可以先找映射前后的下标,再一一映射
bool Del_s_t(vector<int>& nums,int s,int t) {
int i , j;
if(s>=t||nums.size()==0) return false;
for(i=0;i<nums.size()&&nums[i]<s;i++);//找映射左下标,第一个大于等于s的值
for(j=i;j<nums.size()&&nums[j]<=t;j++);//找映射右下标,第一个大于t的值
for(;j<nums.size();j++)
nums[i] = nums[j];//重新映射
//修改数组长度为i
return true;
5. 删除所有指定范围值
void Del_s_t(vector<int>& nums,int s,int t) {
//本质上是重新更改映射
int k =0;//记录不在目标范围的个数
for(int i=0;i<nums.size();i++)
if(nums[i]<s||nums[i]>t)
nums[k++] = nums[i];
//修改数组长度为k
}
6. 有序表中删除重复值
bool Del_same(vector<int>& nums) {
if(nums.size()==0) return false;
int i , j;//双指针映射
for(i=0,j=1;j<nums.size();j++)
if(nums[i]!=nums[j])
nums[++i] = nums[j];//拓展映射数组
//修改数组长度为i+1
return true;
}
7. 有序顺序表合并
vector<int> merge(vector<int>& v1,vector<int>& v2) {
vector<int> res(v1.size()+v2.size());
int i = 0,j=0,k=0;
while(i<v1.size()&&j<v2.size()){
if(v1[i]<v2[j]) res[k++] = v1[i++];
else res[k++] = v2[j++];
}
while(i<v1.size()) res[k++] = v1[i++];
while(i<v1.size()) res[k++] = v2[j++];
return res;
}
8. 两区域元素位置互换(原地)
//先全部逆置,再分区域逆置
void Exchange(vector<int>nums,int m,int n){
Reverse(nums,0,m+n-1);
Reverse(nums,0,n-1);
Reverse(nums,n,m+n-1);
}
void Reverse(vector<int>& nums,int left,int right) {
for(int i=left;i<(left+right)/2;i++)
swap(nums[i],nums[right-i]);
}
9. 二分查找并插入
void bisearch(vector<int> nums,int val.int n){
int low = 0,high = n-1;
int mid;
while(low<=high){//循环结束后,若没找到,high小于val,low大于val
mid = (low + high)/2;
if(nums[mid]==val) break;//找到目标值
else if(nums[mid]<val) low = mid + 1;
else high = mid -1;
}
if(nums[mid]==val&&mid!=n-1)
swap(nums[mid],nums[mid+1]);//题目要求
if(low>high){
for(i=n-1;i>high;i--) nums[i+1] = nums[i];//后移元素,空出high后面元素
nums[high+1] = val;//插入值
}
}
10. 循环左移p个位置
//最优解类似题8,实质上等价于将p个元素区域和n-p个元素区域互换
三个逆置时间复杂度分别为O(p/2),O((n-p)/2),O(n/2)
故时间复杂度为O(n),空间复杂度为O(1)
//解法2借用一个辅助单元实现右移1位的操作,循环p次
//解法3借用p个辅助单元来进行移动
11. 求两升序序列中位数
//由于题目是等长序列,可以简单递归使问题规模不断变小
int medium(vector<int>& nums1, vector<int>& nums2, int s1, int d1, int s2, int d2) {
//之所以偶数递归加一,是因为整除向下取整
int m1 = (s1 + d1) / 2;
int m2 = (s2 + d2) / 2;
if (s1 == d1 && s2 == d2) return nums1[s1] < nums2[s2] ? nums1[s1] : nums2[s2];//边界条件
if (nums1[m1] == nums2[m2]) return nums1[m1];
if (nums1[m1] < nums2[m2]) {
if ((s1 + d1) % 2 == 0)//若元素个数为奇数
return medium(nums1, nums2, m1, d1, s2, m2);//舍弃nums1前面元素和nums2后面元素
else //若元素个数为偶数
return medium(nums1, nums2, m1 + 1, d1, s2, m2);//舍弃并保证双方还是偶数
}
else {
if ((s2 + d2) % 2 == 0)//若元素个数为奇数
return medium(nums1, nums2, s1, m1, m2, d2);//舍弃nums1后面元素和nums2前面元素
else //若元素个数为偶数
return medium(nums1, nums2, s1, m1, m2 + 1, d2);//舍弃并保证双方还是偶数
}
}
12. 找主元素(多数元素)
使用摩尔投票法
//投票选举进行抵消的方式,多数元素必将获胜
int majorityElement(vector<int>& nums) {
int candidate = -1;//不确定候选人
int count = 0;//初始票数为0
for (int num : nums) {//遍历全部投票
if (num == candidate)//投票跟候选人一致
++count;//票数增加
else if (--count <0) {//不一致将票数抵消,如果此时票数为负
candidate = num;//更改当前人为候选人
count = 1;//票数置为1
}
}
return candidate;
}
13. 找未出现最小正整数
数组作哈希表
int FindMissMin(int nums[],int n){
int* hash;
hash = (int*)malloc(sizeof(int)*(n+1));//哈希数组,0位置不分配
memset(hash,0,sizeof(int)*(n+1));//初始化
for(int i=0;i<n;i++)
if(nums[i]>0&&nums[i]<=n)
hash[nums[i]]++;//记录个数
int i;//用于返回结果
for(i=1;i<=n;i++)
if(hash[i]==0) break;
return i;//返回未被记录最小整数
}
14. 三个升序数组的最小距离
贪心更新最左端端点用于计算距离
int FindMinDis(vector<int>&A,vector<int>&B,vector<int>&C){
int i=0.j=0,k=0;//三个下标
int l1 =A.size(),l2 = B.size(),l3 = C.size();
int res = INT_MAX;
while(i<l1&&j<l2&&k<l3){//当最左端无法再移动,跳出循环
int D = abs(A[i]-B[j])+abs(A[i]-C[k])+abs(B[j]-C[k]);//计算距离
if(D<res) res = D;//更新最小距离
//贪心移动下标
if(A[i]<B[j]&&A[i]<C[k]) i++;
else if(B[j]<A[i]&&B[j]<C[k]) j++;
else k++;
}
}