【LeetCode 30天挑战活动】Day 14.Perform String Shifts

题目描述

给定字符串s和二维数组shift,其中,shift数组指示对字符串s进行的字符移动操作。
shift[i] = [direction, amount]
direction:0为向左移动,1为向右移动
amount:移动次数
示例:
Input: s = “abc”, shift = [[0,1],[1,2]]
Output: “cab”
Explanation:
[0,1] means shift to left by 1. “abc” -> “bca”
[1,2] means shift to right by 2. “bca” -> “cab”

解题思路

所谓移动,其实就是对字符串进行一个切割和拼接,核心操作就是substring。但是使用substring的时候想到一个问题,如果移动的次数比字符串本身的长度还要大呢?
写了几个例子之后发现,当移动长度达到字符串本身的长度时,其实字符串就回到了原样(相当于没有进行操作),因此,只需要对移动长度进行一个取余操作就可以。步骤大致如下:
(1)确定移动次数(即移动字符数x
(2)如果是向左移动,即将左边[0, x)部分取下,拼接到字符串右边
(3)如果是向右移动,即将[length - x, end]部分取下,拼接到字符串左边
(4)重复(1)(2)(3)直至所有的移动操作都完成
这个思路也是比较清晰,一步步照着写就可以,代码如下:

class Solution {
    public String stringShift(String s, int[][] shift) {
        if (s == null || s.length() == 0) {
            return s;
        }
        
        for (int i = 0; i < shift.length; ++i) {
            int dire = shift[i][0];
            int amount = shift[i][1] % s.length();
            
            String tmp = null;
            
            if (dire == 0) {
                tmp = s.substring(0, amount);	// 注意,substring不改变原值
                s = s.substring(amount);
                s += tmp;
            }
            else {
                tmp = s.substring(s.length() - amount);
                s = s.substring(0, s.length() - amount);
                s = tmp + s;
            }
            
        }
        
        return s;
    }
}

优化

题目给出了一个提示:

You may notice that left shift cancels the right shift, so count the total left shift times (may be negative if the final result is right shift), and perform it once.

左移和右移其实存在一个相互抵消的效果,因此可以对shift数组进行预处理,得到一个最终的移动方案(只有一个方向的移动)
时间复杂度上虽然和第一个方案一样,都是O(n),因为都要对shift数组进行一次遍历,但是相比较第一个方案少了n-1次字符串处理(其中nshift数组的长度)。代码如下:

class Solution {
    public String stringShift(String s, int[][] shift) {
        if (s == null || s.length() == 0 || shift == null || shift.length == 0) {
            return s;
        }

        // 对移动数组进行预处理
        int[] finalShift = new int[2];
        finalShift = shift[0];
        
        for (int i = 1; i < shift.length; ++i) {
            int dire = shift[i][0];
            int amount = shift[i][1];
            
            if (dire == finalShift[0]) {
                finalShift[1] += amount;
            }
            else {
                if (amount > finalShift[1]) {
                    finalShift[0] = (finalShift[0] == 0)? 1 : 0;
                }
                finalShift[1] = Math.abs(amount - finalShift[1]);
            }
        }
        
        // 下面和方案1是一样的处理
        String tmp = null;
        int dire = finalShift[0];
        int amount = finalShift[1] % s.length();
            
        if (dire == 0) {
            tmp = s.substring(0, amount);
            s = s.substring(amount);
            s += tmp;
        }
        else {
            tmp = s.substring(s.length() - amount);
            s = s.substring(0, s.length() - amount);
            s = tmp + s;
        }
        
        return s;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值