【leetcode算法面试】leetcode题目1-贪心

贪心算法简介

    【定义】 贪心策略是指从问题的初始状态出发,通过若干次的贪心选择而得出最优值(或较优解)的一种解题方法

       贪心算法并不从整体最优考虑,它所作出的选择只是在某种意义上的局部最优选择。当然,希望贪心算法得到的最终结果也是整体最优的。虽然贪心算法不能对所有问题都得到整体最优解,但对许多问题它能产生整体最优解。如单源最短路经问题,最小生成树问题等。在一些情况下,即使贪心算法不能得到整体最优解,其最终结果却是最优解的很好近似。

  贪心算法每一步必须满足一下条件:

  •  可行的:即它必须满足问题的约束。
  •  局部最优:他是当前步骤中所有可行选择中最佳的局部选择。
  •  不可取消:即选择一旦做出,在算法的后面步骤就不可改变了。

该算法存在问题:

1. 不能保证求得的最后解是最佳的;

2. 不能用来求最大或最小解问题;

3. 只能求满足某些约束条件的可行解的范围。

       狭义的贪心算法指的是解最优化问题的一种特殊方法,解决过程中总是做出当下最好的选择,因为具有最优子结构的特点,局部最优解可以得到全局最优解;这种贪心算法是动态规划的一种特例。能用贪心解决的问题,也可以用动态规划解决。

 

题号 题目 说明
45 Jump Game II 跳跃游戏之二 求到达最后一个位置的最少跳跃数
55 Jump Game 跳跃游戏 动态规划 / 贪心算法
121 Best Time to Buy and Sell Stock  
122 Best Time to Buy and Sell Stock II 贪心法 / 动态规划
134 Gas Station 加油站问题  
     

 

45. Jump Game II 跳跃游戏之二

    求到达最后一个位置的最少跳跃数

     ret代表步数,last记录ret步已经覆盖的地方,cur代表ret+1步能到达的最大距离

func jump(nums []int) int {
	var last, cur, ret = 0, 0, 0
	var max = func(a, b int) int {
		if a > b {return a}
		return b
	}
	for i:=0; i last{
			last= cur
			ret++
		}
		cur = max(cur, i + nums[i])
	}
	return ret
}

    题目中的[2,3,1,1,4]。初始状态是这样的:cur表示最远能覆盖到的地方,用红色表示。last表示已经覆盖的地方,用箭头表示

【leetcode算法面试】leetcode题目1-贪心_第1张图片

   接下来,第一元素告诉cur,最远咱可以走2步。于是: 

【leetcode算法面试】leetcode题目1-贪心_第2张图片

    下一循环中,i指向1(图中的元素3),发现,哦,i小于last能到的范围,于是更新last(相当于说,进入了新的势力范围),步数ret加1.同时要更新cur。因为最远距离发现了。

【leetcode算法面试】leetcode题目1-贪心_第3张图片

     接下来,i继续前进,发现i在当前的势力范围内,无需更新last和步数ret。更新cur。

【leetcode算法面试】leetcode题目1-贪心_第4张图片

   i继续前进,接下来发现超过当前势力范围,更新last和步数。cur已然最大了。 

【leetcode算法面试】leetcode题目1-贪心_第5张图片

   最后,i到最后一个元素。依然在势力范围内,遍历完成,返回ret。 

【leetcode算法面试】leetcode题目1-贪心_第6张图片

    参考: https://www.cnblogs.com/lichen782/p/leetcode_Jump_Game_II.html

 

55. [LeetCode] Jump Game 跳跃游戏

     dp[i]表示达到i位置时剩余的步数,dp[i] = max(dp[i - 1], nums[i - 1]) - 1

class Solution {
public:
    bool canJump(vector& nums) {
        vector dp(nums.size(), 0);
        for (int i = 1; i < nums.size(); ++i) {
            dp[i] = max(dp[i - 1], nums[i - 1]) - 1;
            if (dp[i] < 0) return false;
        }
        return true;
    }
};

     贪婪算法Greedy Algorithm,reach,表示最远能到达的位置,初始化为0。遍历数组中每一个数字,如果当前坐标大于reach或者reach已经抵达最后一个位置则跳出循环,否则就更新reach的值为其和i + nums[i]中的较大值

class Solution {
public:
    bool canJump(vector& nums) {
        int n = nums.size(), reach = 0;
        for (int i = 0; i < n; ++i) {
            if (i > reach || reach >= n - 1) break;
            reach = max(reach, i + nums[i]);
        }
        return reach >= n - 1;
    }
};

 

121. Best Time to Buy and Sell Stock

Say you have an array for which the ith element is the price of a given stock on day i.

If you were only permitted to complete at most one transaction (i.e., buy one and sell one share of the stock), design an algorithm to find the maximum profit.

Note that you cannot sell a stock before you buy one.

Example 1:

Input: [7,1,5,3,6,4]
Output: 5
Explanation: Buy on day 2 (price = 1) and sell on day 5 (price = 6), profit = 6-1 = 5.
             Not 7-1 = 6, as selling price needs to be larger than buying price.

Example 2:

Input: [7,6,4,3,1]
Output: 0
Explanation: In this case, no transaction is done, i.e. max profit = 0.

        题的意思就是只交易一次,不止保持最大收益,还保存最低价格,如果当天价格更低,就刷新最小价格(买),同时如果当天价格减去最小价格的收益最大,就刷新最大价格(卖)

