LeetCode 868. 二进制间距 / 398. 随机数索引(水塘抽样) / 883. 三维形体投影面积

868. 二进制间距

2022.4.24 每日一题

题目描述

给定一个正整数 n,找到并返回 n 的二进制表示中两个 相邻 1 之间的 最长距离 。如果不存在两个相邻的 1,返回 0 。

如果只有 0 将两个 1 分隔开(可能不存在 0 ),则认为这两个 1 彼此 相邻 。两个 1 之间的距离是它们的二进制表示中位置的绝对差。例如,“1001” 中的两个 1 的距离为 3 。

示例 1:

输入:n = 22
输出:2
解释:22 的二进制是 “10110” 。
在 22 的二进制表示中,有三个 1,组成两对相邻的 1 。
第一对相邻的 1 中,两个 1 之间的距离为 2 。
第二对相邻的 1 中,两个 1 之间的距离为 1 。
答案取两个距离之中最大的,也就是 2 。

示例 2:

输入:n = 8
输出:0
解释:8 的二进制是 “1000” 。
在 8 的二进制表示中没有相邻的两个 1,所以返回 0 。

示例 3:

输入:n = 5
输出:2
解释:5 的二进制是 “101” 。

提示:

1 <= n <= 10^9

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

思路

class Solution {
    public int binaryGap(int n) {
        //数字在32位的范围内,直接移位判断就好了
        int max = 0;
        int left = 0;
        int idx = 1;
        while(n != 0){
            if((n & 1) == 1){
                if(left == 0){
                    left = idx;
                }else{
                    max = Math.max(idx - left, max);
                    left = idx;
                }
            }
            idx++;
            n >>= 1;
        }
        return max;
    }
}
class Solution:
    def binaryGap(self, n: int) -> int:
        left, idx, res = 0, 1, 0
        while n:
            if n & 1:
                if not left:
                    left = idx
                else:
                    res = max(res, idx - left)
                    left = idx
            n >>= 1
            idx += 1
        return res

398. 随机数索引

2022.4.25 每日一题

题目描述

给你一个可能含有 重复元素 的整数数组 nums ,请你随机输出给定的目标数字 target 的索引。你可以假设给定的数字一定存在于数组中。

实现 Solution 类:

  • Solution(int[] nums) 用数组 nums 初始化对象。
  • int pick(int target) 从 nums 中选出一个满足 nums[i] == target 的随机索引 i 。如果存在多个有效的索引,则每个索引的返回概率应当相等。

示例:

输入
[“Solution”, “pick”, “pick”, “pick”]
[[[1, 2, 3, 3, 3]], [3], [1], [3]]
输出
[null, 4, 0, 2]

解释
Solution solution = new Solution([1, 2, 3, 3, 3]);
solution.pick(3); // 随机返回索引 2, 3 或者 4 之一。每个索引的返回概率应该相等。
solution.pick(1); // 返回 0 。因为只有 nums[0] 等于 1 。
solution.pick(3); // 随机返回索引 2, 3 或者 4 之一。每个索引的返回概率应该相等。

提示:

1 <= nums.length <= 2 * 10^4
-2^31 <= nums[i] <= 2^31 - 1
target 是 nums 中的一个整数
最多调用 pick 函数 10^4 次

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

思路

最简单的当然是一个哈希表搞定,但是空间开的应该不小,但是也通过了

class Solution {
    //最简单的一个思路就是map,但是题上说空间不能太大,估计过不了
    //不过先写一下
    Map<Integer, List<Integer>> map = new HashMap<>();
    public Solution(int[] nums) {
        for(int i = 0; i < nums.length; i++){
            List<Integer> list = map.getOrDefault(nums[i], new ArrayList<>());
            list.add(i);
            map.put(nums[i], list);
        }
    }
    
    public int pick(int target) {
        List<Integer> list = map.get(target);
        Random rd = new Random();
        return list.get(rd.nextInt(list.size()));
    }
}

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

推荐的做法是水塘抽样:
水塘抽样是一系列的随机算法,其目的在于从包含n个项目的集合S中选取k个样本,其中n为一很大或未知的数量,尤其适用于不能把所有n个项目都存放到内存的情况。步骤:

从S中抽取首k项放入「水塘」中
对于每一个S[j]项(j ≥ k):
随机产生一个范围从0到j的整数r
若 r < k 则把水塘中的第r项换成S[j]项

对应到这个题,就是需要有大小为1的水塘,然后从判断需不需要替换

那如果需要选两个或是多个呢,就需要有大小为k的水塘,
每次遍历到target,从0到 i 选取随机数,如果小于k,那么就进行替换,而替换哪个也需要随机,即在0到k选取一个随机数,进行替换
那么对于池子中某个数被替换的概率即为 k/i * 1/k = 1/i
所以对于某个target,它进入池子的概率就是 当前轮次被抽中的概率 乘以 以后不被替换的概率,即:
k/i * (1-1/(i+1))*…(1-1/n)=k/n

