给定两个数组,交换它们的元素,使得两数组元素之和的差绝对值最小


/*
 * =====================================================================================
 *
 *       Filename:  arrydiff.cpp
 *
 *    Description:  test
 *
 *        Version:  1.0
 *        Created:  2012年09月11日 22时34分30秒
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  (http://blog.csdn.net/njzhiyuan)
 *   Organization:  
 *
 * =====================================================================================
 */

#include <iostream>

extern "C" {
#include <stdlib.h>
#include <math.h>
#include <time.h>
}
#include <string>
using namespace std;
/**
*sum_a 第一个数组的和
*a 第一个数组中一个元素
*sum_b 第二个数组的和
*b 第二个数组中一个元素
×函数返回假如交换a、b元素后,两数组元素之和的差,原始试子应为(sum_a - a + b) - (sum_b - b + a)
*/
template<typename T>
inline T get_swap_diff(const T &sum_a, const T &a,const T &sum_b, const T &b){
    return abs(sum_a - sum_b - 2 * a + 2 * b);
}

//此处在std里已有,这里属重复定义,故注释
/*template<typename T>
void swap(T &a, T &b){
    T temp = a;
    a = b;
    b = temp;
}*/

//求数组元素之和
template<typename T, size_t element_nums>
T array_sum(const T(&array)[element_nums]){
    T sum = 0;
    for(size_t i = 0; i < element_nums; ++i)
        sum += *(array + i);
        
    return sum;
}

/**
*实现两个数组间元素的交换,使两数组元素之和的差最小,思想如下:
*如果两数组元素之和的差已经最小,那么任意交换两数组的元素,都不能使差再减小,故这可以作为最外层循环的退出条件。
*依次选取第一个数组的元素a,再从第二个数组中选出一元素b,使得a、b交换能使得两数组元素之和的差减小得最多。
*交换a、b,重新计算两数组的两数组元素之和及它们的差。重复上述步骤,如果不能再使差减小了,就退出外层循环。
*/
template<typename T, size_t element_nums>
void min_diff(T(&arr_a)[element_nums], T(&arr_b)[element_nums]){
    bool flag;
    
    do{
        flag = false;
        
        T sum_a = array_sum(arr_a);
        T sum_b = array_sum(arr_b);
        
        if(sum_a == sum_b) break;

        T diff = abs(sum_a - sum_b);
        
        for(size_t index_a = 0; index_a < element_nums; ++index_a){
            size_t temp_index;
            bool chang_flag = false;
            
            for(size_t index_b = 0; index_b < element_nums; ++index_b){
                if(diff > get_swap_diff(sum_a, *(arr_a + index_a), sum_b, *(arr_b + index_b))){
                    diff = get_swap_diff(sum_a, *(arr_a + index_a), sum_b, *(arr_b + index_b));
                    temp_index = index_b;
                    
                    chang_flag = true;
                }
            }
            
            if(chang_flag){
                swap(*(arr_a + index_a),*(arr_b + temp_index));
                
                //已调用swap交换了元素,两数组的两数组元素之和时须注意。
                sum_a = sum_a + *(arr_a + index_a) - *(arr_b + temp_index);
                sum_b = sum_b + *(arr_b + temp_index) - *(arr_a + index_a);
                
                flag = true;
            }
        }
    }while(flag);
}

//显示数组元素
template<typename T, size_t element_nums>
void array_display(const T (&array)[element_nums]){
    for(size_t i=0; i < element_nums; ++i)
    cout << *(array + i) << '\t';
    
    cout << endl;
}

//给数组元素赋随机值
template<typename T, size_t element_nums>
void create_value(T (&array)[element_nums],int seed = 100){
    size_t i = 0;
    srand((unsigned) time(NULL) + seed);
    
    while(i < element_nums){
        *(array + i++) = static_cast<T>(rand() % 1000);
    }
}

// 下面的几个函数参数中,数组名作为是指针传递参数,实现的功能与以上同名函数相同
template<typename T>
T array_sum(const T *array, size_t element_nums){
    T sum = 0;
    for(size_t i = 0; i < element_nums; ++i)
        sum += *(array + i);
        
    return sum;
}

