玩转算法面试第三章——数组中的问题其实最常见

玩转算法面试第三章——数组中的问题其实最常见

3-1.从二分查找法看如何写出正确的程序

在这里插入图片描述
排序: 选择排序;插入排序;归并排序;快速排序
查找:二分查找法
数据结构:栈;队列;堆

  • 二分查找法
    比数组中查找最大值最小值要难一些
    但是没有实现快速排序法那么复杂。
    在这里插入图片描述
    在这里插入图片描述
    考虑好l和r的区间
    区间为闭区间 [ l…r ]:
    在这里插入图片描述

3-2.改变变量定义,依然可以写出正确的算法

如果l=0,r=n
区间为前闭后开:[l…r)

在这里插入图片描述

有个小bug,存在整型溢出
在这里插入图片描述
在这里插入图片描述

3-3.在LeetCode上解决第一个问题 Move Zeros

在这里插入图片描述
思路:
在这里插入图片描述

把非0元素填补到前面
在这里插入图片描述
后面全填0
在这里插入图片描述
代码:
时间复杂度:O(n)
空间复杂度:O(n)
不是原地操作,另外开辟了空间

#include<iostream>
#include<vector>

using namespace std;

class Solution {
public:

    void moveZeroes(vector<int>& nums) {
        vector<int> noZeroElement;
        for(int i = 0; i < nums.size() ;i++) {
            if (nums[i]!=0)
            {
                noZeroElement.push_back(nums[i]);
            }
        }

        for(int i = 0; i < noZeroElement.size() ; i++){
            nums[i] = noZeroElement[i];
        }
        for(int i = noZeroElement.size(); i < nums.size(); i++)
        {
            nums[i] = 0;
        }
    }
};
int main()
{
    int arr[] = {1,3,0,4,0,0,5,0,7};
    vector<int> vec(arr,arr + sizeof(arr)/sizeof(int));
    Solution().moveZeroes(vec);

    for (int (i) = 0; (i) < vec.size(); ++(i)) {
        cout << vec[i]<< " ";
    }
    cout << endl;
}

3-4.即使简单的问题,也有很多优化的思路

在这里插入图片描述
时间复杂度:O(1)
空间复杂度:O(1)

class Solution1 {
public:
    void moveZeroes(vector<int>& nums) {
        int k = 0 ; // nums中,[0。。。k)的元素均为非0元素
        //遍历到第i个元素后,保证[0…i]中所有非0元素都按照顺序排列在[0…k)中
        for(int i = 0 ; i < nums.size() ; i++)
        {
            if(nums[i] != 0)
            {
                nums[k++] = nums[i];
            }
        }
        for(int i = k ; i < nums.size() ; i++)
        {
            nums[i] = 0;

        }

    }
};

上面是先把非0提到前面然后后面全置位0 ,
我们还可以通过非0元素提前的同时交换0:

class Solution2 {
public:
    void moveZeroes(vector<int>& nums) {
        int k = 0 ; // nums中,[0。。。k)的元素均为非0元素
        //遍历到第i个元素后,保证[0…i]中所有非0元素都按照顺序排列在[0…k)中
        for(int i = 0 ; i < nums.size() ; i++)
        {
            if(nums[i] != 0)
            {
                //swap( nums[k++] , nums[i]);
                //面对特殊的测试用例,避免全0的数组,我们只是扫了一遍指针
                if( i != k)
                {
                	swap( nums[k++] , nums[i]);
                }
                else
                {
					k++;
				}
            }
        }


    }
};
27题

在这里插入图片描述
在这里插入图片描述

26题

在这里插入图片描述

80题

在这里插入图片描述

3-5.三路快排partition思路的应用 Sort Color

75题

在这里插入图片描述
所有元素的取值只有 0、1、2

计数排序

在这里插入图片描述
可以统计每个元素各有多少个,在放回数组

在这里插入图片描述
在这里插入图片描述

有没有方法只扫描一遍就完成排序操作

三路快速排序

在这里插入图片描述

88题

在这里插入图片描述

215题在这里插入图片描述

3-6.对撞指针 Two Sum II - Input Array is Sorted

167题

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
解法如下:通过两个索引,如果小于target就i++
在这里插入图片描述
i++
在这里插入图片描述
如果大于target
在这里插入图片描述
j–
在这里插入图片描述
通过两个索引向中间不断前行,在这个路径上找到答案。
在这里插入图片描述

前面提到的三路快排也可以理解成对撞指针。

125题

在这里插入图片描述
(ctype头文件)
tolower 大写字母转换成小写
isalnum 判断一个字符是否是字母或数字

在这里插入图片描述

344题

在这里插入图片描述
对撞指针去解决。

345题

在这里插入图片描述
原音:a e i o u

11题

在一个数组中找到两个墙,构成的水是最大值。
在这里插入图片描述

3-7.滑动窗口 Minimum Size Subarray Sum

上一节所介绍的对撞指针是双索引
在这里插入图片描述
还有一种双索引的技术是滑动窗口
在这里插入图片描述

209

在这里插入图片描述
什么叫子数组(不要求他们联系):
在这里插入图片描述
连续子数组:
在这里插入图片描述
在这里插入图片描述

思考题:
在这里插入图片描述
优化其sum和,时间复杂度到On2
在这里插入图片描述
滑动窗口算法思路:
在这里插入图片描述
不断的移动 j 直到遇到大与s的位置,记录长度s;
在缩小 i 的长度,sum和会少一些
在这里插入图片描述
如果和又小于s,又可以 j 往后移动,以此类推。
在这里插入图片描述
代码如下:
刚开始窗口里面应该不包含任何元素r = -1
int res = nums.size() + 1 刚开始把初始值设为一个最大值
更新res的最小值。
在这里插入图片描述

3-8.在滑动窗口中做记录 Longest Substring Without Repeating Characters

3题在这里插入图片描述

在这里插入图片描述

在这里插入图片描述在这里插入图片描述
如果j+1位置与 滑动窗口里面重复,当前子串就无法拓展了
在i从左边红色处++,重复的部分已经从数组里去除了。
在这里插入图片描述

关键问题是如何判断没有重复的字符呢?
在这里插入图片描述
通过一个数组就可以通过O1的时间复杂度判断是否重复

如果当前右边界的字符出现的次数为0,就往后移动一位,把这个数的频率++;
在这里插入图片描述
如果右边超出边界,缩小左边的窗口
在这里插入图片描述
在这里插入图片描述

438题

在这里插入图片描述
在这里插入图片描述

76题

在这里插入图片描述

在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值