交换两个数组的元素,使两个数组和的差最小

来源:互联网 发布:mac怎么隐藏硬盘文件 编辑:程序博客网 时间:2024/05/22 08:25

前些时候面试碰到的题目:有两个有序正整数数组array1[N]、array2[M],通过交换两数组的元素,使两个数组的和最接近。

 基本算法思路:

每次从array1、array2选择出一对能使交换后得array1和与array2和的差值变小的组合array1[i]、array2[j]作交换;直到对任意组合array1[i]、array2[j]作交换,array1和与array2和的差值都无法变得更小,算法即结束。

 网上查了下,基本有两种算法:

(1)       暴力算法:采用双重循环取逐一比较组合array1[i]、array2[j],只要交换能让array1和与array2和的差值变小,即进行交换;直到算法结束。

 (2)       贪心算法:采用双重循环逐一比较取组合,找到交换后能让array1和与array2和的差值变得最小的组合array1[i]、array2[j],才进行交换;直到算法结束。

上面的贪心算法中为寻找最优组合,采用双重循环逐一比较,算法时间复杂度最好也只有O(N*M) ( 若N=M即(N^2) )。自己琢磨了一段时间,同样采用贪心算法,发现寻找最优组合的算法时间复杂度可以达O(N+M) ( 若N=M即(N) ),下面是相关分析:

 假设sum(array1) > sum(array2):

当前数组array1和数组aarray2的和之差为:

 A = sum(array1) - sum(array2)

 对组合array1[i]、array2[j],交换后,array1与array2的和之差为:

A' = sum(array1) - array1 [i] + array2 [j] - (sum(array2) - array2 [j] + array1 [i])
           = sum(array1) - sum(array2) - 2 (array1 [i] - array2 [j])
           = A - 2 (array1 [i] - array2 [j])

 设x = array1[i] - array2 [j]

最优组合即为使得x最接近A/2的一对array1[i]、array2[j]组合。

  我给出的寻找最优组合的算法思路:

首先,将i,j初始化为0,

若当前array1[i] - array2 [j]> A/2,即array2 [j]偏小;执行操作j++ 再进行比较;

若当前array1[i] - array2 [j]< A/2,即array2 [i]偏小;执行操作i++ 再进行比较;

直到i=N-1,j=M-1,算法时间复杂度为O(N+M)。

 

举例分析:

Array1[LENGTH2]={7, 15, 18, 23, 38,42}    sum(array1)=  143

 Array2[LENGTH1]={ 3,12,16, 27, 29, 35}    sum(array2)=  122

 A = sum(array1) - sum(array2)=  21

 A/2 = 10.5

需要找一组合array1[i]、array2[j],array1[i] - array2[j] 最接近10.5

 第一次比较array1[ 0 ] - array2[ 0 ] = 4 < 10.5 然后i++

 第二次比较array1[ 1 ] - array2[ 0 ] = 12 > 10.5然后j++

 第三次比较array1[1 ] - array2[ 1 ] = 3 > 10.5然后j++

 …….

如下图所示,总共最多进行了11次比较。

 

与双重循环取逐一比较相比可以发现:双重循环取逐一比较中很多的比较都是多余的,因为对升序数组:

如果array1[ 0 ] - array2[ 0 ] = 4 < 10.5

必有array1[ 0 ] - array2[ 1 ] < array1[ 0 ] - array2[ 0 ] = 4 < 10.5

即与array1[ 0 ] 、array2[ 0 ]相比array1[ 0 ] - array2[ 1 ]绝不是更好的组合

所以接着只需对i++ 即array1[ 1 ] - array2[ 0 ] 与10.5 进行比较

 

如果array1[ 1 ] - array2[ 0 ] = 12 > 10.5

必有array1[ 2 ] - array2[ 0 ] > array1[ 1 ] - array2[ 0 ] = 12 > 10.5

即与array1[ 2 ] 、array2[ 0 ]相比array1[ 1 ] - array2[ 0 ]绝不是更好的组合

所以接着只需对j++ 即array1[ 1 ] - array2[ 1 ] 与10.5 进行比较

 附带C源码:

 #include<stdio.h>
#include<math.h>

#define LENGTH1  8
#define LENGTH2  8

int endflag=0;

int ksort(int *array,int temp,int length,int j)            //用temp替换array[j],并将数组排序
{     
   int k=j;       
   while( k>0&&array[k-1]>temp )
   {
       array[k] = array[k-1];
       k--;
   }  
                            
   while(( k<length-1)&&(array[k+1]<temp) )
  {
       array[k] = array[k+1];
       k++;
   }

   array[k] = temp;

    return 0;
}


