[算法總結] 13 道題搞定 BAT 面試——字符串

本文首發于我的個人博客:尾尾部落

1. KMP 算法

談到字符串問題,不得不提的就是 KMP 算法,它是用來解決字符串查找的問題,可以在一個字符串(S)中查找一個子串(W)出現的位置。KMP 算法把字符匹配的時間復雜度縮小到 O(m+n) ,而空間復雜度也只有O(m)。因為“暴力搜索”的方法會反復回溯主串,導致效率低下,而KMP算法可以利用已經部分匹配這個有效信息,保持主串上的指針不回溯,通過修改子串的指針,讓模式串盡量地移動到有效的位置。

具體算法細節請參考:

  • 字符串匹配的KMP算法
  • 從頭到尾徹底理解KMP
  • 如何更好的理解和掌握 KMP 算法?
  • KMP 算法詳細解析
  • 圖解 KMP 算法
  • 汪都能聽懂的KMP字符串匹配算法【雙語字幕】
  • KMP字符串匹配算法1

1.1 BM 算法

BM算法也是一種精確字符串匹配算法,它采用從右向左比較的方法,同時應用到了兩種啟發式規則,即壞字符規則 和好后綴規則 ,來決定向右跳躍的距離。基本思路就是從右往左進行字符匹配,遇到不匹配的字符后從壞字符表和好后綴表找一個最大的右移值,將模式串右移繼續匹配。 字符串匹配的KMP算法

2. 替換空格

劍指offer:替換空格 請實現一個函數,將一個字符串中的每個空格替換成“%20”。例如,當字符串為We Are Happy.則經過替換之后的字符串為We%20Are%20Happy。

public class Solution {public String replaceSpace(StringBuffer str) {StringBuffer res = new StringBuffer();int len = str.length() - 1;for(int i = len; i >= 0; i--){if(str.charAt(i) == ' ')res.append("02%");elseres.append(str.charAt(i));}return res.reverse().toString();}
}
復制代碼

3. 最長公共前綴

Leetcode: 最長公共前綴 編寫一個函數來查找字符串數組中的最長公共前綴。如果不存在公共前綴,返回空字符串 ""。

首先對字符串數組進行排序,然后拿數組中的第一個和最后一個字符串進行比較,從第 0 位開始,如果相同,把它加入 res 中,不同則退出。最后返回 res

class Solution {public String longestCommonPrefix(String[] strs) {if(strs == null || strs.length == 0)return "";Arrays.sort(strs);char [] first = strs[0].toCharArray();char [] last = strs[strs.length - 1].toCharArray();StringBuffer res = new StringBuffer();int len = first.length < last.length ? first.length : last.length;int i = 0;while(i < len){if(first[i] == last[i]){res.append(first[i]);i++;}elsebreak;}return res.toString();}
}
復制代碼

4. 最長回文串

LeetCode: 最長回文串 給定一個包含大寫字母和小寫字母的字符串,找到通過這些字母構造成的最長的回文串。在構造過程中,請注意區分大小寫。比如 "Aa" 不能當做一個回文字符串。

統計字母出現的次數即可,雙數才能構成回文。因為允許中間一個數單獨出現,比如“abcba”,所以如果最后有字母落單,總長度可以加 1。

class Solution {public int longestPalindrome(String s) {HashSet<Character> hs = new HashSet<>();int len = s.length();int count = 0;if(len == 0)return 0;for(int i = 0; i<len; i++){if(hs.contains(s.charAt(i))){hs.remove(s.charAt(i));count++;}else{hs.add(s.charAt(i));}}return hs.isEmpty() ? count * 2 : count * 2 + 1;}
}
復制代碼

4.1 驗證回文串

Leetcode: 驗證回文串 給定一個字符串,驗證它是否是回文串,只考慮字母和數字字符,可以忽略字母的大小寫。 說明:本題中,我們將空字符串定義為有效的回文串。

兩個指針比較頭尾。要注意只考慮字母和數字字符,可以忽略字母的大小寫。

