18th Feb: 字符串处理(Bloomberg篇)

字符串处理类:


1) First Unique Character in a String


Given a string, find the first non-repeating character in it and return it's index. If it doesn't exist, return -1.


Examples:


s = "leetcode"
return 0.


s = "loveleetcode",
return 2.


Thinking: If there is a character which the first index of it (indexOf()) and the last index(lastIndexOf()) of it are the same. Then this character only exist one time in this string. 


Code: 


public class Solution {
    public int firstUniqChar(String s) {
        if (s == null || s.length() == 0) {
            return -1;
        }
        
        for (int i = 0; i < s.length(); i++) {
            if (s.indexOf(s.charAt(i)) == s.lastIndexOf(s.charAt(i))) {
                return i;
            }
        }
        
        return -1;
    }
}


Complexity Analysis: O(n^2). Because both the indexOf and lastIndexOf are search the string from beginning and end. 


2) Reverse Words in a String


Given an input string, reverse the string word by word.


For example,
Given s = "the sky is blue",
return "blue is sky the".


Thinking: For this problem, we need to consider some extreme cases. If there are spaces at the beginning, between the words and at the end. What should we do?


If the questioner wants us to eliminate the beginning spaces and ending spaces, we should use trim() function in String Class. 


How about replacing the multiple spaces with one single space? Use the regular expression " +" to represent multiple spaces. 


Space Complexity? You can do it with O(1). Also, you can do it with a stack. Below code is to do it with O(1). 


Code: 


public class Solution {
    public String reverseWords(String s) {
        if (s == null) {
            return s;   
        }
        
        s = s.trim();// eliminate the spaces at beginning and end
        
        if (s.length() < 2) {
            return s;
        }
        
        String[] characters = s.split(" +");
        String res = "";
        
        for (int i = characters.length - 1; i > 0; i--) {
            res += characters[i] + " ";
        }
        
        //the ending character should not be followed with space
        res += characters[0];
        
        return res;
    }
}

Feedback: Should always remember that String is an immutable class. Therefore, s = s.trim() can change itself while s.trim() just simply return another string. 


Complexity Analysis: O(n) time. O(1) space. 


3) Group Anagrams


Given an array of strings, group anagrams together.


For example, given: ["eat", "tea", "tan", "ate", "nat", "bat"], 
Return:


[
  ["ate", "eat","tea"],
  ["nat","tan"],
  ["bat"]
]


Thinking: The key idea here is to find the common feature of anagrams. The most obvious one is they all have the same letters but with different sequences. Therefore, if we uniform the sequences, the anagrams will be the same. This is how we decide if two words are anagrams -- Use the alphabetic sorting to uniform two words' sequence. 


Then, we use a HashMap to maintain the uniform sequence and its anagrams. 


Code: 


public class Solution {
    public List<List<String>> groupAnagrams(String[] strs) {
        List<List<String>> ans = new ArrayList<List<String>>();
        if (strs == null || strs.length == 0) {
            return ans;
        }
        
        // classify each word in this string array
        Map<String, List<String>> records = new HashMap<String, List<String>>();
        
        for (String tmp : strs) {
            char[] tmpArray = tmp.toCharArray();
            Arrays.sort(tmpArray);
            String tmpKey = String.valueOf(tmpArray);
            // put it into the records
            if (records.containsKey(tmpKey)) {
                records.get(tmpKey).add(tmp);
            } else {
                List<String> tmpList = new ArrayList<String>();
                tmpList.add(tmp);
                records.put(tmpKey, tmpList);
            }
        }
        
        return new ArrayList<List<String>>(records.values());
    }
}

Feedback: Should notice that if you would like to transform from char array to string, you should use String.valueOf(char[] input) to achieve. 


Complexity Analysis: O(n * mlogm). n is the length of String array. m is the average length of strings in the string array. This bases on the assumption that the hashMap can get and put elements in O(1). 


4) Longest Substring Without Repeating Characters


Given a string, find the length of the longest substring without repeating characters.


Examples:


Given "abcabcbb", the answer is "abc", which the length is 3.


Given "bbbbb", the answer is "b", with the length of 1.


Given "pwwkew", the answer is "wke", with the length of 3. Note that the answer must be a substring, "pwke" is a subsequence and not a substring.


Thinking: 


Counting the longest substring which is without repeating characters. We need to do the counting process from each index of the string. This is because we need to consider this situation: "dvdf". Each time we start with one index, and scan all theunchecked indexes (let us say it j, this requires us to maintain the record of j since the last search) are bigger than it. Using a hashmap to maintain the occurrence (1/ 0), find the index of character which is already in our hashmap. Then the length of the substring will be j - i + 1. Update the answer if it is bigger than the biggest answer record. But each time we move i forward, we need to set the hashmap value of char(i) to be 0. 


We also need to keep in mind that there may be situations that j may be smaller than i. Then we need to manually set the j to the i + 1. 


Code: 


public class Solution {
    public int lengthOfLongestSubstring(String s) {
        if (s == null) {
            return 0;
        }
        
        if (s.length() < 2) {
            return s.length();
        }
        
        int[] occurency = new int[256];
        int max = 1;
        int j = 1;
        
        for (int i = 0; i < s.length(); i++) {
            occurency[s.charAt(i)] = 1;
            j = Math.max(j, i + 1);
            while (j < s.length() && occurency[s.charAt(j)] == 0) {
                occurency[s.charAt(j)] = 1;
                j++;
            }
            max = Math.max(max, j - i);
            occurency[s.charAt(i)] = 0;
        }
        
        return max;
    }
}

