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

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

LeetCode 30串联所有单词的子串31下一个排列

發(fā)布時(shí)間:2025/3/20 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 LeetCode 30串联所有单词的子串31下一个排列 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

標(biāo)題

    • 串聯(lián)所有單詞得字串
    • 下一個(gè)排列

維護(hù)真的不易,如有幫助還請(qǐng)點(diǎn)贊關(guān)注,關(guān)注公眾號(hào)bigsai回復(fù)進(jìn)群即可加入打卡。

串聯(lián)所有單詞得字串

題目描述:

給定一個(gè)字符串 s 和一些長(zhǎng)度相同的單詞 words。找出 s 中恰好可以由 words 中所有單詞串聯(lián)形成的子串的起始位置。
注意子串要與 words 中的單詞完全匹配,中間不能有其他字符,但不需要考慮 words 中單詞串聯(lián)的順序。

示例 1:

輸入:
s = “barfoothefoobarman”,
words = [“foo”,“bar”]
輸出:[0,9]
解釋:
從索引 0 和 9 開始的子串分別是 “barfoo” 和 “foobar” 。
輸出的順序不重要, [9,0] 也是有效答案。

示例 2:

輸入:
s = “wordgoodgoodgoodbestword”,
words = [“word”,“good”,“best”,“word”]
輸出:[]

分析:
這題講真還是挺有技巧和方案的,刷這道題也花了不少心思,需要考慮的點(diǎn)也稍微多一點(diǎn)。題意就是要找到字符串s的某個(gè)字串可以由words中所有單詞組成。返回滿足匹配s子串的首位編號(hào)。

遞歸法:
從處理的方式上理論是可以使用遞歸的,但是由于層數(shù)太多并且個(gè)別比較特殊的數(shù)據(jù)可能導(dǎo)致爆棧TL。這里就有個(gè)教訓(xùn):

主要當(dāng)時(shí)沒(méi)仔細(xì)讀題,沒(méi)有在意每個(gè)單詞長(zhǎng)度都相同所以以為是搜索題,后來(lái)仔細(xì)看題之后才發(fā)現(xiàn)問(wèn)題。

普通哈希法(滑動(dòng)窗口)
對(duì)于有些人叫啥滑動(dòng)窗口啥稀奇古怪的漂亮名稱,這里我就簡(jiǎn)稱為Hash法。如何去分析和處理這個(gè)問(wèn)題呢?我們可以看看一些重要的條件:

  • words中所有單詞長(zhǎng)度都相同
  • 必須使用所有words中的單詞一次

也就是說(shuō)在進(jìn)行匹配的時(shí)候可以根據(jù)單詞進(jìn)行匹配。

但每個(gè)字符串進(jìn)行判斷的時(shí)候,可以進(jìn)行分割成若干單詞數(shù)判斷

用兩個(gè)HashMap儲(chǔ)存單詞數(shù)即可,存儲(chǔ)途中進(jìn)行判斷如果有不滿足直接停止。如果能跑到最后說(shuō)明可以添加這個(gè)標(biāo)記。

具體實(shí)現(xiàn)的代碼為:

