编程之美2.18 数组分割 原创解O(nlogn)的时间复杂度求解:

题目:有一个无序、元素个数为2n的正整数组,要求:如何能把这个数组分割为元素个数为n的两个数组,并使两个子数组的和最接近?

1 1 2 -> 1 1 vs  2

看题时,解法的时间复杂度一般都大于或等于O(n^2)。突然灵感一闪,发现一个新的解法,应该算是一个动态规划的过程吧,思路比较简单,请看代码。空间复杂度O(nlogn),时间复杂度O(n)。但是不能确定是否适用所有正整数组,如果有错,请给出你的测试用例,谢谢!

代码如下:

 1  1 #include <iostream>
 2  2 #include <vector>
 3  3 using namespace std;
 4  4
 5  5 int compare(const void *in_iLeft, const void *in_iRight) {
 6  6     int *a = (int*) in_iLeft;
 7  7     int *b = (int*) in_iRight;
 8  8      return *a - *b ;
 9  9
10 10 }
11 11 int main() {
12 12     vector<int> t_Vec;
13 13     int t_ivalue;
14 14     int t_iLen = 0;
15 15     cin >> t_ivalue;
16 16     while(t_ivalue != 0) {    //输入为0,则停止输入
17 17            t_Vec.push_back(t_ivalue);
18 18         t_iLen ++;
19 19         cin >> t_ivalue;
20 20
21 21      }
22 22      int* t_pArr = new int[t_iLen];
23 23      for(int i = 0; i < t_iLen; i++) {
24 24          t_pArr[i] = t_Vec[i];
25 25      }
26 26      qsort(t_pArr, t_iLen, sizeof(int), compare);
27 27      int* t_pLeftArr = new int[t_iLen];
28 28      int* t_pRightArr = new int[t_iLen];
29 29      memset(t_pLeftArr, 0, t_iLen);
30 30      memset(t_pRightArr, 0, t_iLen);
31 31      int t_iSumLeft = t_pArr[t_iLen-1];
32 32      int t_iSumRight = t_pArr[t_iLen-2];
33 33      int t_iLeftIter = 1;
34 34      int t_iRightIter = 1;
35 35      t_pLeftArr[0] = t_pArr[t_iLen-1];
36 36      t_pRightArr[0] = t_pArr[t_iLen-2];
37 37      for(int i = t_iLen - 3; i >= 0 ; i --) {
38 38         if(t_iSumLeft < t_iSumRight) {
39 39             if(t_pArr[i] > 0) {
40 40                 t_pLeftArr[t_iLeftIter ++] = t_pArr[i];
41 41                 t_iSumLeft += t_pArr[i];
42 42             }else {
43 43                 t_pRightArr[t_iRightIter ++] = t_pArr[i];
44 44                 t_iSumRight += t_pArr[i];
45 45             }
46 46         }else {
47 47             if(t_pArr[i] > 0) {
48 48             t_pRightArr[t_iRightIter ++] = t_pArr[i];
49 49             t_iSumRight += t_pArr[i];
50 50             }else {
51 51             t_pLeftArr[t_iLeftIter ++] = t_pArr[i];
52 52             t_iSumLeft += t_pArr[i];
53 53             }
54 54         }
55 55      }
56 56      cout << "打印原序列:"<< endl;
57 57      for(int i = 0; i < t_iLen; i ++) {
58 58         if(t_pArr[i] != 0) {
59 59         cout << t_pArr[i] << " ";
60 60         }else {
61 61             break;
62 62         }
63 63      }
64 64      cout << endl;
65 65
66 66      cout << "打印第一个序列:";
67 67      for(int i = 0; i < t_iLeftIter; i ++) {
68 68         if(t_pLeftArr[i] != 0) {
69 69         cout << t_pLeftArr[i] << " ";
70 70         }else {
71 71             break;
72 72         }
73 73      }
74 74      cout << endl;
75 75      cout << "第一个序列合为:" << t_iSumLeft << endl;
76 76
77 77      cout << "打印第二个序列:";
78 78      for(int i = 0; i < t_iRightIter; i ++) {
79 79         if(t_pRightArr[i] != 0) {
80 80         cout << t_pRightArr[i] << " ";
81 81         }else {
82 82             break;
83 83         }
84 84      }
85 85      cout << endl;
86 86      cout << "第二个序列合为:" << t_iSumRight << endl;
87 87      t_Vec.clear();
88 88      delete[] t_pArr;
89 89      delete[] t_pLeftArr;
90 90      delete[] t_pRightArr;
91 91       system("pause");
92 92       return 0;
93 93
94 94
95 95 }

但是如果题目改成任意整数时你该怎么解答了呢? :)

时间: 2024-10-25 13:41:47

编程之美2.18 数组分割 原创解O(nlogn)的时间复杂度求解:的相关文章

编程之美2.18—数组分割

