LeetCode 1480. 一维数组的动态和 / 1588. 所有奇数长度子数组的和 / 528. 按权重随机选择(随机化)

1480. 一维数组的动态和

2021.8.28 每日一题

题目描述

给你一个数组 nums 。数组「动态和」的计算公式为:runningSum[i] = sum(nums[0]…nums[i]) 。

请返回 nums 的动态和。

示例 1:

输入:nums = [1,2,3,4]
输出:[1,3,6,10]
解释:动态和计算过程为 [1, 1+2, 1+2+3, 1+2+3+4] 。

示例 2:

输入:nums = [1,1,1,1,1]
输出:[1,2,3,4,5]
解释:动态和计算过程为 [1, 1+1, 1+1+1, 1+1+1+1, 1+1+1+1+1] 。

示例 3:

输入:nums = [3,1,2,10,1]
输出:[3,4,6,16,17]

提示:

1 <= nums.length <= 1000
-10^6 <= nums[i] <= 10^6

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/running-sum-of-1d-array
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

秒了

class Solution {
    public int[] runningSum(int[] nums) {
        for(int i = 1; i < nums.length; i++){
            nums[i] = nums[i] + nums[i - 1];
        }
        return nums;
    }
}

1588. 所有奇数长度子数组的和

2021.8.29 每日一题

题目描述

给你一个正整数数组 arr ,请你计算所有可能的奇数长度子数组的和。

子数组 定义为原数组中的一个连续子序列。

请你返回 arr 中 所有奇数长度子数组的和 。

示例 1:

输入:arr = [1,4,2,5,3]
输出:58
解释:所有奇数长度子数组和它们的和为:
[1] = 1
[4] = 4
[2] = 2
[5] = 5
[3] = 3
[1,4,2] = 7
[4,2,5] = 11
[2,5,3] = 10
[1,4,2,5,3] = 15
我们将所有值求和得到 1 + 4 + 2 + 5 + 3 + 7 + 11 + 10 + 15 = 58

示例 2:

输入:arr = [1,2]
输出:3
解释:总共只有 2 个长度为奇数的子数组,[1] 和 [2]。它们的和为 3 。

示例 3:

输入:arr = [10,11,12]
输出:66

提示:

1 <= arr.length <= 100
1 <= arr[i] <= 1000

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/sum-of-all-odd-length-subarrays
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

刚开始就想用数学规律来做的,结果想了半天没想出来
前缀和吧,然后遍历每个长度和开始位置

class Solution {
    public int sumOddLengthSubarrays(int[] arr) {
        int l = arr.length;
        int[] pre = new int[l + 1];
        for(int i = 1; i <= l; i++){
            pre[i] = pre[i - 1] + arr[i - 1];
        }
        int res = 0;
        for(int i = 1; i <= l; i += 2){
            for(int j = 0; j <= l - i; j++){
                res += pre[j + i] - pre[j];
            }
        }
        return res;
    }
}

数学解法,思路就是统计每个数在奇数长度子数组中出现的次数
怎么统计呢,这个比较不好想
就是统计左右两边的个数,加上自身要成为一个奇数长度子数组,所以左右两边个只能同为奇数或者同为偶数
遍历一遍,把所有数出现的次数乘以当前值加起来就行了
这种思想,包括怎么在一个长度的数组中求奇偶数的个数,也可以巩固一下

class Solution {
    public int sumOddLengthSubarrays(int[] arr) {
        //前缀和过后,写一下On的数学解法
        //主要就是统计每个位置的数出现过多少次
        //考虑每个位置左右两边数的奇偶性,只有左右两边都是奇数个或者偶数个,才可以
        //但是这个怎么写呢
        int l = arr.length;
        int res = 0;
        for(int i = 0; i < l; i++){
            int left = i - 0;       //左边的个数
            int right = l - i - 1;      //右边的个数
            //左边奇数有多少个,left / 2 + right % 2,右边也是right / 2 + right & 2
            //偶数,左边有left / 2 + 1, 右边right / 2 + 1,加1是因为有0
            res += ((left + 1) / 2) * ((right + 1) / 2) * arr[i];
            res += (left / 2 + 1) * (right / 2 + 1) * arr[i];
        }
        return res;
    }
}

528. 按权重随机选择

2021.8.30 每日一题

题目描述

给定一个正整数数组 w ,其中 w[i] 代表下标 i 的权重(下标从 0 开始),请写一个函数 pickIndex ,它可以随机地获取下标 i,选取下标 i 的概率与 w[i] 成正比。

例如,对于 w = [1, 3],挑选下标 0 的概率为 1 / (1 + 3) = 0.25 (即,25%),而选取下标 1 的概率为 3 / (1 + 3) = 0.75(即,75%)。

也就是说,选取下标 i 的概率为 w[i] / sum(w) 。

示例 1:

输入:
[“Solution”,“pickIndex”]
[[[1]],[]]
输出:
[null,0]
解释:
Solution solution = new Solution([1]);
solution.pickIndex(); // 返回 0,因为数组中只有一个元素,所以唯一的选择是返回下标 0。

示例 2:

输入:
[“Solution”,“pickIndex”,“pickIndex”,“pickIndex”,“pickIndex”,“pickIndex”]
[[[1,3]],[],[],[],[],[]]
输出:
[null,1,1,1,1,0]
解释:
Solution solution = new Solution([1, 3]);
solution.pickIndex(); // 返回 1,返回下标 1,返回该下标概率为 3/4 。
solution.pickIndex(); // 返回 1
solution.pickIndex(); // 返回 1
solution.pickIndex(); // 返回 1
solution.pickIndex(); // 返回 0,返回下标 0,返回该下标概率为 1/4 。

由于这是一个随机问题,允许多个答案,因此下列输出都可以被认为是正确的:
[null,1,1,1,1,0]
[null,1,1,1,1,1]
[null,1,1,1,0,0]
[null,1,1,1,0,1]
[null,1,0,1,0,0]

诸若此类。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/random-pick-with-weight
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

第一次做这种产生随机数的题,首先明确如何产生随机数才能使取得下标的概率满足要求
就是按照所给的公式,先计算sum(w),然后计算前缀和,每个下标对应的前缀和就是这个下标的取值范围
当取到一个随机数后,用二分查找,找到对应的下标,返回就行了

class Solution {
    //随机化,怎么设计呢,相当于一个下标对应一个数据的区间,怎么写呢
    //先计算sum(w),就是整个数据产生的范围,最大10的9次,然后在这个范围内生成一个随机数,
    //查看这个随机数在哪个下标对应的范围内
    int sum = 0;
    Random rd = new Random();
    int[] pre;
    int n;
    public Solution(int[] w) {
        n = w.length;
        pre = new int[n + 1];
        for(int i = 1; i <= n; i++){
            pre[i] = pre[i - 1] + w[i - 1];
            sum += w[i - 1];
        }
    }
    
    public int pickIndex() {
        int idx = rd.nextInt(sum);
        //找idx所在的区间下标
        int left = 0;
        int right = n;
        while(left < right){
            int mid = (right - left + 1) / 2 + left;
            if(pre[mid] <= idx){
                left = mid;
            }else{
                right = mid - 1;
            }
        }
        return left;
    }
}

/**
 * Your Solution object will be instantiated and called as such:
 * Solution obj = new Solution(w);
 * int param_1 = obj.pickIndex();
 */

你可能感兴趣的:(LeetCode,leetcode,算法,java)