Skip to content

Commit d1143eb

Browse files
committed
init commit
0 parents  commit d1143eb

File tree

8 files changed

+257
-0
lines changed

8 files changed

+257
-0
lines changed

.github/workflows/go.yml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
name: Go
2+
3+
on:
4+
push:
5+
branches:
6+
- master
7+
pull_request:
8+
branches:
9+
- master
10+
11+
jobs:
12+
build_and_test:
13+
runs-on: ubuntu-latest
14+
steps:
15+
- name: Checkout
16+
uses: actions/checkout@v3
17+
- name: Setup Go
18+
uses: actions/setup-go@v3
19+
with:
20+
go-version: 1.16
21+
- name: Build
22+
run: go build -v ./...
23+
- name: Test
24+
run: go test -v -cover ./...
25+
- name: BenchmarkTest
26+
run: go test -benchmem -run=none -bench ^BenchmarkTest sol/sol

.gitignore

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# If you prefer the allow list template instead of the deny list, see community template:
2+
# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore
3+
#
4+
# Binaries for programs and plugins
5+
*.exe
6+
*.exe~
7+
*.dll
8+
*.so
9+
*.dylib
10+
11+
# Test binary, built with `go test -c`
12+
*.test
13+
14+
# Output of the go coverage tool, specifically when used with LiteIDE
15+
*.out
16+
17+
# Dependency directories (remove the comment below to include it)
18+
# vendor/
19+
20+
# Go workspace file
21+
go.work

.gitlab-ci.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
stages:
2+
- test
3+
build and test:
4+
image: golang:1.16
5+
stage: test
6+
script:
7+
- go build -v ./...
8+
- go test -v -cover ./...
9+
- go test -benchmem -run=none ^BenchmarkTest sol/sol

.husky/pre-commit

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
#!/bin/bash
2+
go test -v -cover ./...

