0
点赞
收藏
分享

微信扫一扫

【学而时习之】线性表之数组OJ

mafa1993 2022-04-04 阅读 65

[线性表–数组OJ] (C/C++实现)

文章目录

1.leetcode 17.04. 消失的数字

题目描述:

示例:nums=[3,0,4,5,7,1,2],n=7 输出:6

解法一:扫一遍数组求出实际总和sum1,再利用==等差数列求和公式==,求出期望的总和sum2

sum2-sum1即为缺失的数字。

代码实现:

class Solution {
public:
    int missingNumber(vector<int>& nums) {
        int sum1=0;
        int sum2=(nums.size()+1)*nums.size()/2;
        for(int i=0;i<nums.size();i++)
            sum1+=nums[i];
        return sum2-sum1;
    }
};

解法二位运算):

首先,我们先来介绍一下异或(^)运算

借助位运算我们可以通过如下操作把这道题解决:

  1. nums数组中的所有元素异或一遍的结果存在ret
  2. ret再同1到n的所有数异或一遍,ret即为缺失的数字

因为,经历了上述操作,1-n出现的数字都异或了两遍,缺失的数字仅异或了一遍

代码实现:

class Solution {
public:
    int missingNumber(vector<int>& nums) {
        int ret=0;
        for(int i=0;i<nums.size();i++)
            ret^=nums[i];
        for(int i=1;i<=nums.size();i++)
            ret^=i;
        return ret;
    }
};

2. 数组中数字出现的次数(leetcode)

题目描述

一个整型数组 nums 里除两个数字之外,其他数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。

示例: nums=[1,1,2,3,3,4,5,5] 输出:[2,4]

代码实现

class Solution {
public:
    vector<int> singleNumbers(vector<int>& nums) {
        int val=0,flag=1;
        for(int i=0;i<nums.size();i++)
            val^=nums[i];
        while((val&flag)==0)
        {
            flag<<=1;
        }
        int a=0,b=0;
        for(int i=0;i<nums.size();i++)
        {
            if(nums[i]&flag)
                a^=nums[i];
            else
                b^=nums[i];
        }
        return {a,b};
    }
};

3. 二分查找(leetcode)

题目描述:

3-1.target 定义在[left,right] (左右都是闭区间的写法)

class Solution {
public:
    int search(vector<int>& nums, int target) {
        int left=0,right=nums.size()-1;
        while(left<=right)
        {
            int mid=(left+right)/2;
            if(nums[mid]>target)
                right=mid-1;
            else
            {
                if(nums[mid]<target)
                    left=mid+1;
                else
                    return mid;
            }
        }
        return -1;
    }
};
 int middle = left + ((right - left) / 2);// 防止溢出 等同于(left + right)/2

3.2. target定义在[left,right)的开区间中(左开右闭区的写法

class Solution {
public:
    int search(vector<int>& nums, int target) {
        int left=0,right=nums.size();//开区间
        while(left<right)//等于的情况没有意义
        {
            int mid=(left+right)/2;//可写成防止溢出的写法
            if(nums[mid]>target)//左区间
                right=mid;
            else
            {
                if(nums[mid]<target)
                    left=mid+1;
                else
                    return mid;
            }
        }
        return -1;
    }
};

解释:

①.while循环中判断条件等于就没有意义

②.target落在左区间内mid-1可能取到而mid不能取到,所以right=mid


4.移除元素(leetcode)

题目描述:

解法一:暴力循环,移动覆盖 O(N^2)

代码实现:

class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        int sz=nums.size();
        for(int i=0;i<sz;i++)
        {
            if(val==nums[i])
            {
                for(int j=i;j<sz-1;j++)
                    nums[j]=nums[j+1];
                i--;
                sz--;
            }
        }
        return sz;
    }
};

**解法二:双指针 **O(N)