public List<Integer> findSubstring(String s, String[] words) {List<Integer>value=new ArrayList<Integer>();Map<String, Integer>map=new HashMap<String, Integer>();for(int i=0;i<words.length;i++){int num=map.getOrDefault(words[i], 0);map.put(words[i], num+1);}int wordlen=words[0].length();int len=words[0].length()*words.length;StringBuilder sBuilder=new StringBuilder(" ");sBuilder.append(s.substring(0, len-1));for(int i=0;i<s.length()-len+1;i++){sBuilder.deleteCharAt(0);sBuilder.append(s.charAt(i+len-1));int num=0;//統(tǒng)計(jì)總共滿足的單詞數(shù)量Map<String, Integer>map2=new HashMap<String, Integer>();//map2.putAll(map);int index=0;while (index<len) {String team=sBuilder.substring(index,index+wordlen);int number=map2.getOrDefault(team, 0);//次數(shù)map2.put(team, number+1);if(number+1>map.getOrDefault(team, 0))break;index+=wordlen;}if(index==len)value.add(i);}return value; }

Hash滑動(dòng)窗口優(yōu)化
可以發(fā)現(xiàn)在上面所涉及的的滑動(dòng)處理中每次都需要重新計(jì)算當(dāng)前字符串的HashMap情況并重新匹配。這樣就有很多已經(jīng)匹配的情況就浪費(fèi)了。

所以就需要優(yōu)化來(lái)去掉重復(fù)的計(jì)算,首先要將字符串分成單詞長(zhǎng)度的組數(shù)來(lái)分別計(jì)算。

然后每組在詳細(xì)進(jìn)行的時(shí)候需要兩個(gè)指針動(dòng)態(tài)向右表示區(qū)間匹配。而Map通常不需要每次都刷新可以重新利用。一個(gè)坐標(biāo)j代表開頭一個(gè)index表示當(dāng)前結(jié)尾

你可能會(huì)遇到以下幾種情況:

  • 遇到新單詞不存在,此時(shí)j和index都移動(dòng)到單詞后重新開始,且儲(chǔ)存的動(dòng)態(tài)map需要clear;

  • 遇到的單詞存在,但是多了,需要將j右移一直到消除這個(gè)多余單詞,同時(shí)修改動(dòng)態(tài)map。

  • 正常情況,疊加匹配更新index和map。

上面步驟完成之后,如果j+len==index那么就說(shuō)明完成匹配,添加此個(gè)編號(hào)。但在此同時(shí),可以判斷下個(gè)單詞是否與當(dāng)前首單詞相等,如果相等直接更新對(duì)應(yīng)j和index順便加入結(jié)果集中,不過(guò)不需要更新動(dòng)態(tài)的map。

有了上述優(yōu)化的思路,就可以碼代碼了。注意細(xì)節(jié)實(shí)現(xiàn),前開后閉等等,具體代碼為:

public List<Integer> findSubstring(String s, String[] words) {List<Integer>value=new ArrayList<Integer>();//返回的結(jié)果Map<String, Integer>map=new HashMap<String, Integer>();//統(tǒng)計(jì)單詞個(gè)數(shù)for(String team:words)//進(jìn)行統(tǒng)計(jì){int num=map.getOrDefault(team, 0);map.put(team, num+1);}int wordlen=words[0].length();//單個(gè)單詞的長(zhǎng)度int len=words[0].length()*words.length;//總長(zhǎng)度for(int i=0;i<wordlen;i++)//分組分別進(jìn)行{int j=i,index=j;Map<String, Integer>map2=new HashMap<String, Integer>();while (j<=s.length()-len&&index+wordlen<=s.length()) {String word=s.substring(index,index+wordlen);int num=map2.getOrDefault(word, 0);map2.put(word, num+1);if(!map.containsKey(word))//不包含該元素,直接跳過(guò){j=index+wordlen;map2.clear(); }else if(map.get(word)<num+1)//元素存在但次數(shù)過(guò)多{String teamstr="";while (!(teamstr=s.substring(j,j+wordlen)).equals(word)) {//找到第一個(gè)不相等得map2.put(teamstr, map2.get(teamstr)-1);j+=wordlen;}map2.put(teamstr, map2.get(teamstr)-1);j+=wordlen;}index+=wordlen;if(index==j+len){value.add(j);while (index+wordlen<=s.length()&&s.substring(j, j+wordlen).equals(s.substring(index, index+wordlen))) {value.add(j+wordlen);j+=wordlen;index+=wordlen;} String teamstr=s.substring(j,j+wordlen);map2.put(teamstr, map2.get(teamstr)-1);j+=wordlen;}}}return value; }

下一個(gè)排列

題目描述:
實(shí)現(xiàn)獲取下一個(gè)排列的函數(shù),算法需要將給定數(shù)字序列重新排列成字典序中下一個(gè)更大的排列。

如果不存在下一個(gè)更大的排列,則將數(shù)字重新排列成最小的排列(即升序排列)。

必須原地修改,只允許使用額外常數(shù)空間。

以下是一些例子,輸入位于左側(cè)列,其相應(yīng)輸出位于右側(cè)列。
1,2,3 → 1,3,2
3,2,1 → 1,2,3
1,1,5 → 1,5,1

分析:
是不是和全排列有點(diǎn)像,但是又不是全排列。是需要找到下一個(gè)字典序。
分析數(shù)列你會(huì)發(fā)現(xiàn)以下兩個(gè)規(guī)律:

首先從右往左交換第一個(gè)正序:

  • 例如1 2 3 5 4 交換3和4成為1 2 4 5 3.

其次根據(jù)交換的區(qū)間內(nèi),從右向左(雙重循環(huán))交換逆序?qū)?#xff1a;

  • 例如上述變成1 2 4 3 5;

具體實(shí)現(xiàn)的時(shí)候,注意位置編號(hào)等問(wèn)題。具體代碼為:

public void nextPermutation(int[] nums) {boolean jud=false;int i,j=0;for( i=nums.length-2;i>=0;i--){for( j=nums.length-1;j>i;j--){if(!jud&&nums[i]<nums[j]){int team=nums[i];nums[i]=nums[j];nums[j]=team;jud=true;break;}}if(jud)break;}if(jud)for(int k=nums.length-1;k>i;k--){for(int m=k-1;m>i;m--){if(nums[k]<nums[m]){int team=nums[k];nums[k]=nums[m];nums[m]=team;}}}int team;if(!jud)for( i=0;i<nums.length/2;i++){team=nums[i];nums[i]=nums[nums.length-1-i];nums[nums.length-1-i]=team;}}


好啦,本次打卡就到這里啦,更多精彩歡迎關(guān)注bigsai,回復(fù)進(jìn)群加入打卡,回復(fù)bigsai獲取珍藏pdf資源。

總結(jié)

以上是生活随笔為你收集整理的LeetCode 30串联所有单词的子串31下一个排列的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。