Skip to content

Commit b84d242

Browse files
author
Dinghao LI
committed
059
1 parent fe05a6a commit b84d242

File tree

12 files changed

+492
-0
lines changed

12 files changed

+492
-0
lines changed
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# 题目描述
2+
请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。
3+
4+
例如, 字符串"+100","5e2","-123","3.1416"和"-1E-16"都表示数值。 但是"12e","1a3.14","1.2.3","+-5"和"12e+4.3"都不是。
5+
6+
# 分析
7+
我们首先分析一下子可能是数值的字符串的格式 在数值之前可能有一个表示正负的’-‘或者’+’。 接下来是若干个0到9的数位表示数值的整数部分(在某些小数里可能没有数值的整数部分)。 如果数值是一个小数,那么在小数点后面可能会有若干个0到9的数位表示数值的小数部分。如果数值用科学计数法表示,接下来是一个’e’或者‘E’,以及紧跟着的一个整数(可以有正负号)表示指数。    判断一个字符串是否符合上述模式时,
8+
9+
首先看第一个字符是不是正负号。
10+
如果是,在字符串上移动一个字符,继续扫描剩余的字符串中0到9的数位。
11+
如果是一个小数,则将遇到小数点。
12+
另外,如果是用科学计数法表示的数值,在整数或者小数的后面还有可能遇到’e’或者’E’。
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
)
6+
7+
func isNumber(str string) bool {
8+
if len(str) == 0 {
9+
return false
10+
}
11+
start := 0
12+
if str[start] == '+' || str[start] == '-' {
13+
start++
14+
}
15+
if start >= len(str) {
16+
return false
17+
}
18+
19+
numberic := true
20+
21+
start = scanDigits(str, start)
22+
23+
24+
if start < len(str) {
25+
if str[start] == '.' {
26+
start++
27+
start = scanDigits(str, start)
28+
if start == len(str) {
29+
return true
30+
}
31+
if str[start] == 'e' || str[start] == 'E' {
32+
numberic, start = isE(str, start)
33+
34+
}
35+
} else if str[start] == 'e' || str[start] == 'E' {
36+
37+
numberic, start = isE(str, start)
38+
39+
} else {
40+
numberic = false
41+
}
42+
}
43+
44+
return numberic && start == len(str)
45+
46+
}
47+
48+
func scanDigits(str string, start int) int {
49+
i := start
50+
for i < len(str) && str[i] <= '9' && str[i] >= '0' {
51+
i++
52+
}
53+
return i
54+
}
55+
56+
func isE(str string, start int) (bool, int) {
57+
if str[start] != 'e' && str[start] != 'E' {
58+
return false, start
59+
}
60+
start++
61+
if start >= len(str) {
62+
return false, start
63+
}
64+
65+
if str[start] == '+' || str[start] == '-' {
66+
start++
67+
}
68+
69+
if start >= len(str) {
70+
return false, start
71+
}
72+
73+
start = scanDigits(str, start)
74+
75+
if start == len(str) {
76+
return true, start
77+
}
78+
return false, start
79+
}
80+
81+
func main() {
82+
fmt.Println("Should be true")
83+
84+
test := "+100"
85+
fmt.Println(test, " is Number ", isNumber(test))
86+
test = "5e2"
87+
fmt.Println(test, " is Number ", isNumber(test))
88+
test = "-123"
89+
fmt.Println(test, " is Number ", isNumber(test))
90+
91+
test = "-3.1416"
92+
fmt.Println(test, " is Number ", isNumber(test))
93+
94+
test = "-3E-16"
95+
fmt.Println(test, " is Number ", isNumber(test))
96+
97+
fmt.Println("")
98+
fmt.Println("Should be false")
99+
100+
test = "12e"
101+
fmt.Println(test, " is Number ", isNumber(test))
102+
103+
test = "1a3.14"
104+
fmt.Println(test, " is Number ", isNumber(test))
105+
106+
test = "1.2.3"
107+
fmt.Println(test, " is Number ", isNumber(test))
108+
109+
test = "+-5"
110+
fmt.Println(test, " is Number ", isNumber(test))
111+
112+
test = "12e+4.3"
113+
fmt.Println(test, " is Number ", isNumber(test))
114+
115+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# 题目描述
2+
3+
请实现一个函数用来找出字符流中第一个只出现一次的字符。例如,当从字符流中只读出前两个字符"go"时,第一个只出现一次的字符是"g"。当从该字符流中读出前六个字符“google"时,第一个只出现一次的字符是"l"。
4+
5+
如果当前字符流没有存在出现一次的字符,返回#字符。
6+
7+
# 分析
8+
9+
类似的题目
10+
11+
[剑指Offer--035-第一个只出现一次的字符位置](https://github.com/DinghaoLI/Coding-Interviews-Golang/tree/master/035-%E7%AC%AC%E4%B8%80%E4%B8%AA%E5%8F%AA%E5%87%BA%E7%8E%B0%E4%B8%80%E6%AC%A1%E7%9A%84%E5%AD%97%E7%AC%A6%E4%BD%8D%E7%BD%AE)
12+
13+
但是第35题只要求我们找到一个字符串中第一个只出现一次字符即可, 但是这道题相当于一个在线算法, 要求我们能对一个源源不断的输入流进行处理
14+
15+
字符只能一个接着一个从字符流中读取出来, 因此我们可以定义一个数据容器来保存字符在字符流中的位置, 当一个字符第一次从字符流中拂去出来的时候, 把它保存在字符流中的位置保存到容器中。
16+
17+
当这个字符再次从字符流中被读取出来的时候, 那么它就不是只出现一次的字符, 也就是被忽略了。这时候就把在数据容器里保存的值更新成一个特殊的值即可。
18+
19+
为了更加高效的解决这个问题, 需要在O(1)的时间内往数据容器里插入一个字符, 以及更新一个字符对应的值。
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
)
6+
7+
type Solution struct {
8+
str string
9+
count []int
10+
}
11+
12+
func (s *Solution) Insert(char byte) {
13+
s.str += string(char)
14+
s.count[char]++
15+
}
16+
17+
func (s *Solution) GetOnceAppear() byte {
18+
for i, v := range s.count {
19+
if v == 1 {
20+
return byte(i)
21+
}
22+
}
23+
return '#'
24+
}
25+
26+
func main() {
27+
sol := &Solution{"", make([]int, 256)}
28+
29+
sol.Insert('g')
30+
fmt.Println(sol.str, " GetOnceAppear: ", string(sol.GetOnceAppear()))
31+
sol.Insert('o')
32+
fmt.Println(sol.str, " GetOnceAppear: ", string(sol.GetOnceAppear()))
33+
sol.Insert('o')
34+
fmt.Println(sol.str, " GetOnceAppear: ", string(sol.GetOnceAppear()))
35+
sol.Insert('g')
36+
fmt.Println(sol.str, " GetOnceAppear: ", string(sol.GetOnceAppear()))
37+
sol.Insert('l')
38+
fmt.Println(sol.str, " GetOnceAppear: ", string(sol.GetOnceAppear()))
39+
sol.Insert('e')
40+
fmt.Println(sol.str, " GetOnceAppear: ", string(sol.GetOnceAppear()))
41+
42+
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
# 题目描述
2+
3+
一个链表中包含环,请找出该链表的环的入口结点。
4+
5+
[LeetCode 142. Linked List Cycle II](https://leetcode.com/problems/linked-list-cycle-ii)
6+
7+
# 双指针法
8+
9+
受到第15题的启发剑指Offer--015-链表中倒数第k个结点, 我们考虑这样一个事实
10+
11+
假设链表长度为N, 那么第N链接到了第k个节点形成了环,即我们需要查找到倒数第N-K+1个节点, 那么环中就有N-K+1个节点,这时候我们定义两个指针$P_1$和$P_2$指向链表的头部, 指针$P_1$先在链表中向前移动n-k+1步,到达第n-k+2个节点, 然后两个指针同步向前移动, 当$P_2$走了K-1步到达环的入口的时候, 指针$P_1$正好走了N+1步, 到达了环的入口, 即两个指针会相遇在环的入口处
12+
13+
那么我们剩下的问题就是如何得到环中节点的数目?
14+
15+
我们可以使用一快一慢两个指针(比如慢指针一次走一步, 慢指针一次走两步),如果走的过程中发现快指针追上了慢指针, 说明遇见了环,而且相遇的位置一定在环内, 考虑一下环内, 从任何一个节点出现再回到这个节点的距离就是环的长度, 于是我们可以进一步移动慢指针,快指针原地不动, 当慢指针再次回到相遇位置时, 正好在环内走了一圈, 从而我们通过计数就可以获取到环的长度
16+
17+
第一步,找环中相汇点。分别用p1,p2指向链表头部,p1每次走一步,p2每次走二步,直到p1==p2找到在环中的相汇点。
18+
19+
第二步,找环的长度。从环中的相汇点开始, p2不动, p1前移, 当再次相遇时,p1刚好绕环一周, 其移动即为环的长度K
20+
21+
第三步, 求换的起点, 转换为求环的倒数第N-K个节点,则两指针left和right均指向起始, right先走K步, 然后两个指针开始同步移动, 当两个指针再次相遇时, right刚好绕环一周回到起点, left则刚好走到了起点位置
22+
23+
```golang
24+
/**
25+
* Definition for singly-linked list.
26+
* type ListNode struct {
27+
* Val int
28+
* Next *ListNode
29+
* }
30+
*/
31+
// https://juejin.im/post/59e5544851882551dd311710
32+
// n为head到entrance的节点数
33+
// m为环的长度
34+
// k为slow过了entrance后走的节点数
35+
// m-k为从fast、slow的相遇点到entrance的节点数(向前走)
36+
// slow = n + k
37+
// fast = qm + n + k (q为正整数,为圈数)
38+
// fast = 2 * slow
39+
// 可得 n = qm -k
40+
// 亦是 n = (q-1)m + (m-k)
41+
// 证毕
42+
func detectCycle(head *ListNode) *ListNode {
43+
slow, fast := head, head
44+
if head == nil || head.Next == nil {
45+
return nil
46+
}
47+
48+
for fast.Next != nil && fast.Next.Next != nil {
49+
fast = fast.Next.Next
50+
slow = slow.Next
51+
if slow == fast {
52+
tmp := head
53+
// n = (q-1)m + (m-k)
54+
// 所以从slow和head同时开始走,当slow==head那说明,这就是entrance
55+
for tmp != slow {
56+
slow = slow.Next
57+
tmp = tmp.Next
58+
}
59+
return tmp
60+
}
61+
}
62+
63+
return nil
64+
}
65+
```
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/**
2+
* Definition for singly-linked list.
3+
* type ListNode struct {
4+
* Val int
5+
* Next *ListNode
6+
* }
7+
*/
8+
// https://juejin.im/post/59e5544851882551dd311710
9+
// n为head到entrance的节点数
10+
// m为环的长度
11+
// k为slow过了entrance后走的节点数
12+
// m-k为从fast、slow的相遇点到entrance的节点数(向前走)
13+
// slow = n + k
14+
// fast = qm + n + k (q为正整数,为圈数)
15+
// fast = 2 * slow
16+
// 可得 n = qm -k
17+
// 亦是 n = (q-1)m + (m-k)
18+
// 证毕
19+
func detectCycle(head *ListNode) *ListNode {
20+
if head == nil || head.Next == nil {
21+
return nil
22+
}
23+
slow := head.Next
24+
fast := head.Next.Next
25+
26+
for fast != nil && fast.Next != nil {
27+
if slow == fast {
28+
break
29+
}
30+
slow, fast = slow.Next, fast.Next.Next
31+
}
32+
33+
tmp := head
34+
// n = (q-1)m + (m-k)
35+
// 所以从slow和head同时开始走,当slow==head那说明,这就是entrance
36+
for tmp!=nil && slow!=nil {
37+
if slow == tmp {
38+
return slow
39+
}
40+
slow, tmp = slow.Next, tmp.Next
41+
}
42+
return nil
43+
}
44+
45+
// 测试地址
46+
// https://leetcode.com/problems/linked-list-cycle-ii/
47+
48+
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# 题意
2+
3+
在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。
4+
5+
例如,链表1->2->3->3->4->4->5
6+
7+
处理后为 1->2->5
8+
9+
# 递归大法好
10+
11+
我们的思路是:
12+
13+
每次返回没有重复的head,如果有重复删除头节点,删完了,就用相同逻辑处理Next节点
14+
15+
[LeetCode 82. Remove Duplicates from Sorted List II](https://leetcode.com/problems/remove-duplicates-from-sorted-list-ii/)
16+
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// 对于每一部分处理方式相同,所以我我们考虑用递归
2+
// 递归
3+
/**
4+
* Definition for singly-linked list.
5+
* type ListNode struct {
6+
* Val int
7+
* Next *ListNode
8+
* }
9+
*/
10+
func deleteDuplicates(head *ListNode) *ListNode {
11+
// 长度 <=1 的 list ,可以直接返回
12+
if head == nil || head.Next == nil {
13+
return head
14+
}
15+
16+
// 要么 head 重复了,那就删除 head
17+
if head.Val == head.Next.Val {
18+
for head.Next != nil && head.Val == head.Next.Val {
19+
head = head.Next
20+
}
21+
// 有重复所以直接不带head
22+
return deleteDuplicates(head.Next)
23+
}
24+
25+
// 要么 head 不重复,递归处理 head 后面的节点
26+
head.Next = deleteDuplicates(head.Next)
27+
return head
28+
}
29+
30+
// 测试地址
31+
// https://leetcode.com/problems/remove-duplicates-from-sorted-list-ii/
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# 题意
2+
3+
给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。
4+
5+
注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。
6+
7+
# 分析
8+
9+
- 如果当前结点有右子树,那么其中序遍历的下一个结点就是其右子树的最左结点比如结点2中序遍历的下一个结点是3
10+
11+
- 如果当前结点没有右子树,而它是其父结点的左子结点那么其中序遍历的下一个结点就是他的父亲结点比如结点1中序遍历的下一个结点是2
12+
13+
- 如果当前结点没有右子树,而它还是其父结点的右子结点,这种情况下其下一个结点应该是当前结点所在的左子树的根,因此我们可以顺着其父节点一直向上遍历,直到找到一个是它父结点的左子结点的结点。

0 commit comments

Comments
 (0)