LeetCode Elementary Algorithm Training-String (Completed)

Introduction

Previous: LeetCode Elementary Algorithm Training-Array

Next: LeetCode Primary Algorithm Training-Linked List

Originally I wanted to start with the beginner and intermediate level and corporate interview algorithms, but in the end we chose to start from the basics, because we did not brush questions for the purpose of brushing questions, but exercise a kind of algorithm thinking in the process of brushing questions, after a lot of training Form a unique insight into the algorithm, cultivate the sensitivity to the algorithm, see the problem, a blueprint for solving the problem can appear in the brain, and slowly build confidence from the beginning, and this is also for the complex algorithm behind Lay the foundation for problem-solving ideas.

Introduction to LeetCode Primary Algorithm

If you also want to train your own algorithmic thinking, you can also join me, starting from the elementary algorithm, start your algorithm journey: elementary algorithm .

Some of your own thinking: Don’t just look at the answer after reading the question, and then recite the question, so that the memory of the implemented algorithm is not strong, you must have your own thinking; and don’t write on IDEA at the beginning, Be sure to try to write it on the whiteboard provided by leetCode and finally put it on IDEA to see if there are any problems, so as to consolidate your basic API usage and proficiency; another point is to be bold, not the cost of trial and error for the interview Low, try to incorporate our ideas into the code

Due to space issues, the blog only lists examples and your own problem-solving answers. For details, you can directly click on the topic to view.

Reverse string

Write a function whose role is to reverse the input string. The input string is given in the form of a character array char[].
Don't allocate extra space to another array, you must modify the input array in place and use O(1) extra space to solve this problem.
You can assume that all characters in the array are printable characters in the ASCII code table.

Example 1:
Input: ["h","e","l","l","o"]
Output: ["o","l","l","e","h"]

Example 2:
Input: ["H","a","n","n","a","h"]
Output: ["h","a","n","n"," a","H"]

class Solution {
    public void reverseString(char[] s) {
        for(int i = 0;i < s.length / 2;i++){
            char temp = s[i];
            s[i] = s[s.length - 1 - i];
            s[s.length - 1 -i] = temp;    
        }
    }
}

Execution time: 1 ms
Memory consumption: 46.5 MB

There is nothing to say about this before we flipped the int array in this way.

Integer inversion

Given a 32-bit signed integer, you need to invert the digits on each of the integers.
Example 1:
Input: 123
Output: 321

Example 2:
Input: -123
Output: -321

Example 3:
Input: 120
Output: 21
Note:
Assuming that our environment can only store the next 32-bit signed integer, the value range is
[− 2 31, 2 31 − 1] [−2^{31}, 2^{31} − 1][231,23 11]. According to this assumption, if the integer overflows after the inversion, it returns 0.

The first method is very inefficient by itself

class Solution {
    public int reverse(int x) {
      boolean isMinusNum = x < 0;
        String s = String.valueOf(Math.abs(x));
        StringBuilder sb = new StringBuilder(s);
        sb.reverse();
         Long aLong;
        try{
             aLong = isMinusNum ? -Long.valueOf(sb.toString()) : Long.valueOf(sb.toString());
        } catch(Exception e){
            return 0;
        }
       
        if (aLong > Integer.MAX_VALUE || aLong < Integer.MIN_VALUE) return 0;
        return aLong.intValue();
    }
}

Execution time: 4 ms
Memory consumption: 37.2 MB

The second method looks at the answer cleverly by taking the remainder and dividing once to get the remainder multiplied by 10 and accumulating, and the physical examination directly determines the rev size in the middle.

class Solution {
    public int reverse(int x) {

        int rev = 0;
        while (x != 0) {
            int tail = x % 10;
            x /= 10;

            if (rev < Integer.MIN_VALUE / 10 || (rev == Integer.MIN_VALUE / 10 && tail < Integer.MIN_VALUE % 10)) {
                return 0;
            }

            if (rev > Integer.MAX_VALUE / 10 || (rev == Integer.MAX_VALUE / 10 && tail > Integer.MAX_VALUE % 10)) {
                return 0;
            }

            rev = rev * 10 + tail;
        }
        return rev;
    
    }
}

