Skip to content

Commit 831b790

Browse files
committed
fix: 贪心
1 parent b27abee commit 831b790

File tree

1 file changed

+46
-117
lines changed

1 file changed

+46
-117
lines changed

09-贪心算法解题思路.md

Lines changed: 46 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -8,44 +8,44 @@
88

99
2、用一种局部最功利的标准,总是能做出在当前看来是最好的选择
1010

11-
3、难点在于证明局部最优解最功利的标准可以得到全局最优解
11+
3、难点在于证明局部最优解可以最终得到全局最优解
1212

13-
4、对于贪心算法的学习主要是以增加阅历和经验为主
13+
4、对于贪心算法的学习主要是以经验为主,尝试为主
1414

1515
### 1.2.1 贪心算法解释
1616

1717
正例:通过一个例子来解释,假设一个数组中N个正数,第一个挑选出来的数乘以1,第二个挑选出来的数乘以2,同理,第N次挑选出来的数乘以N,总的加起来是我们的分数。怎么挑选数字使我们达到最大分数?
1818

1919
> 数组按从小到大的顺序排序,我们按顺序依次挑选,最终结果就是最大的。本质思想是因子随着挑选次数的增加会增大,我们尽量让大数去结合大的因子。
2020
21-
==贪心算法有时是无效的,后面会贪心算法无效的例子==
21+
> 贪心算法有时是无效的,下文会举贪心算法无效的例子
2222
2323
### 1.2.2 贪心算法的证明问题
2424

2525
如何证明贪心算法的有效性?
2626

27-
> 一般来说,贪心算法不推荐证明,很多时候证明是非常复杂的。通过下面例子来说明贪心算法证明的复杂性,从头到尾讲一道利用贪心算法求解的题目。
27+
> 一般来说,贪心算法不推荐证明,很多时候证明是非常复杂的。通过下面例子来说明贪心算法证明的复杂性
2828
2929
例子:给定一个由字符串组成的数组strs,必须把所有的字符串拼接起来,返回所有可能的拼接结果中,字典序最小的结果。
3030

3131
> 字典序概念:直观理解,两个单词放到字典中,从头开始查找这个单词,哪个先被查找到,哪个字典序小。
3232
3333
> 字典序严格定义,我们把字符串当成k进制的数,a-z当成26进制的正数,字符长度一样,abk>abc,那么我们说abk的字典序更大。字符长度不一样ac和b,那么我们要把短的用0补齐,0小于a的accil,那么ac<b0,高位b>a即可比较出来大小。
3434
35-
Java中字符串的ComparTo方法,就是比较字典序
35+
常见的语言标准库中比较字符串的函数,大都是比较字典序
3636

37-
本题思路1:按照单个元素字典序贪心,例如在[ac,bk,sc,ket]字符串数组中,我们拼接出来最终的字符串字典序最小,那么我们依次挑选字典序最小的进行拼接的贪心策略得到acbkketsc。
37+
思路1:按照单个元素字典序贪心,例如在[ac,bk,sc,ket]字符串数组中,我们拼接出来最终的字符串字典序最小,那么我们依次挑选字典序最小的进行拼接的贪心策略得到acbkketsc。
3838

39-
==但是这样的贪心不一定是正确的,例如[ba,b]按照上述思路的贪心结果是bba,但是bab明显是最小的结果==
39+
> 但是这样的贪心不一定是正确的,例如[ba,b]按照上述思路的贪心结果是bba,但是bab明显是最小的结果
4040
41-
本题思路2:两个元素x和y,x拼接y小于等于x拼接y,那么x放前,否则y放前面。例如x=b,y=ba。bba大于bab的字典与,那么ba放前面
41+
思路2:两个元素x和y,x拼接y小于等于y拼接x,那么x放前,否则y放前面。例如x=b,y=ba。bba大于bab的字典序,那么ba放前面
4242

4343

4444
证明:
4545

4646
我们把拼接当成k进制数的数学运算,把a-z的数当成26进制的数,'ks'拼接'ts'实质是ks * 26^2 + te。
4747

48-
目标先证明我们比较的传递性:证明a拼接b小于b拼接a,b拼接c小于等于c拼接b,推出a拼接c小于等于c拼接a
48+
目标先证明我们比较的传递性:证明a拼接b小于b拼接a,b拼接c小于等于c拼接b,推导出a拼接c小于等于c拼接a
4949

5050
a拼接b等于a乘以k的b长度次方 + b。我们把k的x长度次方这个操作当成m(x)函数。所以:
5151

@@ -79,135 +79,64 @@ m(c) * a + c <= m(a) * c + a
7979

8080
再证明任意三个交换都会变为更大的字典序,那么最终数学归纳法,得到思路二的正确性
8181

82-
==所以贪心算法的证明实质是比较复杂的,我们大可不必每次去证明贪心的正确性==
82+
> 所以贪心算法的证明实质是比较复杂的,我们大可不必每次去证明贪心的正确性
8383
84-
```Java
85-
package class09;
84+
```Go
85+
package main
8686

87-
import java.util.ArrayList;
88-
import java.util.Arrays;
89-
import java.util.Comparator;
90-
import java.util.HashSet;
87+
import (
88+
"sort"
89+
"strings"
90+
)
9191