class Solution {public boolean isPalindrome(String s) {if(s.length() == 0)return true;int l = 0, r = s.length() - 1;while(l < r){if(!Character.isLetterOrDigit(s.charAt(l))){l++;}else if(!Character.isLetterOrDigit(s.charAt(r))){r--;}else{if(Character.toLowerCase(s.charAt(l)) != Character.toLowerCase(s.charAt(r)))return false;l++;r--;} }return true;}
}
復制代碼

4.2 最長回文子串

LeetCode: 最長回文子串 給定一個字符串 s,找到 s 中最長的回文子串。你可以假設 s 的最大長度為1000。

以某個元素為中心,分別計算偶數長度的回文最大長度和奇數長度的回文最大長度。

class Solution {private int index, len;public String longestPalindrome(String s) {if(s.length() < 2)return s;for(int i = 0; i < s.length()-1; i++){PalindromeHelper(s, i, i);PalindromeHelper(s, i, i+1);}return s.substring(index, index+len);}public void PalindromeHelper(String s, int l, int r){while(l >= 0 && r < s.length() && s.charAt(l) == s.charAt(r)){l--;r++;}if(len < r - l - 1){index = l + 1;len = r - l - 1;}}
}
復制代碼

4.3 最長回文子序列

LeetCode: 最長回文子序列 給定一個字符串s,找到其中最長的回文子序列。可以假設s的最大長度為1000。 最長回文子序列和上一題最長回文子串的區別是,子串是字符串中連續的一個序列,而子序列是字符串中保持相對位置的字符序列,例如,"bbbb"可以使字符串"bbbab"的子序列但不是子串。

動態規劃: dp[i][j] = dp[i+1][j-1] + 2 if s.charAt(i) == s.charAt(j) otherwise, dp[i][j] = Math.max(dp[i+1][j], dp[i][j-1])

class Solution {public int longestPalindromeSubseq(String s) {int len = s.length();int [][] dp = new int[len][len];for(int i = len - 1; i>=0; i--){dp[i][i] = 1;for(int j = i+1; j < len; j++){if(s.charAt(i) == s.charAt(j))dp[i][j] = dp[i+1][j-1] + 2;elsedp[i][j] = Math.max(dp[i+1][j], dp[i][j-1]);}}return dp[0][len-1];}
}
復制代碼

5. 字符串的排列

Leetcode: 字符串的排列 給定兩個字符串 s1 和 s2,寫一個函數來判斷 s2 是否包含 s1 的排列。 換句話說,第一個字符串的排列之一是第二個字符串的子串。

我們不用真的去算出s1的全排列,只要統計字符出現的次數即可。可以使用一個哈希表配上雙指針來做。

class Solution {public boolean checkInclusion(String s1, String s2) {int l1 = s1.length();int l2 = s2.length();int [] count = new int [128];if(l1 > l2)return false;for(int i = 0; i<l1; i++){count[s1.charAt(i) - 'a']++;count[s2.charAt(i) - 'a']--;}if(allZero(count))return true;for(int i = l1; i<l2; i++){count[s2.charAt(i) - 'a']--;count[s2.charAt(i-l1) - 'a']++;if(allZero(count))return true;}return false;}public boolean allZero(int [] count){int l = count.length;for(int i = 0; i < l; i++){if(count[i] != 0)return false;}return true;}
}
復制代碼

6. 打印字符串的全排列

劍指offer:字符串的排列 輸入一個字符串,按字典序打印出該字符串中字符的所有排列。例如輸入字符串abc,則打印出由字符a,b,c所能排列出來的所有字符串abc,acb,bac,bca,cab和cba。

把問題拆解成簡單的步驟: 第一步求所有可能出現在第一個位置的字符(即把第一個字符和后面的所有字符交換[相同字符不交換]); 第二步固定第一個字符,求后面所有字符的排列。這時候又可以把后面的所有字符拆成兩部分(第一個字符以及剩下的所有字符),依此類推。這樣,我們就可以用遞歸的方法來解決。

public class Solution {ArrayList<String> res = new ArrayList<String>();public ArrayList<String> Permutation(String str) {if(str == null)return res;PermutationHelper(str.toCharArray(), 0);Collections.sort(res);return res;}public void PermutationHelper(char[] str, int i){if(i == str.length - 1){res.add(String.valueOf(str));}else{for(int j = i; j < str.length; j++){if(j!=i && str[i] == str[j])continue;swap(str, i, j);PermutationHelper(str, i+1);swap(str, i, j);}}}public void swap(char[] str, int i, int j) {char temp = str[i];str[i] = str[j];str[j] = temp;}
}
復制代碼