Execution time: 1 ms
Memory consumption: 37.2 MB

The first unique character in the string

Given a string, find its first unique character and return its index. If it does not exist, -1 is returned.
Example:

s = "leetcode"
returns 0

s = "loveleetcode"
returns 2
tips: You can assume that the string contains only lowercase letters.

class Solution {
    public int firstUniqChar(String s) {
        int[] locates = new int[26];
        
        for(int i = 0;i<s.length();i++){
            int num = s.charAt(i) - 'a';
            locates[num] ++;
        }
        
        for(int i = 0;i<s.length();i++){
           int num= s.charAt(i) -  'a';
           if(locates[num] == 1){
               return i;
           }
        }
        
        return -1;
    }
}

Execution time: 7 ms
Memory consumption: 40.3 MB The
first idea is this, define a 26-size int array, first traverse the string, and calculate the distance of the letter compared to the'a' in the 26-size array. Position, and then traverse to a corresponding position number +1.
After traversing it, it is judged to return as long as it appears once in the 26-size int array.

There is also a clever way to perform faster.

Traverse 26 English lowercase letters, use the indexOf and lastIndexOf of the string to determine whether the first and last occurrences of the character are consistent, indicating that they only appear once, and then find the smallest one of these indexes.

class Solution {
    public int firstUniqChar(String s) {
       int firstUniqIndex = s.length();
       for(char i = 'a';i<='z';i++) {
           int index = s.indexOf(i);
           if(index != -1 && index == s.lastIndexOf(i)){
               firstUniqIndex = Math.min(firstUniqIndex,index);
           }
       }
        return firstUniqIndex == s.length() ? -1 : firstUniqIndex;
    }
}

Execution time: 2 ms
Memory consumption: 40.2 MB

Valid letter variants

Given two strings s and t, write a function to determine whether t is an anagram of s.
Example 1:
Input: s = "anagram", t = "nagaram"
Output: true

Example 2:
Input: s = "rat", t = "car"
Output: false
Note:
You can assume that the string contains only lowercase letters.
Advanced:
What if the input string contains unicode characters? Can you adjust your solution to deal with this situation?

class Solution {
    public boolean isAnagram(String s, String t) {
       if (s == null || t == null) return false;
        if (s.length() != t.length()) return false;
        if (s.length() == 0 && t.length() == 0) return true;
        char[] chars = s.toCharArray();
        char[] chars1 = t.toCharArray();
        Arrays.sort(chars);
        Arrays.sort(chars1);
        //这里刚开始用的是Arrays.toString转为string然后在eqauls 但是那样执行有 8 -11ms 然后发现这里直接一个循环就搞定了,Arrays.equals也是用的循环比对。
        for (int i = 0; i < chars.length; i++) {
            if (chars[i] != chars1[i]) {
                return false;
            }
        }
        return true;
    }
}

Execution time: 3 ms
Memory consumption: 39.8 MB

Another way is to use 26 int arrays in the first unique character in the string. If the two strings are the same after adjusting the positions, then each letter must be x%2==0. Each string position is +1 and another string is -1. Finally, each position must be 0. So if there is a non-zero character, one must have more characters than the other.

class Solution {
    public boolean isAnagram(String s, String t) {
       if (s == null || t == null) return false;
        if (s.length() != t.length()) return false;
        if (s.length() == 0 && t.length() == 0) return true;
    
        int[] nums = new int[26];
        
        for(int i = 0;i < s.length();i++) {
            nums[s.charAt(i) - 'a'] ++;
            nums[t.charAt(i) - 'a'] --;
        }
        
        for(int i = 0;i < nums.length;i++) {
            if(nums[i] != 0){
                return false;
            }
        }
        return true;
    }
}
Verify palindrome string

Given a string, verify whether it is a palindrome, consider only letters and numbers, and ignore the case of letters.
Explanation: In this question, we define an empty string as a valid palindrome string.
Example 1:
Input: "A man, a plan, a canal: Panama"
Output: true

