LeetCode 868. 二进制间距 / 398. 随机数索引(水塘抽样) / 883. 三维形体投影面积
Posted Zephyr丶J
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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)]
'''
以上是关于LeetCode 868. 二进制间距 / 398. 随机数索引(水塘抽样) / 883. 三维形体投影面积的主要内容,如果未能解决你的问题,请参考以下文章
LeetCode 868 二进制间距[二进制] HERODING的LeetCode之路