这里我们介绍两种双指针实现方式来完成这一题

  1. 快慢指针

    思路:

    1. 我们开始时使得slowfast都为0
    2. 如果nums[fast] != val 和那么fastslow一起走,如果fast指的值等于valfast走而slow不走
    3. 每次fastslow实现一起走的时候,即为把fast指的的值给slow

    这样我们可以证明:fast走完一遍时,0~slow所有的值都不等于val

    class Solution {
    public:
        int removeElement(vector<int>& nums, int val) {
            int slow=0;
            for(int fast=0;fast<nums.size();fast++)
                if(nums[fast]!=val)
                    nums[slow++]=nums[fast];
            return slow;
        }
    };
    
  2. 左右指针

    思路:

    代码实现:

    class Solution {
    public:
        int removeElement(vector<int>& nums, int val) {
            int left=0,right=nums.size()-1;
            while(left<=right)
            {
                if(val==nums[left])
                {
                    nums[left]=nums[right];
                    right--;
                }
                else
                    left++;
            }
            return left;
        }
    };
    

5. 删除有序数组中的重复项(leetcode)

题目描述

思路:

  1. 升序排列:说明数组中重复出现的元素一定是连续的,不可能间断

  2. 我们用k表示删除元素(重复元素)的个数,val记录==上一层循环的nums[i]==

  3. 在当前循环层中如果val==nums[i],说明该层循环nums[i]为重复元素,根据我们在2中给的定义,k需要加1,val可以更新(但没必要)

  4. 当前循环层中的值不等于val,说明这个不是重复元素,i-k位置上的元素即为在[0,i)这个区间中第一个出现重复的元素(1中连续性结合2中定义得出)

  5. 扫完一遍后,nums.size()-k即为剩下元素的个数,且满足[0,nums.size()-k]区间上·不存在重复元素。

代码实现:

class Solution {
public:
    int removeDuplicates(vector<int>& nums) {
        int k=0,val=nums[0];
        for(int i=1;i<nums.size();i++)
        {
            if(val==nums[i])
            {
                k++;
            }
            else
            {
                val=nums[i];
                nums[i-k]=nums[i];
            }
        }
        return nums.size()-k;
    }
};

6.合并两个有序数组(leetcode)

题目描述:

思路:

因为两个数组都排好序,只需同时扫两个数组,每次把小的放到ans数组中

m==n扫完一遍后,两数组按序插入到ans

如果m != n最后只需把长的数组后面的元素统统放到ans中即可。

(这也是我们后续要写的==归并排序==的归并操作)

代码实现:

class Solution {
public:
    void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
        vector<int> ans;
        int i=0,j=0;
        while(i<m&&j<n)
        {
            if(nums1[i]<nums2[j])
                ans.push_back(nums1[i++]);
            else
                ans.push_back(nums2[j++]);
        }
        while(i<m)
            ans.push_back(nums1[i++]);
        while(j<n)
            ans.push_back(nums2[j++]);
        nums1=ans;
    }
};

7.轮转数组(leetcode)

解法一(原数组与轮转数组间的下标关系):

代码实现:

class Solution {
public:
    void rotate(vector<int>& nums, int k) {
       int size=nums.size();
       vector<int> ans(size);
       for(int i=0;i<size;i++)
           ans[(i+k)%size]=nums[i];
       nums=ans;
    }
};

解法二:三次逆置(个人觉得这个方法超秀😍😍)

代码实现:

class Solution {
public:
    void reverse(vector<int>& nums, int begin, int end)
    {
        int i=begin,j=end;
        while(i<j)
        {
            int tmp=nums[i];
            nums[i]=nums[j];
            nums[j]=tmp;
            i++,j--;
        }
    }
    void rotate(vector<int>& nums, int k) {
        int size=nums.size();
        reverse(nums,0,size-k%size-1);
        reverse(nums,size-k%size,size-1);
        reverse(nums,0,size-1);
    }
};

举报

相关推荐

0 条评论