Skip to content

Commit 148d42f

Browse files
committed
feat: leetcode 398
1 parent bbdb0be commit 148d42f

File tree

8 files changed

+194
-2
lines changed

8 files changed

+194
-2
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
<p align="center">
44
<!-- TOPICS COUNT START -->
5-
<img src="https://img.shields.io/badge/-进度:333-green" alt="进度:333">
5+
<img src="https://img.shields.io/badge/-进度:334-green" alt="进度:334">
66
<!-- TOPICS COUNT END -->
77
<a href="./assets/docs/TOPICS.md"><img src="https://img.shields.io/badge/-题库目录-blue" alt="题库目录"></a>
88
<a href="./assets/docs/CATEGORIES.md"><img src="https://img.shields.io/badge/-题库分类-red" alt="题库分类"></a>

assets/data/categories.json

+12
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,12 @@
176176
"path": "./problemset/insert-delete-getrandom-o1/README.md",
177177
"difficulty": "中等"
178178
},
179+
{
180+
"id": "398",
181+
"title": "随机数索引",
182+
"path": "./problemset/random-pick-index/README.md",
183+
"difficulty": "中等"
184+
},
179185
{
180186
"id": "432",
181187
"title": "全 O(1) 的数据结构",
@@ -1571,6 +1577,12 @@
15711577
"path": "./problemset/utf-8-validation/README.md",
15721578
"difficulty": "中等"
15731579
},
1580+
{
1581+
"id": "398",
1582+
"title": "随机数索引",
1583+
"path": "./problemset/random-pick-index/README.md",
1584+
"difficulty": "中等"
1585+
},
15741586
{
15751587
"id": "420",
15761588
"title": "强密码检验器",

assets/data/topics.json

+11-1
Original file line numberDiff line numberDiff line change
@@ -2579,6 +2579,16 @@
25792579
"url": "https://leetcode-cn.com/problems/rotate-function/",
25802580
"path": "./problemset/rotate-function/README.md"
25812581
},
2582+
{
2583+
"id": "398",
2584+
"title": {
2585+
"cn": "随机数索引",
2586+
"en": "random-pick-index"
2587+
},
2588+
"difficulty": "中等",
2589+
"url": "https://leetcode-cn.com/problems/random-pick-index/",
2590+
"path": "./problemset/random-pick-index/README.md"
2591+
},
25822592
{
25832593
"id": "420",
25842594
"title": {
@@ -3329,4 +3339,4 @@
33293339
"url": "https://leetcode-cn.com/problems/sum-of-subarray-ranges/",
33303340
"path": "./problemset/sum-of-subarray-ranges/README.md"
33313341
}
3332-
]
3342+
]

assets/docs/CATEGORIES.md

+2
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
| 290. [单词规律](../../problemset/word-pattern/README.md) | 简单 |
3434
| 355. [设计推特](../../problemset/design-twitter/README.md) | 中等 |
3535
| 380. [O(1) 时间插入、删除和获取随机元素](../../problemset/insert-delete-getrandom-o1/README.md) | 中等 |
36+
| 398. [随机数索引](../../problemset/random-pick-index/README.md) | 中等 |
3637
| 432. [全 O(1) 的数据结构](../../problemset/all-one-data-structure/README.md) | 困难 |
3738
| 599. [两个列表的最小索引总和](../../problemset/minimum-index-sum-of-two-lists/README.md) | 简单 |
3839
| 653. [两数之和 IV - 输入 BST](../../problemset/two-sum-iv-input-is-a-bst/README.md) | 简单 |
@@ -303,6 +304,7 @@
303304
| 307. [ 区域和检索 - 数组可修改](../../problemset/range-sum-query-mutable/README.md) | 中等 |
304305
| 310. [最小高度树](../../problemset/minimum-height-trees/README.md) | 中等 |
305306
| 393. [UTF-8 编码验证](../../problemset/utf-8-validation/README.md) | 中等 |
307+
| 398. [随机数索引](../../problemset/random-pick-index/README.md) | 中等 |
306308
| 420. [强密码检验器](../../problemset/strong-password-checker/README.md) | 困难 |
307309
| 521. [最长特殊序列](../../problemset/longest-uncommon-subsequence/README.md) | 简单 |
308310
| 537. [复数乘法](../../problemset/complex-number-multiplication/README.md) | 中等 |

assets/docs/TOPICS.md

+2
Original file line numberDiff line numberDiff line change
@@ -516,6 +516,8 @@
516516

517517
[396. 旋转函数](../../problemset/rotate-function/README.md)
518518

519+
[398. 随机数索引](../../problemset/random-pick-index/README.md)
520+
519521
[420. 强密码检验器](../../problemset/strong-password-checker/README.md)
520522

