Code Caprice String Java

Article directory

  • (Simple) 344. Reverse a string
  • (simple) 541. Reverse a string||
  • (Simple) Pointing to Offer 05. Replace spaces
  • (Moderate) 151. Reverse words in a string
  • (Easy) Pointing to Offer 58 – II. Left Rotating Strings
  • (*Medium – KMP Algorithm) 28. Find the subscript of the first occurrence in a string
  • (*simple – KMP algorithm) 459. Repeated substrings

(simple) 344. Reverse a string

class Solution {<!-- -->
    public void reverseString(char[] s) {<!-- -->
        int left = 0;
        int right = s.length - 1;
        while (left < right) {<!-- -->
            char tmp = s[left];
            s[left] = s[right];
            s[right] = tmp;
            left ++ ;
            right--;
        }
    }
}

Complexity analysis:

  • Time complexity: O(N), where N is the length of the character array. A total of N/2 exchanges were performed
  • Space complexity: O(1), only constant space is used to store several variables

(Simple) 541. Reverse String||


My idea: 2k characters as a group, first add the first k characters (or less than k characters) to StringBuilder, then call the reverse() method, and then add the last k characters (or less than 2k characters) Add to StringBuilder and finally add this group as a whole to the answer

class Solution {<!-- -->
    public String reverseStr(String s, int k) {<!-- -->
        int n = s. length();
        int i = 0;
        StringBuilder stringBuilder = new StringBuilder();
        while (i < n) {<!-- -->
            StringBuilder strk = new StringBuilder();
            while (i < n & amp; & amp; strk. length() < k) {<!-- -->
                strk.append(s.charAt(i));
                i + + ;
            }
            strk. reverse();
            while (i < n & amp; & amp; strk. length() >= k & amp; & amp; strk. length() < 2 * k) {<!-- -->
                strk.append(s.charAt(i));
                i + + ;
            }
            stringBuilder.append(strk);
        }
        return stringBuilder.toString();
    }
}


My other idea: convert the string s into a character array, and then find a suitable interval in the character array for exchange

import java.util.regex.Pattern;

class Solution {<!-- -->
    public String reverseStr(String s, int k) {<!-- -->
        int n = s. length();
        char[] charArray = s.toCharArray();
        boolean flag = true;
        int i = 0;
        while (i < n) {<!-- -->
            if (flag) {<!-- -->
                int left = i;
                int right = i + k > n ? n - 1 : i + k - 1;
                while (left < right) {<!-- -->
                    char tmp = charArray[left];
                    charArray[left] = charArray[right];
                    charArray[right] = tmp;
                    left ++ ;
                    right--;
                }
                i = i + k;
                flag = false;
            } else {<!-- -->
                if (i + k >= n) {<!-- -->
                    break;
                } else {<!-- -->
                    i + = k;
                    flag = true;
                }
            }
        }
        return new String(charArray);
    }
}


Other ways of writing

It is also a simulation, reversing substrings of length k starting with each subscript starting at a multiple of 2k. If the length of the substring is less than k, reverse the entire substring.

class Solution {<!-- -->
    public String reverseStr(String s, int k) {<!-- -->
        int n = s. length();
        char[] charArray = s.toCharArray();
        for (int i = 0; i < n; i + = 2 * k) {<!-- -->
            reverse(charArray, i, Math. min(i + k, n) - 1);
        }
        return new String(charArray);
    }

    public void reverse(char[] arr, int left, int right) {<!-- -->
        while (left < right) {<!-- -->
            char tmp = arr[left];
            arr[left] = arr[right];
            arr[right] = tmp;
            left ++ ;
            right--;
        }
    }
}


Complexity analysis:

  • Time complexity: O(n), where n is the length of string s
  • Space complexity: O(1) and O(n), depending on the nature of the string type in the language used. If the string is modifiable, it can be modified directly on the original string, and the space complexity is O(1), otherwise O(n) space is needed to temporarily convert the string into a modifiable data structure (such as an array) , the space complexity is O(n).

(simple) sword refers to Offer 05. Replace spaces

Method 1

class Solution {<!-- -->
    public String replaceSpace(String s) {<!-- -->
        return s.replaceAll(" ", " ");
    }
}