class Solution {
    //看了一下标签是水塘抽样,记得写过一次,不过忘了..
    //去百度了一下,水塘抽样适用于样本很多的情况下(内存放不下)抽取其中几个
    //具体做法就是:创建一个k大小的池塘,然后放入k个样本,下面每次抽取,都有k/n的概率被替换
    //具体解释看题解

    //对应于这道题,需要统计每个数字的个数,然后每次pick的时候,创建这个数字个数大小的的池塘
    //然后如果后续选到了target...感觉不行
    //去了一下官解的方法,遍历了整个数组,相当于创建了一个1的水池,
    //然后就是用水塘采样的逻辑,保证每个target选到的概率是1/个数
    
    Random rd;
    int[] nums;
    public Solution(int[] nums) {
        this.nums = nums;
        rd = new Random();
    }
    
    public int pick(int target) {
        int res = 0;
        int count = 0;
        for(int i = 0; i < nums.length; i++){
            if(nums[i] == target){
                count++;
                int t = rd.nextInt(count);
                if(t == 0)
                    res = i;
            }
        }
        return res;
    }
}

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

randrange()
randrange() 方法返回指定递增基数集合中的一个随机数,基数默认值为1
random.randrange ([start,] stop [,step])

class Solution:

    def __init__(self, nums: List[int]):
        self.nums = nums

    def pick(self, target: int) -> int:
        res = count = 0
        for i, num in enumerate(self.nums):
            if num == target:
                count += 1
                if randrange(count) == 0:
                    res = i
        return res


# Your Solution object will be instantiated and called as such:
# obj = Solution(nums)
# param_1 = obj.pick(target)

883. 三维形体投影面积

2022.4.26 每日一题

题目描述

在 n x n 的网格 grid 中,我们放置了一些与 x,y,z 三轴对齐的 1 x 1 x 1 立方体。

每个值 v = grid[i][j] 表示 v 个正方体叠放在单元格 (i, j) 上。

现在,我们查看这些立方体在 xy 、yz 和 zx 平面上的投影。

投影 就像影子,将 三维 形体映射到一个 二维 平面上。从顶部、前面和侧面看立方体时,我们会看到“影子”。

返回 所有三个投影的总面积 。

示例 1:

在这里插入图片描述输入:[[1,2],[3,4]]
输出:17
解释:这里有该形体在三个轴对齐平面上的三个投影(“阴影部分”)。

示例 2:

输入:grid = [[2]]
输出:5

示例 3:

输入:[[1,0],[0,2]]
输出:8

提示:

n == grid.length == grid[i].length
1 <= n <= 50
0 <= grid[i][j] <= 50

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

思路

写完看题解,才发现n和m是相同的,那么可以不创建temp,直接grid[j][i]就可以统计列,python里写下

class Solution {
    public int projectionArea(int[][] grid) {
        //计算投影面积
        //俯视图,就是有几个点,面积就是几
        //正视图,就是看每一列的最大值
        //侧视图,就是看每一行的最大值
        int m = grid.length;
        int n = grid[0].length;
        int up = 0;
        int front = 0;
        int left = 0;
        int[] temp = new int[n];
        for(int i = 0; i < m; i++){
            int max = 0;
            for(int j = 0; j < n; j++){
                if(grid[i][j] != 0)
                    up++;
                max = Math.max(max, grid[i][j]);
                temp[j] = Math.max(temp[j], grid[i][j]);
            }
            left += max;
        }

        for(int t : temp)
            front += t;
        return front + left + up;
    }
}
class Solution:
    def projectionArea(self, grid: List[List[int]]) -> int:
        n = len(grid)
        up = left = front = 0
        for i in range(n):
            temp1 = temp2 = 0
            for j in range(n):
                if grid[i][j]:
                    up += 1
                temp1 = max(temp1, grid[i][j])
                temp2 = max(temp2, grid[j][i])
            left += temp1
            front += temp2
        return up + left + front

这里两个点,一个是zip,一个是*
首先*的作用是把其中的元素变成一个一个独立的部分,这里是将一个二维数组,变成了几个一维数组
然后用 zip将每个数组中的元素打包成一个个元组

class Solution:
    def projectionArea(self, grid: List[List[int]]) -> int:
        up = sum(v > 0 for t in grid for v in t)
        left = sum(max(t) for t in grid)
        front = sum(max(t) for t in zip(*grid))
        return up + left + front

a = [[1,2,3], [2,3,4]]
print(type(a))
print(*a)
print(zip(*a))
print(type(zip(*a)))
print(list(zip(*a)))

'''
<class 'list'>
[1, 2, 3] [2, 3, 4]
<zip object at 0x000002C8DD778DC8>
<class 'zip'>
[(1, 2), (2, 3), (3, 4)]

'''
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值