Skip to content

Commit 3d7329e

Browse files
committed
275
1 parent 87f09cf commit 3d7329e

File tree

3 files changed

+177
-0
lines changed

3 files changed

+177
-0
lines changed

SUMMARY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,4 +230,5 @@
230230
* [268. Missing Number](leetcode-268-Missing-Number.md)
231231
* [273. Integer to English Words](leetcode-273-Intege-to-English-Words.md)
232232
* [274. H-Index](leetcode-274-H-Index.md)
233+
* [275. H-Index II](leetcode-275-H-IndexII.md)
233234
* [更多](more.md)

leetCode-50-Pow.md

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,117 @@ public double powIteration(double x, int n) {
253253

254254
空间复杂度:O(1)。
255255

256+
# 更新
257+
258+
2020.3.16 更新。感谢 [@为爱卖小菜](https://leetcode-cn.com/u/wei-ai-mai-xiao-cai/) 指出,上边的解法虽然都能 `AC`,但是以上全错,少考虑了一种情况。
259+
260+
前边我们分析到 ` -2147483648` 需要单独讨论。
261+
262+
> 但这样的话会出问题,之前在 [29题](https://leetcode.windliang.cc/leetCode-29-Divide-Two-Integers.html) 讨论过,问题出在 n = - n 上,因为最小负数 $$-2^{31}$$取相反数的话,按照计算机的规则,依旧是$$-2^{31}$$,所以这种情况需要单独讨论一下。
263+
>
264+
> ```java
265+
> if (n == -2147483648) {
266+
> return 0;
267+
> }
268+
> ```
269+
270+
但当 `n = -2147483648` 个时候,并不是所有的 $$x^n$$ 结果都是 `0`。
271+
272+
当 `x` 等于 `-1` 或者 `1` 的时候结果是 `1` 。前边的解法也考虑到了。
273+
274+
下边 `x` 等于 `-1` 的时候我们顺便考虑了 `n` 是其他数的情况,所以没直接返回 `1`。
275+
276+
```java
277+
if (x == -1) {
278+
if ((n & 1) != 0) {
279+
return -1;
280+
} else {
281+
return 1;
282+
}
283+
}
284+
if (x == 1.0f)
285+
return 1;
286+
```
287+
288+
但其实 `x` 是浮点数,我们还少考虑了 `-1``0``0``1` 之间的数,此时的 $$x^n$$ 的结果应该是正无穷。
289+
290+
此外 `x == 0` 的话,数学上是不能算的,这里的话也输出正无穷。
291+
292+
综上,我们的前置条件如下
293+
294+
```java
295+
if (x == -1) {
296+
if ((n & 1) != 0) {
297+
return -1;
298+
} else {
299+
return 1;
300+
}
301+
}
302+
if (x == 1.0f){
303+
return 1;
304+
}
305+
306+
if(n == -2147483648){
307+
if(x > -1 && x < 1 ){
308+
return Double.POSITIVE_INFINITY;
309+
}else{
310+
return 0;
311+
}
312+
}
313+
```
314+
315+
上边就是当 `n = -2147483648` 的所有情况了。对于 $$x^n$$`x` 分成了四种情况。
316+
317+
`x == -1` 结果是 `1`,上边的代码我们顺便把 `n` 是其它数的情况也顺便考虑了。
318+
319+
`x == 1` 结果是 `1`
320+
321+
`-1 < x < 1` ,结果是正无穷。
322+
323+
`x < -1` 或者 `x > 1` ,结果是 `0`
324+
325+
[@为爱卖小菜](https://leetcode-cn.com/u/wei-ai-mai-xiao-cai/) 也提供了一个新方法,可以把上边的所有情况统一起来。
326+
327+
因为当 `n = -2147483648` 的时候我们无法正确计算,我们可以把 $$x^{-2147483648}$$ 分解成 $$x^{-2147483647} * x^{-1}$$ 。这样的话两部分都可以成功求解了。
328+
329+
对于解法三,可以改写成下边的样子。其他解法也类似。
330+
331+
```java
332+
public double myPow(double x, int n) {
333+
double mul = 1;
334+
if (n > 0) {
335+
mul = powIteration(x, n);
336+
} else {
337+
//单独考虑 n = -2147483648
338+
if (n == -2147483648) {
339+
return myPow(x, -2147483647) * (1 / x);
340+
}
341+
n = -n;
342+
mul *= powIteration(x, n);
343+
mul = 1 / mul;
344+
}
345+
return mul;
346+
}
347+
348+
public double powIteration(double x, int n) {
349+
double ans = 1;
350+
//遍历每一位
351+
while (n > 0) {
352+
//最后一位是 1,加到累乘结果里
353+
if ((n & 1) == 1) {
354+
ans = ans * x;
355+
}
356+
//更新 x
357+
x = x * x;
358+
//n 右移一位
359+
n = n >> 1;
360+
}
361+
return ans;
362+
}
363+
```
364+
365+
366+
256367
#
257368

258369
从一般的方法,到递归,最后的解法,直接从 2 进制考虑,每一个数字,都可以转换成 2 的幂次的和,从而实现了最终的解法。

leetcode-275-H-IndexII.md

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
# 题目描述(中等难度)
2+
3+
![](https://windliang.oss-cn-beijing.aliyuncs.com/275.png)
4+
5+
`H-Index`,和 [上一道题](https://leetcode.wang/leetcode-274-H-Index.html) 一样,只不过这道题给定的数组是有序的,详细的可以先做一下上一题。
6+
7+
# 解法一
8+
9+
先看一下之前的其中一个的做法。
10+
11+
![img](https://windliang.oss-cn-beijing.aliyuncs.com/274_3.jpg)
12+
13+
我们从 `0` 开始遍历,依次判断点是否在直线下方,如果出现了点在直线上方(包括在直线上),那么当前点的垂线与直线交点的纵坐标就是 `H-Index` 了。
14+
15+
点的垂线与直线交点的纵坐标的求法是 `n - i``n` 是数组长度,`i` 是数组下标。
16+
17+
代码如下。
18+
19+
```java
20+
public int hIndex(int[] citations) {
21+
Arrays.sort(citations);
22+
int n = citations.length;
23+
for (int i = 0; i < n; i++) {
24+
// 点在直线上方
25+
if (citations[i] >= n - i) {
26+
return n - i;
27+
}
28+
}
29+
return 0;
30+
}
31+
32+
```
33+
34+
说白了,我们是要寻找**第一个**在直线上方(包括在直线上)的点,给定数组是有序的,所以我们可以用二分查找。
35+
36+
```java
37+
public int hIndex(int[] citations) {
38+
int n = citations.length;
39+
int low = 0;
40+
int high = n - 1;
41+
while (low <= high) {
42+
int mid = (low + high) >>> 1;
43+
//在直线上方
44+
if (citations[mid] >= n - mid) {
45+
if (mid == 0) {
46+
return n;
47+
}
48+
//前一个点是否在直线下方
49+
int before = mid - 1;
50+
if (citations[before] < n - before) {
51+
return n - mid;
52+
}
53+
54+
high = mid - 1;
55+
} else {
56+
low = mid + 1;
57+
}
58+
}
59+
return 0;
60+
}
61+
```
62+
63+
#
64+
65+
主要就是二分查找的应用了。

0 commit comments

Comments
 (0)