翻转单词顺序VS左旋转字符串

左旋转字符串 

public class Solution {
    public String LeftRotateString(String str,int n) {
        if(str == null || str.length() ==0){
            return str;
        }
        int len = str.length();
        char[] charArrays = str.toCharArray();
        reverse(charArrays,0,n-1);
        reverse(charArrays,n,len-1);
        reverse(charArrays,0,len-1);
        return String.valueOf(charArrays);
    }

    private void reverse(char[] charArrays, int i, int j) {
        char temp;
        while (i < j){
            temp = charArrays[i];
            charArrays[i] = charArrays[j];
            charArrays[j] = temp;
            i++;
            j--;
        }
    }
}

 翻转单词顺序

public class Solution {
    public String ReverseSentence(String str) {
        if(str == null ||str.trim().length() ==0){
            return str;
        }
        StringBuilder sb = new StringBuilder();
        String res = reverse(str);
        String[] newString = res.split(" ");
        for(int i =0;i<newString.length;i++){
            sb.append(reverse(newString[i]+" "));
        }
        return sb.toString().trim();
    }

    private String reverse(String str) {
        StringBuilder newStr = new StringBuilder();
        for(int i = str.length()-1;i>=0;i--){
            newStr.append(str.charAt(i));
        }
        return String.valueOf(newStr);
    }
}

题目一:翻转单词顺序序列

牛客最近来了一个新员工Fish,每天早晨总是会拿着一本英文杂志,写些句子在本子上。同事Cat对Fish写的内容颇感兴趣,有一天他向Fish借来翻看,但却读不懂它的意思。例如,“student. a am I”。后来才意识到,这家伙原来把句子单词的顺序翻转了,正确的句子应该是“I am a student.”。Cat对一一的翻转这些单词顺序可不在行,你能帮助他么?

思路

观察字符串变化规律,你会发现这道题很简单。只需要对每个单词做翻转,然后再整体做翻转就得到了正确的结果。

Trim()源码

public String trim() {
    int len = value.length;// 有效字符(不是空格)结束位置
    int st = 0;// 有效字符(不是空格)起始位置
    char[] val = value; // 字符数组   /* avoid getfield opcode */

    while ((st < len) && (val[st] <= ' ')) { // 从起始位置开始遍历,获取起始连续空格的最后空格位置
        st++;// st值发生变化,说明起始有空格,st就是起始需要截取的位置
    }
    while ((st < len) && (val[len - 1] <= ' ')) { // 从末尾位置开始遍历,获取末尾连续空格的第一个空格位置
        len--;// len值发生变化,说明末尾有空格,len是末尾需要截取的位置
    }
    return ((st > 0) || (len < value.length)) ? substring(st, len) : this;// 判断是否有空格需要截取,有截取,没有返回原String
}

代码

class Solution {
    public String reverseWords(String s) {
       char[] data = s.toCharArray();
        if (data == null || data.length < 1) {
        return String.valueOf(data);
    }

    reverse(data, 0, data.length - 1);

    int start = 0;
    int end = 0;

    while (start < data.length) {
        if (data[start] == ' ') {
            start++;
            end++;
        } else if (end == data.length || data[end] == ' ') {
            reverse(data, start, end - 1);
            end++;
            start = end;
        } else {
            end++;
        }
    }

    return String.valueOf(data);
    }
    public static void reverse(char[] data, int start, int end) {
    if (data == null || data.length < 1 || start < 0 || end > data.length || start > end) {
        return;
    }

    while (start < end) {
        char tmp = data[start];
        data[start] = data[end];
        data[end] = tmp;

        start++;
        end--;
    }
}
}

代码2

//第二种思路,先将整个字符串反转,再逐个单词反转
public String ReverseSentence(String str) {
    if (str == null || str.length() == 0)
    {
        return str;
    }
    if (str.trim().length() == 0)
    {
        return str;
    }
    StringBuilder sb = new StringBuilder();
    String re = reverse(str);
    String[] s = re.split(" ");
    for (int i = 0; i < s.length - 1; i++) {
        sb.append(reverse(s[i]) + " ");
    }
    sb.append(reverse(s[s.length-1]));
    return String.valueOf(sb);
}

public String reverse(String str) {
    StringBuilder sb = new StringBuilder();
    for (int i = str.length() - 1; i >= 0 ; i--) {
        sb.append(str.charAt(i));
    }
    return String.valueOf(sb);
}

LeetCode代码

public class Test2 {
    public static void main(String[] args) {
        String s = "  hello world!  ";
        System.out.println(reverseWords(s));
    }
    public static String reverseWords(String s) {
        String[] words = s.trim().split("\\s+");
        StringBuilder ans = new StringBuilder();
        for(int i = words.length - 1; i >= 0; i--) {
            ans.append(words[i] + " ");
        }

        return ans.toString().trim();
    }
}
	

题目二:左旋转字符串