Example 2:
Input: "race a car"
Output: false

Use the pointer method to compare.

class Solution {
    public boolean isPalindrome(String s) {
        if(s == null) return false;
        s = s.toLowerCase();
        //之前还加了个计算数字和字母的数量来判断下边循环结束,答案中可以使用i < j来做条件
        int i = 0,j = s.length() - 1;
        while(i < j) {
            char left = s.charAt(i);
            char right = s.charAt(j);
            if(!((left >= 'a' && left <= 'z') ||(left >= '0' && left <= '9') ) ){
                i++;
                continue;
            }

            if(!((right >= 'a' && right <= 'z') ||(right >= '0' && right <= '9'))) {
                j--;
                continue;
            }
            if(left != right) {
                return false;
            }
           
            i++;
            j--;
        }
        return true;
    }
}

Execution time: 3 ms
Memory consumption: 39.7 MB

String conversion to integer (atoi)

Please implement an atoi function to convert a string to an integer.

First, the function discards useless beginning space characters as needed, until it finds the first non-space character. The following conversion rules are as follows:

If the first non-blank character is a positive or negative sign, combine this sign with as many consecutive numeric characters as possible to form a signed integer.
If the first non-blank character is a number, it is directly combined with the following consecutive number characters to form an integer.
The string may also have extra characters after the valid integer part, so these characters can be ignored and they should not affect the function.
Note: If the first non-space character in the string is not a valid integer character, the string is empty or the string contains only blank characters, your function does not need to be converted, that is, it cannot be converted effectively.

In any case, if the function cannot perform a valid conversion, please return 0.

prompt:

The blank characters in this question only include the space character ''.
Assuming that our environment can only store 32-bit signed integers, the value range is [−231, 231 − 1]. If the value exceeds this range, please return INT_MAX (231 − 1) or INT_MIN (−231).

Example 1:

Input: "42"
Output: 42
Example 2:

Input: "-42"
Output: -42
Explanation: The first non-blank character is'- ', which is a negative sign.
We try our best to combine the minus sign with all subsequent numbers, and finally get -42.
Example 3:
Input: "4193 with words"
Output: 4193
Explanation: The conversion ends at the number '3' because the next character is not a number.

Example 4:
Input: "words and 987"
Output: 0
Explanation: The first non-empty character is'w', but it is not a number or a positive or negative sign. Therefore, effective conversion cannot be performed.

Example 5:
Input: "-91283472332"
Output: -2147483648
Explanation: The number "-91283472332" exceeds the range of a 32-bit signed integer.
Therefore INT_MIN (−231) is returned.

class Solution {
    public int myAtoi(String str) {
        if (str == null || str.length() == 0) return 0;
        boolean haveFirstValidChar = false;
        boolean haveValidNumAfterZero = false;
        boolean isMinus = false;

        int firstCharType = -1; //0 zero 1 symbol 2 validnum

        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < str.length(); i++) {
            char c = str.charAt(i);
            if (!haveFirstValidChar) {
                if (!isValidChar(c)) {
                    return 0;
                } else if (!isSpace(c)) {
                    haveFirstValidChar = true;
                    if (isZero(c)) {
                        firstCharType = 0;
                        if (i == str.length() - 1 || (i < str.length() - 1 && !isNum(str.charAt(i + 1)))) {
                            return 0;
                        }
                    }

                    if (isValidNum(c)) {
                        firstCharType = 2;
                    }

                    if (isValidSymbol(c)) {
                        firstCharType = 1;
                        if (i == str.length() - 1 || (i < str.length() - 1 && !isNum(str.charAt(i + 1)))) {
                            return 0;
                        }
                    }

                    isMinus = (c == '-');

                    if (firstCharType != 0) {
                        sb.append(c);
                    }
                }
            } else if (firstCharType == 0 && isNum(c)) {
                if (haveValidNumAfterZero) {
                    sb.append(c);
                } else if (!isZero(c)) {
                    haveValidNumAfterZero = true;
                    sb.append(c);
                }
            } else if (firstCharType == 1 && isNum(c)) {
                if (haveValidNumAfterZero) {
                    sb.append(c);
                } else if (!isZero(c)) {
                    haveValidNumAfterZero = true;
                    sb.append(c);
                }
            } else if (firstCharType == 2 && isNum(c)) {
                sb.append(c);
            } else {
                break;
            }
        }

