Example013
原文链接:Example013
题目
有 N
个个位正整数存放在 int
型数组 A[0, …, N-1]
中,N
为已定义的常量且 N≤9
,数组 A[]
的长度为 N
,另给一个 int
型变量 i
,要求只用上述变量(A[0]~A[N-1]
与 i
,这 N+1
个整型变量〉写一个算法,找出这 N
个整数中的最小者,并且要求不能破坏数组 A[]
中的数据。
分析
对于普通的寻找数组最小值的方法如下,在方法中会用到两个变量 min
和 i
。其中 min
用来记录数组中的最小值,而 i
用来作为循环变量控制循环。
/**
* 寻找数组 A 中的最小数
*
* @param A 由 N 个个位正整数组成的整型数组
* @return 得到数组中整数的最小数
*/
public int min(int[]A){
// 初始时,将数组第一个元素置为最小值
int min=A[0];
// 循环数组所有元素
for(int i=0;i<N; i++){
// 如果发现数组中有元素比最小值还小
if(A[i]<min){
// 那么更新记录最小值的变量,将该数记为最小值
min=A[i];
}
}
// 返回最小值
return min;
}
但现在要求只用一个变量 i
,也就是说必须用变量 i
来保存最小值和循环变量控制循环。
从题目中得知数组中元素个数最多为 9 个,并且数组中每个数都是个位数,这就给了我们操作的空间。
我们可以用一个十位数 num([10,99]
)来完成操作,其中让十位数记录最小值 [1, 9]
,而个位数记录循环变量 [0, 9]
。
我们可以利用 num/10
得到十位上的数值,而利用 num%10
得到个位上的数,每次 num%10+1
就可以让循环变量加 1 控制循环。
图解
略。
C实现
核心代码:
/**
* 求数组中的最小值
* @param A 指定数组
* @return 最小值
*/
int min(int A[]) {
// 十位记录最小值,个位记录循环变量
int i = A[0] * 10 + 0;// 其中 0 就表示循环变量,而A[0]表示临时最小值,乘以 10 是因为它表示十位
// 其中 i%10 就得到个位数,即循环变量
while (i % 10 < N) {
// i/10 可以得到十位数,即记录的最小值,通过 A[i%10] 就相当于 A[0]、A[1] 访问数组中对应下标的值,然后比较大小
if (i / 10 > A[i % 10]) {
// 如果该数比记录的最小值还要小,那么就更新变量 i,更新 i 的十位为新的最小值,并且也要更新循环变量,继续数组中的下一个元素
// A[i%10]就是新的十位,而乘以 10 是让它成为一个两位数,i%10 是获取原来的个位数
i = A[i % 10] * 10 + i % 10;
}
// 加 1 就是让个位数加1,就是新的循环变量,等价于原来的 i++
i += 1;
}
// 返回最小值,要除以 10 才能得到十位数表示的最小值
return i / 10;
}
完整代码:
#include <stdio.h>
#define N 8
/**
* 求数组中的最小值
* @param A 指定数组
* @return 最小值
*/
int min(int A[]) {
// 十位记录最小值,个位记录循环变量
int i = A[0] * 10 + 0;// 其中 0 就表示循环变量,而A[0]表示临时最小值,乘以 10 是因为它表示十位
// 其中 i%10 就得到个位数,即循环变量
while (i % 10 < N) {
// i/10 可以得到十位数,即记录的最小值,通过 A[i%10] 就相当于 A[0]、A[1] 访问数组中对应下标的值,然后比较大小
if (i / 10 > A[i % 10]) {
// 如果该数比记录的最小值还要小,那么就更新变量 i,更新 i 的十位为新的最小值,并且也要更新循环变量,继续数组中的下一个元素
// A[i%10]就是新的十位,而乘以 10 是让它成为一个两位数,i%10 是获取原来的个位数
i = A[i % 10] * 10 + i % 10;
}
// 加 1 就是让个位数加1,就是新的循环变量,等价于原来的 i++
i += 1;
}
// 返回最小值,要除以 10 才能得到十位数表示的最小值
return i / 10;
}
int main() {
int A[] = {2, 4, 6, 1, 5, 3, 7, 8};
// 调用函数
int m = min(A);
printf("最小值:%d", m);
}
执行结果:
最小值:1
事实上,书上的写法是利用 i 的十位上的数字作为循环变量,将 i 的个位上的数字来代替题目中的 min 的功能,而利用 i%10
取得 i 个位上的数字,i/10
取得 i 十位上的数字。代码如下:
void min(int A[], int &i) {// 用 i 来保存最小值
i=A[0];// i先保存存入A[0]的值
while(i/10<=N-1) { // 取 i 的十位上的数字作为循环变量,与 N-1 作比较
if(i%10>A[i/10]) { // 取 i 的个位上的数字与 A[i/10] 中的各数值比较
i=i-i%10;// 如果 i 的个位上的数字大于 A[I/10] 中数字
i=i+A[i/10];// 则将 i 的个位上的数字换成 A[I/10]
}
i=i+10;// i 的十位上的数字加 1,即对 A[] 中的下一个数字进行检测
}
i=i%10;// 循环结束后,i 的个位上的数字保存了 A[] 中的最小值,将 i 更新为 i 的个位上的数字
}
Java实现
核心代码:
/**
* 求数组 A 中的最小值
*
* @param A 全是个位正整数的数组
* @return 数组中的最小值
*/
public int min(int[]A){
// 十位记录最小值,个位记录循环变量
int i=A[0]*10+0;// 其中 0 就表示循环变量,而A[0]表示临时最小值,乘以 10 是因为它表示十位
// 其中 i%10 就得到个位数,即循环变量
while((i%10)<N){
// i/10 可以得到十位数,即记录的最小值,通过 A[i%10] 就相当于 A[0]、A[1] 访问数组中对应下标的值,然后比较大小
if((i/10)>A[i%10]){
// 如果该数比记录的最小值还要小,那么就更新变量 i,更新 i 的十位为新的最小值,并且也要更新循环变量,继续数组中的下一个元素
// A[i%10]就是新的十位,而乘以 10 是让它成为一个两位数,i%10 是获取原来的个位数
i=A[i%10]*10+(i%10);
}
// 加 1 就是让个位数加1,就是新的循环变量,等价于原来的 i++
i+=1;
}
// 返回最小值,要除以 10 才能得到十位数表示的最小值
return i/10;
}
完整代码:
public class SeqList {
private final int N = 8;
/**
* 求数组 A 中的最小值
*
* @param A 全是个位正整数的数组
* @return 数组中的最小值
*/
public int min(int[] A) {
// 十位记录最小值,个位记录循环变量
int i = A[0] * 10 + 0;// 其中 0 就表示循环变量,而A[0]表示临时最小值,乘以 10 是因为它表示十位
// 其中 i%10 就得到个位数,即循环变量
while ((i % 10) < N) {
// i/10 可以得到十位数,即记录的最小值,通过 A[i%10] 就相当于 A[0]、A[1] 访问数组中对应下标的值,然后比较大小
if ((i / 10) > A[i % 10]) {
// 如果该数比记录的最小值还要小,那么就更新变量 i,更新 i 的十位为新的最小值,并且也要更新循环变量,继续数组中的下一个元素
// A[i%10]就是新的十位,而乘以 10 是让它成为一个两位数,i%10 是获取原来的个位数
i = A[i % 10] * 10 + (i % 10);
}
// 加 1 就是让个位数加1,就是新的循环变量,等价于原来的 i++
i += 1;
}
// 返回最小值,要除以 10 才能得到十位数表示的最小值
return i / 10;
}
}
测试代码:
public class SeqListTest {
public static void main(String[] args) {
SeqList list = new SeqList();
int[] A = new int[]{2, 4, 3, 5, 7, 1, 6, 8};
int min = list.min(A);
System.out.println("最小值:" + min);
}
}
执行结果:
最小值:1