Skip to main content

4、贪心双指针问题

Y-aong...About 6 min算法算法贪心算法双指针

4、贪心双指针问题

605. 种花问题open in new window——种花问题

假设有一个很长的花坛,一部分地块种植了花,另一部分却没有。可是,花不能种植在相邻的地块上,它们会争夺水源,两者都会死去。

给你一个整数数组 flowerbed 表示花坛,由若干 01 组成,其中 0 表示没种植花,1 表示种植了花。另有一个数 n ,能否在不打破种植规则的情况下种入 n 朵花?能则返回 true ,不能则返回 false

示例 1:

输入:flowerbed = [1,0,0,0,1], n = 1
输出:true

示例 2:

输入:flowerbed = [1,0,0,0,1], n = 2
输出:false

提示:

  • 1 <= flowerbed.length <= 2 * 104
  • flowerbed[i]01
  • flowerbed 中不存在相邻的两朵花
  • 0 <= n <= flowerbed.length

我觉得这道题非常巧妙,难度也不算太大,但是思路也还是比较巧妙的,让你觉得有思路但是又有点难以下手。其实只要把条件处理清楚了也是比较好做的。

1 0 0 0 1 0 0 1

情况一:当i = 0, nums[i]==1,我们需要判断i=3的情况,

情况二:当i=3,nums[i] =0,我们有需要分两个情况:

  • 情况一:nums[i+1] == 1,i = i+1+2,加一是到情况一,再加2是从情况一开始判断
  • 情况二:nums[i+1] == 0,这个位置我们是可以种花的

问题一,能不能种n个花:

class Solution:
    def canPlaceFlowers(self, flowerbed: List[int], n: int) -> bool:
     
        left = 0
        while left < len(flowerbed) and n > 0:
            if flowerbed[left] == 1:
                left += 2
            elif flowerbed[left] == 0:
                if left + 1 == len(flowerbed) or flowerbed[left + 1] == 0:
                    n -= 1
                    left += 2
                else:
                    left += 3
        return n == 0

问题二:最多中多少个花

class Solution:
    def canPlaceFlowers(self, flowerbed: List[int]) -> bool:
        left = 0
        result = 0
        while left < len(flowerbed):
            if flowerbed[left] == 1:
                left += 2
            elif flowerbed[left] == 0:
                if left + 1 == len(flowerbed) or flowerbed[left + 1] == 0:
                    result += 1
                    left += 2
                else:
                    left += 3
        return result

问题三:返回种完花的花坛

class Solution:
    def canPlaceFlowers(self, flowerbed: List[int]) -> bool:
        left = 0

        while left < len(flowerbed):
            if flowerbed[left] == 1:
                left += 2
            elif flowerbed[left] == 0:
                if left + 1 == len(flowerbed) or flowerbed[left + 1] == 0:
                    flowerbed[left] = 1
                    left += 2
                else:
                    left += 3
        return flowerbed

11. 盛最多水的容器open in new window

给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0)(i, height[i])

找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。

返回容器可以储存的最大水量。

**说明:**你不能倾斜容器。

示例 1:

img
img
输入:[1,8,6,2,5,4,8,3,7]
输出:49 
解释:图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。

示例 2:

输入:height = [1,1]
输出:1

思路:

当前矩形的面积是多少:(right-left)*min(height[left], height[right])

只要能想到这里就很好解决了

class Solution:
    def maxArea(self, height: List[int]) -> int:
        result = 0

        left = 0
        right = len(height) - 1
        while left <= right:
            cur_area = min(height[left], height[right]) * (right - left )
            result = max(cur_area, result)

            if height[left] < height[right]:
                left += 1
            else:
                right -= 1
        return result

881. 救生艇open in new window

给定数组 peoplepeople[i]表示第 i 个人的体重 ,船的数量不限,每艘船可以承载的最大重量为 limit

每艘船最多可同时载两人,但条件是这些人的重量之和最多为 limit

返回 承载所有人所需的最小船数

示例 1:

输入:people = [1,2], limit = 3
输出:1
解释:1 艘船载 (1, 2)

示例 2:

输入:people = [3,2,2,1], limit = 3
输出:3
解释:3 艘船分别载 (1, 2), (2) 和 (3)

示例 3:

输入:people = [3,5,3,4], limit = 5
输出:4
解释:4 艘船分别载 (3), (3), (4), (5)

思路:

优先让船装重量小的两个人,然后在装重量大的一个人的,那么我们需要先对重量进行排序,让重量少的尽量在一起且有序,然后使用双指针进行遍历

