数据结构与算法--翻转单词顺序

翻转单词顺序
  • 题目:输入一个英文句子,翻转句子中的单词顺序,但是单词内的字符顺序不变,例如:I am a software engineer -> engineer software a am I
方案一:空间换时间
  • 空间换时间方法,还是如上案例中,I am a software engineer,分析如上:
    • 统计出字符串中空格位置,按空格拆分
    • 通过空格的顺序逐个拆解原字符串
    • 将拆解后的字符串按照单词从后面开始复制
    • 例如最后一个空格位置 15,那么第一个单词的位置应该是15+1 ~ str.length-1
    • 依次类推逐个向前复制
    • 如下图所示
      在这里插入图片描述
  • 如上分析有如下代码:
/**
 * 反转字符串中单词顺序,I am a software engineer -> engineer software a am I
 * @author liaojiamin
 * @Date:Created in 16:59 2021/7/1
 */
public class ReverStr {
    public static void main(String[] args) {
        String str = "I am a software engineer";
        char[] target = str.toCharArray();
        char[] result = reverMyStr(target);
        for (char c : result) {
            System.out.print(c);
        }
    }


    /**
     * 方案一:空间换时间方法,
     * 空间复杂度O(n),时间复杂度O(n)
     * */
    public static char[] reverMyStr(char[] target){
        if(target == null || target.length <= 0){
            return target;
        }
        int[] isSpace = new int[target.length];
        int positionSpace = 0;
        char[] result = new char[target.length];
        int resultPosition = 0;
        for (int i = 0; i < target.length; i++) {
            if(target[i] == ' '){
                isSpace[positionSpace++] = i;
            }
        }
        int positionEnd = target.length -1;
        positionSpace--;
        for (int i = positionSpace; ; i--) {
            int start = 0;
            if(i>=0){
                start = isSpace[i] + 1;
            }
            result = splitCharArray(start, positionEnd, target, result, resultPosition);
            resultPosition += (positionEnd - start +1);
            if(start != 0){
                //最后一次不需要再添加空格
                result[resultPosition++]=' ';
                positionEnd = isSpace[i] -1;
            }
            if(start == 0){
                return result;
            }
        }
    }

    public static char[] splitCharArray(int start, int end, char[] target, char[] result, int position){
        for(int i=start; i <=end;i++){
            result[position++] = target[i];
        }
        return result;
    }
}
  • 方案一中其实就是模拟一个字符串拆分函数split,只是在拆分后在对具体的单词进行顺序的变化,整体时间复杂度,第一次遍历得出拆分点空格,第二次逐个对拆分后的字符进行复制,所以时间复杂度O(n),空间复杂度O(n)
方案二:多次翻转
  • 本题中需要得到单个单词顺序上的翻转,但是实际字符是正向的,分析如下:
    • 翻转字符串,得到一个完全翻转的,此时目的在于,然后面的单词位置能移动到签名,实现单词顺序的变化
    • 此时得到的是一个单词,字母都是逆序的字符串
    • 统计现有字符串中空格,依据空格区分每个单词
    • 分别对每个单词字符串进行单独翻转得到最终结果。
    • 如下图:

在这里插入图片描述

  • 经如上分析有如下代码:
/**
 * 反转字符串中单词顺序,I am a software engineer -> engineer software a am I
 * @author liaojiamin
 * @Date:Created in 16:59 2021/7/1
 */
public class ReverStr {
    public static void main(String[] args) {
        String str = "I am a software engineer";
        char[] target = str.toCharArray();
        char[] result_1 = reverTwice(target);
        for (char c : result_1) {
            System.out.print(c);
        }
    }

    /**
     * 方案二:反转两次
     * 先全部反转字符,在逐个单词颠倒
     * 时间复杂度O(n) 空间复杂度O(1)
     * */
    public static char[] reverTwice(char[] target){
        if(target == null || target.length <= 0){
            return target;
        }
        target = reverAll(target, 0, target.length -1);
        int[] isSpace = new int[target.length];
        int positionSpace = 0;
        for (int i = 0; i < target.length; i++) {
            if(target[i] == ' '){
                isSpace[positionSpace++] = i;
            }
        }
        positionSpace--;
        int start = 0;
        for (int i = 0; ; i++) {
            int end = target.length -1;
            if(i <= positionSpace){
                end = isSpace[i] - 1;
            }
            target = reverAll(target, start, end);
            if(i <= positionSpace){
                start = isSpace[i] +1;
            }else {
                return target;
            }
        }
    }