7. 第一個只出現一次的字符

劍指offer: 第一個只出現一次的字符 在一個字符串(0<=字符串長度<=10000,全部由字母組成)中找到第一個只出現一次的字符,并返回它的位置, 如果沒有則返回 -1.

先在hash表中統計各字母出現次數,第二次掃描直接訪問hash表獲得次數。也可以用數組代替hash表。

import java.util.HashMap;
public class Solution {public int FirstNotRepeatingChar(String str) {int len = str.length();if(len == 0)return -1;HashMap<Character, Integer> map = new HashMap<>();for(int i = 0; i < len; i++){if(map.containsKey(str.charAt(i))){int value = map.get(str.charAt(i));map.put(str.charAt(i), value+1);}else{map.put(str.charAt(i), 1);}}for(int i = 0; i < len; i++){if(map.get(str.charAt(i)) == 1)return i;}return -1;}
}
復制代碼

8. 翻轉單詞順序列

劍指offer: 翻轉單詞順序列 LeetCode: 翻轉字符串里的單詞

借助trim()和 split()就很容易搞定

public class Solution {public String reverseWords(String s) {if(s.trim().length() == 0)return s.trim();String [] temp = s.trim().split(" +");String res = "";for(int i = temp.length - 1; i > 0; i--){res += temp[i] + " ";}return res + temp[0];}
}
復制代碼

9. 旋轉字符串

Leetcode: 旋轉字符串 給定兩個字符串, A 和 B。 A 的旋轉操作就是將 A 最左邊的字符移動到最右邊。 例如, 若 A = 'abcde',在移動一次之后結果就是'bcdea' 。如果在若干次旋轉操作之后,A 能變成B,那么返回True。

一行代碼搞定

class Solution {public boolean rotateString(String A, String B) {return A.length() == B.length() && (A+A).contains(B);}
}
復制代碼

9.1 左旋轉字符串

劍指offer: 左旋轉字符串 匯編語言中有一種移位指令叫做循環左移(ROL),現在有個簡單的任務,就是用字符串模擬這個指令的運算結果。對于一個給定的字符序列S,請你把其循環左移K位后的序列輸出。例如,字符序列S=”abcXYZdef”,要求輸出循環左移3位后的結果,即“XYZdefabc”。是不是很簡單?OK,搞定它!

在第 n 個字符后面將切一刀,將字符串分為兩部分,再重新并接起來即可。注意字符串長度為 0 的情況。

public class Solution {public String LeftRotateString(String str,int n) {int len = str.length();if(len == 0)return "";n = n % len;String s1 = str.substring(n, len);String s2 = str.substring(0, n);return s1+s2;}
}
復制代碼

9.2 反轉字符串

LeetCode: 反轉字符串 編寫一個函數,其作用是將輸入的字符串反轉過來。

class Solution {public String reverseString(String s) {if(s.length() < 2)return s;int l = 0, r = s.length() - 1;char [] strs = s.toCharArray(); while(l < r){char temp = strs[l];strs[l] = strs[r];strs[r] = temp;l++;r--;}return new String(strs);}
}
復制代碼

10. 把字符串轉換成整數

劍指offer: 把字符串轉換成整數 將一個字符串轉換成一個整數(實現Integer.valueOf(string)的功能,但是string不符合數字要求時返回0),要求不能使用字符串轉換整數的庫函數。 數值為0或者字符串不是一個合法的數值則返回0。

public class Solution {public int StrToInt(String str) {if(str.length() == 0)return 0;int flag = 0;if(str.charAt(0) == '+')flag = 1;else if(str.charAt(0) == '-')flag = 2;int start = flag > 0 ? 1 : 0;long res = 0;while(start < str.length()){if(str.charAt(start) > '9' || str.charAt(start) < '0')return 0;res = res * 10 + (str.charAt(start) - '0');start ++;}return flag == 2 ? -(int)res : (int)res;}
}
復制代碼

11. 正則表達式匹配

