Skip to content

Commit fe05a6a

Browse files
author
Dinghao LI
committed
053
1 parent bd8a50c commit fe05a6a

File tree

16 files changed

+584
-0
lines changed

16 files changed

+584
-0
lines changed

044-扑克牌顺子/README.md

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# 题意
2+
题目描述
3+
4+
LL今天心情特别好,因为他去买了一副扑克牌,发现里面居然有2个大王,2个小王(一副牌原本是54张)
5+
6+
他随机从中抽出了5张牌,想测测自己的手气,看看能不能抽到顺子,如果抽到的话,他决定去买体育彩票 ,嘿嘿!!“红心A,黑桃3,小王,大王,方片5”, “Oh My God!”不是顺子.....LL不高兴了,他想了想,决定大\小王可以看成任何数字,并且A看作1,J为11,Q为12,K为13。 上面的5张牌就可以变成“1,2,3,4,5”(大小王分别看作2和4),“So Lucky!”。
7+
8+
LL决定去买体育彩票啦。 现在,要求你使用这幅牌模拟上面的过程,然后告诉我们LL的运气如何。为了方便起见,你可以认为大小王是0。
9+
10+
样例输入
11+
12+
3 5 1 0 4
13+
14+
3 5 4 7 6
15+
16+
3 5 7 4 8
17+
18+
样例输出
19+
20+
So Lucky!
21+
22+
So Lucky!
23+
24+
Oh My God!
25+
26+
# 排序后看0能不能填补空缺
27+
28+
可以把5张牌看成由5个数字组成的数组。大、小王是特殊的数字,我们不妨把它们定义为0,这样就能和其他扑克牌区分开来了。
29+
30+
接下来我们分析怎样判断5个数字是不是连续的,最直观的方法是把数组排序。值得注意的是,由于0可以当成任意数字,我们可以用0去补满数组中的空缺。如果排序之后的数组不是连续的,即相邻的两个数字相隔若干个数字,但只要我们有足够的0可以补满这两个数字的空缺,这个数组实际上还是连续的。举个例子,数组排序之后为{0,1,3,4,5},在1和3之间空缺了一个2,刚好我们有一个0,也就是我们可以把它当成2去填补这个空缺。
31+
32+
于是我们需要做3件事:
33+
34+
首先把数组排序
35+
36+
再统计数组中的0的个数
37+
38+
最后统计排序之后的数组中相邻数字之间的空缺总数。
39+
40+
如果空缺的总数小于或者等于0的个数,那么这个数组就是连续的;反之则不连续。
41+
42+
最后,我们还需要注意一点:
43+
44+
如果数组中的非0数字重复出现,则该数组不是连续的。
45+
46+
### 但是我们考虑一下子题目中特殊条件对顺子有什么要求
47+
48+
条件: 5张牌,顺子,除0之外不能重复
49+
50+
结论: 非0元素的极差(最大值最小值的差)不超过4, 非0元素不重复
51+
52+
非0元素的极差不查过4
53+
首先5张牌的顺子,即使包含了0,那么最大值和最小值的差值肯定不超过4,否则的话一定不是顺子
54+
55+
比如{ 1,2,3,4,6 },最大最小值的差(极差)为6-1=5>4
56+
57+
正好满足的情况,{1, 2, 3, 4, 5},极差刚好是4
58+
59+
可以填补的情况,0填补的位置分四种情况,前面 {0, 2, 3, 4, 5},,中间{1, 2, 0, 4, 5}和结尾{1, 2, 3, 4, 0,},以及混合情况,这些情况下极差都不可能超过4
60+
61+
这个比较好判断,我们维护一个非0的最大最小值,那么判断极差即可
62+
63+
非0元素不重复
64+
接着是怎么判断非0元素是否重复呢?
65+
66+
我们可以通过位运算,设置一个标识flag
67+

