循环移位算法

循环移位法

参考文章:内容连接。主要从 数组,字符串,链表 三种情况下,介绍循环移位的具体实现。这里只梳理一下文章脉络。

数组循环移位

方法一:取模法

这个方法在 Leetcode 189 中已经用过了,作者这里考虑了两种新情况:

  • 如果移位位数 K 是数组长度 len(s) 的倍数的话,那么就不用移位了;
  • 如果 K 是负数,就是往相反方向(向左移)

取模法由于需要开辟一个新数组,长度为 len(s),这会增加算法的空间开销,并不符合空间为 O(1) 的原地算法。

方法二:时间换空间

如果要解决上面的问题,那我们便一次一次的考虑,总共移动 K 次。这样时间复杂度变成了 O(N*K),最大可达 O(N^2)。

方法三:空间换时间

就是将数组长度变成原来的两倍,拼在一起。这在 leetcode-189 也有相关的描述。

三次翻转法

所谓“翻转”,比如[0,N],就是把 0 和 N 交换位置,1和(N-1)交换位置……。算法描述:

  • 先把[0, n - k - 1]翻转
  • 然后把[n - k, n - 1]翻转
  • 最后把[0, n - 1]翻转
    这个算法其实很好证明。我们用箭头代表方向,初始数组为 A->B | C->D ;经过前两次反转后变成了 B<-A | D<-C ;最后整体翻转,C->D | A->B。翻转看箭头的方向就好了,这是自己想的比较直观的证明。实现翻转的代码描述为:
while (start < end) {
    t = list[start];
    list[start] = list[end];
    list[end] = t;
    start++;
    end--;
}

字符串移位

这里给出的例题为检查是否包含的问题。直观解法是每移动一次就判断一次,那么需要判断 len(s) 次。

暴力法

就是上面最直观的方法。实现思路是:已知 S1 和 S2,每次都把 S1 左移一位,用指针 P1 和 P2 开始对两个字符串开始检查;每左移一次,两个指针就循环检查一次。

用空间换时间

拼接两个 S1 字符串,然后用两个指针开始对于新的 S1 和 S2 进行检查。

取模法

取模法实际上是对于空间换时间算法的取巧。我们假象 S1 后面还有一个 S1,实际上是用取模的方法实现的。

链表循环移位

源于 leetcode-61,难度中等。这里便不再展开了。

猜你喜欢

转载自www.cnblogs.com/rongyupan/p/12630051.html