题目: 有一个没有排序,元素个数为2N的正整数数组.要求把它分割为元素个数为N的两个数组,并使两个子数组的和最接近. 基本思想: 假设数组A[1..2N]所有元素的和是SUM.模仿动态规划解0-1背包问题的策略,令S(k, i)表示前k个元素中任意i个元素的和的集合. 显然: S(k, 1) = {A[i] | 1<= i <= k} S(k, k) = {A[1]+A[2]+-+A[k]} S(k, i) = S(k-1, i) U {A[k] + x | x属于S(k-1, i-1) }

编程之美2.17 数组循环移位

问题描述: 设计一个算法,把一个含有N元素的数组循环左移或者右移K位. 解决方法: 1. 暴力解法------O(KN) 2. 颠倒位置------O(N) 具体思路和代码: 1. 暴力解法------O(KN) 思路:循环K次,每次移动一位 代码: 1 //右移 2 void s1(int A[], int n, int k) 3 { 4 k = k % n; 5 for(int i = 0; i < k; i++) 6 { 7 int t = A[n-1]; 8 for(int j = n-

编程之美6:数组循环移位

楼主又来~(≧▽≦)/~啦啦啦,科研,就是要这么一鼓作气.额,其实楼主的老本行是推公式啊,做这些算法题,其实是楼主在偷懒.额,话不多说了,快请出我们今天的主角吧!还是关于数组的-数组循环移位. 下面我们来看下题目的要求. 题目要求: 设计一个算法,把一个含有N个元素的数组循环右移K位,要求时间复杂度为O(N),且只允许使用两个附加变量. 题目解答 我们来自己给个例子,来帮助自己思考.如数组为[1, 2, 3, 4, 5, 6, 7, 8],循环移位4次. 原始序列:[1, 2, 3, 4, 5,

编程之美2.17—数组循环移位(旋转数组)

题目: 把一个含有N个元素的额数组循环右移K位,要求时间复杂度O(N),且只允许使用两个附加变量. 解法一:O(N^2) 每次将数组中的元素右移移位,循环K次.当K>N时,右移K位和右移K%N位是一样的. MyShift(int a[],int N,int K) { K%=N; while(K--) { int t=a[N-1]; for(int i=N-1;i>0;i--) a[i]=a[i-1]; a[0]=t; } } 解法二:O(N) 假如数组abcd1234 1.逆序abcd:abc

编程之美 2.18数组分割

1.插入法 import java.util.*; public class Main{ public static void main(String[] args) { int[] nums={1,5,7,8,9,6,3,11,20,17}; int N=5; ArrayList<ArrayList<Integer>> lists=new ArrayList<ArrayList<Integer>>(); for(int i=0;i<=N;i++){

编程之美2.17之数组循环移位

题目描述:设计一个算法,把一个含有N个元素的数组循环右移K位,要求算法的时间复杂度位O(Log2N),且只允许使用两个附加变量. 什么意思呢,就是说如果输入序列为:abcd1234,右移2位即变为34abcd12.唯一的要求就是使用两个附加变量. 其实这道题编程珠玑上面也出现过,书中给出的一种符合题意的解法是巧妙地进行翻转.以把abcd1234右移4位为例: 第一步:翻转1234,abcd1234---->abcd4321 第二步:翻转abcd,abcd4321---->dcba4321 第三

编程之美2.14 求数组的子数组之和的最大值

问题描述: 一个有N个整数元素的一维数组(A[0], A[1], A[2],...,A[n-1]),这个数组当然有很多子数组,那么子数组之和的最大值是什么呢? 解法: 1. 暴力解法-------O(N^3) 2. 改进版暴力解法-------O(N^2) *3. 分治算法-------O(NlogN)(暂时未去实现) 4. 数组间关系法-------O(N) 具体思路和代码: 1.暴力解法 思路:Sum[i,...,j]为数组第i个元素到第j个元素的和,遍历所有可能的Sum[i,...,j].

编程之美2.13 子数组最大乘积

问题描述: 给定一个长度为N的整数数组,只允许用乘法,不能用除法,计算任意(N-1)个数的组合乘积中最大的一组,并写出算法的时间复杂度. 解法: 1.暴力解法------O(n^2) 2.前后缀法------O(n) 3.统计法--------O(n) 具体思路和代码: 1.暴力解法: 思路:利用两层循环,依次删掉一个,其余的做乘法,计算出最大的. 代码: 1 int s1(int A[], int n) 2 { 3 int s = 1; 4 int max; 5 for(int i = 1;

【目录】编程之美

编程之美 2.1 二进制数中1的个数 2.2 阶乘 2.4 1的数目 2.5 寻找最大的k个数 2.6 精确表达浮点数 2.7求最大公约数 2.8 找符合条件的整数 2.10 求数组中最大的数和最小的数 2.12快速寻找满足条件的两个数 2.13 子数组的最大乘积 2.14 求数组的子数组之和的最大值 2.15 子数组之和的最大值(二维) 2.16 求数组的最大递增子序列 2.17 数组循环位移 2.18 数组分割 2.19 区间重合判断 2.20程序理解和时间分析 2.21 只考加法的面试题