代码随想录第34天|1005. K 次取反后最大化的数组和、134. 加油站、135. 分发糖果

88 阅读1分钟

1005. K 次取反后最大化的数组和

1. first idea

class Solution:
    def largestSumAfterKNegations(self, nums: List[int], k: int) -> int:
        # 1. find the negative elements with the largest abs value.
        # 2. Top(k) of these elements.
        all_pos_list = []
        nums.sort()  # low -> high 这样绝对值最大的负数将率先取反,较小的负数如果没有被反转就留下。
        for num in nums:
            if (k > 0) and (num < 0):
                all_pos_list.append(-num)
                k -= 1
            else:
                all_pos_list.append(num)

        all_pos_list.sort()  # low -> high 反转后的顺序需要更新顺序,更新后如果k还有剩余,则对最小的值进行反转,这样因为多余反转的损失最小。
        
        print(all_pos_list)
        max_sum = 0
        k %= 2
        for pos_num in all_pos_list:
            if k != 0:
                max_sum -= pos_num
                k -= 1
            else:
                max_sum += pos_num
        
        return max_sum

134. 加油站

1. first idea

我觉得

  1. 当前一定要有足够的汽油开往下一站。car + gas[i] > cost[i]
  2. 如果能开往下一站,那么剩的油越多越好。start=argimax=i=0ncar+gas[i]cost[i]start = \arg_i \max = \sum_{i=0}^n car + gas[i] - cost[i]
  3. 如果有两个起点都满足上述内容,那么遍历即可。

每个加油站的剩余量rest[i]为gas[i] - cost[i]。

2. doc reading

代码随想录 (programmercarl.com)

i从0开始累加rest[i],和记为curSum,一旦curSum小于零,说明[0, i]区间都不能作为起始位置,因为这个区间选择任何一个位置作为起点,到i这里都会断油,

那么起始位置从i+1算起,再从0计算curSum。

如果 curSum<0 说明 区间和1 + 区间和2 < 0, 那么 假设从上图中的位置开始计数curSum不会小于0的话,就是 区间和2>0。

区间和1 + 区间和2 < 0 同时 区间和2>0,只能说明区间和1 < 0, 那么就会从假设的箭头初就开始从新选择其实位置了。

那么局部最优:当前累加rest[i]的和curSum一旦小于0,起始位置至少要是i+1,因为从i之前开始一定不行。全局最优:找到可以跑一圈的起始位置

class Solution:
    def canCompleteCircuit(self, gas: List[int], cost: List[int]) -> int:
        if sum(gas) < sum(cost):
            return -1
        else:
            start_idx = 0
            while start_idx < len(gas):  # 不停寻找起点
                idx = start_idx
                retain = 0
                end_idx = (start_idx + len(gas) - 1) % len(gas)  # 计算对应的终点
                while idx != end_idx:  # 在起点到终点之间的油的变动。
                    retain = retain + gas[idx] - cost[idx]
                    if retain < 0:
                        # 说明当前区间[start_idx, idx]之间不可能存在起点。
                        break
                    else:
                        idx = (idx + 1) % len(gas)
                if idx == end_idx:
                    # 顺利到达终点。
                    break
                else:
                    start_idx = idx + 1
            return start_idx

135. 分发糖果

1. first idea

  1. 先算nn个糖果。
  2. 找到评分最低的那个孩子。
  3. 如果左侧的孩子比当前孩子评分高,那么就+1.
  4. 如果左孩子比当前孩子评分低,那么就不动.

2. doc reading

代码随想录 (programmercarl.com)

  1. 初始candycandy数组每个单元都为11.
  2. 先从左往右,如果ratings[i]>ratings[i1]ratings[i]>ratings[i - 1], 那么candy[i]=candy[i1]+1candy[i] = candy[i - 1] + 1
  3. 再从右往左,如果ratings[i]>ratings[i+1]ratings[i]>ratings[i + 1], 那么candy[i]=max(candy[i+1]+1,candy[i])candy[i] = max(candy[i + 1] + 1, candy[i]).
class Solution:
    def candy(self, ratings: List[int]) -> int:
        candy_list = [1] * len(ratings)
        # 从左往右。
        for idx in range(1, len(ratings)):
            if ratings[idx] > ratings[idx - 1]:
                candy_list[idx] = candy_list[idx - 1] + 1
        for idx in range(len(ratings) - 2, -1, -1):
            if ratings[idx] > ratings[idx + 1]:
                candy_list[idx] = max(candy_list[idx], candy_list[idx + 1] + 1)
        return sum(candy_list)