template<typename T>
void min_diff(T *arr_a,T *arr_b,size_t element_nums){
    bool flag;
    
    do{
        flag = false;
        
        T sum_a = array_sum(arr_a,element_nums);
        T sum_b = array_sum(arr_b,element_nums);

        if(sum_a == sum_b) break;

        T diff = abs(sum_a - sum_b);
        
        for(size_t index_a = 0; index_a < element_nums; ++index_a){
            size_t temp_index;
            bool chang_flag = false;
            
            for(size_t index_b = 0; index_b < element_nums; ++index_b){
                if(diff > get_swap_diff(sum_a, *(arr_a + index_a), sum_b, *(arr_b + index_b))){
                    diff = get_swap_diff(sum_a, *(arr_a + index_a), sum_b, *(arr_b + index_b));
                    temp_index = index_b;
                    
                    chang_flag = true;
                }
            }
            
            if(chang_flag){
                swap(*(arr_a + index_a),*(arr_b + temp_index));
                
                sum_a = sum_a + *(arr_a + index_a) - *(arr_b + temp_index);
                sum_b = sum_b + *(arr_b + temp_index) - *(arr_a + index_a);
                
                flag = true;
            }
        }
    }while(flag);
}

template<typename T>
void array_display(const T *array,size_t element_nums){
    for(size_t i=0; i < element_nums; ++i)
    cout << *(array + i) << '\t';
    
    cout << endl;
}

template<typename T >
void create_value(T *array,size_t element_nums,int seed = 100){
    size_t i = 0;
    
    srand((unsigned) time(NULL) + seed);
    while(i < element_nums){
        *(array + i++) = static_cast<T>(rand() % 1000);
    }
}

//指针形式参数系列函数的测试
void pt_test(){ 
    while(true){
        size_t array_size;
        
        string size_temp; //避免直接cin>>array_size,因为输入非数值字符时,会导致意想不到的错误
        cout << "Please input the size of array: ";
        cin>>size_temp;
        
        if((array_size = atol(size_temp.c_str())) < 1)
            array_size = 10;
        
        long *array_a;
        long *array_b;
        
        if((array_a = new long[array_size]) == NULL){
            cout << "Apply space for the first array failed!"<<endl;
            break;
        }
        
        if((array_b = new long[array_size]) == NULL){
            cout << "Apply space for the second array failed!"<<endl;
            delete[] array_a;
            break;
        }
        
        create_value(array_a,array_size);
        create_value(array_b,array_size,rand());
        
        cout << "before the change:\n";    
        array_display(array_a,array_size);
        array_display(array_b,array_size);
        cout << "array_a sum " << array_sum(array_a,array_size) << endl;
        cout << "array_b sum " << array_sum(array_b,array_size) << endl;
        
        min_diff(array_a,array_b,array_size);
        
        cout << "after the change:\n";    
        array_display(array_a,array_size);
        array_display(array_b,array_size);
        cout << "array_a sum " << array_sum(array_a,array_size) << endl;
        cout << "array_b sum " << array_sum(array_b,array_size) << endl;
        
        delete[] array_a;
        delete[] array_b;
        
        cout << "Do you want to continue with this program? Y/N : ";
        char response;
        cin>>response;
        if(response != 'Y' && response != 'y')
            break;
    }
}

//引用形式参数系列函数的测试
void ref_test(){
    const size_t size =10;
    int array_a[size];
    int array_b[size];
    
    create_value(array_a);
    create_value(array_b,rand());
    
    cout << "before the change:\n";    
    array_display(array_a);
    array_display(array_b);
    cout << "array_a sum " << array_sum(array_a) << endl;
    cout << "array_b sum " << array_sum(array_b) << endl;
    
    min_diff(array_a,array_b);
    
    cout << "after the change:\n";    
    array_display(array_a);
    array_display(array_b);
    cout << "array_a sum " << array_sum(array_a) << endl;
    cout << "array_b sum " << array_sum(array_b) << endl;
}

int main(int argc, char *argv[]){
    ref_test();
    pt_test();    
    return 0;
}



 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
根据引用\[1\]和引用\[2\]的内容,我们可以使用状态压缩法来枚举所有可能的分组情况。对于给定数组,我们可以将每个元素放入数组1或数组2中,用二进制的1和0来表示。然后,我们可以计算每种分组情况下两个数组的和之绝对值,并找到最小的值。 举个例子,对于输入数组nums = \[2,-1,0,4,-2,-9\],我们可以将其分成 \[2,4,-9\] 和 \[-1,0,-2\] 两个数组,它们的和之绝对值为 abs((2 + 4 + -9) - (-1 + 0 + -2)) = 0。这就是最优的分组方案。 因此,我们可以通过枚举所有可能的分组情况,并计算每种情况下的值,找到最小的值来实现将数组分成两个数组,并最小化数组和的。 #### 引用[.reference_title] - *1* [2035. 将数组分成两个数组并最小化数组和的 折半搜索](https://blog.csdn.net/yu_duan_hun/article/details/125899854)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [[Leetcode]5897. 将数组分成两个数组并最小化数组和的](https://blog.csdn.net/gshgsh1228/article/details/120692058)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值