92-
public class Code01_LowestLexicography {
92+
// 方法1 暴力法穷举,排列组合。略
9393

94-
// 暴力法穷举,排列组合
95-
public static String lowestString1(String[] strs) {
96-
if (strs == null || strs.length == 0) {
97-
return "";
98-
}
99-
ArrayList<String> all = new ArrayList<>();
100-
HashSet<Integer> use = new HashSet<>();
101-
process(strs, use, "", all);
102-
String lowest = all.get(0);
103-
for (int i = 1; i < all.size(); i++) {
104-
if (all.get(i).compareTo(lowest) < 0) {
105-
lowest = all.get(i);
106-
}
107-
}
108-
return lowest;
94+
// LowestStringByGreedy 方法2 贪心法
95+
func LowestStringByGreedy(strs []string) string {
96+
if len(strs) == 0 {
97+
return ""
10998
}
11099

111-
// strs里放着所有的字符串
112-
// 已经使用过的字符串的下标,在use里登记了,不要再使用了
113-
// 之前使用过的字符串,拼接成了-> path
114-
// 用all收集所有可能的拼接结果
115-
public static void process(String[] strs, HashSet<Integer> use, String path, ArrayList<String> all) {
116-
// 所有字符串都是用过了
117-
if (use.size() == strs.length) {
118-
all.add(path);
119-
} else {
120-
for (int i = 0; i < strs.length; i++) {
121-
if (!use.contains(i)) {
122-
use.add(i);
123-
process(strs, use, path + strs[i], all);
124-
use.remove(i);
125-
}
126-
}
127-
}
128-
}
100+
Sort(strs, func(a, b string) int {
101+
return strings.Compare(a, b)
102+
})
129103

130-
public static class MyComparator implements Comparator<String> {
131-
@Override
132-
public int compare(String a, String b) {
133-
return (a + b).compareTo(b + a);
134-
}
104+
res := ""
105+
for i := 0; i < len(strs); i++ {
106+
res += strs[i]
135107
}
108+
return res
109+
}
136110

137-
// 思路二,贪心解法
138-
public static String lowestString2(String[] strs) {
139-
if (strs == null || strs.length == 0) {
140-
return "";
141-
}
142-
Arrays.sort(strs, new MyComparator());
143-
String res = "";
144-
for (int i = 0; i < strs.length; i++) {
145-
res += strs[i];
146-
}
147-
return res;
148-
}
111+
type Comparator func(a, b string) int
149112

150-
// for test
151-
public static String generateRandomString(int strLen) {
152-
char[] ans = new char[(int) (Math.random() * strLen) + 1];
153-
for (int i = 0; i < ans.length; i++) {
154-
int value = (int) (Math.random() * 5);
155-
ans[i] = (Math.random() <= 0.5) ? (char) (65 + value) : (char) (97 + value);
156-
}
157-
return String.valueOf(ans);
158-
}
113+
func Sort(values []string, comparator Comparator) {
114+
sort.Sort(sortable{values, comparator})
115+
}
159116

160-
// for test
161-
public static String[] generateRandomStringArray(int arrLen, int strLen) {
162-
String[] ans = new String[(int) (Math.random() * arrLen) + 1];
163-
for (int i = 0; i < ans.length; i++) {
164-
ans[i] = generateRandomString(strLen);
165-
}
166-
return ans;
167-
}
117+
type sortable struct {
118+
values []string
119+
comparator Comparator
120+
}
168121

169-
// for test
170-
public static String[] copyStringArray(String[] arr) {
171-
String[] ans = new String[arr.length];
172-
for (int i = 0; i < ans.length; i++) {
173-
ans[i] = String.valueOf(arr[i]);
174-
}
175-
return ans;
176-
}
122+
func (s sortable) Len() int {
123+
return len(s.values)
124+
}
177125

178-
public static void main(String[] args) {
179-
int arrLen = 6;
180-
int strLen = 5;
181-
int testTimes = 100000;
182-
String[] arr = generateRandomStringArray(arrLen, strLen);
183-
System.out.println("先打印一个生成的字符串");
184-
for (String str : arr) {
185-
System.out.print(str + ",");
186-
}
187-
System.out.println();
188-
System.out.println("test begin");
189-
for (int i = 0; i < testTimes; i++) {
190-
String[] arr1 = generateRandomStringArray(arrLen, strLen);
191-
String[] arr2 = copyStringArray(arr1);
192-
if (!lowestString1(arr1).equals(lowestString2(arr2))) {
193-
for (String str : arr1) {
194-
System.out.print(str + ",");
195-
}
196-
System.out.println();
197-
System.out.println("Oops!");
198-
}
199-
}
200-
System.out.println("finish!");
201-
}
126+
func (s sortable) Swap(i, j int) {
127+
s.values[i], s.values[j] = s.values[j], s.values[i]
128+
}
202129

130+
func (s sortable) Less(i, j int) bool {
131+
return s.comparator(s.values[i], s.values[j]) < 0
203132
}
204133
```
205134

206135
> 全排列的时间复杂度为:O(N!)
207136
208137
> 每一种贪心算法有可能都有属于他自身的特有证明,例如哈夫曼树算法,证明千变万化
209138
210-
==贪心策略算法,尽量不要陷入复杂的证明==
139+
> 贪心策略算法,尽量不要陷入复杂的证明
211140
212141
## 1.2 贪心算法求解思路
213142

0 commit comments

Comments
 (0)