Skip to content

Commit ffff364

Browse files
committed
015
1 parent 6e15efb commit ffff364

File tree

12 files changed

+436
-0
lines changed

12 files changed

+436
-0
lines changed
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
# 题意
2+
3+
> 输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。
4+
5+
样例输入
6+
7+
3 4 5 -1
8+
9+
样例输出
10+
11+
1 2 32
12+
13+
## 通过移位测试每一位
14+
15+
我们很容易想到的算法就是
16+
通过移位的方法,挨个判断其每一位
17+
18+
但是这个算法有致命的缺陷,我们假设通过移位的方式可以获取到其每一位,但是并不总是对的
19+
20+
##逻辑右移与算术右移
21+
22+
比如一个有符号位的8位二进制数11001101,逻辑右移就不管符号位,如果移一位就变成01100110。算术右移要管符号位,右移一位变成10100110。
23+
24+
逻辑左移=算数左移,右边统一添0
25+
逻辑右移,左边统一添0
26+
算数右移,左边添加的数和符号有关
27+
28+
e.g:1010101010,其中[]位是添加的数字
29+
30+
> 逻辑左移一位:010101010[0]
31+
> 算数左移一位:010101010[0]
32+
> 逻辑右移一位:[0]101010101
33+
> 算数右移一位:[1]101010101
34+
35+
因此如果输入负数,那么我们的算法简单的判断是不是0来终结,岂不是要死循环
36+
37+
## 避免负数移位的死循环
38+
39+
为了负数时候避免死循环,我们可以不右移数字n,转而去移动测试位
40+
41+
那么思考我们的循环结束条件,flag一直左移(乘以2),当超出表示标识范围的时候,我们就可以终止了,但是这样子的话,最高位的符号位没有测试,因此要单独测试,同时由于会溢出,我们的flag需要用long来标识
42+
43+
## 整数中有几个1就循环几次--lowbit优化
44+
45+
我们分析n以n-1两个数的差别,
46+
47+
- 如果n!=0,那么其二进制位中至少有一个1
48+
49+
- 如果n的最低位是1(奇数),那么n-1正好把这个最低位的1变成0,其他位不变
50+
51+
- 如果n的最低位是0(偶数),那么假设其右起第一个1位于m位,即m位后面全是0,那么n-1的第m位由1变成0,而第m位后面的所有0均变成1,m位之前的所有位保持不变。
52+
53+
因此通过分析发现:
54+
55+
**把一个整数n减去1,再和原来的整数做与运算,会把该整数最右边一个1变成0,那么该整数有多少个1,就会进行多少次与运算**
56+
57+
即循环的次数,即二进制中1的个数
58+
59+
>如果一个整数不为0,那么这个整数至少有一位是1。如果我们把这个整数减1,那么原来处在整数最右边的1就会变为0,原来在1后面的所有的0都会变成1(如果最右边的1后面还有0的话)。其余所有位将不会受到影响。 举个例子:一个二进制数1100,从右边数起第三位是处于最右边的一个1。减去1后,第三位变成0,它后面的两位0变成了1,而前面的1保持不变,因此得到的结果是1011.我们发现减1的结果是把最右边的一个1开始的所有位都取反了。这个时候如果我们再把原来的整数和减去1之后的结果做与运算,从原来整数最右边一个1那一位开始所有位都会变成0。如1100&1011=1000.也就是说,把一个整数减去1,再和原整数做与运算,会把该整数最右边一个1变成0.那么一个整数的二进制有多少个1,就可以进行多少次这样的操作。
60+
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package problem010
2+
3+
4+
func Ones(n int) int {
5+
count := 0;
6+
for n!=0 {
7+
count++
8+
n = n & (n-1)
9+
}
10+
return count
11+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package problem010
2+
3+
import (
4+
"testing"
5+
)
6+
7+
func Test_case(t *testing.T) {
8+
if Ones(0) == 0 {
9+
t.Log("Pass")
10+
} else {
11+
t.Error("Failed")
12+
}
13+
// int64
14+
if Ones(-1) == 64 {
15+
t.Log("Pass")
16+
} else {
17+
t.Error("Failed value: ",Ones(-1))
18+
}
19+
20+
if Ones(8) == 1 {
21+
t.Log("Pass")
22+
} else {
23+
t.Error("Failed")
24+
}
25+
26+
27+
if Ones(5) == 2 {
28+
t.Log("Pass")
29+
} else {
30+
t.Error("Failed")
31+
}
32+
33+
}
34+
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# 题意
2+
3+
> 给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。
4+
5+
前面所说的指数为负数只是边界的一种情况,学习算法,必须全面了解所有的边界
6+
7+
指数幂的所有边界包括:
8+
9+
- 指数为0的情况,不管底数是多少都应该是1
10+
- 指数为负数的情况,求出的应该是其倒数幂的倒数
11+
- 指数为负数的情况下,底数不能为0
12+
13+
正整数幂次可以用位运算来求
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package problem011
2+
3+
import (
4+
"errors"
5+
)
6+
7+
8+
func Pow(base float64, exp int) (float64, error) {
9+
if exp == 0 {
10+
return 1, nil
11+
}
12+
if exp < 0 && base == 0 {
13+
return -1 , errors.New("base == 0 and exp < 0")
14+
}
15+
16+
if exp > 0 {
17+
return PowNormal(base, exp), nil
18+
} else {
19+
res := PowNormal(base, -exp)
20+
res = 1/res
21+
return res, nil
22+
}
23+
24+
}
25+
26+
27+
func PowNormal(base float64, exp int) float64 {
28+
res, temp := 1.0, base
29+
for exp != 0 {
30+
if exp&1 == 1 {
31+
res *= temp
32+
}
33+
temp *= temp
34+
exp >>= 1
35+
}
36+
return res
37+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package problem011
2+
3+
import (
4+
"testing"
5+
)
6+
7+
func Test_case(t *testing.T) {
8+
res, _ := Pow(0, 0)
9+
if res == 1 {
10+
t.Log("Pass")
11+
} else {
12+
t.Error("Failed")
13+
}
14+
15+
res, _ = Pow(2, -1)
16+
if res == 0.5 {
17+
t.Log("Pass")
18+
} else {
19+
t.Error("Failed value: ")
20+
}
21+
22+
res, _ = Pow(2, 3)
23+
if res == 8 {
24+
t.Log("Pass")
25+
} else {
26+
t.Error("Failed")
27+
}
28+
29+
res, _ = Pow(2, -2)
30+
if res == 0.25 {
31+
t.Log("Pass")
32+
} else {
33+
t.Error("Failed")
34+
}
35+
36+
res, err := Pow(0, -2)
37+
if err != nil {
38+
t.Log("Pass")
39+
} else {
40+
t.Error("Failed")
41+
}
42+
43+
}
44+
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# 题意
2+
3+
给定一个数字N,打印从1到最大的N位数。
4+
5+
输入
6+
7+
每个输入文件仅包含一组测试样例。
8+
9+
对于每个测试案例,输入一个数字N(1<=N<=5)。 输出 对应每个测试案例,依次打印从1到最大的N位数。
10+
11+
样例输入
12+
13+
1
14+
15+
样例输出
16+
17+
1 2 3 4 5 6 7 8 9
18+
19+
这题其实没什么太大意义,控制好溢出就好了。
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"errors"
6+
)
7+
8+
var MaxInt int = int(^uint(0) >> 1)
9+
10+
// problem 011
11+
func Pow(base float64, exp int) (float64, error) {
12+
if exp == 0 {
13+
return 1, nil
14+
}
15+
if exp < 0 && base == 0 {
16+
return -1 , errors.New("base == 0 and exp < 0")
17+
}
18+
19+
if exp > 0 {
20+
return PowNormal(base, exp), nil
21+
} else {
22+
res := PowNormal(base, -exp)
23+
res = 1/res
24+
return res, nil
25+
}
26+
27+
}
28+
29+
func PowNormal(base float64, exp int) float64 {
30+
res, temp := 1.0, base
31+
for exp != 0 {
32+
if exp&1 == 1 {
33+
res *= temp
34+
}
35+
temp *= temp
36+
exp >>= 1
37+
}
38+
return res
39+
}
40+
41+
// 012
42+
func showN(n int) error {
43+
top, _ := Pow(10, n)
44+
45+
if (int(top) > MaxInt){
46+
return errors.New("Overflow")
47+
}
48+
49+
for i := 1; i < int(top); i++ {
50+
fmt.Println(i)
51+
}
52+
return nil
53+
}
54+
55+
func main() {
56+
showN(1)
57+
showN(3)
58+
}
59+
60+
61+
62+
63+
64+
65+
66+
67+
68+
69+
70+
71+
72+
73+
74+
75+
76+
77+
78+
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#题意
2+
3+
题目描述
4+
5+
输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。
6+
7+
样例输入
8+
9+
5 1 2 3 4 5
10+
11+
样例输出
12+
13+
1 3 5 2 4
14+
15+
下面我们考虑算法复杂度的同时还会考虑其稳定性,(排序的稳定型则是指相同元素在数组中的相对位置是否发生变化),这里的稳定性我们理解为,顺序交换后,各个奇数(或者偶数)在数组中的相对位置是否发生变化
16+
17+
## 不影响顺序 => 冒泡解法
18+
最简单的思路就是从头到尾扫描一遍数组,每遇见一个偶数时,就拿出这个数字,并把位于这个数字之后的所有数字往前挪动一位,然后把当前这个偶数放到最后。
19+
20+
这样每次遇到一个偶数就要挪动$O(n)$个数字,因此总的时间复杂度是$O(n^2)$
21+
22+
但是这种方法不仅暴力而且还需要复杂的挪动工作,因此我们对比一下冒泡排序,每次循环前偶后奇就交换
23+
24+
同时我们设立一个标识,来标识数组是否已经符合要求
25+
26+
当再次循环时,发现没有要交换的数据,说明数组已经符合要求
27+
28+
## 高效但是影响顺序 => 双指针
29+
由于题目中只要求记奇数在偶数之前,那么我们在扫描这个数组的时候,如果发现一个偶数出现在奇数之前就交换他们的位置,这样一趟后就满足要求了。
30+
31+
因此我们
32+
33+
维护两个索引或者指针,一个指向数组的第一个元素,并向后移动,一个指向数组的最后一个元素,并向前移动。
34+
35+
如果第一个指针指向的元素是偶数,而第二个指针指向的元素是奇数,说明偶数在奇数前面,那么就交换这两个数。
36+
37+
直到两个指针相遇为止
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
)
6+
7+
8+
func oddFirst(s []int){
9+
left, right := 0, len(s)-1
10+
for left < right {
11+
for s[right]%2==0 && left<right{
12+
right--
13+
}
14+
for s[left]%2==1 && left<right{
15+
left++
16+
}
17+
if left==right {
18+
break
19+
}
20+
if left<right {
21+
s[left], s[right] = s[right], s[left]
22+
}
23+
}
24+
}
25+
26+
27+
28+
func main() {
29+
//test
30+
31+
l := []int{1,2,3,4,5,6,7}
32+
fmt.Println("before: ", l)
33+
oddFirst(l)
34+
fmt.Println("after: ",l)
35+
36+
l = []int{2,2,2,2,5,6,7}
37+
fmt.Println("before: ", l)
38+
oddFirst(l)
39+
fmt.Println("after: ",l)
40+
}
41+
42+
43+
44+
45+

0 commit comments

Comments
 (0)