顺序表应用题

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++;
    }
}
posted @ 2022-08-20 18:35  失控D大白兔  阅读(16)  评论(0编辑  收藏  举报