刷题日记:面试经典 150 题 DAY1

88. 合并两个有序数组

原题链接88. 合并两个有序数组

第一直觉:双指针,从前向后进行遍历。问题是题目要求将合并后的数组存储在第一个数组里,一开始没看见,解决方法是补一步数组复制即可。时间复杂度和额外空间复杂度都是 O ( m + n ) O(m+n) O(m+n)

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

后面去学习了官方题解给出的空间复杂度为 O ( 1 ) O(1) O(1)的解法。
直觉上,上面做法完全没有利用到nums1数组后面的部分,所以优化要从如何利用这部分空间开始。整体还是要选择双指针,但是从前向后这个做法行不通。
所以选择从后向前进行遍历即可。这里有一个问题,就是合并后新数组会不会覆盖原nums1的元素。简单的进行判断是不会的:假设我们从后向前已经合并了 ( n + s ) (n+s) (n+s)个元素(毕竟只有占满后面n个空位才有可能覆盖到原nums1的元素),再假设nums1我们已经遍历了 t t t个,nums2数组我们已经遍历了 l l l个,由于 n + s = t + l , l ≤ n n+s = t+l,l \leq n n+s=t+l,ln,得 t ≤ s t \leq s ts,即没有影响

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

27. 移除元素

原题链接:27. 移除元素

考虑双指针,本来想一个放数组头一个放数组尾,这样处理边界条件没处理明白。遂考虑快慢两指针。

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

26. 删除有序数组中的重复项

原题链接 26. 删除有序数组中的重复项

思路和上一题一模一样

class Solution {
public:
    int removeDuplicates(vector<int>& nums) {
        int slow = 0, fast = 0;
        for(;fast < nums.size();slow++) {
            nums[slow] = nums[fast];
            while(fast < nums.size() && nums[fast] == nums[slow]) {
                fast++;
            }
        }
        return slow;
    }
};

80. 删除有序数组中的重复项 II

原题链接:80. 删除有序数组中的重复项 II

和上题几乎一模一样,先按照上题的思路写

class Solution {
public:
    int removeDuplicates(vector<int>& nums) {
        int slow = 2, fast = 2;
        int len = nums.size();
        if(len <= 2) {
            return len;
        }
        for(;fast < len;slow++) {
            while(fast < len && nums[fast] == nums[slow-2]) {
                fast++;
            }
            nums[slow] = nums[fast++];
        }
        return slow;
    }
};

未通过[1,1,1]这样的边界,这是因为fast可能会在循环判断前就超出数组边界,加一句判断即可

class Solution {
public:
    int removeDuplicates(vector<int>& nums) {
        int slow = 2, fast = 2;
        int len = nums.size();
        if(len <= 2) {
            return len;
        }
        for(;fast < len;slow++) {
            while(fast < len && nums[fast] == nums[slow-2]) {
                fast++;
            }
            if(fast >= len) break;
            nums[slow] = nums[fast++];
        }
        return slow;
    }
};

感觉不是很优雅,去学习了题解

class Solution {
public:
    int removeDuplicates(vector<int>& nums) {
        int slow = 2, fast = 2;
        int len = nums.size();
        if(len <= 2) {
            return len;
        }
        for(;fast < len;fast++) {
            if(nums[slow-2] != nums[fast]) {
                nums[slow++] = nums[fast];
            }
        }
        return slow;
    }
};

感觉可能是for循环中判断和自增的东西保持一致比较好

169. 多数元素

原题链接 169. 多数元素

一个很经典的问题,官方题解中给出了较全的做法。有两个方法没那么直觉且有学习价值

  • 分治
  • Boyer-Moore 投票算法

分治法基于:

  • 将整体分成两个部分,整体的众数至少是其中一个部分的多数元素
  • 每次对半劈开,递归求解。合并时要判断其中一部分的多数元素是不是整体的多数元素

代码如下:

class Solution {
    int count(vector<int>& arr,int x,int h,int l) {
        int sum = 0;
        for(int i = l;i <= h;i++) {
            if(arr[i] == x) {
                sum++;
            }
        }
        return sum;
    }
    int f(vector<int>& nums,int h,int l) {
        if(h == l) {
            return nums[h];
        }
        int mid = (h+l)/2;
        int m_bound = (h-l+1)/2;
        int right_m = f(nums,h,mid+1);
        int left_m = f(nums,mid,l);
        if(count(nums,left_m,h,l) > m_bound) {
            return left_m;
        }
        if(count(nums,right_m,h,l) > m_bound) {
            return right_m;
        }
        return 0;
    }
public:
    int majorityElement(vector<int>& nums) {
        return f(nums,nums.size()-1,0);
    }
};

Boyer-Moore 投票算法基于:在一个集合中,如果同时拿掉两个不同的元素,集合的多数元素不变。(如果两个都不是原多数元素,显然不改变;如果其中一个是,则经过简单的计算也可得知不变)整个算法流程如下

  • 初始化一个计数和一个candidate
  • 如果当前计数为0,将当前元素赋给candidate
  • 如果当前元素和candidate相等,计数加1
  • 不等,减一
class Solution {
public:
    int majorityElement(vector<int>& nums) {
        int count = 0, candidate = nums[0];
        for(int num : nums) {
            if(count == 0) {
                candidate = num;
            }
            if(candidate == num) {
                count++;
            } else {
                count--;
            }
        }
        return candidate;
    }
};
  • 9
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值