杂题分享--部分翻转字符串

 * 描述:
 * 给定一个字符串str和长度leftsize,
 * 请把str左侧leftsize的部分和右部分做整体交换。要求额外空间复杂度O(1)。
 * 例如:
 * 输入: abcde 3
 * 输出: deabc
 * 输入: abcdefgh 5
 * 输出: fghabcde
解法一:(10W人中99000人都会的解法) 
    应用左神一句话,大家都会得东西,你拿出来毫无意义,拿什么凸显自己,人家凭啥要你。
分三次翻转 先翻转前 leftsize个 在翻转其它的 最后整体翻转 
先翻转 left --> left + leftsize
然后翻转 left + leftsize + 1 --> right 
最后翻转 整体

例如: abcde 3  
    首先翻转 abc -> cba
    然后翻转 de -> ed 
    此时整个字符串为 cbaed
    然后翻转整个字符串结果为:deabc
复杂度分析:
    空间复杂度:O(1) 只有有限的几个变量
    时间复杂度:
        假设左半部分是 L 右半部分是 R     
        翻转左边 L / 2
        翻转右边 R / 2
        整体翻转 (L + R) / 2
        时间复杂度 大约是 O(2n)
解法一代码实现:
public class Code1 {
    // 从 left 到 fight 翻转字符串 
    public static void reserve(char[] chars, int left, int right) {
        while (left < right) {
            char temp = chars[left];
            chars[left++] = chars[right];
            chars[right--] = temp;
        }
    }

    //分三次翻转 先翻转前 leftsize个 在翻转其它的 最后整体翻转
    //先翻转 left --> mid 然后翻转 mid + 1 --> right 最后翻转 整体
    public static String solution1(char[] chars, int left, int mid, int right) {
        reserve(chars, left, mid);
        reserve(chars, mid + 1, right);
        reserve(chars, left, right);
        return String.valueOf(chars);
    }

    public static String solution1(String str, int leftsize) {
        //判空
        if (leftsize <= 0 || leftsize >= str.length()) {
            return str;
        }
        return solution1(str.toCharArray(),0,leftsize - 1, str.length() - 1);
    }
    public static void main(String[] args){
        System.out.println(solution1("abcde", 3));
    }
}
解法二:
abcdefgh 5
    将上例划分为左右两个部分 左5 右str.length - 5 = 3  abcde(left) fgh(right)
    取左右部分最小的值为same 作为交换条件 即为 same = 3
    首先顺序交换 前三个和后三个 abc fgh
    交换完成之后 结果为 fgh de abc
    由于是交换之前左部分长 所以是左部分开头same(3)个已经处理完毕 fgh
    新的左部分变为 5-3 = 2 de 右部分为 3 abc
    新的same = 左右部分字符个数的最小值 即为 2
    接下来只需要更改对应指针的值 此问题就递归为 deabc 2(same)
    此时是右边长 de abc
    还是顺序交换最短的部分所包含的字符数次 也就是2次  左2 < 右3
    结果就变为 bcade
    由于是交换之前右边长 所以 右侧same(2)个处理完毕 de
    新的左部分为 bc 2 右部分为 a 1
    此时变为子问题 bca 1(same)
    继续交换 结果 acb
    由于是交换之前左部分长 所以a 不动 此时变为子问题 cb 1(same)
    由于是左边等于右边的长度 所以进行最后一次交换
    结果为bc
总体变化流程为:||之间的表示已经处理完毕
   abcdefgh -> |fgh| deabc -> |fgh| bca |de| -> |fgha| cb |de| -> fghabcde
   abcdefgh 5   -> deabc 2 -> bca 1 -> cb 1
解法二代码实现:
public class Code2 {
    //此题的注释以例二为例
    public static String solution2(String s, int leftsize) {
        //判空
        if (leftsize <= 0 || leftsize >= s.length()) {
            return s;
        }
        char[] str = s.toCharArray();
        int L = 0;
        int R = str.length - 1;
        int lpart = leftsize; //左半部分 5 左边未处理的字符数
        int rpart = s.length() - leftsize;//右半部分 3 右边未处理的字符数
        int same = Math.min(lpart, rpart); //相同个数的部分 same = 3
        exchange(str, L, R, same);
        //在这个exchange 结束之后 整个字符串 变为fghdeabc
        //此结果意味着前 same个字符已经处理好了 剩下就是递归处理后面
        //需要做的仅仅就是玩好 L R same 这三个变量而已
        while (lpart - rpart != 0) { //此条件表示还有未处理的字符
            if (lpart - rpart > 0) { //左边长  fghdeabc
                L += same; //于是L左移same个,表示前same(3)个已经处理好了 L指向d
                lpart -= same;//也就是意味着 rpart 中已经有same个处理完了
            } else {
                //同理 右边长 以abcdefgh 3 为例
                //第一交换之后 结果为 fghdeabc 右边长表示 右边3个已经交换完毕
                //此时只需要递归处理 前面 fghde 即可
                R -= same; //修改R的指向
                rpart -= same;//也就是意味着 rpart 中已经有same个处理完了
            }
            same = Math.min(lpart, rpart);
            exchange(str, L, R, same);
        }
        return String.valueOf(str);
    }

    //str 从左出发数 size个 和 从右出发 数size个 交换
    //以例二为例:abcdefgh 5 -> fghabcde
    //size = 3  第一次交换完成之后结果为 fghdeabc
    //也就是前三个和后三个顺序交换
    public static void exchange(char[] str, int L, int R, int sameSize) {
        int i = R - sameSize + 1;// 7 - 3 + 1 = 5 (d的位置)
        char tmp = 0;
        while (sameSize-- != 0) { //size就是交换的次数
            tmp = str[L];
            str[L++] = str[i];
            str[i++] = tmp;
        }
    }
    public static void main(String[] args){
        //Test
        System.out.println(solution2("abcde", 3));
        System.out.println(solution2("abcdefgh", 5));
        System.out.println(solution2("abcdefgh", 3));
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值