README.md

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
# golang_valid_palindrome
2+
3+
A phrase is a **palindrome** if, after converting all uppercase letters into lowercase letters and removing all non-alphanumeric characters, it reads the same forward and backward. Alphanumeric characters include letters and numbers.
4+
5+
Given a string `s`, return `true` *if it is a **palindrome**, or* `false` *otherwise*.
6+
7+
## Examples
8+
9+
**Example 1:**
10+
11+
```
12+
Input: s = "A man, a plan, a canal: Panama"
13+
Output: true
14+
Explanation: "amanaplanacanalpanama" is a palindrome.
15+
16+
```
17+
18+
**Example 2:**
19+
20+
```
21+
Input: s = "race a car"
22+
Output: false
23+
Explanation: "raceacar" is not a palindrome.
24+
25+
```
26+
27+
**Example 3:**
28+
29+
```
30+
Input: s = " "
31+
Output: true
32+
Explanation: s is an empty string "" after removing non-alphanumeric characters.
33+
Since an empty string reads the same forward and backward, it is a palindrome.
34+
```
35+
36+
**Constraints:**
37+
38+
- `1 <= s.length <= 2 * 105`
39+
- `s` consists only of printable ASCII characters.
40+
41+
## 解析
42+
43+
給定一個字串 s ,
44+
45+
假設經過一個運算只看是英文字母的字元,且把所有大寫英文字元轉成小寫後變成 s’
46+
47+
要求寫一個演算法判斷 s 在經過以上轉換後是否是回文字串
48+
49+
一個字串 s 如果是回文, 代表 i = 0..(n/2-1)
50+
51+
s[i] = s[n-1-i], where n = len(s)
52+
53+
由以上定義可以發現透過給定 2 個指標 一個從字串最前面 一個從字串最後面
54+
55+
當兩個指標位置不同時做以下比較
56+
57+
每次當遇到兩個字元相同時,兩個指標共同推進一個單位往下一個可以比較的字元去比較
58+
59+
遇到兩個字元不同時,則代表不是回文 回傳 false
60+
61+
特別要注意的是當其中一個指標遇到不是非英文字元,則需要直接把指標往下一個位置移動
62+
63+
然後往一下個開始指標開始比較
64+
65+
假設直到最後一個指標都相同則代表是回文 所以回傳 true
66+
67+
演算法詳細如下圖
68+
69+
![](https://i.imgur.com/BxTUXpO.png)
70+
71+
## 程式碼
72+
```go
73+
package sol
74+
75+
func isPalindrome(s string) bool {
76+
lp, rp := 0, len(s)-1
77+
var isAlphaBet = func(c byte) bool {
78+
if ('a' <= c && 'z' >= c) || ('A' <= c && 'Z' >= c) {
79+
return true
80+
}
81+
return false
82+
}
83+
var toLower = func(c byte) byte {
84+
if 'A' <= c && 'Z' >= c {
85+
return (c - 'A') + 'a'
86+
}
87+
return c
88+
}
89+
for lp <= rp {
90+
if !isAlphaBet(s[lp]) {
91+
lp++
92+
continue
93+
}
94+
if !isAlphaBet(s[rp]) {
95+
rp--
96+
continue
97+
}
98+
if toLower(s[rp]) != toLower(s[lp]) {
99+
return false
100+
}
101+
rp--
102+
lp++
103+
}
104+
return true
105+
}
106+
```
107+
108+
## 困難點
109+
110+
1. 從 palindrome 定義思考出透過左右指標同時逼近來檢查
111+
112+
## Solve Point
113+
114+
- [x] 初始化 lp = 0, rp = len(s) -1
115+
- [x] for lp ≤ rp 做以下運算
116+
- [x] 當 s[lp] 不在 ‘a’,’z’ 之間 且不在 ‘A’ ,‘Z’之間, 更新 lp += 1 continue
117+
- [x] 當 s[rp] 不在 ‘a’,’z’ 之間 且不在 ‘A’ ,‘Z’之間, 更新 rp -= 1 continue
118+
- [x] 當 toLower(s[rp]) ≠ toLower(s[lp]) , 回傳 false
119+
- [x] rp—; lp++
120+
- [x] 回傳 true

go.mod

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module sol
2+
3+
go 1.16

sol/solution.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package sol
2+
3+
func isPalindrome(s string) bool {
4+
lp, rp := 0, len(s)-1
5+
var isAlphaBet = func(c byte) bool {
6+
if ('a' <= c && 'z' >= c) || ('A' <= c && 'Z' >= c) {
7+
return true
8+
}
9+
return false
10+
}
11+
var toLower = func(c byte) byte {
12+
if 'A' <= c && 'Z' >= c {
13+
return (c - 'A') + 'a'
14+
}
15+
return c
16+
}
17+
for lp <= rp {
18+
if !isAlphaBet(s[lp]) {
19+
lp++
20+
continue
21+
}
22+
if !isAlphaBet(s[rp]) {
23+
rp--
24+
continue
25+
}
26+
if toLower(s[rp]) != toLower(s[lp]) {
27+
return false
28+
}
29+
rp--
30+
lp++
31+
}
32+
return true
33+
}

sol/solution_test.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package sol
2+
3+
import "testing"
4+
5+
func BenchmarkTest(b *testing.B) {
6+
s := "A man, a plan, a canal: Panama"
7+
for idx := 0; idx < b.N; idx++ {
8+
isPalindrome(s)
9+
}
10+
}
11+
func Test_isPalindrome(t *testing.T) {
12+
type args struct {
13+
s string
14+
}
15+
tests := []struct {
16+
name string
17+
args args
18+
want bool
19+
}{
20+
{
21+
name: "A man, a plan, a canal: Panama",
22+
args: args{s: "A man, a plan, a canal: Panama"},
23+
want: true,
24+
},
25+
{
26+
name: "race a car",
27+
args: args{s: "race a car"},
28+
want: false,
29+
},
30+
{
31+
name: " ",
32+
args: args{s: " "},
33+
want: true,
34+
},
35+
}
36+
for _, tt := range tests {
37+
t.Run(tt.name, func(t *testing.T) {
38+
if got := isPalindrome(tt.args.s); got != tt.want {
39+
t.Errorf("isPalindrome() = %v, want %v", got, tt.want)
40+
}
41+
})
42+
}
43+
}

0 commit comments

Comments
 (0)