算法训练营第1天

题目链接:704. 二分查找 & 27. 移除元素
今日学习的文章链接704. 二分查找 & 27. 移除元素和视频链接704. 二分查找 & 27.移除元素

704. 二分查找

自己看到题目的第一想法

二分查找,因为nums数组是升序,所以每次只需要比较下标的一半的值与target的大小关系。
因为是vector容器,所以可以使用vector_name.size()获得容器内元素个数,并且支持[]操作符获取指定元素。这样可以使用下标来进行取值和判断,比使用迭代器要方便的多。
需要手动模拟三个变量head tail middle在两种情况下的变化,从第二种情况得出循环的判定条件是head <= tail。两个示例已覆盖边界条件,无需其他判定。

class Solution {
public:
    int search(vector<int>& nums, int target) {
        int middle = 0, head = 0, tail = nums.size() - 1;
        while (head <= tail) {
            middle = (head + tail) / 2;
            
            if (target == nums[middle]) return middle;
            else if (target > nums[middle]) head = middle + 1;
            else tail = middle - 1;
        }
        return -1;
    }
};

看完代码随想录之后的想法

除了升序还需要注意无重复元素,否则返回的下标不是唯一的。此题难在边界条件确认,也就是循环不变量,每个循环开始之前,边界要确认下来,一般来讲常用两种情况:左闭右闭或左闭右开,循环不变量的意思就是在每次二分过程中,区间都要遵循自己的规定。

时复:O(logn),因为每次取一半。

自己实现过程中遇到哪些困难

时复一开始没有写。

今日收获,记录一下自己的学习时长

学到了左闭右开区间的写法,两个写法相同点在于坚持循环不变量

27. 移除元素

自己看到题目的第一想法

题干很长,有点儿唬人,看了半天,直接开写。暴力解法:新建一个vector数组,把不等于val的元素放进去,nums指向新的vector数组。

// 需要额外的数组,空间复杂度 O(n),时间复杂度 O(n)
class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        int k = 0;
        vector<int> expectedNums;
        for (auto i = nums.begin(); i < nums.cend(); i++) {
            if (*i != val) expectedNums.push_back(*i), k++;
        }
        nums = expectedNums;
        return k;
    }
};

看完代码随想录之后的想法

题目要求原地操作,所以不可用使用另外的数组。原地暴力解法:

// 时间复杂度 O(n^2),空间复杂度 O(1)
class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        int size = nums.size();
        for (int i = 0; i < size; i++) {
            if (nums[i] == val) {
                for (int j = i + 1; j < size; j++) {
                    nums[j - 1] = nums[j];
                }
                i--;
                size--;
            }
        }
        return size;
    }
};

快慢双指针解法:
思路在于数组的“删除”并不是真正的删除,而是更新也可以叫做覆盖。一个快指针,一个慢指针,快-寻找,慢-更新,更新是主要操作,因为是需要一个不含val的新数组,所以碰到不等于val的就进行更新。

// 时间复杂度 O(n),空间复杂度 O(1)
class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        int slow = 0, fast = 0;
        for (; fast < nums.size(); fast++) {
            if (nums[fast] != val) {
                nums[slow] = nums[fast];
                slow++;
            }
        }
        return slow;
    }
};

可以所代码简化,但是只是等价变形,并且不利于后来复习。

自己实现过程中遇到哪些困难

双指针解法需要自己模拟一遍,因为需要在原数组上进行更新覆盖,所以看起来/理解起来有点儿复杂。
最后返回slow就是新数组的个数,因为fast作为寻找新元素的快指针已经到循环终止条件了,不会再有新的元素,同时slow此时已经是指向下一个待判断元素。

今日收获,记录一下自己的学习时长

快慢双指针算法。

曾经的解法

1、卡题目条件,50是数组元素的最大值。用到库函数sort()

// 时间复杂度 O(nlogn),空间复杂度 O(1)
class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        int cnt = 0;
        for (int i = 0; i < nums.size(); i++) {
            if (nums[i] == val) {
                nums[i] = 51;
                cnt++;
            }
        }
        sort(nums.begin(), nums.end());
        // for (int i : nums) {
        //     cout << i << " ";
        // }
        return nums.size() - cnt;
    }
};

2、前后双指针解法:

class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        //特判:全部元素=val
        int flag = 0, cnt = 0;
        for (int i : nums) {
            if (i != val) flag = 1; 
            else cnt++;
        } 
        if (flag == 0) return 0;
        
        int i = 0, j = nums.size() - 1, tmp = 51;
        while (i < j) {
            if (nums[i] != val && i < j) {
                i++;                 
            }            
            if (nums[j] == val && i < j) {
                j--;                
            } 
            tmp = nums[i];
            nums[i] = nums[j];
            nums[j] = tmp;            
        }        
        //cout << nums.size() << cnt;
        return nums.size() - cnt;
    }
};
  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值