int mini_tmp(int *min_i , int *min_j , int *min_temp, int now_temp, int i, int j) //如果当前组合比最优组合更好,则重置最优组合
{
 
 if( (*min_temp) > now_temp)
  {
   *min_i = i;
   
   *min_j = j;
   
   *min_temp = now_temp;
   
  }
 return 0; 
 
}


int kv_change(int *array1,int *sum1,int leng1,int *array2,int *sum2,int leng2,int flag)     //sum1<sum2  

     int i,j,k;
    
     int temp = 0,temp1 = *sum2 - *sum1,temp2;
     
     int min_i=0,min_j=0,min_temp = temp1;
      
   for(i=0,j=0;;)
   {

     if( (j==leng2-1)&&(i==leng1-1) )
     {
              
               mini_tmp(&min_i , &min_j , &min_temp, abs( 2*(array2[j]-array1[i]) - temp1 ), i, j);

               break;
     }
     else if( (j==leng2-1)&&(i<leng1-1) )
     {
     
         if( abs( 2*(array2[j]-array1[i]) - temp1) < abs( temp1 - 2*(array2[j]-array1[i+1]) ) )
         {         
              mini_tmp(&min_i , &min_j , &min_temp, abs( 2*(array2[j]-array1[i]) - temp1 ), i, j);
              break;
         } 
         else
         {
           i++;
         }
    
     }
     else if( (j<leng2-1)&&(i==leng1-1) )
     {      
        
         if( abs( 2*(array2[j]-array1[i]) - temp1 ) < abs( temp1 - 2*(array2[j-1]-array1[i]) ) )
         {
              mini_tmp(&min_i , &min_j , &min_temp, abs( 2*(array2[j]-array1[i]) - temp1 ), i, j);
              break;
         } 
         else
         {
           j--;
         }      
     }       
     else
     { 
           mini_tmp(&min_i , &min_j , &min_temp, abs( 2*(array2[j]-array1[i]) - temp1 ), i, j);
          
           if( 2*(array2[j]-array1[i]) < temp1 )
           {
                    j++;        
           } 
           else if( 2*(array2[j]-array1[i]) > temp1 )
          {
              i++; 
          }
          else
          {  
             endflag = 1;                 
             break;
          } 
   
       } 

      }
     
     
     if( 1 )
     {     
     
     i = min_i;
     j = min_j;
     
     temp2 = min_temp;
     
  //    printf("min_i = %d ,min_j = %d ,min_temp = %d\n", min_i ,min_j ,min_temp );
     
   //  temp2 = abs( temp1 - 2*(array2[j]-array1[i]) );        

     if(temp2<temp1)
     {
      
     if(flag)
      {    
          printf("Exchange array1[%d] = %d ,array2[%d] =%d\n",i,array1[i],j,array2[j]);
     }
     else
     {
        printf("Exchange array2[%d] = %d ,array1[%d] =%d\n",i,array1[i],j,array2[j]);
    
     }    

          
     temp = array1[i];                       //change need to sort
  
        *sum1 = *sum1 + (array2[j]-array1[i]);   
        *sum2 = *sum2 - (array2[j]-array1[i]);     
       
        ksort( array1, array2[j], leng1, i);     //sort array1
        
        ksort( array2, temp, leng2, j);      //sort array2
  
       
      }
      else              // the end,no need to change anymore
      {
         endflag = 1;
      }
     
     }
   
      return 0;
}


int main(void)
{
 int array1[LENGTH1]={7, 15, 18, 23, 38,42,57,64},array2[LENGTH2]={ 3,12,16, 27, 29, 35,43,50};
 
 int i,j,k;
 
 int temp = 0,temp1 = 0,temp2 = -1;
 
 int sum1=0,sum2=0;
 
 for(i=0;i<LENGTH1;i++)
 {
  sum1+=array1[i];
  printf("%d ",array1[i]);
  }
  printf("\n");   
 for(j=0;j<LENGTH2;j++)
 {
  sum2+=array2[j];
  printf("%d ",array2[j]);
 }
   printf("\n");   
 
 while( (sum1 != sum2)&&(endflag != 1) )
 {
  
   printf("sum1 = %d ,sum2 =%d \n",sum1,sum2);
 
   if(sum1 < sum2)
   {

           kv_change(array1, &sum1, LENGTH1, array2, &sum2, LENGTH2, 1 );
   }

   else
   {

           kv_change(array2, &sum2, LENGTH2, array1, &sum1, LENGTH1, 0);
   } 
   
   
     for(i=0;i<LENGTH1;i++)
     {
          printf("%d ",array1[i]);
      }
      printf("\n");   
     for(j=0;j<LENGTH2;j++)
     { 
        printf("%d ",array2[j]);
     }
     printf("\n"); 
   
  }

 return 0;
}

原创粉丝点击