劍指offer:正則表達式匹配 請實現一個函數用來匹配包括’.’和’*’的正則表達式。模式中的字符’.’表示任意一個字符,而’*’表示它前面的字符可以出現任意次(包含0次)。 在本題中,匹配是指字符串的所有字符匹配整個模式。例如,字符串”aaa”與模式”a.a”和”ab*ac*a”匹配,但是與”aa.a”和”ab*a”均不匹配

動態規劃: 這里我們采用dp[i+1][j+1]代表s[0..i]匹配p[0..j]的結果,結果自然是采用布爾值True/False來表示。 首先,對邊界進行賦值,顯然dp[0][0] = true,兩個空字符串的匹配結果自然為True; 接著,我們對dp[0][j+1]進行賦值,因為 i=0 是空串,如果一個空串和一個匹配串想要匹配成功,那么只有可能是p.charAt(j) == '*' && dp[0][j-1] 之后,就可以愉快地使用動態規劃遞推方程了。

public boolean isMatch(String s, String p) {if (s == null || p == null) {return false;}boolean[][] dp = new boolean[s.length()+1][p.length()+1];dp[0][0] = true;for (int j = 0; i < p.length(); j++) {if (p.charAt(j) == '*' && dp[0][j-1]) {dp[0][j+1] = true;}}for (int i = 0 ; i < s.length(); i++) {for (int j = 0; j < p.length(); j++) {if (p.charAt(j) == '.') {dp[i+1][j+1] = dp[i][j];}if (p.charAt(j) == s.charAt(i)) {dp[i+1][j+1] = dp[i][j];}if (p.charAt(j) == '*') {if (p.charAt(j-1) != s.charAt(i) && p.charAt(j-1) != '.') {dp[i+1][j+1] = dp[i+1][j-1];} else {dp[i+1][j+1] = (dp[i+1][j] || dp[i][j+1] || dp[i+1][j-1]);}}}}return dp[s.length()][p.length()];
}
復制代碼

12. 表示數值的字符串

劍指offer: 表示數值的字符串 請實現一個函數用來判斷字符串是否表示數值(包括整數和小數)。例如,字符串”+100″,”5e2″,”-123″,”3.1416″和”-1E-16″都表示數值。 但是”12e”,”1a3.14″,”1.2.3″,”+-5″和”12e+4.3″都不是。

設置三個標志符分別記錄“+/-”、“e/E”和“.”是否出現過。

public class Solution {public boolean isNumeric(char[] str) {int len = str.length;boolean sign = false, decimal = false, hasE = false;for(int i = 0; i < len; i++){if(str[i] == '+' || str[i] == '-'){if(!sign && i > 0 && str[i-1] != 'e' && str[i-1] != 'E')return false;if(sign && str[i-1] != 'e' && str[i-1] != 'E')return false;sign = true;}else if(str[i] == 'e' || str[i] == 'E'){if(i == len - 1)return false;if(hasE)return false;hasE = true;}else if(str[i] == '.'){if(hasE || decimal)return false;decimal = true;}else if(str[i] < '0' || str[i] > '9')return false;}return true;}
}
復制代碼

13. 字符流中第一個不重復的字符

劍指offer: 字符流中第一個不重復的字符 請實現一個函數用來找出字符流中第一個只出現一次的字符。例如,當從字符流中只讀出前兩個字符”go”時,第一個只出現一次的字符是”g”。當從該字符流中讀出前六個字符“google”時,第一個只出現一次的字符是”l”。

用一個哈希表來存儲每個字符及其出現的次數,另外用一個字符串 s 來保存字符流中字符的順序。

import java.util.HashMap;
public class Solution {HashMap<Character, Integer> map = new HashMap<Character, Integer>();StringBuffer s = new StringBuffer();//Insert one char from stringstreampublic void Insert(char ch){s.append(ch);if(map.containsKey(ch)){map.put(ch, map.get(ch)+1);}else{map.put(ch, 1);}}//return the first appearence once char in current stringstreampublic char FirstAppearingOnce(){for(int i = 0; i < s.length(); i++){if(map.get(s.charAt(i)) == 1)return s.charAt(i);}return '#';}
}
復制代碼

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/537928.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/537928.shtml
英文地址,請注明出處:http://en.pswp.cn/news/537928.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Sqlserver備份存儲過程