Feedback: Remember that there are 256 characters in total in ASCII system. 


Complexity Analysis: O(1) space complexity and O(n^2) worst time complexity.  


5) Word Search


Given a 2D board and a word, find if the word exists in the grid.


The word can 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.


For example,
Given board =


[
  ['A','B','C','E'],
  ['S','F','C','S'],
  ['A','D','E','E']
]
word = "ABCCED", -> returns true,
word = "SEE", -> returns true,
word = "ABCB", -> returns false.


Thinking: Observe the example we can see that the target word must appear as the sequence of characters in the 'matrix'. Therefore, once we meet a character which is same as the first character of the target word, we can search if there is a word adjacent to it (left, right, up, down) which is the same as the second character. And we can keep doing such search process until we reach the length of string.


We need to set the character found for last character to be '\0' in order to prevent counting it for multiple times. But, don't forget to bring it back. 


Also, remember to check the boundary of matrix when you are searching the characters around the current positions. (row > -1 && col > -1 && row < board.length && col < board[0].length). 


Code: 


public class Solution {
    private boolean match(char[][] board, int row, int col, String word, int index) {
        if (index == word.length()) {
            return true;
        }
        
        if (row > -1 && col > -1 && row < board.length && col < board[0].length && board[row][col] == word.charAt(index)) {
            board[row][col] = '\0';
            boolean ans = match(board, row + 1, col, word, index + 1)
                            || match(board, row, col + 1, word, index + 1)
                            || match(board, row - 1, col, word, index + 1)
                            || match(board, row, col - 1, word, index + 1);
            
            board[row][col] = word.charAt(index);
            return ans;
        } else {
            return false;
        }
    }
    
    public boolean exist(char[][] board, String word) {
        if (board == null || board.length == 0) {
            return false;
        }
        
        if (word == null || word.length() == 0) {
            return true;
        }
        
        for (int i = 0; i < board.length; i++) {
            for (int j = 0; j < board[0].length; j++) {
                if (board[i][j] == word.charAt(0)) {
                    boolean ans = match(board, i, j, word, 0);
                    
                    if (ans) {
                        return true;
                    }
                }
            }
        }
        
        return false;
    }
}

Complexity Analysis: O(n^2). 


6) Longest Palindromic Substring


Given a string s, find the longest palindromic substring in s. You may assume that the maximum length of s is 1000.


Example:


Input: "babad"


Output: "bab"


Note: "aba" is also a valid answer.
Example:


Input: "cbbd"


Output: "bb"


Thinking: We need to consider what are the two situations of palindromic substring. One: this character is the same as the character which has distance of 2 from here. Two: this character is the same to the character next to me. 


For the former situation, the length of palindromic string will increase two. The length of palindromic string will increase one in the latter situation. 


If you have already known that there is a length of n palindromic substring before this index. The criteria of judging whether this index character can constitute a new palindromic string is to see whether the substring from index - length - 1 or index - length to index make a perfect criteria. (based on the two situations above).


In this question, we need to consider the initialization. 


Code:


public class Solution {
    private boolean isPalindromic(String s, int begin, int end) {
        if (begin < 0) {
            return false;
        }
        
        while (begin < end) {
            if (s.charAt(begin++) != s.charAt(end--)) {
                return false;
            }
        }
        
        return true;
    }
    
    public String longestPalindrome(String s) {
        if (s == null || s.length() < 2) {
            return s;
        }
        
        int maxLength = 1;
        String ans = s.substring(0, 1);
        
        for (int i = 1; i < s.length(); i++) {
            if (isPalindromic(s, i - maxLength - 1, i)) {
                ans = s.substring(i - maxLength - 1, i + 1);
                maxLength += 2;
            }
            
            if (isPalindromic(s, i - maxLength, i)) {
                ans = s.substring(i - maxLength, i + 1);
                maxLength += 1;
            }
        }
        
        return ans;
    }
}

Complexity Analysis: Worst Case O(n^2). Like input "aaaaaaaaaaa". 


7) Word Break


Given a non-empty string s and a dictionary wordDict containing a list of non-empty words, determine if s can be segmented into a space-separated sequence of one or more dictionary words. You may assume the dictionary does not contain duplicate words.


For example, given
s = "leetcode",
dict = ["leet", "code"].


Return true because "leetcode" can be segmented as "leet code".


Thinking: 这题注意题目说的one or more dictionary words. 所以,如果整个leetcode在dictionary 上有的话,可以把space加到单词的前面。前面的word是"",这个是在字典里肯定有的。所以,在动态规划的状态存储数字里面, space[0] = true. 这个动态规划的数组表示的意思是,当前坐标前的字符串是否在字典里存在(能否在当前坐标前加空格)。有了这个状态数组之后,我们这道题的返回答案就转变为这个数组的最后一位是否是true了。注意这是一个长度是str.length() + 1的数组。因为有str.length + 1的缝隙可以插空格。


public class Solution {
    public boolean wordBreak(String s, List<String> wordDict) {
        if (s == null || s.length() == 0) {
            return true;
        }
        
        boolean[] space = new boolean[s.length() + 1];
        space[0] = true;
        
        for (int i = 1; i <= s.length(); i++) {
            for (int j = i - 1; j > -1; j--) {
                if (space[j] && wordDict.contains(s.substring(j, i))) {
                    space[i] = true;
                }
            }
        }
        
        return space[s.length()];
    }
}


最差的时间复杂度是O(n^2),且空间复杂度是O(1). 






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值