程序员进阶之算法练习(十七)

2023-09-23 18:40:35 浏览数 (2)

前言

正文6道题目来自leetcode––为求职为生的编程网站,目的是工作闲暇之时锤炼代码功底。

如何从这篇文章受益?

先看题目大意,对照Example的样例理解题目意思; 尝试解答,得到自己的答案,并分析时间和空间复杂度; 思考完毕,看题目解析,对比分析自己解法的异同和优劣。

题目大都是LeetCode的hard难度。

正文

41.First Missing Positive

题目链接

题目大意:

给出一个数组,找到数组中没有的最小正整数。

要求:O(N)的时间和O(1)的空间复杂度;

Example Given 1,2,0 return 3, and 3,4,-1,1 return 2.

** 题目解析:**

先不考虑题目要求的时间、空间复杂度;

暴力的做法有两个:

1、时间最快,空间不限:数组aN,然后出现数字k就ak=1标志出现;

2、时间、空间都不限:排序,遍历一遍数组;

回到题目的要求,时间复杂度要求是O(N),可以肯定是会用到方法1;

现在要求O(1)的空间复杂度,那么就必须利用上给出的数组。

遍历数组,如果数字k小于n且非负,那么ak-1=k-1;

然后遍历一遍,ai != i的就行是解。

** 复杂度解析:**

O(N)的时间和O(1)的空间复杂度;

** 其他解法:**

基数排序。

从低位开始,

当前第i位,统计0出现x次,1出现y次,(x y == n)

再次扫描数组,可以直接确定每个数字该排在哪里。

if bit = 0 then

idx = total_y (total_x-left_x)

....

基数排序解法

45. Jump Game II

题目链接

**题目大意: **

给出一个数组,数组上的值表示能前进的距离;

现在从pos=0的位置向右出发,问最少需要走几步才能到达终点。

Example 输入 A = 2,3,1,1,4 返回 2 因为可以从pos=0走到pos=1,然后直接到达pos=4;

题目解析:

第一反应就是bfs,但是bfs需要每次判断距离i 1, i k内的点是否访问,导致时间复杂度是O(N^2);

这个题也可以用动态规划:

dpi表示到达i的最短步数;

那么状态方程可以写成dpi k=min(dpi k, dpi 1); k∈1, nums(i)

这样对于每个i都需要去更新后面numsi状态,故而复杂度也是O(N^2);

对状态转移方程稍作修改:

dpi = min(dpi, dpk 1); k numk >= i 且 k < i

这样可以建一个dpi的优先队列,先按照步数排序,再按能到达的距离排序;

每次从队列的顶端拿出步数最小的dp值,判断pos的有效区间是否覆盖当前位置i;

如果不覆盖,那么对i 1必然也不覆盖,可以丢弃;

如果覆盖,则直接dpi=dpk 1,并把(dpi,i numsi)放入优先队列;

复杂度是O(NlogN)。

提交后,非常遗憾的收获TLE...

仔细观察dpi的性质,可以得出一个结论:

步数越大,能到达的距离就越远;

那么先建一个队列,保证步数最小的在前面,后面是步数大但是覆盖距离较远的备选;

这样可以O(1)取出最优解;

并且可以设定一个maxRight,表示队列当前最远的覆盖距离,如果没有大于这个数字,可以不用放入队列;

这样可以在O(N)的时间/空间复杂度解决问题。

** 复杂度解析: **

O(N)的时间/空间复杂度解决问题。

84. Largest Rectangle in Histogram

题目链接

** 题目大意:**

给出一个数组,数组ai表示第i栋楼的高度;

求出最大矩形的面积。

example, Given heights = 2,1,5,6,2,3, return 10。

样例的图

最大的面积

题目解析:

维护一个高度不减少的栈,每次可以通过栈,快速得出面积。

** 复杂度解析:**

时间复杂度是O(N)

空间复杂度是O(N)

** 代码量:**

代码语言:javascript复制
int largestRectangleArea(vector<int>& heights) {
        int ret = 0;
        heights.push_back(0);
        stack<int> s;
        for (int col = 0; col < heights.size();   col) {
            while (!s.empty() && heights[col] < heights[s.top()]) {
                int top = s.top();
                s.pop();
                int area = heights[top] * (s.empty() ? col : (col - s.top() - 1));
                ret = max(ret, area);
            }
            s.push(col);
        }
        return ret;
    }

85. Maximal Rectangle

题目链接

** 题目大意:**

给出一个01矩阵,求全为1的最大的矩形的面积;

For example, given the following matrix: 1 0 1 0 0 1 0 1 1 1 1 1 1 1 1 1 0 0 1 0 Return 6.

最大面积如上,为6

** 题目解析:**

假设最后的矩形是(i, j)到(x, y),01矩阵为n*m矩阵;

从1到n枚举y,那么要求变成矩形贴着底边,然后面积尽可能大。

把与底部连着的1统计起来,例如当row=3的时候,分别为3,1,3,2,2;

此时,题目与84. Largest Rectangle in Histogram完全一致;

维护一个高度不减少的栈,每次可以通过栈,快速得出面积。

** 复杂度解析:**

时间复杂度是O(N)

空间复杂度是O(N)

97. Interleaving String

题目链接

题目大意:

给出三个字符串s1,s2,s3;

判断字符串s3能否由字符串s1和s2组成,要求s1的字符串内字符的相对顺序不变,s2同理。(假如s1=abc,那么在s3中,就不能变成bac,相对顺序必须是abc)

For example, Given: s1 = "aabcc", s2 = "dbbca", When s3 = "aadbbcbcac", return true. When s3 = "aadbbbaccc", return false.

** 题目解析:**

动态规划。

dpi 表示s1的前i个字符,s2的前j个字符,组成的字符串是否为s3的前i j个字符。

dp0=true,表示初始状态。

假设dpi=true,那么表示s1的前i个字符,s2的前j个字符,与s3的前i j个字符是匹配的。

那么只要s1i 1==s3i j 1,那么dpi 1=true;

同理,有dpi=true && s2j 1 == s3i j 1 => dpi=true

最后看dpn是否为true即可。

** 复杂度解析:**

时间和空间复杂度是O(NM) N是s1长度,M是s2长度;

*** 135. Candy ***

题目链接

** 题目大意:**

n个人排成一行,每个人有一个rating的数值。

现在给所有人分配糖果,要求:

1、每个人至少有一个;

2、rating比身边人高的分配到更多的糖果。

问最少需要多少糖果。

题目解析:

假设所有人rating一致,那么需要n个糖果;

如果有一人rating更高,那么需要n 1;

如果有2人rating更高,则看两个人是否相邻,需要n 2或n 3个糖果;

以此,可以得出一种分配方案:

从最小的rating值开始分配,每次观看旁边的人是否有糖果:

如果身边人有糖果,则分配max(左边, 右边) 1;

如果身边人没有糖果,则分配1;

时间复杂度为O(NLogN),排序耗时。

收获一枚TLE;

那么对算法进行优化。

根据分配糖果的条件2,我们知道在一个单调递增中:(单调递减可以逆着看,就是单调递增)

分配的结果是1、2、3、4、5这样的序列;

那么,一个数组可以分成多个单调递增的序列;

然后反着遍历,找到单调递减的序列;

剩下的部分可以全部填1。

复杂度解析:

时间复杂度是O(N)

空间复杂度是O(N)

总结

给自己定的小目标50题,因为第一页某些题目质量较低,加了一些比较容易的目前进度33/50。

0 人点赞