zoukankan      html  css  js  c++  java
  • 如何交换两个等长整形数组使其数组和的差最小(C和java实现)

    1. 问题描述

      有两个数组a,b,大小都为n,数组元素的值任意整形数,无序;
      要求:通过交换a,b中的元素,使[数组a元素的和]与[数组b元素的和]之间的差最小。

    2. 求解思路:

        当前数组a和数组b的和之差为
        A = sum(a) - sum(b)
        a的第i个元素和b的第j个元素交换后,a和b的和之差为
        A' = sum(a) - a[i] + b[j] - (sum(b) - b[j] + a[i])
            = sum(a) - sum(b) - 2 (a[i] - b[j])
            = A - 2 (a[i] - b[j])
        设x = a[i] - b[j], 则 |A'| = |A-2x|
        假设A > 0, 
        当x在(0,A)之间时,做这样的交换才能使得交换后的a和b的和之差变小,x越接近A/2效果越好, 如果找不到在(0,A)之间的x,则当前的a和b就是答案。
        所以算法大概如下:
        在a和b中寻找使得x在(0,A)之间并且最接近A/2的i和j,交换相应的i和j元素,重新计算A后,重复前面的步骤直至找不到(0,A)之间的x为止。

    3. C语言实现

      1 #include <stdio.h>
      2 #include <stdlib.h>
      3 #include <time.h>
      4 #define N 100
      5 int A[N];
      6 int B[N];
      7 //随机初始化一个数组
      8 void init(int a[], int n)
      9 {
     10   int i;
     11   for(i = 0; i < n; ++i)
     12     a[i] = rand() % N;
     13 }
     14 //输出数组
     15 void print(int a[], int n)
     16 {
     17   int i;
     18   for(i = 0; i < n; ++i)
     19     printf("%d ", a[i]);
     20   printf("
    --------------------------------------------
    ");
     21 }
     22  
     23 //求数组和
     24 int sum(int a[], int n)
     25 {
     26   int i, sum = 0;
     27   for(i = 0; i < n; ++i)
     28     sum += a[i]; 
     29   return sum;
     30 }
     31 //交换整数
     32 void swap(int *a, int *b)
     33 {
     34   int temp = *a;
     35   *a = *b;
     36   *b = temp;
     37 }
     38 //n1,n2为数组A和B中实际初始化的元素个数
     39 int solve(int n1, int n2)
     40 {
     41   int i, j; //循环迭代变量
     42   int x, y; //用于保存可交换数字对的索引
     43   int maxSum, minSum; //分别用于保存两个数组的数字之和
     44   int diff; //diff = sum1 - sum2
     45   int maxdiff; // 2 * (A[x] - B[y])
     46   int flag; //标记是否找到可交换的数字对
     47   int temp;
     48   int *pMax; //指向数字总和较大的数组
     49   int *pMin; //指向数字总和较小的数组
     50         
     51   //随机初始化数组
     52   init(A, n1);
     53   init(B, n2);
     54   print(A, n1);
     55   print(B, n2);
     56   //求数组中数字之和
     57   maxSum = sum(A, n1);
     58   minSum = sum(B, n2);
     59         
     60   if(maxSum == minSum)
     61     {
     62       printf("There is no need to swap!
    ");
     63       return 0;
     64     }
     65         
     66   //令pMax和pMin分别指向数字总和大的数组以及总和小的数组
     67   pMax = A;
     68   pMin = B;
     69   if(maxSum < minSum)
     70     {
     71       pMax = B;
     72       pMin = A;
     73       swap(&maxSum, &minSum);
     74     }
     75   //循环交换两个数组中的数字对,在交换的过程中,始终
     76   //保持pMax数组的数字总和大于或者等于pMin数组的数字总和。
     77   //也就是保持diff >= 0
     78   diff = maxSum - minSum;
     79   while(1)
     80     {
     81       flag = 0;
     82       x = y = 0;
     83       maxdiff = 0;
     84       //寻找能够使diff减小的数字对。
     85       //从趋势上来看,
     86       //减小的幅度越大diff收敛的越快,
     87       //while循环的次数也越少
     88       for(i = 0; i < n1; ++i)
     89     {
     90       for(j = 0; j < n2; ++j)
     91         {
     92           temp = pMax[i] - pMin[j];
     93           if(temp > 0 && (diff - 2 * temp) >= 0)
     94         {
     95           if(maxdiff < 2 *temp)
     96             {
     97               maxdiff = 2 * temp;
     98               x = i;
     99               y = j;
    100               flag = 1;
    101             }
    102         }
    103         }
    104     }
    105       if(flag) //找到了可以使diff减小的数字对
    106     {
    107       printf("swap, pMax[%d]:%d, pMin[%d]:%d
    ", x, pMax[x], y, pMin[y]);
    108       diff -= maxdiff;
    109       swap(pMax + x, pMin + y);
    110       print(A, n1);
    111       print(B, n2);
    112       printf("diff = %d
    ", diff);
    113 
    114     }
    115       else //没有找到可以交换的数字对,终止while循环
    116     {
    117       break;
    118     }
    119     }
    120   return diff; //返回两个数组经交换后的最小差值
    121 }
    122 
    123 int main(int argc, char **argv)
    124 {
    125   
    126   srand(time(NULL));
    127   printf("min difference:%d
    ", solve(5, 5)); 
    128   //  system("pause");
    129   //  pause();
    130   return 0;
    131 }    

     4. java实现

      1 import java.util.Arrays;
      2 
      3 /**
      4  * 
      5  * @author Administrator
      6  * 
      7  */
      8 public class TestUtil {
      9     private int[] arrysMin = null;
     10 
     11     private int[] arrysMax = null;
     12 
     13     private int matchNum = 0;
     14 
     15     private boolean hasMatched = false;
     16 
     17     /**
     18      * 返回数组的所有元素的总和
     19      * 
     20      * @param arrays
     21      *            待计算数组
     22      * @return 所有元素的总和值
     23      */
     24     public int getArraySum(int[] arrays) {
     25         int sum = 0;
     26         if (null != arrays) {
     27             for (int i : arrays) {
     28                 sum += i;
     29             }
     30         }
     31         return sum;
     32     }
     33 
     34     /**
     35      * 返回数组的差值
     36      * 
     37      * @param array1
     38      *            集合一
     39      * @param array2
     40      *            集合二
     41      * @return 差值
     42      */
     43     public int getTowArraysMacth(int[] array1, int[] array2) {
     44         Integer l1 = getArraySum(array1);
     45         Integer l2 = getArraySum(array2);
     46 
     47         if ((l1 - l2) / 2 > 0) {
     48             arrysMax = array1;
     49             arrysMin = array2;
     50             return (l1 - l2) / 2;
     51         } else {
     52             arrysMax = array2;
     53             arrysMin = array1;
     54             return (l2 - l1) / 2;
     55         }
     56     }
     57 
     58     private boolean isReturn(int[] arrayMax, int[] arrayMin) {
     59         Integer l1 = getArraySum(arrayMax);
     60         Integer l2 = getArraySum(arrayMin);
     61 
     62         if ((l1 - l2) > 0) {
     63             return false;
     64         } else {
     65             return true;
     66         }
     67     }
     68 
     69     public void doMatch() {
     70         // 保证大的数组总和永远是大的,以防递归进入死循环
     71         if (isReturn(arrysMax, arrysMin)) {
     72             return;
     73         }
     74         // 获取元素总和大的与小的差值平均值
     75         int diff = getTowArraysMacth(arrysMax, arrysMin);
     76         // 使用一个大数字初始化最小绝对值,后面做比较
     77         int abs = getArraySum(arrysMax);
     78         int tempElement = 0;
     79         // 最终大数组要交换的下标
     80         int maxIndex = -1;
     81         int minIndex = -1;
     82         if (null != arrysMax && null != arrysMin) {
     83             for (int i = 0; i < arrysMax.length; i++) {
     84                 for (int j = 0; j < arrysMin.length; j++) {
     85                     int temp = arrysMax[i] - arrysMin[j];
     86                     if (temp > 0 && diff > temp) {
     87                         // 如果元素差值和元素总和大的与小的差值平均值正好相等,直接交换元素OK
     88                         if (Math.abs(diff - temp) == 0) {
     89                             tempElement = arrysMin[j];
     90                             arrysMin[j] = arrysMax[i];
     91                             arrysMax[i] = tempElement;
     92                             matchNum++;
     93                             hasMatched = true;
     94                             return;
     95                         } else {
     96                             // 否则完全遍历,最终找出元素差值和总和差值平均值差距最小的两元素,
     97                             if (abs > Math.abs(diff - temp)) {
     98                                 abs = Math.abs(diff - temp);
     99                                 maxIndex = i;
    100                                 minIndex = j;
    101                             }
    102                         }
    103                     }
    104                 }
    105             }
    106             //如果没有找到匹配项,且在已变换的数组中找到了满足条件的变量,则继续递归
    107             if (!hasMatched && (maxIndex != -1 || minIndex != -1)) {
    108                 // 交换差距最小的两元素
    109                 System.out.printf("第%d次交换, Max[%d]:%d, Min[%d]:%d
    ", ++matchNum, maxIndex, arrysMax[maxIndex], minIndex, arrysMin[minIndex]);
    110                 tempElement = arrysMin[minIndex];
    111                 arrysMin[minIndex] = arrysMax[maxIndex];
    112                 arrysMax[maxIndex] = tempElement;
    113                 System.out.println("交换后Max数组:" + Arrays.toString(arrysMax));
    114                 System.out.println("交换后Min数组:" + Arrays.toString(arrysMin));
    115                 System.out.println();
    116                 // 递归
    117                 doMatch();
    118             }
    119         }
    120     }
    121 
    122     public int getMatchNum() {
    123         return matchNum;
    124     }
    125 
    126     /**
    127      * @param args
    128      */
    129     public static void main(String[] args) {
    130         TestUtil tu = new TestUtil();
    131         int[] a1 = { 11, 2, 4, 6, 47 };
    132         int[] a2 = { 4, 5, 8, 9, 2 };
    133         System.out.println("交换前数组a1:" + Arrays.toString(a1));
    134         System.out.println("交换前数组a2:" + Arrays.toString(a2));
    135         // 进行第一次分出,两元素的总和谁大谁小
    136         tu.getTowArraysMacth(a1, a2);
    137         // 开始进行处理交换
    138         tu.doMatch();
    139         // 打印交换结果
    140         System.out.println("交换次数:" + tu.getMatchNum());
    141         System.out.println("a1数组元素和:" + tu.getArraySum(a1));
    142         System.out.println("a2数组元素和:" + tu.getArraySum(a2));
    143         System.out.println("交换后原数组a1:" + Arrays.toString(a1));
    144         System.out.println("交换后原数组a2:" + Arrays.toString(a2));
    145     }
    146 }

     参考链接:http://blog.csdn.net/kittyjie/article/details/4386742

          http://www.myexception.cn/program/758365.html (此页面中的java实现是有问题的,本文已对其作出修改)

  • 相关阅读:
    An analysis of a simple Java basic interview question: short s1=1; s1 = s1 +1 will report an error?
    <bits/stdc++.h> in C++
    linux 下配置可视化git 冲突合并工具kdiff3
    加分
    对老师的意见和课程总结
    12月19日
    12月18日
    12月17日
    12月16日
    12月15日
  • 原文地址:https://www.cnblogs.com/beanmoon/p/3689107.html
Copyright © 2011-2022 走看看