leetcode:字符串

来源:互联网 发布:网络搜索优化方案 编辑:程序博客网 时间:2024/05/20 02:51

242. 判断2个字符串是否是anagram

anagram的定义是:字符元素相同,但顺序不同的一对字符串

思路:将两个字符串排序,然后进行比较。

    bool isAnagram(string s, string t) {        sort(s.begin(), s.end());        sort(t.begin(), t.end());        return s == t;    }

注意:这里使用了STL的sort()函数。

318. 寻找一对不含相同字母的字符串,求其长度之积的最大值

给出若干字符串,找出其中一对字符串,要求它们不能有相同的字符(字符只考虑小写字母)。计算所有满足条件的字符串对的长度之积,求其最大值。

思路
分析题目,字符最多只有26个字母,因此每个字符串可以用一个26位二进制数来表示它含有哪些字母。

  1. 通过将1移位的方式,在vector中依次保存words[i]的二进制信息,该信息记录了该字符串是否含有某一字母;
  2. 两两配对,判断两个字符串是否有相同的字母(用位与的方式)。若没有,则计算长度之积;
  3. 最后返回长度之积的最大值。
class Solution {public:    int maxProduct(vector<string>& words) {        vector<int> v;        //v中依次保存着words[i]中是否存在某个字母的二进制信息        for(int i=0;i<words.size();i++){            int temp=0;            for(int j=0;j<words[i].size();j++){                temp |= 1<<(words[i][j]-'a');            }            v.push_back(temp);        }        int max=0;        //两两配对,判断2个字符串是否含有相同的字母        for(int i=0;i<words.size();i++){            for(int j=i+1;j<words.size();j++){                if((v[i]&v[j])==0 && max<(words[i].size()*words[j].size()))                    max=words[i].size()*words[j].size();            }        }       return max;    }};

241. 添加括号的不同方式

Given a string of numbers and operators, return all possible results from computing all the different possible ways to group numbers and operators. The valid operators are +, - and *.

Example 1 Input: “2-1-1”.((2-1)-1) = 0 (2-(1-1)) = 2 Output: [0, 2]Example 2 Input: “2*3-4*5”(2*(3-(4*5))) = -34 ((2*3)-(4*5)) = -14 ((2*(3-4))*5) = -10 (2*((3-4)*5)) = -10 (((2*3)-4)*5) = 10 Output: [-34, -14, -10, -10, 10]

思路
递归。

  1. 从左往右扫描表达式,遇到操作符时,对操作符左右两边的表达式递归调用函数;
  2. 递归函数会返回所有可能的计算结果。将该操作符左边和右边的不同结果进行运算;并保存到ret中;
  3. 递归结束的条件是当前传入的表达式不含操作符。
class Solution {public:    vector<int> diffWaysToCompute(string input) {        vector<int> ret;        for (int i = 0; i < input.size(); i++)        {            if (input[i] == '+' || input[i] == '-' || input[i] == '*')            {                vector<int> left = diffWaysToCompute(input.substr(0, i));                vector<int> right = diffWaysToCompute(input.substr(i + 1));                for (int j = 0; j < left.size(); j++)                {                    for (int k = 0; k < right.size(); k++)                    {                        if (input[i] == '+')                            ret.push_back(left[j] + right[k]);                        else if (input[i] == '-')                            ret.push_back(left[j] - right[k]);                        else                            ret.push_back(left[j] * right[k]);                    }                }            }        }        if (ret.empty())            ret.push_back(atoi(input.c_str()));        return ret;    }};

394. 解码字符串(Java)

题意
在字符串当中,有一个特殊的格式 :k[S],遇到这种状况,需要把S重复k次,注意是可以嵌套的。
思路
用到了DFS。
先将’]’ 之前的信息(要重复的部分及重复次数)压到stack里,等到了’]’再一个一个推出还原。思路非常清晰,但是实现起来并不简单。得注意细节及其处理方式,比如数字可能出现两位及以上; 并列关系[],[]和包含关系[[]]如何巧妙区分。另外发现大循环用while而不是for可能更方便一些。

