python数据结构之贪心算法

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/haiyu94/article/details/79450443

目录

  1. 贪心算法的基础知识
  2. 分糖果 (LeetCode 455)
  3. 摇摆序列(LeetCode 376)
  4. 移除K个数字(LeetCode 402)
  5. 跳跃游戏1 (LeetCode 55)
  6. 跳跃游戏2 (LeetCode 45)
  7. 射击气球(LeetCode 452)

1. 贪心算法的基础知识

贪心算法就是每次都贪心地选择当前最好的那个(局部最优解),不去考虑以后的情况,而且选择了就不能够“反悔”了,如果原问题满足贪心选择性质和最优子结构,那么最后得到的解就是最优解。

贪心算法和其他的算法比较有明显的区别,动态规划每次都是综合所有子问题的解得到当前的最优解(全局最优解),而不是贪心地选择;回溯法是尝试选择一条路,如果选择错了的话可以“反悔”,也就是回过头来重新选择其他的试试。

2. 分糖果 (LeetCode 455)

2.1题目

Assume you are an awesome parent and want to give your children some cookies. But, you should give each child at most one cookie. Each child i has a greed factor gi, which is the minimum size of a cookie that the child will be content with; and each cookie j has a size sj. If sj >= gi, we can assign the cookie j to the child i, and the child i will be content. Your goal is to maximize the number of your content children and output the maximum number.
Note:
You may assume the greed factor is always positive.
You cannot assign more than one cookie to one child.
Example 1:
Input: [1,2,3], [1,1]
Output: 1
Explanation: You have 3 children and 2 cookies. The greed factors of 3 children are 1, 2, 3.
And even though you have 2 cookies, since their size is both 1, you could only make the child whose greed factor is 1 content.
You need to output 1.

2.2思路

对贪婪系数和饼干大小都按从小到大的顺序排序,当满足饼干大小大于等于贪婪系数时,计数加1,直到贪婪系数或饼干大小遍历结束。

2.3代码

class Solution(object):
    def findContentChildren(self, g, s):
        """
        :type g: List[int]
        :type s: List[int]
        :rtype: int
        """
        i = len(g) - 1
        j = len(s) - 1
        cnt = 0
        g = sorted(g)
        s = sorted(s)
        while min(i,j) >= 0:
            if s[j] >= g[i]:
                cnt += 1
                j -= 1
            i -= 1
        return cnt

3. 摇摆序列(LeetCode 376 Wiggle Subsequence)

3.1题目

A sequence of numbers is called a wiggle sequence if the differences between successive numbers strictly alternate between positive and negative. The first difference (if one exists) may be either positive or negative. A sequence with fewer than two elements is trivially a wiggle sequence.

For example, [1,7,4,9,2,5] is a wiggle sequence because the differences (6,-3,5,-7,3) are alternately positive and negative. In contrast, [1,4,7,2,5] and [1,7,4,5,5] are not wiggle sequences, the first because its first two differences are positive and the second because its last difference is zero.

Given a sequence of integers, return the length of the longest subsequence that is a wiggle sequence. A subsequence is obtained by deleting some number of elements (eventually, also zero) from the original sequence, leaving the remaining elements in their original order.

Examples:
Input: [1,7,4,9,2,5]
Output: 6
The entire sequence is a wiggle sequence.

Input: [1,17,5,10,13,15,10,5,16,8]
Output: 7
There are several subsequences that achieve this length. One is [1,17,10,13,10,16,8].

Input: [1,2,3,4,5,6,7,8,9]
Output: 2

3.2思路

一次遍历,nums[i] - nums[i-1] != 0且与上一个差异号时,则满足条件,结果+1,也就是说在遍历过程中将连续递增的部分和连续递减的部分分别进行合并,实现o(n)时间复杂度。

3.3代码

