Content
011 Container With Most Water(M)
Description
Given n non-negative integers a1, a2, …, an , where each represents a point at coordinate (i, ai). n vertical lines are drawn such that the two endpoints of the line i is at (i, ai) and (i, 0). Find two lines, which, together with the x-axis forms a container, such that the container contains the most water.
Notice that you may not slant the container.
示例可以参照链接leetcode011,题目实际就是求最大面积:
A
r
e
a
=
M
a
x
(
m
i
n
(
h
e
i
g
h
t
[
i
]
,
h
e
i
g
h
t
[
i
]
)
∗
(
j
−
i
)
)
{
0
<
=
i
<
j
<
h
e
i
g
h
t
.
s
i
z
e
(
)
}
Area = Max(min(height[i], height[i]) * (j-i)) \{0 <= i < j < height.size()\}
Area=Max(min(height[i],height[i])∗(j−i)){0<=i<j<height.size()}
Analysis & Solution
(1)暴力穷举
直接考虑,我们可以穷举出所有的
m
i
n
(
h
e
i
g
h
t
[
i
]
,
h
e
i
g
h
t
[
j
]
)
∗
(
j
−
i
)
min(height[i], height[j]) * (j-i)
min(height[i],height[j])∗(j−i),找出其中的最大值,显然时间复杂度为
O
(
n
2
)
O(n^2)
O(n2)。
(2)双指针
如何减少计算?这里可以引入双指针,指向数组的左端和右端。这时时间复杂度仅为
O
(
n
2
)
O(n^2)
O(n2)。
指针移动条件如何确定?直观上看,我们希望面积越大越好,因此应该舍弃
h
e
i
g
h
t
[
i
]
height[i]
height[i]和
h
e
i
g
h
t
[
j
]
height[j]
height[j]中较小的,即若
h
e
i
g
h
t
[
i
]
<
h
e
i
g
h
t
[
j
]
height[i]<height[j]
height[i]<height[j],令
i
+
+
i++
i++,否则
j
−
−
j--
j−−。
这是否合理呢?当
h
e
i
g
h
t
[
i
]
<
h
e
i
g
h
t
[
j
]
height[i]<height[j]
height[i]<height[j],实际此时的面积是以
h
e
i
g
h
t
[
i
]
height[i]
height[i]为高度的最大面积(指针移动后底边减少,因此面积只会更小)。因此指针移动条件是合理的。
Code
int maxArea(vector<int>& height)
{
int N = height.size();
int maxArea = 0;
int i = 0, j = N - 1;
while(i < j)
{
int curArea = min(height[i], height[j]) * (j - i);
maxArea = max(maxArea, curArea);
if(height[i] < height[j]) i++;
else j--;
}
return maxArea;
}
014 Longest Common Prefix
Description
Write a function to find the longest common prefix string amongst an array of strings.
If there is no common prefix, return an empty string “”.
题意为给出一个字符串构成的数组,求出这些字符串的公共前缀。(无公共前缀输出空字符串)
Analysis & Solution
这道题的方法比较多,我目前实现了其中一种复杂度较高的。
思路是首先编写一个函数可以求出两个字符串的公共前缀。然后,对于字符串数组,从前向后遍历,前面求出的公共前缀与后面的字符串用上述函数求公共前缀。遍历完成时,得到的就是数组中所有字符串的公共前缀。
Code
string longestCommonPrefix(vector<string>& strs)
{
int N = strs.size();
if(N == 0) return "";
if(N == 1) return strs[0];
int i = 0;
string res = longestCommonPrefix(strs[0], strs[1]);
for(int i = 2; i < N; i++)
res = longestCommonPrefix(res, strs[i]);
return res;
}
string longestCommonPrefix(string s1, string s2)
{
int len = min(s1.length(), s2.length());
int i = 0;
string res = "";
while(i < len && s1[i] == s2[i])
{
res.append(1, s1[i]);
i++;
}
return res;
}
015 3Sum
Description
Given an array nums of n integers, are there elements a, b, c in nums such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.
Notice that the solution set must not contain duplicate triplets.
题意为在数组中找出三个元素,使得它们的和为0,枚举出所有这样的组合并去除重复。
Analysis & Solution
若遍历所有三个元素,暴力枚举需花费时间
O
(
n
3
)
O(n^3)
O(n3),这是不可接受的,在leetcode平台提交也会超时。
如何减少列举的数量呢?只能偷看力扣的题解了。。。解法还是比较难构思的。
首先对数组进行排序。为什么排序呢?原数组本身是没有“结构”的,我们通过排序引入了“结构”,仅用
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn)的时间就为后面提供了很多方便。
然后我们就可以引入双指针。因为要找三个元素,因此我们先固定一个位置k,两个指针i和j分别指向k的下一个位置和数组末尾。
(1)nums[k]>0:由于数组已经排序,说明后面元素都为正,不可能有和为0的三元组,跳出循环。
(2)每次对i,j,k三个位置的元素求和,若sum==0,将此时的三元组存入结果;若sum>0,我们希望和更小,令右指针移动(j–);否则令左指针移动(i++)。
(3)去重。对于i,j,k在移动前,我们都需要判断与下一个元素是否相同,相同则直接跳过,可以省去重复的判断。
Code
vector<vector<int>> threeSum(vector<int>& nums)
{
vector<vector<int>> res;
int N = nums.size();
if(N < 3) return res;
sort(nums.begin(), nums.end());
for(int k = 0; k < N; k++)
{
if(nums[k] > 0) break;
if(k > 0 && nums[k] == nums[k-1]) continue;
int i = k + 1, j = N - 1;
while(i < j)
{
int sum = nums[k] + nums[i] + nums[j];
if(sum == 0)
{
vector<int> triplet{nums[k], nums[i], nums[j]};
res.push_back(triplet);
while(i < j && nums[i] == nums[i+1]) i++;
while(i < j && nums[j] == nums[j-1]) j--;
i++;
j--;
}
else if(sum > 0) j--;
else i++;
}
}
return res;
}