044-扑克牌顺子/problem044.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"sort"
6+
)
7+
8+
func poker(nums []int) string {
9+
sort.Ints(nums)
10+
start := 0
11+
for nums[start] == 0 {
12+
start++
13+
}
14+
for i := start+1; i < len(nums); i++{
15+
if nums[i] - nums[i-1] -1 > start || nums[i] == nums[i-1] {
16+
return "Oh my god"
17+
}
18+
start -= (nums[i] - nums[i-1] -1)
19+
fmt.Println(i, start)
20+
}
21+
if start >= 0 {
22+
return "So lucky"
23+
}
24+
return "Oh my god"
25+
}
26+
27+
func main() {
28+
arr1 := []int{ 1, 3, 2, 6, 4 };
29+
fmt.Println(arr1, " => ", poker(arr1))
30+
31+
arr2 := []int{ 3, 5, 1, 0, 4, };
32+
fmt.Println(arr2, " => ", poker(arr2))
33+
34+
arr3 := []int{ 1, 0, 0, 1, 0 };
35+
fmt.Println(arr3, " => ", poker(arr3))
36+
}
37+
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# 题意
2+
题目描述
3+
4+
每年六一儿童节,NowCoder都会准备一些小礼物去看望孤儿院的小朋友,今年亦是如此。
5+
6+
HF作为NowCoder的资深元老,自然也准备了一些小游戏。
7+
8+
其中,有个游戏是这样的:
9+
10+
首先,让小朋友们围成一个大圈。然后,他随机指定一个数m,让编号为0的小朋友开始报数。
11+
12+
每次喊到m的那个小朋友要出列唱首歌,然后可以在礼品箱中任意的挑选礼物,并且不再回到圈中,从他的下一个小朋友开始,继续0...m-1报数....这样下去....直到剩下最后一个小朋友,可以不用表演,
13+
14+
并且拿到NowCoder名贵的“名侦探柯南”典藏版(名额有限哦!!^_^)。
15+
16+
请你试着想下,哪个小朋友会得到这份礼品呢?
17+
18+
# 递推公式-获取最后的胜利者的序号
19+
无论是用链表实现还是用数组实现都有一个共同点:要模拟整个游戏过程,不仅程序写起来比较烦,而且时间复杂度高达$O(nm)$,当n,m非常大(例如上百万,上千万)的时候,几乎是没有办法在短时间内出结果的。我们注意到原问题仅仅是要求出最后的胜利者的序号,而不是要读者模拟整个过程。因此如果要追求效率,就要打破常规,实施一点数学策略。
20+
21+
为了讨论方便,先把问题稍微改变一下,并不影响原意: 我们知道第一个人(编号一定是(m-1)) 出列之后,剩下的n-1个人组成了一个新的约瑟夫环(以编号为k=m mod n的人开始):
22+
23+
k k+1 k+2 ... n-2,n-1,0,1,2,... k-2
24+
25+
并且从k开始报0。 我们把他们的编号做一下转换:
26+
27+
k --> 0
28+
k+1 --> 1
29+
k+2 --> 2
30+
...
31+
...
32+
k-2 --> n-2
33+
34+
变换后就完完全全成为了(n-1)个人报数的子问题,假如我们知道这个子问题的解:例如x是最终的胜利者,那么根据上面这个表把这个x变回去不刚好就是n个人情况的解吗?!!变回去的公式很简单,相信大家都可以推出来:x'=(x+k) mod n 如何知道(n-1)个人报数的问题的解?对,只要知道(n-2)个人的解就行了。(n-2)个人的解呢?当然是先求(n-3)的情况 ---- 这显然就是一个倒推问题!好了,思路出来了,下面写递推公式:
35+
令f表示i个人玩游戏报m退出最后胜利者的编号,最后的结果自然是f[n]
36+
37+
递推公式
38+
39+
让f[i]为i个人玩游戏报m退出最后的胜利者的编号,最后的结果自然是f[n]
40+
41+
f[1] = 0; f[i] = (f[i - 1] + m) mod i;
42+
43+
有了这个公式,我们要做的就是从1-n顺序算出f的数值,最后结果是f[n]
44+
45+
注意我们的编号是从0开始,如果从1开始可以返回f[n] + 1
46+
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
)
6+
7+
func cycle(n,m int) int {
8+
if n < 1 || m < 1 {
9+
return -1
10+
} else if n == 1{
11+
return 0
12+
} else {
13+
// F[n] = (F[n - 1] + m) % n
14+
return (cycle(n-1,m) + m) % n
15+
}
16+
}
17+
18+
func main() {
19+
20+
fmt.Println(3,2, " => ", cycle(3,2))
21+
22+
fmt.Println(4,2, " => ", cycle(4,2))
23+
24+
fmt.Println(5,2, " => ", cycle(5,2))
25+
}