    /**
     * 按指定位置反转
     * */
    public static char[] reverAll(char[] target, int start, int end){
        while (start < end){
            char temp = target[start];
            target[start] = target[end];
            target[end] = temp;
            start++;
            end--;
        }
        return target;
    }
}
变种题型
  • 题目:定义字符串的左旋转操作就是把字符串签名的若干字符转移到字符的尾部。请定义一个函数,实现字符串的左旋操作功能, 例如输入字符串I am a software engineer 4 -> a software engineerI am
方案一:空间换时间
  • 最直观的方法,直接定义一个新的数组复制需要的段。分析如下:
    • 如上题案例中,只需要将指定前面的字符转到最后,如果用字符串移动每个字符都要操作 指定数子的次数
    • 如果定义新的数组,则只需要将指定阶段复制过去
    • 如上指定位4,我们先将后面字符串 5~length-1 位置的字符复制到新数组开始位置
    • 然后将0~4 位置数组复制到新数组的后面
    • 得到的新数组就是我们需要的结果
    • 如下图

在这里插入图片描述

  • 如上分析有如下代码
/**
 * 指定位置反转字符串
 * 案例 I am a software engineer 4 -> a software engineerI am
 * @author liaojiamin
 * @Date:Created in 18:47 2021/7/1
 */
public class ReverPositionStr {
    public static void main(String[] args) {
        char[] target = "I am a software engineer".toCharArray();
        char[] result = reverPosition(target, 4);
        for (char c : result) {
            System.out.print(c);
        }
    }
   

    /**
     * 方案一:空间换时间
     * 时间复杂度O(n),空间复杂度O(n)
     * */
    public static char[] reverPosition(char[] target, int position){
        if(target == null || target.length <= 0 || target.length <= position){
            return target;
        }
        char[] result = new char[target.length];
        int positionResult = 0;
        for (int i = position; i < target.length; i++) {
            result[positionResult++]=target[i];
        }
        for(int i=0;i<position;i++){
            result[positionResult++] = target[i];
        }
        return result;
    }
}
  • 如上案例实现,遍历一次数组即可完成复制,因此时间复杂度O(n),空间复杂度显然是O(n)
方案二:多次翻转
  • 依据第一题中的思路,有如下分析:
    • 既然需要翻转指定位置,我们可以将本字符串看成是两个单词,
    • 本次单词通过指定的位置进行拆分,这样理解的话就和第一题是一模一样的
    • 我们依然多次翻转,第一次全文翻转,得到一个顺序上是正确的字符
    • 第二次,依据指定位置4,此时的位置应该是 length-1-4+1 ~length-1的位置翻转
    • 第三次,翻转0~length-1-4 的位置,得到我们需要的值

在这里插入图片描述

  • 如上分析有如下代码:
/**
 * 指定位置反转字符串
 * 案例 I am a software engineer 4 -> a software engineerI am
 * @author liaojiamin
 * @Date:Created in 18:47 2021/7/1
 */
public class ReverPositionStr {
    public static void main(String[] args) {
        char[] target = "I am a software engineer".toCharArray();
        char[] result_1 = reverPositionTwice(target, 4);
        for (char c : result_1) {
            System.out.print(c);
        }
    }
    /**
     * 方案二:反转两次
     * 时间复杂度O(n)
     *
     * */
    public static char[] reverPositionTwice(char[] target, int position){
        if(target == null || target.length <= 0 || target.length <= position){
            return target;
        }
        target = reverAll(target, 0, target.length -1);
        target = reverAll(target, 0, target.length-1 - position);
        target = reverAll(target, target.length-1 - position + 1, target.length-1);
        return target;
    }

    /**
     * 按指定位置反转
     * */
    public static char[] reverAll(char[] target, int start, int end){
        while (start < end){
            char temp = target[start];
            target[start] = target[end];
            target[end] = temp;
            start++;
            end--;
        }
        return target;
    }
}

上一篇:数据结构与算法–有序数组中找出和为s的两个数字
下一篇:数据结构与算法–判断扑克牌是否顺子

  • 12
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 28
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 28
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值