Datawhale|LeetCodeTencent Task03(lc11,14,15)

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])(ji)){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])(ji),找出其中的最大值,显然时间复杂度为 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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值