汇编语言中有一种移位指令叫做循环左移(ROL),现在有个简单的任务,就是用字符串模拟这个指令的运算结果。对于一个给定的字符序列S,请你把其循环左移K位后的序列输出。例如,字符序列S=”abcXYZdef”,要求输出循环左移3位后的结果,即“XYZdefabc”。是不是很简单?OK,搞定它!

思路

例如:输入字符串"abcdefg"和数字2,该函数将返回左旋转2位得到的结果"cdefgab";

第一步:翻转字符串“ab”,得到"ba";

第二步:翻转字符串"cdefg",得到"gfedc";

第三步:翻转字符串"bagfedc",得到"cdefgab";

或者:

第一步:翻转整个字符串"abcdefg",得到"gfedcba"

第二步:翻转字符串“gfedc”,得到"cdefg"

第三步:翻转字符串"ba",得到"ab"

代码

public class Test {
    public static void main(String[] args) {
        System.out.println(LeftRotateString("abcdefg",2));
    }
    public static String LeftRotateString(String pStr,int num){
        if(pStr == null ||pStr.length() <num){
            throw new RuntimeException();
        }
        String str1 = pStr.substring(0,2);
        String str2 = pStr.substring(2,pStr.length());

        StringBuilder stringBuilders = new StringBuilder();
        String str11 = help(str1);
        String str22 = help(str2);
        stringBuilders.append(str11);
        stringBuilders.append(str22);
        return help(stringBuilders.toString());
    }

    private static String help(String str1) {
        int start = 0;
        int end = str1.length()-1;
        char[] data = str1.toCharArray();
        while (start < end) {
            char tmp = data[start];
            data[start] = data[end];
            data[end] = tmp;

            start++;
            end--;
        }
        return new String(data);
    }
}

代码2

public String LeftRotateString(String str,int n) {
        if (str == null || str.trim().length() == 0) {
			return str;
		}
        int len = str.length();
        n = n % len;// 当len=3,n=4,其实相当于左旋转1位,所以需要取余
        char[] charstr = str.toCharArray();
        //先旋转前面的
        reverse(charstr, 0, n-1);
        //再旋转后面的字符串
        reverse(charstr, n, len -1);
        //最后整体反转
        reverse(charstr, 0, len-1);
        return String.valueOf(charstr);
    }
    //实现的是charstrs从i到j的反转,也可以使用上题中stringbuffer的反转方式
	private void reverse(char[] charStrs, int i, int j) { 
		while(i<j) {
			char temp = charStrs[i];
			charStrs[i] =charStrs[j];
			charStrs[j] = temp;
			i++;
			j--;
		}
	}

LeetCode

旋转字符串

给定两个字符串, A 和 B。

A 的旋转操作就是将 A 最左边的字符移动到最右边。 例如, 若 A = 'abcde',在移动一次之后结果就是'bcdea' 。如果在若干次旋转操作之后,A 能变成B,那么返回True。

示例 1:

输入: A = 'abcde', B = 'cdeab'

输出: true

示例 2:

输入: A = 'abcde', B = 'abced'

输出: false

注意:

A 和 B 长度不超过 100。

方法1 (大神代码)

思路:首先确认两个字符串的长度要相等。其次只要保证A+A 的字符串中包含B就可以了。因为A+A已经包含了所有可移动的方案。

public static boolean rotateString(String A, String B) {
        return A.length() == B.length() && (A+A).contains(B);
    }

    public static void main(String[] args) {
        String a = "abcde";
        String b = "abced";
        boolean flag = rotateString(a,b);
        System.out.println(flag);
    }

方法2()KMP算法(待研究)

判断一个串是否为另一个串的子串的最优时间复杂度的算法是 KMP 算法。和方法二相同,我们只需要用 KMP 算法判断 B 是否为 A + A 的子串即可。KMP 算法较难理解,这里给出了力扣第 28 题 实现 strstr() 讨论区中一个高赞 KMP 算法详解,以及著名博主 Matrix67 的 KMP 算法详解。

class Solution {
    public boolean rotateString(String A, String B) {
        int N = A.length();
        if (N != B.length()) return false;
        if (N == 0) return true;

        //Compute shift table
        int[] shifts = new int[N+1];
        Arrays.fill(shifts, 1);
        int left = -1;
        for (int right = 0; right < N; ++right) {
            while (left >= 0 && (B.charAt(left) != B.charAt(right)))
                left -= shifts[left];
            shifts[right + 1] = right - left++;
        }

        //Find match of B in A+A
        int matchLen = 0;
        for (char c: (A+A).toCharArray()) {
            while (matchLen >= 0 && B.charAt(matchLen) != c)
                matchLen -= shifts[matchLen];
            if (++matchLen == N) return true;
        }

        return false;
    }
}
复杂度分析

时间复杂度:O(N)O(N),其中 NN 是字符串 A 的长度。

空间复杂度:O(N)O(N)。