leetcode笔记|面试经典150

数组、字符串

一、合并有序数组

给你两个按 非递减顺序 排列的整数数组 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;
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值