798. 得分最高的最小轮调 / 1109. 航班预订统计

798. 得分最高的最小轮调【困难题】【每日一题】

思路:【差分+前缀和】

  1. 这种困难题显然我是不会写的,所以我直接看题解,连题解都看了好久哎~。

  2. 看的是宫水三叶的题解。

  3. 遍历nums数组,设当前下标为i,设当前元素nums[i]经过k次轮调之后可以得分。

  4. 轮调即数组左移,所以经过k次轮调之后,i位置元素的新下标为i-k,当i-k小于0时,说明这个元素轮调到了原来位置的后面,此时新下标为(i-k+n)
    mod
    n。(设nums长度为n)。由于必须同时满足合法移动(即下标不能小于0),且能够得分,那么只能考虑范围更小的情况,于是假设新下标在i前边,即新下标为
    i-k,那么新下标必然满足

  5. 0<= i-k <= n-1,推导出 k<=i 且 k>=i+1-n

  6. 而同时,为了保证nums[i]经过k次轮调之后可以得分,那么k次轮调之后的新位置

    i-k>=nums[i] ,推导出 k <= i-nums[i]

  7. 因为nums[i] >= 0, 所以 i-nums[i ] <= i,两个不等式取交集的话肯定取范围更小的那个,所以k的取值范围为

    i+1-n <= k <= i-nums[i]

  8. 考虑这个k的取值区间仅当左端点<=右端点时有效,那么当左端点>右端点时,那么这个k的取值区间可以转换为 0<= k <= i-nums[i-1] 和 i+1-n <= k <= n-1 这两段。

  9. 确定好 k 的取值范围后,定义查分数组cnt,长度为n+1(多1位是防止数组越界),对左端点加1标记,右端点减1标记,最后累加求cnt数组的前缀和,即为每个轮调次数k能够取得的最大得分。
    10.那个区间处理理解的还不是很透彻,也讲不太清楚,好菜呀~

代码:

class Solution {
    public int bestRotation(int[] nums) {
        int len = nums.length;
        int[] cnt = new int[len+1];
        for (int i = 0; i < len; i++) {
            int l = (i+1) % len , r = (i-nums[i]+len) % len;
            if (l<=r){
                cnt[l] += 1;
                cnt[r+1] -= 1;
            }else {
                cnt[0] += 1;
                cnt[r+1] -= 1;
                cnt[l] += 1;
                cnt[len] -= 1;
            }
        }
        int ans = 0,max = cnt[0];
        for (int i = 1; i <= len ; i++) {
            cnt[i] += cnt[i-1];
            if (cnt[i] > max){
                max = cnt[i];
                ans = i;
            }
        }
        return ans;
    }
}

1109. 航班预订统计【中等题】

思路:【差分+前缀和】

  1. 遍历每条预订记录,定义记录第0位为起始航班编号start,第1位记录为结束航班编号end,第2位为每个航班上的预订座位数目num。
  2. 定义差分数组cnt,对每条记录的起始航班位置+num标记,对每条记录的结束航班位置-num标记。
  3. 对差分数组求前缀和。

代码:

class Solution {
    public int[] corpFlightBookings(int[][] bookings, int n) {
        int[] cnt = new int[n+1],ans = new int[n];
        for (int[] booking : bookings) {
            int start = booking[0]-1,end = booking[1]-1,num = booking[2];
            cnt[start] += num;
            cnt[end + 1] -= num;
        }
        ans[0] = cnt[0];
        for (int i = 1; i < n; i++) {
            ans[i] += ans[i-1] + cnt[i];
        }
        return ans;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值