class Solution(object):
    def wiggleMaxLength(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        size = len(nums)
        if size < 2:
            return size
        delta = nums[1] - nums[0]
        ans = 1 + (delta != 0)
        for i in range(2, size):
            newdelta = nums[i] - nums[i-1]
            if newdelta != 0 and newdelta * delta <= 0:
                ans += 1
                delta = newdelta
        return ans

4. 移除K个数字(LeetCode 402 Remove K Digits)

4.1题目

Given a non-negative integer num represented as a string, remove k digits from the number so that the new number is the smallest possible.

Note:
The length of num is less than 10002 and will be ≥ k.
The given num does not contain any leading zero.

Example 1:
Input: num = “1432219”, k = 3
Output: “1219”
Explanation: Remove the three digits 4, 3, and 2 to form the new number 1219 which is the smallest.
Example 2:
Input: num = “10200”, k = 1
Output: “200”
Explanation: Remove the leading 1 and the number is 200. Note that the output must not contain leading zeroes.
Example 3:
Input: num = “10”, k = 2
Output: “0”
Explanation: Remove all the digits from the number and it is left with nothing which is 0.

4.2思路

逐次删除,寻找数字中第一次出现nums[i]>nums[i+1]的位置,删除nums[i],则nums[i]=nums[:i]+nums[i+1:]。如此循环k次结束。

4.3代码

class Solution(object):
    def removeKdigits(self, num, k):
        """
        :type num: str
        :type k: int
        :rtype: str
        """
        while k > 0:
            k -= 1
            i = 0
            while i < len(num) - 1:
                if num[i] > num[i+1]:
                    break
                i += 1
            num = num[:i] + num[i+1:]
        if len(num) == 0:
            return '0'
        else:
            return str(int(num))

5. 跳跃游戏1 (LeetCode 55 Jump Game)

5.1题目

Given an array of non-negative integers, you are initially positioned at the first index of the array.

Each element in the array represents your maximum jump length at that position.

Determine if you are able to reach the last index.

For example:
A = [2,3,1,1,4], return true.

A = [3,2,1,0,4], return false.

5.2思路

从起始位置开始判断,不断扩展可以的到达的位置,最后判断可以到达的位置是否超过最后的位置,如果大于等于,则可以到达,否则,不可以。

5.3代码

class Solution(object):
    def canJump(self, nums):
        """
        :type nums: List[int]
        :rtype: bool
        """
        size = len(nums)
        if size <= 1:
            return True
        reach = 1
        i = 0
        while i < reach and reach < size:
            reach = max(reach, i + 1 + nums[i])
            i += 1
        return reach >= size

6. 跳跃游戏2 (LeetCode 45 Jump Game II)

6.1题目

Given an array of non-negative integers, you are initially positioned at the first index of the array.

Each element in the array represents your maximum jump length at that position.

Your goal is to reach the last index in the minimum number of jumps.

For example:
Given array A = [2,3,1,1,4]

The minimum number of jumps to reach the last index is 2. (Jump 1 step from index 0 to 1, then 3 steps to the last index.)

6.2思路

该题与上一题的区别在于求解到达最后所使用的最小步数。思路是不断扩展可以调到的区域,在这个区域内把下一个可达的区域算出来,直到结束。

6.3代码

class Solution(object):
    def jump(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        size = len(nums)
        if size <= 1:
            return 0
        left = 0
        right = 0
        ans = 0
        while True:
            old_right = right
            ans += 1
            while left <= old_right:
                new_right = left + nums[left]
                if new_right >= size - 1:
                    return ans
                right = max(right, new_right)
                left += 1

7. 射击气球(LeetCode 452 Minimum Number of Arrows to Burst Balloons)

7.1题目

There are a number of spherical balloons spread in two-dimensional space. For each balloon, provided input is the start and end coordinates of the horizontal diameter. Since it’s horizontal, y-coordinates don’t matter and hence the x-coordinates of start and end of the diameter suffice. Start is always smaller than end. There will be at most 104 balloons.

An arrow can be shot up exactly vertically from different points along the x-axis. A balloon with xstart and xend bursts by an arrow shot at x if xstart ≤ x ≤ xend. There is no limit to the number of arrows that can be shot. An arrow once shot keeps travelling up infinitely. The problem is to find the minimum number of arrows that must be shot to burst all balloons.

Example:

Input:
[[10,16], [2,8], [1,6], [7,12]]

Output:
2

Explanation:
One way is to shoot one arrow for example at x = 6 (bursting the balloons [2,8] and [1,6]) and another arrow at x = 11 (bursting the other two balloons).

7.2思路

求击爆所有气球所需要的最少箭数,将所有气球的坐标按照左坐标从小到大进行排序,求包含公共部分线段的个数。

7.3代码

class Solution(object):
    def findMinArrowShots(self, points):
        """
        :type points: List[List[int]]
        :rtype: int
        """
        size = len(points)
        if size <= 1:
            return size
        points = sorted(points, key = lambda x: x[0])
        left = points[0][0]
        right = points[0][1]
        count = 1
        for i in range(1, size):
            if points[i][0] >= left and points[i][0] <= right:
                left = points[i][0]
                if points[i][1] < right:
                    right = points[i][1]
            else:
                count += 1
                left = points[i][0]
                right = points[i][1]
        return count

猜你喜欢

转载自blog.csdn.net/haiyu94/article/details/79450443