        if (!haveFirstValidChar) {
            return 0;
        }

        if ((firstCharType == 0 || firstCharType == 1) && !haveValidNumAfterZero) {
            return 0;
        }

        String result = sb.toString();

        if (result.charAt(0) == '+') {
            result = result.substring(1);
        }

        if (isMinus) {
            if (result.length() < 11) {
                return Integer.valueOf(result);
            } else if (result.length() > 11) {
                return Integer.MIN_VALUE;
            } else {
                int tenInt = Integer.valueOf(result.substring(0, 10));
                int lastInt = Integer.valueOf(result.substring(10, 11));
                return tenInt < Integer.MIN_VALUE / 10 || (tenInt == Integer.MIN_VALUE / 10 && lastInt > 8) ? Integer.MIN_VALUE : Integer.valueOf(result);
            }
        } else if (result.length() < 10) {
            return Integer.valueOf(result);
        } else if (result.length() > 10) {
            return Integer.MAX_VALUE;
        } else {
            int tenInt = Integer.valueOf(result.substring(0, 9));
            int lastInt = Integer.valueOf(result.substring(9, 10));
            return tenInt > Integer.MAX_VALUE / 10 || (tenInt == Integer.MAX_VALUE / 10 && lastInt > 7) ? Integer.MAX_VALUE : Integer.valueOf(result);
        }
    }
    
    private boolean isValidChar(char c){
        return isValidSymbol(c) || isNum(c) || isSpace(c);
    }
    
    private boolean isValidSymbol(char c){
        return '-' == c || '+' == c;
    }
    
    private boolean isNum(char c){
        return c <= '9' && c >= '0';
    }
    
    private boolean isValidNum(char c){
        return c <= '9' && c > '0';
    }
    
    private boolean isSpace(char c){
        return ' ' == c;
    }
    
    private boolean isZero(char c){
        return '0' == c;
    }
}

Execution time: 4 ms
Memory consumption: 39.7 MB
This is my own approach and time needs to be optimized. Study other people's algorithms. The gap arises when I think it is too complicated to analyze and classify carefully.

class Solution {
    public int myAtoi(String str) {
       int res = 0;
        int max = Integer.MAX_VALUE / 10;
        boolean hasStarted = false, isNegative = false;
        for (char ch : str.toCharArray()) {
            if (ch == ' ' && !hasStarted)
                continue;
            else if (ch == '+' && !hasStarted)
                hasStarted = true;
            else if (ch == '-' && !hasStarted) {
                hasStarted = true;
                isNegative = true;
            } else if (ch >= '0' && ch <= '9') {
                hasStarted = true;
                int val = ch - '0';
                if (res > max || (res == max && val > 7))
                    return isNegative ? Integer.MIN_VALUE : Integer.MAX_VALUE;
                else
                    res = res * 10 + val;
            } else
                break;
        }

        return isNegative ? -res : res;
    }

}
Implement strStr()

Implement the strStr() function.
Given a haystack string and a needle string, find the first position (starting from 0) where the needle string appears in the haystack string. If it does not exist, -1 is returned.

Example 1:
Input: haystack = "hello", needle = "ll"
Output: 2

Example 2:
Input: haystack = "aaaaa", needle = "bba"
Output: -1

Explanation:
When needle is an empty string, what value should we return? This is a good question in an interview.
For this question, we should return 0 when needle is an empty string. This is consistent with the definition of strstr() in C language and indexOf() in Java.

class Solution {
    public int strStr(String haystack, String needle) {
        if(haystack == null || needle == null) return -1;
    
       if(haystack.contains(needle)) {
          return haystack.indexOf(needle);
       } else {
           return -1;
       }
        
    }
}

Execution time: 0 ms
Memory consumption: 38.3 MB