查了網上找不到快速備份Sqlserver存儲過程的方法&#xff0c;心里想&#xff0c;如果Sqlserver不自帶這個功能&#xff0c;真是太low了。步驟1&#xff1a;打開存儲過程文件夾步驟2&#xff1a;按 F7 鍵&#xff0c;打開“對象資源管理器詳細信息”窗口步驟3&#xff1a;點擊“…

仿拉鉤app(一)---爬蟲數據準備

工欲善其事必先利其器&#xff0c;準備做一個拉鉤的app&#xff0c;但是沒數據可怎么辦&#xff0c;那就直接扒褲衩去爬吧 一般爬蟲的思路為&#xff1a; 分析頁面結構是否有接口模仿請求&#xff08;解決反爬的各種方式&#xff09;解析數據存儲數據按照以上的思路&#xff0c…

小哼買書JAVA編寫,04_小哼買書

現在來看一個具體的例子“小哼買書”(根據全國青少年信息學奧林匹克聯賽 NOIP2006 普及組第一題改編),來實踐一下 章所學的三種排序算法。Paste_Image.png小哼的學校要建立一個圖書角,老師派小哼去找一些同學做調查,看看同學們都喜歡讀哪些書。小哼讓每個同學寫出一個自己最想讀…

[Err] 22007 - [SQL Server]從 nvarchar 數據類型到 datetime 數據類型的轉換產生一個超出范圍的值。

報錯語句&#xff1a; cast(Replace(Replace(P.DeliverDate,.,-),/,-) as datetime)改為 cast(Replace(Replace(P.DeliverDate,.,-),/,-) as datetime2)使用 datetime2 代替 datetime

linux Postfix + dovecot + extmail + extman + mysql

配置環境&#xff1a;RHEL5.5 i386DNS MX[rootstation40 ~]# host -t MX tianyun.comtianyun.com mail is handled by 10 mail.tianyun.com.[rootstation40 ~]# [rootstation40 ~]# ping mail.tianyun.comPING mail.tianyun.com (192.168.0.2) 56(84) bytes of data.64 bytes f…

php 接口安全解決方案,php接口數據安全解決方案(一)

前言目的&#xff1a;1.實現前后端代碼分離&#xff0c;分布式部署2.利用token替代session實現狀態保持&#xff0c;token是有時效性的滿足退出登錄&#xff0c;token存入redis可以解決不同服務器之間session不同步的問題&#xff0c;滿足分布式部署3.利用sign&#xff0c;前端…

Teamview連接Windows server問題

場景&#xff1a; 服務器在集團總部杭州&#xff0c;網管在集團寧波分公司&#xff0c;連接服務器通過內網遠程桌面。過程&#xff1a; 網管給了tv的賬號&#xff0c;密碼。連接的時候一直連不上去。卡在“正在初始化連接參數”。后來網管不信&#xff0c;遠程桌面了下&#xf…

nginx An attempt was made to access a socket in a way forbidden by its access permissions

在安裝了 sqlserver2008 的win7 與 win2008 上啟動 nginx&#xff0c;綁定80端口&#xff0c;報錯&#xff1a; nginx An attempt was made to access a socket in a way forbidden by its access permissions查了百度&#xff0c;說修改注冊表&#xff0c;但我的電腦上找不到文…

php codesniffer 代碼規范,規范三:PHP_CodeSniffer 輔佐代碼規范

>也可以參考此文&#xff1a;https://www.cnblogs.com/huangbx/p/php_codesniffer.html[TOC]我用的是wamp&#xff0c;環境是php7.0.23# (一)下載 pear打開http://pear.php.net/go-pear.phar&#xff0c;會顯示代碼&#xff0c;不用管他&#xff0c;直接copys復制到本地&…

php的cms是什么意思,phpcms是什么系統

什么是phpcms&#xff1f;Phpcms 是國內領先的網站內容管理系統&#xff0c;同時也是一個開源的PHP開發框架。Phpcms由內容模型、會員、問吧、專題、財務、訂單、廣告、郵件訂閱、 短消息、自定義表單、全站搜索等20多個功能模塊組成&#xff0c;內置新聞、圖片、下載、信息、產…

