# 字符串循环左移

给定一个字符串S[0, ...N-1],要求把S的前k个字符移动到S的尾部
如把字符串 'abcdef' 前面的2个字符 'a', 'b' 移动到字符串的尾部
得到新的字符串 'cdefab',即字符串循环左移k

循环左移k位等价于循环右移n-k位

算法要求: 时间复杂度O(n) 空间复杂度 O(1)
1
2
3
4
5
6
7

# 方法1: 暴力法

/**
 * 方法一:暴力法
 * 每次循环左移一位,调用 k 次即可
 * 时间复杂度O(kN) 空间复杂度 O(1)
 */
1
2
3
4
5

# 方法2: 三次拷贝

/**
 * 方法二:三次拷贝
 * S[0, ...k] -> T[0, ...k]
 * S[k+1, ...N-1] -> S[0, N-k-1]
 * T[0, ...k] -> S[N-k, ...N-1]
 * 时间复杂度O(N) 空间复杂度 O(K)
 */
1
2
3
4
5
6
7

# 方法3: 翻转

/**
 * 方法三:翻转
 * (X'Y')' = YX
 * 如: abcdef
 * X = ab, X' = ba
 * Y = cdef, Y' = fedc
 * (X'Y')' = (bafedc)' = cdefab
 * 时间复杂度 O(N) 空间复杂度 O(1)
 * 在完美洗牌中还会遇到这个问题
 */

function reverseString(str, from, to) {
  var strAry = str.split('')
  // 字符串从 from 到 to 位置进行翻转
  while (from < to) {
    let t = strAry[from]
    strAry[from++] = strAry[to]
    strAry[to--] = t
  }
  return strAry.join('')
}

function leftRotateString(str, m) {
  // str 前 m 位 移到 str 的尾部
  var len = str.length
  m %= len
  str = reverseString(str, 0, m - 1)
  str = reverseString(str, m, len - 1)
  str = reverseString(str, 0, len - 1)
  return str
}

var a = '123456789'
console.log(leftRotateString(a, 3))
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34