This is relatively simple and ready-made, but I suggest you look at the implementation of contains and indexOf.

Appearance series

Given a positive integer n (1 ≤ n ≤ 30), output the nth item of the appearance sequence.
Note: Each item in the integer sequence will be represented as a string.
"Appearance sequence" is a sequence of integers, starting from the number 1, each item in the sequence is a description of the previous item. The first five items are as follows:

  1. 1
    
  2. 1 1
    
  3. 2 1
    
  4. 1 2 1 1
    
  5. 1 1 1 2 2 1
    

The first item is the number 1
describing the previous item, this number is 1 that is "one 1", recorded as 11 to
describe the previous item, this number is 11 that is "two 1", recorded as 21 to
describe the previous item, this number It is 21 that is "one 2 and one 1", which is recorded as 1211 to
describe the previous item. This number is 1211, which is "one 1 one 2 two 1", which is recorded as 111221

Example 1:

Input: 1
Output: "1"
Explanation: This is a basic example.

Example 2:
Input: 4
Output: "1211"
Explanation: When n = 3, the sequence is "21", where we have two groups of "2" and "1", "2" can be pronounced as "12", which is Frequency = 1 and value = 2; something like "1" can be read as "11". So the answer is "12" and "11" combined together, which is "1211".

class Solution {
    public String countAndSay(int n) {
         if (n < 1 && n > 30) throw new IllegalArgumentException("no serialize");
        if (n == 1) return "1";
        StringBuilder sb = new StringBuilder();

        int count = 1;
        String seed = "1";
        for (int i = 1; i < n; i++) {
            count = 1;
            sb.delete(0,sb.length());
            for (int j = 0; j < seed.length(); j++) {
                if (j + 1 < seed.length()) {
                    if (seed.charAt(j) == seed.charAt(j + 1)) {
                        count++;
                    } else {
                        sb.append(count);
                        sb.append(seed.charAt(j));
                        count = 1;
                    }
                } else {
                    sb.append(count);
                    sb.append(seed.charAt(j));
                }
            }
            seed = sb.toString();
        }

        return sb.toString();
    }
}

Execution time: 4 ms
Memory consumption: 37.1 MB

This is actually a two-layer loop, and the result of each inner loop is the seed of the next loop.

Longest common prefix

Write a function to find the longest common prefix in a string array.
If there is no common prefix, an empty string "" is returned.
Example 1:
Input: ["flower","flow","flight"]
Output: "fl"

Example 2:
Input: ["dog","racecar","car"]
Output: ""
Explanation: There is no common prefix for input.

Note:
All input only contains lowercase letters az.

class Solution {
    public String longestCommonPrefix(String[] strs) {
          if (strs == null || strs.length == 0) return "";

        if(strs.length == 1 && strs[0] != null) return strs[0];
        
        String pre = "";
        boolean havePre = true;
        for (int i = 0; i < strs[0].length(); i++) {
            pre = strs[0].substring(0, i + 1);
            for (int j = 0; j < strs.length; j++) {
                if (!strs[j].startsWith(pre) || strs[j].length() < pre.length()) {
                    if(i == 0) {
                        return "";
                    } else {
                        return pre.substring(0, i);
                    }
                }
            }
        }
        return pre;
    }
}

Execution time: 5 ms
Memory consumption: 37.9 MB

This self-written method may not use startwith, then it may be faster to use characters to judge.

Take a look at the fastest way:

class Solution {
    public String longestCommonPrefix(String[] strs) {
         if (strs == null || strs.length == 0) {
            return "";
        }
        String pre = strs[0];
        for(String str: strs){
            while(str.indexOf(pre) != 0){
                pre = pre.substring(0,pre.length() - 1);
            }
        }
        return pre;
    }
}

118/118 passed test cases
Status: Passed
Execution time: 0 ms
Memory consumption: 37.8 MB
This is a search from back to front, str.indexOf(pre) == 0 skip to find the next one, if not, shorten the character Continue to find the string and repeat the above operation.

Guess you like

Origin blog.csdn.net/u011148116/article/details/107175417