【python】 time模塊和datetime模塊詳解 【轉】

一、time模塊 time模塊中時間表現的格式主要有三種&#xff1a; a、timestamp時間戳&#xff0c;時間戳表示的是從1970年1月1日00:00:00開始按秒計算的偏移量 b、struct_time時間元組&#xff0c;共有九個元素組。 c、format time 格式化時間&#xff0c;已格式化的結構使時間更…

spring boot Exception in Thread “main” java.lang.classNoFoundException

在客戶測試環境部署&#xff0c;通過打包成jar&#xff0c;使用命令 nohup java -jar /usr/local/tomcat/shirencai/ct-peixun-provider.jar –spring.profiles.activestage > /usr/local/tomcat/shirencai/ct-peixun-provider-temp.txt & 報錯后來排查以為是內存不夠。…

php源碼自動識別文本中的鏈接,自動加載識別文件Auto.php

用于本應用的控制器自動加載類設置&#xff0c;用法如同\CodeIgniter\Config\AutoloadConfig自動加載識別文件:dayrui/App/應用目錄/Config/Auto.php語法格式&#xff1a;<?php // 自動加載識別文件return [/*** 命名空間映射關系*/psr4 > [],/*** 類名映射關系*/classm…

如何識別“答非所問”?使用gensim進行文本相似度計算

在文本處理中&#xff0c;比如商品評論挖掘&#xff0c;有時需要了解每個評論分別和商品的描述之間的相似度&#xff0c;以此衡量評論的客觀性。 評論和商品描述的相似度越高&#xff0c;說明評論的用語比較官方&#xff0c;不帶太多感情色彩&#xff0c;比較注重描述商品的屬性…

防抓包重放php,超簡單最基本的WEB抓包改包重放的方法

【注意&#xff1a;此文章為博主原創文章&#xff01;轉載需注意&#xff0c;請帶原文鏈接&#xff0c;至少也要是txt格式&#xff01;】很多很多剛剛接觸的同事問我如何抓包&#xff0c;如果講用工具可能還涉及什么裝證書&#xff0c;熟悉使用工具等等&#xff0c;特別繁瑣&am…

mysql查詢很慢優化方法1

解決方法&#xff1a; 關聯的字段建索引。 具體分析如下&#xff1a;舉例&#xff1a; 表格&#xff1a;培訓學生表&#xff0c;班級報名表 需求&#xff1a;查詢出學生報了哪些班級 兩表有個關聯字段“CD”&#xff08;學生學號&#xff09;。 視圖sql&#xff1a; SELECTt_px…

ubuntu進行apt-get時候出現Package ssh is not available, but is referred to by another package 錯誤...

今天在ubuntu進行ssh安裝的時候&#xff0c;出現如下錯誤。Reading package lists... Done Building dependency tree... Done Package ssh is not available, but is referred to by another package. This may mean that the package is missing, has been obsoleted, or is …

php找出函數定義位置,WordPress如何快速定位PHP函數所在文件位置及代碼行號?

有時候我們需要修改別人源碼里的代碼&#xff0c;卻找不到對應的函數放在了哪兒&#xff0c;就可以用使用本文介紹的辦法&#xff0c;幫你快速定位函數位置。特別是某些寫法不規范的WordPress主題&#xff0c;各種模塊&#xff0c;函數到處放&#xff0c;找半天的那種。那么Wor…

微信公眾號每次調用接口正確或錯誤的返回碼

原文連接&#xff1a;https://blog.csdn.net/pansanday/article/details/65448868 ----------------------------------------- 公眾號每次調用接口時&#xff0c;可能獲得正確或錯誤的返回碼&#xff0c;開發者可以根據返回碼信息調試接口&#xff0c;排查錯誤。 全局返回碼…

Phoenix:全局索引設計實踐

概述 全局索引是Phoenix的重要特性&#xff0c;合理的使用二級索引能降低查詢延時&#xff0c;讓集群資源得以充分利用。 本文將講述如何高效的設計和使用索引。 全局索引說明 全局索引的根本是通過單獨的HBase表來存儲數據表的索引數據。我們通過如下示例看索引數據和主表數據…