class Solution:
    def numRescueBoats(self, people: List[int], limit: int) -> int:
        result = 0

        left = 0
        right = len(people) - 1

        people.sort()
        while left <= right:
            if people[left] + people[right] > limit:
                right -= 1
            else:
                left += 1
                right -= 1

            result += 1

        return result

611. 有效三角形的个数open in new window

给定一个包含非负整数的数组 nums ,返回其中可以组成三角形三条边的三元组个数。

示例 1:

输入: nums = [2,2,3,4]
输出: 3
解释:有效的组合是: 
2,3,4 (使用第一个 2)
2,3,4 (使用第二个 2)
2,2,3

示例 2:

输入: nums = [4,2,3,4]
输出: 4

提示:

  • 1 <= nums.length <= 1000
  • 0 <= nums[i] <= 1000

这题我一开始使用的回溯算法,因为我看到了这个是求的是组合

class Solution:
    def triangleNumber(self, nums: List[int]) -> int:
        result = []
        self.back_tracking(nums, [], result, 0)
        print(result)
        return len(result)

    def check(self, path: list):
        x, y, z = path
        return x + y > z and x + z > y and y + z > x

    def back_tracking(self, nums: list, path: list, result: list, index: int):
        if len(path) == 3 and self.check(path):
            result.append(path[:])
            return

        for i in range(index, len(nums)):
            path.append(nums[i])
            self.back_tracking(nums, path, result, i + 1)
            path.pop()

正确思路:

三角形的定义,任意两边之和要大于第三边,因此我们需要先对数据进行排序,然后遍历数据用较短的两个边相加和第三个边进行比较,判断是否满足条件,感觉和三数之和有点相似

class Solution:
    def triangleNumber(self, nums: List[int]) -> int:
        # x, y, z从小到大,一定满足x+y > z
        nums.sort()
        result = 0

        for right in range(2, len(nums)):
            left = 0
            middle = right - 1
			# 先确定最右边
            while left < middle :
                if nums[left] + nums[middle] > nums[right]:
                    # 这里一旦满足条件就可以证明[left, middle]之间的所有数都是可以组合为三角形的
                    result += middle - left
                    middle -= 1
                else:
                    left += 1
        return result                

       

问题:为什么要先确定最右边,先确定最左边结果如何算,先确定中间做不到

for left in range( len(nums)-2):
    middle = left + 1
    right = len(nums)-1
    while middle <= right:
        if nums[left] + nums[middle] > nums[right]:
            result += ?

524. 通过删除字母匹配到字典里最长单词open in new window

给你一个字符串 s 和一个字符串数组 dictionary ,找出并返回 dictionary 中最长的字符串,该字符串可以通过删除 s 中的某些字符得到。

如果答案不止一个,返回长度最长且字母序最小的字符串。如果答案不存在,则返回空字符串。

示例 1:

输入:s = "abpcplea", dictionary = ["ale","apple","monkey","plea"]
输出:"apple"

示例 2:

输入:s = "abpcplea", dictionary = ["a","b","c"]
输出:"a"

提示:

  • 1 <= s.length <= 1000
  • 1 <= dictionary.length <= 1000
  • 1 <= dictionary[i].length <= 1000
  • sdictionary[i] 仅由小写英文字母组成

思路:

求dictionary长度最长且字母序最小的字符串是否在s中出现

我们首先可以通过双指针判断字符串a是否存在于字符串b中,接下来就是字母序最小,长度最长,这个可以通过排序实现

dictionary = ["ale", "apple", "monkey", "plea"]

dictionary.sort(key=lambda obj: obj)
dictionary.sort(key=lambda obj: len(obj), reverse=True)
print(dictionary)
# ['monkey', 'apple', 'plea', 'ale']

这个排序有可能不熟,其实我也不熟

class Solution:
    def findLongestWord(self, s: str, dictionary: List[str]) -> str:
        # 排序字典序最小且长度最长
        dictionary.sort(key=lambda obj: (-len(obj), obj))

        s_length = len(s)
        for word in dictionary:
            word_index = 0
            s_index = 0
            word_length = len(word)
            
            while word_index < word_length and s_index < s_length:
                if word[word_index] == s[s_index]:
                    word_index += 1
                s_index += 1

                if word_index == word_length:
                    return word
        return ""

Comments
  • Latest
  • Oldest
  • Hottest
Powered by Waline v2.15.8