public static String decodeString(String s) {    Stack<Integer> count = new Stack<>();    Stack<String> result = new Stack<>();//用Stack处理包含关系    result.push("");    int i = 0;    while(i<s.length()){        char a = s.charAt(i);        if(a >= '0' && a <= '9'){ //如果该字符是数字            int p1 = i;            while(Character.isDigit(s.charAt(i+1))) i++;            count.push(Integer.parseInt(s.substring(p1,i+1)));        } //将重复的次数存入count中        else if (a == '[') {            result.push("");//用初始化空字符串处理并列关系        }         else if(a == ']') {            String temp = new String(result.pop());            StringBuilder sb = new StringBuilder();            int nloop = count.pop();            for(int j = 0; j < nloop;j++)                sb.append(temp);            result.push(result.pop()+sb.toString());        }         else {            result.push(result.pop()+a);        }        i++;    }    return result.pop();}

423. 重构数字(Java)

题意
Given a non-empty string containing an out-of-order English representation of digits 0-9, output the digits in ascending order.
Note:
Input contains only lowercase English letters.
Input is guaranteed to be valid and can be transformed to its original digits. That means invalid inputs such as “abc” or “zerone” are not permitted.
Input length is less than 50,000.

Example 1:
Input: “owoztneoer”

Output: “012”

Example 2:
Input: “fviefuro”

Output: “45”

思路:
原先想的思路过于复杂,结果超时。然后看到一个很巧妙的思路,首先分析题目,0~9对应的英文字母,有那么些规律,可以从中找到相关的规律。

我们可以观察得到:
* 只有Zero:包含z,剩下的都没有
* 只有Two:包含w,其他都没有
* 除了0,2,只有six包含x
* 除了0,2,6,只有…. 等等以此类推

* 找到每一个规律后,就可以开始了。

完整代码:

public class Solution {    public String originalDigits(String s) {         //只包含0~9,我直接if了         char chars[] = s.toCharArray();         int n = s.length();         int[] count = new int[10];         for (int i = 0; i < n; i++){            char c = s.charAt(i);            if (c == 'z') count[0]++; //只有0有z            else if (c == 'w') count[2]++; // 2 -> w            else if (c == 'x') count[6]++; // 6 -> x            else if (c == 'g') count[8]++; // 8-> g            else if (c == 'u') count[4]++; // 4 -> u            //上面是独有的,下面是可以计算出来的            else if (c == 's') count[7]++; // 6/7 ->s            else if (c == 'f') count[5]++; // 4/5 -> f            else if (c == 'h') count[3]++; // 3/8 - > h            else if (c == 'i') count[9]++; // 5/6/8/9 ->i            else if (c == 'o') count[1]++; // 0/1/2/4 ->o         }         //计算         count[7] -= count[6];         count[5] -= count[4];         count[3] -= count[8];         count[9] = count[9] - count[8] - count[5] - count[6];         count[1] = count[1] - count[0] - count[2] - count[4];         StringBuilder sb = new StringBuilder();         for (int i = 0; i <= 9; i++){            for (int j = 0; j < count[i]; j++){                sb.append(i);            }         }        return sb.toString();    }}

424. 最长的替换重复子串(Java)

题意:
Given a string that consists of only uppercase English letters, you can replace any letter in the string with another letter at most k times. Find the length of a longest substring containing all repeating letters you can get after performing the above operations.

Note:
Both the string’s length and k will not exceed 104.

Example 1:

Input: s = “ABAB”, k = 2

Output: 4

Explanation:
Replace the two ‘A’s with two ‘B’s or vice versa.
Example 2:

Input: s = “AABABBA”, k = 1

Output: 4

Explanation:
Replace the one ‘A’ in the middle with ‘B’ and form “AABBBBA”.
The substring “BBBB” has the longest repeating letters, which is 4.

思路:
从头至尾,逐个扫描字符(但要忽略与前一个字符相同的字符,因为这个字符已经计算过了)。计算以当前字符开始的子字符串的最大长度,然后从中选取其最大值。要注意的是,当j到达len,而count大于0时,该最大长度

templen = j-i+Math.min(count,i);

其他情况下,

templen = j-i;

完整代码:

public class Solution {    public int characterReplacement(String s, int k) {        int len=s.length();        int maxlen=0;        int templen=0;        for(int i=0;i<len;i++) {//从头至尾,逐个扫描字符,但要忽略与前一个字符相同的字符,因为这个字符已经计算过了            if(i>0 && s.charAt(i)==s.charAt(i-1)) continue;            char cur_letter=s.charAt(i);//当前位置上的字符            int count = k;            int j;            for(j=i+1;j<len;j++) {//遇到不同的字符,将其替换                if(s.charAt(j) != cur_letter) count--;                if(count<0) break;            }            if(j==len && count>0) templen = j-i+Math.min(count,i);//以当前字符开始的子字符串的最大长度            else templen=j-i;            maxlen=Math.max(maxlen,templen);//从所有子字符串中选出最大的那个长度        }        return maxlen;    }}

395. 每个字母都出现至少k次的子串

Find the length of the longest substring T of a given string (consists of lowercase letters only) such that every character in T appears no less than k times.
思路:
用暴力法肯定不行,总的思路是递归调用。具体来说,对于字符串s,遍历它,将重复次数不足k的字母作为分隔符,分割s。对于分割出来的子串,递归调用方法,求它的最长子串长度。最后,返回长度中的最大值。
完整代码:

public class Solution {      public int longestSubstring(String s, int k) {          if(k<=1)    return s.length();          int[] repeat=new int[26];        for(int i=0;i<s.length();i++)   repeat[s.charAt(i)-'a']++;        StringBuilder reg=new StringBuilder("[");          boolean firstSplit=true;          for(int i=0;i<26;i++){              if(repeat[i]>0&&repeat[i]<k){                  if(firstSplit){                      reg.append((char)(i+'a'));                      firstSplit=false;                  }                  else{                      reg.append((char)(i+'a'));                  }              }          }        reg.append("]");//reg里存储了出现次数小于k的字母,作为不同的分隔符        if(reg.length()>2){//如果有分隔符               int max=0;              int tmpAns=0;              String[] strs=s.split(reg.toString());              for(String str:strs){                  tmpAns=longestSubstring(str, k);                  if(tmpAns>max){                      max=tmpAns;                  }              }              return max;          }          else{//没有分隔符,说明s中的每一个字符出现的次数都大于等于k            return s.length();          }      }  }  

212. 搜索字符串 II

Given a 2D board and a list of words from the dictionary, find all words in the board.

Each word must be constructed from letters of sequentially adjacent cell, where “adjacent” cells are those horizontally or vertically neighboring. The same letter cell may not be used more than once in a word.

For example,
Given words = [“oath”,”pea”,”eat”,”rain”] and board =

[  ['o','a','a','n'],  ['e','t','a','e'],  ['i','h','k','r'],  ['i','f','l','v']]

Return [“eat”,”oath”].

思路:
用普通的DFS(回溯法)会超时,更好的思路是使用Trie树和剪枝。因为要避免重复,先用了一个set存结果,然后再转存到result中。

public class Solution {    public List<String> findWords(char[][] board, String[] words) {        Set<String> res = new HashSet<String>();        if(board==null || words==null || board.length==0 || words.length==0) return new ArrayList<String>(res);        boolean[][] visited = new boolean[board.length][board[0].length];         Trie trie = new Trie();        for(String word : words) {            trie.insert(word);        }        for(int i=0; i<board.length; i++) {            for(int j=0; j<board[0].length; j++) {                search(board, visited, trie, i, j, new StringBuilder(), res);            }        }        return new ArrayList<String>(res);    }    private void search(char[][] board,boolean[][] visited,Trie trie,int i,int j, StringBuilder sb, Set<String> res) {            if(i<0 || i>board.length-1 || j<0 || j>board[0].length-1 || visited[i][j])  return;            sb.append(board[i][j]);            String s = sb.toString();            visited[i][j] = true;            if(trie.startsWith(s)) {                if(trie.search(s)) res.add(s);                search(board, visited, trie, i-1, j, sb, res);                search(board, visited, trie, i+1, j, sb, res);                search(board, visited, trie, i, j-1, sb, res);                search(board, visited, trie, i, j+1, sb, res);            }            sb.deleteCharAt(sb.length() - 1);            visited[i][j] = false;        }}class TrieNode {    // Initialize your data structure here.    char c;    boolean leaf;    HashMap<Character, TrieNode> children = new HashMap<Character, TrieNode>();    public TrieNode(char c) {        this.c = c;    }    public TrieNode(){};}class Trie {    private TrieNode root;    public Trie() {        root = new TrieNode();    }    // Inserts a word into the trie.    public void insert(String word) {        Map<Character, TrieNode> children = root.children;        for(int i=0; i<word.length(); i++) {            char c = word.charAt(i);            TrieNode t;            if(children.containsKey(c)) {                t = children.get(c);            } else {                t = new TrieNode(c);                children.put(c, t);            }            children = t.children;            if(i==word.length()-1) t.leaf=true;        }    }    // Returns if the word is in the trie.    public boolean search(String word) {        TrieNode t = searchNode(word);        return t!=null && t.leaf;    }    public boolean startsWith(String prefix) {        return searchNode(prefix) != null;    }    private TrieNode searchNode(String word) {        Map<Character, TrieNode> children = root.children;        TrieNode t = null;        for(int i=0; i<word.length(); i++) {            char c = word.charAt(i);            if(!children.containsKey(c)) return null;            t = children.get(c);            children = t.children;        }        return t;    }}

5. 最长回文字符串(Java)

思路:
中心扩展法。因为回文字符串是中心轴对称的,所以如果我们从下标 i 出发,用2个指针向 i 的两边扩展判断是否相等,那么只需要对0到n-1的下标都做此操作,就可以求出最长的回文子串。但需要注意的是,回文字符串有奇偶对称之分,即"abcba"与"abba"2种类型,因此需要分别判断。
设函数int Palindromic ( string &s, int i ,int j) 是求由下标 i 和 j 向两边扩展的回文串的长度,那么对0至n-1的下标,分别调用2次此函数:
int lenOdd = Palindromic( str, i, i )int lenEven = Palindromic (str , i , i+1 ),即可求得以下标i为奇回文和偶回文的子串长度。
最后,取所有长度中的最大值。

public class Solution {    public  String longestPalindrome(String s) {          if (s.length() <= 1) return s;          String longest = s.substring(0, 1);          for (int i = 0; i < s.length(); i++) {              String tmp = helper(s, i, i);              if (tmp.length() > longest.length()) {                  longest = tmp;              }            tmp = helper(s, i, i + 1);              if (tmp.length() > longest.length()) {                  longest = tmp;              }          }          return longest;      }      public String helper(String s, int begin, int end) {          while (begin >= 0 && end <= s.length() - 1  && s.charAt(begin) == s.charAt(end)) {              begin--;              end++;          }          String subS = s.substring(begin + 1, end);          return subS;      }  }

3. 最长无重复元素的子串

求一个字符串的最长无重复元素子串。
思路:
我们建立一个256位大小的整型数组来实现哈希表,这样做的原因是ASCII表一共能表示256个字符,所以可以记录所有字符。定义两个变量res和left,res记录最长无重复子串的长度,left指向该无重复子串左边的起始位置,然后我们遍历整个字符串。
对于每一个遍历到的字符,如果哈希表中该字符串对应的值为0,说明没有遇到过该字符,则此时计算最长无重复子串,i - left +1,其中i是最长无重复子串最右边的位置,left是最左边的位置;还有一种情况也需要计算最长无重复子串,就是当哈希表中的值小于left,这是由于此时出现过重复的字符,left的位置更新了,如果又遇到了新的字符,就要重新计算最长无重复子串。最后每次都要在哈希表中将当前字符对应的值赋值为i+1。
这里解释下程序中那个if条件语句中为啥要有个m[s[i]] < left,我们用一个例子来说明,当输入字符串为"abbca"的时候,当i=4时,也就是即将要开始遍历最后一个字母a时,此时哈希表表中a对应1,b对应3,c对应4,left为2,即当前最长的子字符串的左边界为第二个b的位置,而第一个a已经不在当前最长的字符串的范围内了,那么对于i=4这个新进来的a,应该要加入结果中,而此时未被更新的哈希表中a为1,不是0,如果不判断它和left的关系的话,就无法更新结果,那么答案就会少一位,所以需要加m[s[i]] < left。

class Solution {public:    int lengthOfLongestSubstring(string s) {        int m[256] = {0}, res = 0, left = 0;        for (int i = 0; i < s.size(); ++i) {            if (m[s[i]] == 0 || m[s[i]] < left) {                res = max(res, i - left + 1);            }             else left = m[s[i]];            m[s[i]] = i + 1;        }        return res;    }};
0 0
原创粉丝点击