关于旋转数组问题的环状替换解法的数学推导

关于旋转数组问题的环状替换解法的数学推导

目录

  • 关于模运算的推导
  • 对旋转数组的数学分析

关于模运算的推导

一数与别数之商的余,有:

5/3 = 1… 2
5 mod 3 = 2 (5%3 = 2)

一数在一模下与别数同余,有:

5 mod 3 = 2
8 mod 3 = 2
5 ≡ 8 (mod 3)

当N ≡ M (mod n),P ≡ L (mod n),c属Z有:

N+c ≡ M+c (mod n)
Nc ≡ Mc (mod n)
N+P ≡ M+L (mod n)

对旋转数组的数学分析

原题

给定一个整数数组 nums,将数组中的元素向右轮转 k 个位置,其中 k 是非负数。
示例 1:

输入: nums = [1,2,3,4,5,6,7], k = 3
输出: [5,6,7,1,2,3,4]
解释:
向右轮转 1 步: [7,1,2,3,4,5,6]
向右轮转 2 步: [6,7,1,2,3,4,5]
向右轮转 3 步: [5,6,7,1,2,3,4]

示例 2:

输入:nums = [-1,-100,3,99], k = 2
输出:[3,99,-1,-100]
解释: 
向右轮转 1 步: [99,-1,-100,3]
向右轮转 2 步: [3,99,-1,-100]

解法

将一数直接移动至最终位置,并用一变量储存原数,反复进行直到移动全部完成。

数学分析

设一数在数组中的初始指针为x,其末位置指针为y,a为任意数,b为移动次数,数组长度为n,
则有以下方程:

(x+k*b) mod n = y

y < n,又有y mod n = y,故:

x+k*b ≡ y (mod n)

进而:

k*b ≡ y-x (mod n)

x = y时,k*b ≡ 0 (mod n),此时指针回到初始位置,又有:

k*b = a*n

又因,当k与n已知时可变化为a关于b的线性函数:

b = a*(n/k)

a为任意数,n与k为正整数,函数在a≧ 0时连续单调递增。
这意味着指针始终可能回到初始位置。

因为二数共除其最大公约数后互质(其共同因数只有1),故:

k*b/gcd(n,k) = a*n/gcd(n,k),或k*b/gcd(a,k) = a*n/gcd(a,k)

但后者不便计算,所求得:

b = a*t/gcd(a,k)
当t=1, b = a/gcd(a,k)

故用前者,又有贝祖定理为:

当a与b互素时,方程a*x+b*y = m有解(m=dt,t属Z,d=gcd(a,b))
当x = 0时,b
y = m, d = b
//greatest common divisor(最大公约数)

得:b = a/gcd(n,k)


int gcd(int a, int b) {
    return b ? gcd(b, a % b) : a;
}

void swap(int* a, int* b) {
    int t = *a;
    *a = *b, *b = t;
}

void rotate(int* nums, int numsSize, int k) {
    k = k % numsSize;
    int count = gcd(k, numsSize);
    for (int start = 0; start < count; ++start) {
        int current = start;
        int prev = nums[start];
        do {
            int next = (current + k) % numsSize;
            swap(&nums[next], &prev);
            current = next;
        } while (start != current);
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值