2021-04-03:給定兩個字符串str1和str2,想把str2總體插入到str1中的某個位置,造成最大的字典序,返回字典序最大的結果。java
福大大 答案2021-04-03:git
1.暴力法。
2.DC3算法。天然智慧想不到,須要練敏感度。
2.1.構造字符串。str = str1+最小字符+str2。
2.2.對str進行dc3算法,求出rank數組。
2.3.遍歷0到str1長度,找到小於str2起始位置的序號。
2.4.根據序號算出bestSplit值。時間緊,先放一放。
2.5.根據bestSplit拆分str1,而後合併。返回str1左+str2+str1右。github
代碼用golang編寫。代碼以下:golang
package main import ( "fmt" "index/suffixarray" "math/rand" "time" "unsafe" ) func main() { rand.Seed(time.Now().Unix()) //YJWBRFKBMYQWFCRTSA //YTOFNTX cnt := 0 const TOTAL = 10000 for i := 0; i < TOTAL; i++ { s1 := newRandString() s2 := newRandString() fmt.Println("s1 = ", s1) fmt.Println("s2 = ", s2) ret1 := right(s1, s2) ret2 := maxCombine(s1, s2) fmt.Println("暴力的答案:", ret1) fmt.Println("DC3的答案:", ret2) if ret1 == ret2 { fmt.Println("正確") cnt++ } else { fmt.Println("錯誤") } fmt.Println("-------------") } fmt.Println("總數:", TOTAL) fmt.Println("正確:", cnt) } func newRandString() string { retLen := rand.Intn(20) + 5 ret := make([]byte, retLen) for i := 0; i < retLen; i++ { ret[i] = byte(rand.Intn(26) + 'A') } return string(ret) } func right(s1 string, s2 string) string { if len(s1) == 0 { return s2 } if len(s2) == 0 { return s1 } ans := s1 + s2 temp := "" best := len(s1) for i := 0; i < len(s1); i++ { temp = s1[0:i] + s2 + s1[i:] if temp > ans { ans = temp best = i } } fmt.Println("暴力best = ", best) return ans } // 正式方法 O(N+M) + O(M^2) // N : s1長度 // M : s2長度 func maxCombine(s1 string, s2 string) string { if len(s1) == 0 { return s2 } if len(s2) == 0 { return s1 } str1 := []byte(s1) str2 := []byte(s2) N := len(str1) M := len(str2) min := str1[0] max := str1[0] for i := 1; i < N; i++ { min = getMin(min, str1[i]) max = getMax(max, str1[i]) } for i := 0; i < M; i++ { min = getMin(min, str2[i]) max = getMax(max, str2[i]) } all := make([]byte, N+M+1) index := 0 for i := 0; i < N; i++ { all[index] = str1[i] - min + 2 index++ } all[index] = 1 index++ for i := 0; i < M; i++ { all[index] = str2[i] - min + 2 index++ } dc3 := NewFddSa(all) comp := N + 1 for i := 0; i < N; i++ { if dc3.Rank[i] < dc3.Rank[comp] { best := bestSplit(s1, s2, i) //best := i //這句代碼是錯的 fmt.Println("DC3的best = ", best) return s1[0:best] + s2 + s1[best:] } } return s1 + s2 } func bestSplit(s1 string, s2 string, first int) int { N := len(s1) M := len(s2) end := N for i, j := first, 0; i < N && j < M; i, j = i+1, j+1 { if s1[i] < s2[j] { end = i break } } bestPrefix := s2 bestSplit := first for i, j := first+1, M-1; i <= end; i, j = i+1, j-1 { curPrefix := s1[first:i] + s2[0:j] if curPrefix >= bestPrefix { bestPrefix = curPrefix bestSplit = i } } if bestSplit != first { fmt.Println("注意,first = ", first, " ,bestSplit = ", bestSplit) } return bestSplit } func getMax(a byte, b byte) byte { if a > b { return a } else { return b } } func getMin(a byte, b byte) byte { if a < b { return a } else { return b } } type FddSa struct { Sa []int Rank []int } func NewFddSa(bytes []byte) *FddSa { ret := &FddSa{} ret.Rank = make([]int, len(bytes)) ret.Sa = make([]int, len(bytes)) index := suffixarray.New(bytes) p1 := uintptr(unsafe.Pointer(index)) //獲取指針 p1 += 24 p2 := *(*[]int32)(unsafe.Pointer(p1)) //將指針轉行成切片 for i := 0; i < len(bytes); i++ { ret.Sa[i] = int(p2[i]) //sa數組 ret.Rank[int(p2[i])] = i //rank數組 } return ret }
執行結果以下:
算法