Problem

You are given a string s containing lowercase English letters, and a matrix shift, where shift[i] = [directioni, amounti]:

  • directioni can be 0 (for left shift) or 1 (for right shift).
  • amounti is the amount by which string s is to be shifted.
  • A left shift by 1 means remove the first character of s and append it to the end.
  • Similarly, a right shift by 1 means remove the last character of s and add it to the beginning.

Return the final string after all operations.

Examples

Example 1:

1
2
3
4
5
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"

Example 2:

1
2
3
4
5
6
7
Input: s = "abcdefg", shift = [[1,1],[1,1],[0,2],[1,3]]
Output: "efgabcd"
Explanation:   
[1,1] means shift to right by 1. "abcdefg" -> "gabcdef"
[1,1] means shift to right by 1. "gabcdef" -> "fgabcde"
[0,2] means shift to left by 2. "fgabcde" -> "abcdefg"
[1,3] means shift to right by 3. "abcdefg" -> "efgabcd"

Constraints:

  • 1 <= s.length <= 100
  • s only contains lower case English letters.
  • 1 <= shift.length <= 100
  • shift[i].length == 2
  • directioni is either 0 or 1.
  • 0 <= amounti <= 100

Solution

Intuition

Instead of performing each shift operation one by one, we can combine all shifts into a single net shift. Left and right shifts can be combined by adding/subtracting their amounts, and the result can be applied in one go.

Approach

Sum all left shifts and right shifts. The net shift is (right - left) modulo the string length. Apply the net shift to the string in one operation.

Code

C++
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
#include <vector>
#include <string>
using namespace std;
class Solution {
public:
    string stringShift(string s, vector<vector<int>>& shift) {
        int n = s.size(), net = 0;
        for (auto& op : shift) net += (op[0] ? op[1] : -op[1]);
        net = ((net % n) + n) % n;
        return s.substr(n - net) + s.substr(0, n - net);
    }
};
Go
1
2
3
4
5
6
7
8
func stringShift(s string, shift [][]int) string {
    n, net := len(s), 0
    for _, op := range shift {
        if op[0] == 0 { net -= op[1] } else { net += op[1] }
    }
    net = ((net % n) + n) % n
    return s[n-net:] + s[:n-net]
}
Java
1
2
3
4
5
6
7
8
class Solution {
    public String stringShift(String s, int[][] shift) {
        int n = s.length(), net = 0;
        for (int[] op : shift) net += (op[0] == 1 ? op[1] : -op[1]);
        net = ((net % n) + n) % n;
        return s.substring(n - net) + s.substring(0, n - net);
    }
}
Kotlin
1
2
3
4
5
6
7
8
9
class Solution {
    fun stringShift(s: String, shift: Array<IntArray>): String {
        val n = s.length
        var net = 0
        for (op in shift) net += if (op[0] == 1) op[1] else -op[1]
        net = ((net % n) + n) % n
        return s.substring(n - net) + s.substring(0, n - net)
    }
}
Python
1
2
3
4
5
6
def stringShift(s: str, shift: list[list[int]]) -> str:
    n, net = len(s), 0
    for d, a in shift:
        net += a if d == 1 else -a
    net = (net % n + n) % n
    return s[-net:] + s[:-net] if net else s
Rust
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
fn string_shift(s: &str, shift: Vec<Vec<i32>>) -> String {
    let n = s.len();
    let mut net = 0;
    for op in shift.iter() {
        if op[0] == 1 { net += op[1]; } else { net -= op[1]; }
    }
    let net = ((net % n as i32) + n as i32) % n as i32;
    let bytes = s.as_bytes();
    let mut res = Vec::with_capacity(n);
    res.extend_from_slice(&bytes[(n as i32 - net) as usize..]);
    res.extend_from_slice(&bytes[..(n as i32 - net) as usize]);
    String::from_utf8(res).unwrap()
}
TypeScript
1
2
3
4
5
6
7
function stringShift(s: string, shift: number[][]): string {
    const n = s.length;
    let net = 0;
    for (const [d, a] of shift) net += d === 1 ? a : -a;
    net = ((net % n) + n) % n;
    return s.slice(n - net) + s.slice(0, n - net);
}

Complexity

  • ⏰ Time complexity: O(n)
  • 🧺 Space complexity: O(n)