高频算法面试(字符串Java版)——01翻转字符串

  • 【题目:翻转字符串】
    给定一英文句子,在单词间做逆序调整,单词内的字符不变。

  • 【举例】
    eg1. you love code. ——> code. love you

  • 【思路】
    (1) 整体逆序:you love code. ——> .edoc evol uoy

    (2) 遍历锁定每个单词 :以空格分隔单词, l l r r ,分别为记录每个单词位置的左右游标,其中(下面的赋值请画图理解),
    l = { 0 l=\left\{ \begin{array}{lcl} 起始位置0\\ 或\,遍历过程中左侧为空格的位置 \end{array}\right. r = { r=\left\{ \begin{array}{lcl} 句子末尾位置\\ 或\,遍历过程中右侧为空格的位置 \end{array}\right.

    (3) 每个单词逆序:.edoc evol uoy ——> code. love you
    其中,逆序函数,reverse 思路: 首尾互换,次首尾互换…所以,该函数的参数中需要增加左右游标,begin,end,记录当前互换的位置信息。

  • 【代码】

//逆转字符串
public void reverse( char[] chas, int begin, int end )
{
    char temp = 0;//char型变量0表示空字符
    while( begin < end )
    {
        //字符互换
        temp = chas[begin];
        chas[begin] = chas[end];
        chas[end] = temp;
        //移动左右游标
        begin++;
        end--;
    }
}
//逆转句子,单词间逆序
public void rotateSentence( char[] chas )
{
    if( chas == null || chas.length == 0 )
    {
        return;
    }
    reverse( chas, 0, chas.length-1 );
    int l = -1;
    int r = -1;
    for( int i = 0; i < chas.length; i++ )
    {
        //尚未遇到空格,则确定当前单词的左右游标
        if( chas[i] != ' ' )
        {
            l = ( ( i == 0 ) || ( chas[i-1] == ' ' ) ? i : l );
            r = ( ( i == chas.length-1 ) || ( chas[i+1] == ' ') ? i : r );
        }
        //当前位置字符为空格
        //如果有单词,将之前找到的单词逆置
        if( l != -1 && r != -1 )
        {
            reverse( chas, l, r );
            l = -1;
            r = -1;
        }
    }
}
  • 【时间复杂度】
    O(n)
  • 【空间复杂度】
    额外的空间复杂度为O(1)
  • 【检查】
    考虑代码中是否有越界情况
    考虑输入为空的情况,针对字符串、字符数组,特殊考虑null和空字符串""的情况,具体说明见下面的代码,所以才会有上面的判断代码: chas == null || chas.length == 0。
char[] chas1 = null;//null不能判断长度,chas1.length会抛出NullPointerException异常
String str = "";
char[] chas2 = str.toCharArray();//""空字符的字符数组长度为0
System.out.println(chas1==null?1:2);
System.out.println(chas2.length);

输出结果分别为:1 和 0

  • 【测试用例】
    功能测试:多个字符句子,单个单词的句子
    特殊字符测试:null,空字符"",只有一个空格的字符" "
  • 【变形一:左旋转字符串】:
    给定一个整数n,将大小为n的左半边字符转移到字符串的尾部。
  • 【举例】
    eg1. 字符串:you love code. 整数:2 ——> u love code.yo
  • 【思路】
    一个比较巧妙的方法
    (1) 将原字符串按照整数值,分为左右两部分: yo和u love code.
    (2) 分别将左右两部分字符串逆序操作:oy 和.edoc evol u
    (3) 再对整体字符串进行逆序操作:u love code.yo
    其中,逆序操作reverse函数同上一道题。
  • 【代码】
//左旋字符串
public void rotate1( char[] chas, int n )
{
    if( chas == null || n <= 0 || n >= chas.length )
    {
        return;
    }
    reverse( chas, 0, n-1 );
    reverse( chas, n,chas.length-1 );
    reverse( chas, 0, chas.length-1 );
}
  • 【时间复杂度】
    O(n)
  • 【空间复杂度】
    额外的空间复杂度为O(1)
  • 【检查】
    考虑代码中是否有越界情况
    考虑输入为空的情况
  • 【测试用例】
    功能测试:将字符串左旋0个,1个,n-1个,n个,n+1个字符
    特殊字符测试:null,空字符""
  • 【变形二】:
    翻转中间由各种符号隔开的字符串。
  • 【举例】
    eg1. 字符串:you;love;code; 分隔符:; ——> uoy;evol;edoc;
  • 【思路】
    (一) 思路一:与上面例题思路基本相同
    (1) 遍历锁定每个单词 :以指定分隔符分隔单词, l l r r ,分别为记录每个单词位置的左右游标
    (2) 对每个单词进行逆序操作
    (二) 思路二:采用Java内特有的处理字符串的函数
    (1) 指定分隔符为delim:StringTokenizer( String str, String delim )
    (2) 判断字符串中是否还有分隔符:boolean hasMoreToken( String delim)
    (3) 只要还有分隔符,就取从当前位置到下一个分隔符之前的字符串:String nextToken( String delim )
    (4) 逆置上一步取得的字符串,输出,同时输出分隔符
    (5) 重复(3)(4)的操作,直至没有分隔符
  • 【代码】
    (一)
//逆转句子,单词内逆序
public void rotateSentence2( char[] chas, char delim )
{
    if( chas == null || chas.length == 0 )
    {
        return;
    }
    int l = -1;
    int r = -1;
    for( int i = 0; i < chas.length; i++ )
    {
        //尚未遇到分隔符delim,则确定当前单词的左右游标
        if( chas[i] != delim )
        {
            l = ( ( i == 0 ) || ( chas[i-1] == delim ) ? i : l );
            r = ( ( i == chas.length-1 ) || ( chas[i+1] == delim) ? i : r );
        }
        //当前位置字符为delim
        //如果有单词,将之前找到的单词逆置
        else
        {
            reverse(chas, l, r);
        }
    }
}

(二)

import java.util.Scanner;
import java.util.StringTokenizer;

public class Rotate
{
    public static void main( String[] args )
    {
        Scanner sc = new Scanner( System.in );
        System.out.println("请输入字符串:");
        String str = sc.nextLine();
        StringTokenizer st = new StringTokenizer( str, ";");
        while( st.hasMoreTokens() )
        {
            String streverse = new StringBuffer( st.nextToken() ).reverse().toString();
            System.out.print( streverse );
            System.out.print( ";" );
        }
    }
}

思路(二),给出了完整的可运行代码,大家可以自行体会一下字符串的读取操作Scanner的用法;理解一下String,StingBuffer的区别,String类是字符串常量,StringBuffer是字符串变量,可扩充,可修改,而Java中自带的reverse函数是将一个输入流倒序输出,不可以用于字符串上。变形二的其他细节本文就不再赘述了。

(文中题源摘自剑指offer,程序员代码面试指南,牛客网面经,思路均为作者原创总结,文中如有错误,烦请各位读者指出,让我们共同进步,一起成长!)

发布了3 篇原创文章 · 获赞 0 · 访问量 108

猜你喜欢

转载自blog.csdn.net/qq_21998503/article/details/105536757