521523
[429. N 叉树的层序遍历](../../problemset/n-ary-tree-level-order-traversal/README.md)
+95
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
# 随机数索引
2+
3+
> 难度:中等
4+
>
5+
> https://leetcode-cn.com/problems/random-pick-index/
6+
7+
## 题目
8+
9+
给定一个可能含有重复元素的整数数组,要求随机输出给定的数字的索引。 您可以假设给定的数字一定存在于数组中。
10+
11+
注意:数组大小可能非常大。 使用太多额外空间的解决方案将不会通过测试。
12+
13+
### 示例:
14+
15+
```
16+
int[] nums = new int[] {1,2,3,3,3};
17+
Solution solution = new Solution(nums);
18+
19+
// pick(3) 应该返回索引 2,3 或者 4。每个索引的返回概率应该相等。
20+
solution.pick(3);
21+
22+
// pick(1) 应该返回 0。因为只有nums[0]等于1。
23+
solution.pick(1);
24+
```
25+
26+
## 解题
27+
28+
### 哈希表
29+
30+
```ts
31+
/**
32+
* 哈希表
33+
*/
34+
export class Solution {
35+
indexMap = new Map<number, number[]>()
36+
37+
/**
38+
* @desc 时间复杂度 O(N) 空间复杂度 O(N)
39+
* @param nums
40+
*/
41+
constructor(nums: number[]) {
42+
for (let i = 0; i < nums.length; i++) {
43+
const num = nums[i]
44+
if (this.indexMap.has(num))
45+
this.indexMap.get(num)!.push(i)
46+
else
47+
this.indexMap.set(num, [i])
48+
}
49+
}
50+
51+
/**
52+
* @desc 时间复杂度 O(1) 空间复杂度 O(N)
53+
* @param nums
54+
*/
55+
pick(target: number): number {
56+
const idxs = this.indexMap.get(target)
57+
if (!idxs) return -1
58+
if (idxs.length === 1) return idxs[0]
59+
60+
return idxs[(Math.random() * idxs.length) >> 0]
61+
}
62+
}
63+
```
64+
65+
### 水塘抽样
66+
67+
```ts
68+
/**
69+
* 水塘抽样
70+
*/
71+
export class Solution2 {
72+
/**
73+
* @desc 时间复杂度 O(1) 空间复杂度 O(1)
74+
* @param nums
75+
*/
76+
constructor(public nums: number[]) {}
77+
78+
/**
79+
* @desc 时间复杂度 O(N) 空间复杂度 O(1)
80+
* @param nums
81+
*/
82+
pick(target: number): number {
83+
let ans = 0
84+
for (let i = 0, cnt = 0; i < this.nums.length; i++) {
85+
if (this.nums[i] === target) {
86+
// 记录target的次数
87+
cnt++
88+
if ((Math.random() * cnt) >> 0 === 0) ans = i
89+
}
90+
}
91+
92+
return ans
93+
}
94+
}
95+
```
+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { expect, it } from 'vitest'
2+
import { Solution, Solution2 } from '.'
3+
4+
it.each([
5+
['哈希表', Solution],
6+
['水塘抽样', Solution2],
7+
])('随机数索引:%s', (_, Ctor) => {
8+
const solution = new Ctor([1, 2, 3, 3, 3])
9+
expect(solution.pick(3)).toMatch(/2|3|4/)
10+
expect(solution.pick(1)).toBe(0)
11+
})

problemset/random-pick-index/index.ts

+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/**
2+
* 哈希表
3+
*/
4+
export class Solution {
5+
indexMap = new Map<number, number[]>()
6+
7+
/**
8+
* @desc 时间复杂度 O(N) 空间复杂度 O(N)
9+
* @param nums
10+
*/
11+
constructor(nums: number[]) {
12+
for (let i = 0; i < nums.length; i++) {
13+
const num = nums[i]
14+
if (this.indexMap.has(num))
15+
this.indexMap.get(num)!.push(i)
16+
else
17+
this.indexMap.set(num, [i])
18+
}
19+
}
20+
21+
/**
22+
* @desc 时间复杂度 O(1) 空间复杂度 O(N)
23+
* @param nums
24+
*/
25+
pick(target: number): number {
26+
const idxs = this.indexMap.get(target)
27+
if (!idxs) return -1
28+
if (idxs.length === 1) return idxs[0]
29+
30+
return idxs[(Math.random() * idxs.length) >> 0]
31+
}
32+
}
33+
34+
/**
35+
* 水塘抽样
36+
*/
37+
export class Solution2 {
38+
/**
39+
* @desc 时间复杂度 O(1) 空间复杂度 O(1)
40+
* @param nums
41+
*/
42+
constructor(public nums: number[]) {}
43+
44+
/**
45+
* @desc 时间复杂度 O(N) 空间复杂度 O(1)
46+
* @param nums
47+
*/
48+
pick(target: number): number {
49+
let ans = 0
50+
for (let i = 0, cnt = 0; i < this.nums.length; i++) {
51+
if (this.nums[i] === target) {
52+
// 记录target的次数
53+
cnt++
54+
if ((Math.random() * cnt) >> 0 === 0) ans = i
55+
}
56+
}
57+
58+
return ans
59+
}
60+
}

0 commit comments

Comments
 (0)