Method 2

class Solution {<!-- -->
    public String replaceSpace(String s) {<!-- -->
        StringBuilder stringBuilder = new StringBuilder();
        for (int i = 0; i < s. length(); i ++ ) {<!-- -->
            char c = s.charAt(i);
            if (c == ' ') {<!-- -->
                stringBuilder. append(" ");
            } else {<!-- -->
                stringBuilder.append(c);
            }
        }
        return stringBuilder.toString();
    }
}


Other ideas

Since each replacement changes from 1 character to 3 characters, it is convenient to use a character array for replacement. The length of the established character array is 3 times the length of s, which ensures that the character array can accommodate all replaced characters.

class Solution {<!-- -->
    public String replaceSpace(String s) {<!-- -->
        int n = s. length();
        char[] array = new char[n * 3];
        int index = 0;
        for (int i = 0; i < n; i ++ ) {<!-- -->
            char c = s.charAt(i);
            if (c == ' ') {<!-- -->
                array[index + + ] = '%';
                array[index + + ] = '2';
                array[index + + ] = '0';
            } else {<!-- -->
                array[index + +] = c;
            }
        }
        return new String(array, 0, index);
    }
}

(moderate) 151. Reverse words in a string

class Solution {<!-- -->
    public String reverseWords(String s) {<!-- -->
    //Use trim() to remove the spaces at the beginning and end, and use split() to split according to " "
        String[] splits = s.trim().split(" ");
        StringBuilder stringBuilder = new StringBuilder();
        for (int i = splits. length - 1; i >= 0; i--) {<!-- -->
//But there will be multiple spaces between words, skip directly when encountering splits[i].length==0
            if (splits[i]. length() == 0) {<!-- -->
                continue;
            }

            stringBuilder.append(splits[i]);

            if (i != 0) {<!-- -->
                stringBuilder. append(" ");
            }
        }
        return stringBuilder.toString();
    }
}


Official idea, solution one: use language features

Many languages provide methods such as split, reverse, and join for strings, so the operation can be completed by calling the built-in API

import java.util.Arrays;
import java.util.Collections;
import java.util.List;

class Solution {<!-- -->
    public String reverseWords(String s) {<!-- -->
        s = s. trim();
        List<String> wordList = Arrays.asList(s.split("\s + "));
        Collections. reverse(wordList);
        return String. join(" ", wordList);
    }
}

Complexity analysis:

  • Time complexity: O(n), where n is the length of the input string
  • Space complexity: O(n), used to store the results after string segmentation

Official idea, method 2: write the corresponding function by yourself

These functions are different in different programming languages. The main difference is that some languages have immutable strings (such as Python, Java), and some languages have variable strings (such as C++).

For languages with immutable strings, the strings must first be converted into other mutable data structures, and spaces need to be removed during the conversion.

For languages with variable strings, there is no need to open up additional space, and the strings are implemented directly on the string. In this case, reversing characters and stripping spaces can be done together.

class Solution {<!-- -->
    public String reverseWords(String s) {<!-- -->
        
        //Remove redundant characters at the beginning, end and middle
        StringBuilder sb = trimSpace(s);
        
        // reverse the entire string
        reverse(sb, 0, sb. length() - 1);
        
        //Separate by spaces, reverse each word
        reverseEachWord(sb);
        return sb.toString();
    }

    private void reverseEachWord(StringBuilder sb) {<!-- -->
        int start = 0;
        int end = 0;
        int n = sb. length();
        while (end < n) {<!-- -->
            while (end < n & amp; & amp; sb.charAt(end) != ' ') {<!-- -->
                end + + ;
            }
            reverse(sb, start, end - 1);
            start = end + 1;
            end + + ;
        }
    }

    private void reverse(StringBuilder sb, int left, int right) {<!-- -->
        while (left < right) {<!-- -->
            char tmp = sb.charAt(left);
            sb.setCharAt(left, sb.charAt(right));
            sb. setCharAt(right, tmp);
            left ++ ;
            right--;
        }
    }