046-求1+2+3+...+n/README.md

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# 题意
2+
题目描述
3+
4+
求1+2+3+...+n,
5+
6+
要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。
7+
8+
样例输入
9+
10+
3
11+
12+
5
13+
14+
样例输出
15+
16+
6
17+
18+
15
19+
20+
# 递归+短路判断终止
21+
计算1+2+3+...+n, 可以认为是一个递归的过程, 这点很容易理解
22+
23+
但是怎么不用分支判断来保证递归的终止呢
24+
25+
通过短路运算0&&cout使条件为假值,从而不执行输出语句,那么我们也可以通过短路来实现循环终止,从n开始递减进程递归的相加运算当递归至0时使递归短路即可。
26+
27+
代码如下
28+
```java
29+
class Solution
30+
{
31+
public:
32+
int SumRecursion(int n)
33+
{
34+
int ans = n;
35+
//debug <<n <<endl;
36+
n && (ans += SumRecursion(n - 1));
37+
return ans;
38+
}
39+
};
40+
```
41+
其实也可以用下面的语句
42+
43+
ans && (ans += Sum_Solution(n - 1));
44+
45+
ans每次均被初始化为n, 因此用n或者ans进行短路运算都可以,其本质就是通过n进行短路运算判断
46+
47+
https://github.com/gatieme/CodingInterviews/blob/master/046-%E6%B1%821%2B2%2B3%2B...%2Bn/README.md
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# 题意
2+
题目描述
3+
4+
写一个函数,求两个整数之和,要求在函数体内不得使用+、-、*、/四则运算符号。
5+
6+
样例输入
7+
8+
3 4
9+
10+
7 9
11+
12+
样例输出
13+
14+
7
15+
16+
16
17+
18+
## 过程如下
19+
20+
首先看十进制是如何做的: 5+7=12,三步走
21+
22+
相加各位的值,不算进位,得到5 + 7 = 2(不算进位)
23+
24+
计算进位值,得到10. 如果这一步的进位值为0,那么第一步得到的值就是最终结果。
25+
26+
重复上述两步,只是相加的值变成上述两步的得到的结果2和10,得到12。
27+
28+
我们可以用三步走的方式计算二进制值相加:
29+
30+
5 -=> 101 7 -=> 111
31+
32+
相加各位的值,不算进位,得到010,二进制每位相加就相当于各位做异或操作,101^111=010
33+
34+
计算进位值,得到1010,相当于各位做与操作得到101,再向左移一位得到1010,(101&111)<<1。
35+
36+
重复上述两步, 各位相加 010^1010=1000,进位值为100=(010&1010)<<1。
37+
38+
继续重复上述两步:1000^100 = 1100,进位值为0,跳出循环,1100为最终结果。
39+
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
)
6+
7+
func Add(n, m int) int {
8+
tmp := 0
9+
for m != 0 {
10+
tmp = n ^ m
11+
m = (n & m) << 1
12+
n = tmp
13+
}
14+
return n
15+
}
16+
17+
func main() {
18+
19+
fmt.Println("5+7: ", Add(5, 7))
20+
fmt.Println("50+70: ", Add(50, 70))
21+
fmt.Println("15+7: ", Add(15, 7))
22+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# 题意
2+
3+
题目描述
4+
5+
设计一个不能被继承的类
6+
7+
## golang: 臣妾做不到
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#题意
2+
3+
将一个字符串转换成一个整数,要求不能使用字符串转换整数的库函数。
4+
5+
6+
[LeetCode 8. String to Integer (atoi)](https://leetcode.com/problems/string-to-integer-atoi/)
7+
8+
```
9+
Example 1:
10+
11+
Input: "42"
12+
Output: 42
13+
```
14+
```
15+
Example 2:
16+
17+
Input: " -42"
18+
Output: -42
19+
Explanation: The first non-whitespace character is '-', which is the minus sign. Then take as many numerical digits as possible, which gets 42.
20+
```
21+
```
22+
Example 3:
23+
24+
Input: "4193 with words"
25+
Output: 4193
26+
Explanation: Conversion stops at digit '3' as the next character is not a numerical digit.
27+
```
28+
```
29+
Example 4:
30+
31+
Input: "words and 987"
32+
Output: 0
33+
Explanation: The first non-whitespace character is 'w', which is not a numerical digit or a +/- sign. Therefore no valid conversion could be performed.
34+
```
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"math"
6+
)
7+
8+
func myAtoi(str string) int {
9+
res := 0
10+
flag := 1
11+
start := 0
12+
for start <= len(str)-1 && str[start] == ' ' {
13+
start++
14+
}
15+
if start <= len(str)-1 {
16+
if str[start] == '-' {
17+
flag = -1
18+
start++
19+
} else if str[start] == '+' {
20+
start++
21+
}
22+
}
23+
for start <= len(str)-1 && isDigital(str[start]) {
24+
if res == 0 {
25+
fmt.Println(int(str[start] - '0'))
26+
res += int(str[start] - '0')
27+
start++
28+
} else {
29+
res = res*10 + int((str[start] - '0'))
30+
start++
31+
}
32+
if res*flag > math.MaxInt32 {
33+
return math.MaxInt32
34+
} else if res*flag < math.MinInt32 {
35+
return math.MinInt32
36+
}
37+
}
38+
39+
res *= flag
40+
return res
41+
}
42+
43+
func isDigital(b byte) bool {
44+
if b <= '9' && b >= '0' {
45+
return true
46+
}
47+
return false
48+
}
49+
50+
func main() {
51+
52+
fmt.Println(" 42", " => ", myAtoi(" 42"))
53+
fmt.Println(" 42asdfsdf", " => ", myAtoi(" 42asdfsdf"))
54+
fmt.Println(" -42asdfsdf", " => ", myAtoi(" -42asdfsdf"))
55+
fmt.Println("9223372036854775808", " => ", myAtoi("9223372036854775808"))
56+
fmt.Println("-9223372036854775808", " => ", myAtoi("-9223372036854775808"))
57+
58+
}

0 commit comments

Comments
 (0)