最大公约数的应用 - 分享

1.先看一家大公司笔试题

[color=blue][b]数组中有n个数据,要将它们顺序循环向后移动k位,即前面的元素向后移动k位,后面的元素则循环向前移k位,例如,0、1、2、3、4循环移动3位后为2、3、4、0、1。考虑到n会很大,不允许用2n以上 个空间来完成此题。[/b][/color]

[b]1.1 算法1:[/b]

(1) 问题分析:

由数学知识,通过求余运算就可以解决"循环"后移的问题。

(2) 代码:

package boke.written;

import java.util.Arrays;

/**
* 题目:数组中有n个数据,要将它们顺序循环向后移动k位,即前面的元素向后移动k位,后面的元素则循环
* 向前移k位,例如,0、1、2、3、4循环移动3位后为2、3、4、0、1。考虑到n会很大,不允许用2n以上 个空间来完成此题。
*
* @since jdk1.5及其以上
* @author 毛正吉
* @version 1.0
* @date 2010.06.20
*
*/
public class GCDTest1 {

/**
* @param args
*/
public static void main(String[] args) {
int[] a = { 0, 1, 2, 3, 4 };
int n = a.length;
int[] b = new int[n];
int k = 3;

for (int i = 0; i < n; i++) {
b[(k + i) % n] = a[i]; // 求余解决循环后移
}

System.out.println(Arrays.toString(b));

}

}


(3) 算法分析:

时间复杂度为O(n), 空间效率为O(2n).

[b]1.2 算法2:[/b]

(1) 问题分析:

在算法有空间限制的情况下,一个简单的方法是:

<1> 将最后一个存储空间的数据存储在临时存储空间中。

<2> 其余数逐个向后移动一位。共操作k次就能完成问题的要求。

(2) 代码:

package boke.written;

import java.util.Arrays;

/**
* 题目:数组中有n个数据,要将它们顺序循环向后移动k位,即前面的元素向后移动k位,后面的元素则循环
* 向前移k位,例如,0、1、2、3、4循环移动3位后为2、3、4、0、1。考虑到n会很大,不允许用2n以上 个空间来完成此题。
*
* @since jdk1.5及其以上
* @author 毛正吉
* @version 1.0
* @date 2010.06.20
*
*/
public class GCDTest2 {

/**
* @param args
*/
public static void main(String[] args) {
int[] a = { 0, 1, 2, 3, 4 };
int n = a.length;
int k = 3;
int temp;
int j;

for (int i = 0; i < k; i++) {
temp = a[n - 1]; // 最后一个存储空间的数据存储在临时存储空间中

for (j = n - 1; j > 0; j--) { // 其余数据逐个向后移动一位
a[j] = a[j - 1];
}

a[0] = temp;
}

System.out.println(Arrays.toString(a));

}

}


(3) 算法分析:

若要考虑到有k>n的可能性,这样的移动会出现重复操作,可以在输入数据后,执行k = k % n操作,可以保证不出现重复移动的情况。这时算法的移动(赋值)次数为k * n,当n较大时,算法的效率比较低。

时间复杂度为O(n * k), 空间效率为O(n).

[b]1.3 算法3:[/b]

(1) 问题分析:可以用一个临时存储空间把每一个数据一次移动到位呢?

<1> 一组循环移动的情况:

通过计算可以确定某个元素移动后的具体位置,如n=5,k=3时,0、1、2、3、4循环移动3位后为2、3、4、0、1。知道为什么吗?可通过计算得出0移动到3的位置,3移动到1的位置,1移动到4的位置,4移动到2的位置,2移动到0的位置;一组移动(0-3-1-4-2-0)正好将全部数据按要求进行了移动。

<2> 多组循环移动的情况:

再看一个例子,当n=6,k=3时,0、1、2、3、4、5经移动的结果是3、4、5、0、1、2。
共有3组移动:0-3-0, 1-4-1, 2-5-2才能将全部数据操作完毕。

那么,循环移动的的组数与n、k有怎么样的关系呢?再看一个例子。

当n=6,k=2时,0、1、2、3、4、5经移动的结果是4、5、0、1、2、3。
共有2组移动:0-2-4-0, 1-3-5-1才能将全部数据操作完毕。

<3> 归纳总结:

由以上的分析和实例,可感知到循环移动的组数与n与k的最大公约数有关。

<4> 算法设计:

[color=red][b] a. 求n和k的最大公约数m[/b][/color]
[color=red][b] b. 进行m组循环移动[/b][/color]
[color=red][b]c. 每组移动进行n/m次。[/b][/color]
[color=red][b]d. 某个元素移动的具体位置为: (i + k) % n[/b][/color]
(2) 代码:

package boke.written;

import java.util.Arrays;

/**
* 题目:数组中有n个数据,要将它们顺序循环向后移动k位,即前面的元素向后移动k位,后面的元素则循环
* 向前移k位,例如,0、1、2、3、4循环移动3位后为2、3、4、0、1。考虑到n会很大,不允许用2n以上 个空间来完成此题。
*
* @since jdk1.5及其以上
* @author 毛正吉
* @version 1.0
* @date 2010.06.20
*
*/
public class GCDTest3 {

/**
* @param args
*/
public static void main(String[] args) {
int[] a = { 0, 1, 2, 3, 4, 5};
int n = a.length;
int k = 3;
int m;
int i;
int j;
int b0;
int b1;
int t;

m = ff(n, k); // 最大公约数

for (j = 0; j < m; j++) {
b0 = a[j];
t = j;

for (i = 0; i < n/m; i++) {
t = (t + k) % n;
b1 = a[t];
a[t] = b0;
b0 = b1;
}

}
System.out.println(Arrays.toString(a));

}

/**
* 求a和b的最大公约数
*
* @param a
* @param b
* @return
*/
public static int ff(int a, int b) {
int i, t = 1;
for (i = 2; i <= a && i <= b; i++) {
while ((a % i == 0) && (b % i == 0)) {
t = t * i;
a = a / i;
b = b / i;
}
}
return t;
}

}


(3) 算法分析:

算法中,每组循环移动都是从前向后进行的,这样每次移动之前,都需要将后面的数据存入辅助存储空间中,一次移动需要两次赋值,
总体大约需要2n次。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值