日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > windows >内容正文

windows

2024-01-17:lc的30. 串联所有单词的子串

發布時間:2024/1/18 windows 30 coder
生活随笔 收集整理的這篇文章主要介紹了 2024-01-17:lc的30. 串联所有单词的子串 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

2024-01-17:用go語言,給定一個字符串 s 和一個字符串數組 words。 words 中所有字符串 長度相同。

s 中的 串聯子串 是指一個包含 words 中所有字符串以任意順序排列連接起來的子串。

例如,如果 words = ["ab","cd","ef"],

那么 "abcdef", "abefcd","cdabef",

"cdefab","efabcd", 和 "efcdab" 都是串聯子串,

"acdbef" 不是串聯子串,因為他不是任何 words 排列的連接。

返回所有串聯字串在 s 中的開始索引。

你可以以 任意順序 返回答案。

1 <= s.length <= 10^4,

1 <= words.length <= 5000,

1 <= words[i].length <= 30。

words[i] 和 s 由小寫英文字母組成。

輸入:s = "barfoothefoobarman", words = ["foo","bar"]。

輸出:[0,9]。

來自lc的30. 串聯所有單詞的子串。

答案2024-01-17:

來自左程云。

靈捷3.5

大體過程如下:

  1. 定義一些常量和變量,包括 BASEMAXN,以及存儲結果的切片 ans

  2. 實現 hashValue 函數,用于計算字符串的哈希值。這里使用一個基于索引的簡單哈希函數將字符串映射為一個唯一的整數。

  3. 實現 buildHash 函數,用于構建字符串的前綴哈希數組。通過動態規劃的方式計算每個位置的哈希值。

  4. 實現 hashValueRange 函數,用于計算子串的哈希值。利用前綴哈希數組,根據子串的起始和結束位置計算哈希值。

  5. 創建一個哈希表 mapCount 用于存儲 words 中每個單詞的出現次數。

  6. 構建字符串 s 的前綴哈希數組 hash

  7. 創建一個數組 pow,用于存儲 BASE 的冪次方,便于后續計算子串的哈希值。

  8. 創建一個滑動窗口 window,用于記錄當前窗口中每個單詞出現的次數。

  9. 循環遍歷 s 中每個起始位置的可能性(即從 0 到 wordLen-1)。

  10. 在每個起始位置,初始化一個變量 debt 用于記錄還需要湊齊的單詞數。

  11. 在每個起始位置,遍歷 words 中的單詞,依次將其添加到窗口中,并更新 debt 的值。

  12. 如果 debt 等于 0,表示窗口中已經包含了所有 words 中的單詞,則將當前起始位置加入結果數組 ans 中。

  13. 對于每個起始位置,向右移動窗口,同時更新窗口中單詞的出現次數。

  14. 檢查窗口中的哈希值和單詞出現次數是否符合要求,如果符合則將當前起始位置加入結果數組 ans 中。

  15. 清空滑動窗口 window

  16. 返回結果數組 ans。

總的時間復雜度:O(n * m * k),其中 n 是字符串 s 的長度,m 是 words 的長度,k 是單詞的平均長度。

總的額外空間復雜度:O(n),其中 n 是字符串 s 的長度,主要用于存儲哈希表、前綴哈希數組和結果數組。

go完整代碼如下:

package main

import (
	"fmt"
)

var BASE = 499
var MAXN = 10001

func hashValue(str string) int64 {
	if str == "" {
		return 0
	}
	n := len(str)
	ans := int64(str[0]-'a') + 1
	for j := 1; j < n; j++ {
		ans = ans*int64(BASE) + int64(str[j]-'a') + 1
	}
	return ans
}

func buildHash(str string) []int64 {
	hash := make([]int64, len(str))
	hash[0] = int64(str[0]-'a') + 1
	for j := 1; j < len(str); j++ {
		hash[j] = hash[j-1]*int64(BASE) + int64(str[j]-'a') + 1
	}
	return hash
}

func hashValueRange(l, r int, hash []int64, pow []int64) int64 {
	ans := hash[r-1]
	if l > 0 {
		ans -= hash[l-1] * pow[r-l]
	}
	return ans
}

func findSubstring(s string, words []string) []int {
	var ans []int
	if len(s) == 0 || len(words) == 0 {
		return ans
	}

	wordLen := len(words[0])
	wordNum := len(words)
	allLen := wordLen * wordNum

	mapCount := make(map[int64]int)
	for _, key := range words {
		v := hashValue(key)
		mapCount[v]++
	}

	hash := buildHash(s)
	pow := make([]int64, MAXN)
	pow[0] = 1
	for j := 1; j < MAXN; j++ {
		pow[j] = pow[j-1] * int64(BASE)
	}

	window := make(map[int64]int)

	for init := 0; init < wordLen && init+allLen <= len(s); init++ {
		debt := wordNum
		for l, r, part := init, init+wordLen, 0; part < wordNum; l += wordLen {
			cur := hashValueRange(l, r, hash, pow)
			window[cur]++
			if window[cur] <= mapCount[cur] {
				debt--
			}
			r += wordLen
			part++
		}
		if debt == 0 {
			ans = append(ans, init)
		}

		for l1, r1, l2, r2 := init, init+wordLen, init+allLen, init+allLen+wordLen; r2 <= len(s); l1, r1, l2, r2 = l1+wordLen, r1+wordLen, l2+wordLen, r2+wordLen {
			out := hashValueRange(l1, r1, hash, pow)
			in := hashValueRange(l2, r2, hash, pow)
			window[out]--
			if window[out] < mapCount[out] {
				debt++
			}
			window[in]++
			if window[in] <= mapCount[in] {
				debt--
			}
			if debt == 0 {
				ans = append(ans, r1)
			}
		}

		for key := range window {
			delete(window, key)
		}
	}

	return ans
}

func main() {
	s := "barfoothefoobarman"
	words := []string{"foo", "bar"}

	result := findSubstring(s, words)

	fmt.Println(result)
}

總結

以上是生活随笔為你收集整理的2024-01-17:lc的30. 串联所有单词的子串的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。