class Solution {
public:
    int maxProfit(vector& prices) {
        if( prices.size() <=1) return 0;
        int minpr = prices[0];
        int maxpro = 0;       
        for( int i = 0;i < prices.size();i++)
        {
            if(prices[i] < minpr)            
                minpr = prices[i];
            
            else if(maxpro < (prices[i] - minpr))
                    maxpro = prices[i] - minpr;
            
        }
        return maxpro;
    }
};
func maxProfit(prices []int) int {
	if len(prices) <= 1 {
		return 0
	}

	var (
		minPrice = prices[0]
		maxPro   = 0
	)

	for i := 0; i < len(prices); i++ {
		if minPrice > prices[i] {
			minPrice = prices[i]
		}

		if maxPro < prices[i]-minPrice {
			maxPro = prices[i] - minPrice
		}
	}

	return maxPro
}

 

122. Best Time to Buy and Sell Stock II

Say you have an array for which the ith element is the price of a given stock on day i.

Design an algorithm to find the maximum profit. You may complete as many transactions as you like (i.e., buy one and sell one share of the stock multiple times).

Note: You may not engage in multiple transactions at the same time (i.e., you must sell the stock before you buy again).

Example 1:

Input: [7,1,5,3,6,4]
Output: 7
Explanation: Buy on day 2 (price = 1) and sell on day 3 (price = 5), profit = 5-1 = 4.
             Then buy on day 4 (price = 3) and sell on day 5 (price = 6), profit = 6-3 = 3.

Example 2:

Input: [1,2,3,4,5]
Output: 4
Explanation: Buy on day 1 (price = 1) and sell on day 5 (price = 5), profit = 5-1 = 4.
             Note that you cannot buy on day 1, buy on day 2 and sell them later, as you are
             engaging multiple transactions at the same time. You must sell before buying again.

Example 3:

Input: [7,6,4,3,1]
Output: 0
Explanation: In this case, no transaction is done, i.e. max profit = 0.

     只要我们发现前后两数呈递增关系,则可以进行交易。比较鸡贼的方法,只要有收益就交易,就是出现上升段

class Solution {
public:
    int maxProfit(vector& prices) {
        int res = 0, n = prices.size();
        for (int i = 0; i < n - 1; ++i) {
            if (prices[i] < prices[i + 1]) {
                res += prices[i + 1] - prices[i];
            }
        }
        return res;
    }
};

func maxProfit(prices []int) int {
	var ret = 0
	for i := 1; i < len(prices); i++ {
		if prices[i] > prices[i-1] {
			ret += prices[i] - prices[i-1]
		}
	}
	return ret
}

 

134. [LeetCode] Gas Station 加油站问题

There are N gas stations along a circular route, where the amount of gas at station i is gas[i].

You have a car with an unlimited gas tank and it costs cost[i] of gas to travel from station i to its next station (i+1). You begin the journey with an empty tank at one of the gas stations.

Return the starting gas station's index if you can travel around the circuit once in the clockwise direction, otherwise return -1.

Note:

  • If there exists a solution, it is guaranteed to be unique.
  • Both input arrays are non-empty and have the same length.
  • Each element in the input arrays is a non-negative integer.

Example 1:

Input: 
gas  = [1,2,3,4,5]
cost = [3,4,5,1,2]

Output: 3

Explanation:
Start at station 3 (index 3) and fill up with 4 unit of gas. Your tank = 0 + 4 = 4
Travel to station 4. Your tank = 4 - 1 + 5 = 8
Travel to station 0. Your tank = 8 - 2 + 1 = 7
Travel to station 1. Your tank = 7 - 3 + 2 = 6
Travel to station 2. Your tank = 6 - 4 + 3 = 5
Travel to station 3. The cost is 5. Your gas is just enough to travel back to station 3.
Therefore, return 3 as the starting index.

Example 2:

Input: 
gas  = [2,3,4]
cost = [3,4,3]

Output: -1

Explanation:
You can't start at station 0 or 1, as there is not enough gas to travel to the next station.
Let's start at station 2 and fill up with 4 unit of gas. Your tank = 0 + 4 = 4
Travel to station 0. Your tank = 4 - 3 + 2 = 3
Travel to station 1. Your tank = 3 - 3 + 3 = 3
You cannot travel back to station 2, as it requires 4 unit of gas but you only have 3.
Therefore, you can't travel around the circuit once no matter where you start.

     一个圆形的跑道,上面有 N 个加油站,每个加油站能加的油是 gas[i],假设你的车能加无限的油量,从第 i 个加油站跑到第 i+1 个加油站所消耗的油是 cost[i], 返回从第几个加油站能够顺时针跑完一圈,如果从任意一个都不能跑完的话,就返回-1 

func canCompleteCircuit(gas []int, cost []int) int {
	var pos, sum, total = 0, 0, 0

	for i := 0; i < len(gas); i++ {
		sum += gas[i] - cost[i]
		total += gas[i] - cost[i]
		if sum < 0 {
			pos = i + 1
			sum = 0
		}
	}
	if total < 0 {
		return -1
	}
	return pos
}

 

你可能感兴趣的:(#,算法)