leetcode:字符串

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中
            count.push(Integer.parseInt(s.substring(p1,i+1)));
        } 
        else if (a == '[') {
            result.push("");//用初始化空字符串处理并列关系
        } 
        else if(a == ']') {
	        //temp保存的是当前括号内需要重复的子字符串
            String temp = new String(result.pop());
            //sb是重复了指定次数以后的字符串
            StringBuilder sb = new StringBuilder();
            int nloop = count.pop();
            for(int j = 0; j < nloop;j++)
                sb.append(temp);
            //重复完毕后,将sb添加进栈顶的子串中
            result.push(result.pop()+sb.toString());
        }
        //如果是最正常的普通字符,就直接添加到栈顶的子串中
        else {
            result.push(result.pop()+a);
        }
        i++;
    }
    //最后result内肯定只有栈底一个元素,它就是解码后的结果
    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对应的英文字母,有那么些规律,可以从中找到相关的规律。

我们可以观察得到:
* 只有0(Zero):包含z,剩下的都没有
* 只有2(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. 最长的替换重复子串

题意:
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.

思路:
滑动窗口

完整代码:

class Solution
{
public:
    int findmax(int count[])
    {
        int res = 0;
        for (int i = 0; i < 26; i++)
        {
            if (count[i] > res)
                res = count[i];
        }

        return res;
    }

    int characterReplacement(string s, int k)
    {
        int start = 0, end = 0, res = 0, maxcur = 0;
        int count[26] = {0};
        while (end < s.size())
        {
            count[s[end] - 'A']++;
            maxcur = max(maxcur, findmax(count));

            while ((end - start + 1 - maxcur) > k)
            {
                count[s[start] - 'A']--;
                start++;
            }

            res = max(res, end - start + 1);
            end++;
        }

        return res;
    }
};

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. 最长无重复元素的子串

求一个字符串的最长无重复元素子串。
思路:
滑动窗口

class Solution
{
public:
    bool valid(int cnt[])
    {
        for (int i = 0; i < 256; i++)
        {
            if (cnt[i] > 1)
                return false;
        }

        return true;
    }

    int lengthOfLongestSubstring(string s)
    {
        int left = 0, right = 0, ans = 0;
        int cnt[256] = {0};

        for (; right < s.size(); right++)
        {
            cnt[s[right]]++;

            if (!valid(cnt))
            {
                cnt[s[left]]--;
                left++;
            }

            ans = max(ans, right - left + 1);
        }

        return ans;
    }
};
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值