    private StringBuilder trimSpace(String s) {<!-- -->
        int left = 0;
        int right = s. length() - 1;
        while (left <= right) {<!-- -->

            //Remove the blank string at the beginning of the string
            while (left <= right & amp; & amp; s. charAt(left) == ' ') {<!-- -->
                left ++ ;
            }

            //Remove the blank string at the end of the string
            while (left <= right & amp; & amp; s.charAt(right) == ' ') {<!-- -->
                right--;
            }

            StringBuilder stringBuilder = new StringBuilder();
            while (left <= right) {<!-- -->
                char c = s.charAt(left);
                if (c != ' ') {<!-- -->
                    stringBuilder.append(c);
                } else if (stringBuilder. charAt(stringBuilder. length() - 1) != ' ') {<!-- -->
                    stringBuilder.append(c);
                }
                left ++ ;
            }
            return stringBuilder;
        }
        return null;
    }
}


Complexity analysis:

  • Time complexity: O(n), where n is the length of the input string, because the string needs to be traversed completely
  • Space complexity: Java and Python methods require O(n) space to store characters, while C++ methods only require O(1) additional space to store several variables

Official idea, method three: double-ended queue

Since the double-ended queue supports the method of inserting from the head of the queue, we can process words one by one along the string, then push the word into the head of the queue, and then convert the queue into a string

import java.util.ArrayDeque;
import java.util.Deque;

class Solution {<!-- -->
    public String reverseWords(String s) {<!-- -->
        int n = s. length();
        int left = 0;
        int right = s. length() - 1;

        //Remove the blank string at the beginning of the string
        while (left <= right & amp; & amp; s. charAt(left) == ' ') {<!-- -->
             + + left;
        }

        //Remove the blank string at the end of the string
        while (left <= right & amp; & amp; s.charAt(right) == ' ') {<!-- -->
            --right;
        }

        Deque<String> deque = new ArrayDeque<>();
        StringBuilder word = new StringBuilder();

        while (left <= right) {<!-- -->
            char c = s.charAt(left);
            if (word.length() != 0 & amp; & amp; c == ' ') {<!-- -->
                deque.offerFirst(word.toString());
                word.setLength(0);
            } else if (c != ' ') {<!-- -->
                word.append(c);
            }
             + + left;
        }
        deque.offerFirst(word.toString());

        return String. join(" ", deque);
    }
}


Complexity analysis:

  • Time complexity: O(n), where n is the length of the input string
  • Space complexity: O(n), the double-ended queue requires O(n) space to store words.

In fact, the double-ended queue and stack in this place mean the same thing.

(Simple) Pointer to Offer 58 – II. Rotate strings to the left


To put it simply, it is to cut the string into two parts, exchange the positions of the two parts, splice them into a new string and return

class Solution {<!-- -->
    public String reverseLeftWords(String s, int n) {<!-- -->
        int len = s. length();
        char[] chars = new char[len];
        int index = 0;
        for (int i = n; i < len; i ++ ) {<!-- -->
            chars[index + + ] = s.charAt(i);
        }
        for (int i = 0; i < n; i ++ ) {<!-- -->
            chars[index + + ] = s.charAt(i);
        }
        return new String(chars);

    }
}

class Solution {<!-- -->
    public String reverseLeftWords(String s, int n) {<!-- -->

        int len = s. length();

        StringBuilder stringBuilder = new StringBuilder(len);

        for (int i = n; i < len; i ++ ) {<!-- -->
            stringBuilder.append(s.charAt(i));
        }
        for (int i = 0; i < n; i ++ ) {<!-- -->
            stringBuilder.append(s.charAt(i));
        }

        return stringBuilder.toString();

    }
}

(*Medium – KMP Algorithm) 28. Find the subscript of the first match in a string

The most traditional string matching problem, the first reaction in my mind is the KMP algorithm, but I don’t remember what the idea is, so I wrote the violent matching method

class Solution {<!-- -->
    public int strStr(String haystack, String needle) {<!-- -->

        int n = needle. length();
        int h = haystack. length();

        if (n > h) {<!-- -->
            return -1;
        }

        int i = 0;
        int j;
        while (i < h) {<!-- -->
            if (haystack.charAt(i) != needle.charAt(0)) {<!-- -->
                i + + ;
            } else {<!-- -->
                int k = i + 1;
                j = 1;
                while (k < h & amp; & amp; k < i + n & amp; & amp; haystack.charAt(k) == needle.charAt(j)) {<!-- -->
                    k++;
                    j + + ;
                }
                if (k == i + n) {<!-- -->
                    return i;
                } else {<!-- -->
                    i + + ;
                }
            }
        }
        return -1;
    }
}

The brute force method is to match the string needle and all substrings of length m of the string haystack once.

In order to reduce unnecessary matching, every time we fail to match, we immediately stop the matching of the current substring and match the next substring. If the current string matches successfully, just return the starting position of the current substring. If all substrings fail to match, -1 is returned

class Solution {<!-- -->
    public int strStr(String haystack, String needle) {<!-- -->

        int m = needle.length();//short
        int n = haystack.length();//long

        for (int i = 0; i + m <= n; i ++ ) {<!-- -->
            boolean flag = true;
            for (int j = 0; j < m; j ++ ) {<!-- -->
                if (haystack. charAt(i + j) != needle. charAt(j)) {<!-- -->
                    flag = false;
                    break;
                }
            }
            if (flag) {<!-- -->
                return i;
            }
        }
        return -1;
    }
}


Complexity analysis:

  • Time complexity: O(nm), where n is the length of the string haystack, and m is the length of the string needle. In the worst case, the string needle needs to be matched once with all substrings of length m of the string haystack.
  • Space complexity: O(1), only requires constant space to save several variables.

KMP algorithm

The time complexity of the brute force method is O(mn), while the time complexity of KMP is O(m + n), because it can extract effective information for multiplexing in the process of non-exact matching, so as to reduce the cost of repeated matching. consume

The brute force method matches strings. When different positions appear, the pointer of the original string is moved to the next position of the starting point, and the pointer of the matching string is moved to the starting position. Continue to try to match, and find that it does not match, the pointer of the original string will always move backwards until it can be matched with the matching string.

import java.util.Arrays;

class Solution {<!-- -->
    public int strStr(String haystack, String needle) {<!-- -->

        int haystackLength = haystack. length();
        int needleLen = needle. length();

        if(needleLen > haystackLength){<!-- -->
            return -1;
        }

        char[] haystackArr = haystack. toCharArray();
        char[] needleArr = needle.toCharArray();
        int[] next = new int[needleLen];
        getNext(next, needle. toCharArray());
        int i = 0;
        int j = 0;
        while (i < haystackLength) {<!-- -->
            if (haystackArr[i] != needleArr[j]) {<!-- -->
                while (j != 0 & amp; & amp; haystackArr[i] != needleArr[j]) {<!-- -->
                    j = next[j - 1];
                }
                if (j == 0 & amp; & amp; haystackArr[i] != needleArr[j]) {<!-- -->
                    i + + ;
                }
            } else {<!-- -->
                i + + ;
                j + + ;
            }

            if (j == needleLen) {<!-- -->
                return i - j;
            }
        }
        return -1;
    }

    private void getNext(int[] next, char[] arr) {<!-- -->
        int len = arr. length;
        int j = 0;
        int i = 1;
        while (i < len) {<!-- -->
            if (arr[i] == arr[j]) {<!-- -->
                next[i] = j + 1;
                i + + ;
                j + + ;
            } else {<!-- -->
                while (j > 0 & amp; & amp; arr[i] != arr[j]) {<!-- -->
                    j = next[j - 1];
                }
                if (j == 0 & amp; & amp; arr[i] != arr[j]) {<!-- -->
                    next[i] = 0;
                    i + + ;
                }
            }
        }
    }
}

(*simple – KMP algorithm) 459. Repeated substring

Assuming that the original string S is formed by repeating the substring s N times, then S + S has the substring s repeated 2N times, then now there are S=Ns, S + S=2Ns, where N>=2. If the condition is true, the two s are destroyed by pinching the head and the tail, and there are at least 2(N-1)s in S + S, and because N>=2, the index in S + S is from [0, length-2] must appear more than once in

class Solution {<!-- -->
    public boolean repeatedSubstringPattern(String s) {<!-- -->
        return (s + s).substring(1, (s + s).length() - 1).contains(s);
    }
}