数据结构 --- 数组

来源:互联网 发布:ps大小尺寸怎么调整mac 编辑:程序博客网 时间:2024/04/29 22:14

1. 求数组中第二大的数

1.  //定义两个变量2.  const int MINNUMBER = -32767 ;  3.  int find_sec_max( int data[], int count)                     4.  {                                                       5.      int maxnumber = data[0] ;                               6.      int sec_max = MINNUMBER ;                   7.      for ( int i =1 ; i < count ; i++)                       8.      {   9.          if ( data[i] > maxnumber ) 10.         { 11.              sec_max = maxnumber ; 12.              maxnumber = data[i] ; 13.         } 14.         else 15.         { 16.             if ( data[i] > sec_max ) 17.             sec_max = data[i] ; 18.         } 19.     } 20.     return sec_max ; 21. }

2. 求数组的子数组之和的最大值 — 动态规划

设sum[i]为以第i个元素结尾且和最大的连续子数组。假设对于元素i,所有以它前面的元素结尾的子数组的长度都已经求得,那么以第i个元素结尾且和最大的连续子数组实际上,要么是以第i-1个元素结尾且和最大的连续子数组加上这个元素,要么是只包含第i个元素,即sum[i] = max(sum[i-1] + a[i], a[i])。可以通过判断sum[i-1] + a[i]是否大于a[i]来做选择,而这实际上等价于判断sum[i-1]是否大于0。由于每次运算只需要前一次的结果,因此并不需要像普通的动态规划那样保留之前所有的计算结果,只需要保留上一次的即可,因此算法的时间和空间复杂度都很小。

1.  int MaxSubSum1(int *A,int n)  2.  {  3.      int start, all;  4.      all = start = A[n-1];  5.      for(int i = n-2; i >= 0; i--)  6.      {  7.          start = Max(A[i], start + A[i]);  //包含当前元素的最大值8.          all = Max(all, start);  9.      }  10.     return all;  11. }  12.  int MaxSubSum2(int *A, int n)13.  {14.     int sum = 0, cur = 0;15.     int max = -(1 << 31);16.     while(cur < n)17.     {18.         sum += A[cur++];19.         if(max < sum)20.             max = sum;21.         else if(sum < 0) //A中有正数和负数22.             sum = 0;23.     }24.     return max;25.   }26. 27. int MaxSubSum3(int *A, int n)28. {29.    int max = A[0];30.    int sum = 0;31.    for(int i = 0; i < n; i++)32.    {33.        if(sum >= 0)34.            sum += A[i];35.        else36.            sum = A[i];37.        if(sum > max)38.            max = sum;39.    }40.    return max;41. }

3. 数对之差的最大值 – 动态规划

在数组中,数字减去它右边的数字得到一个数对之差。求所有数对之差的最大值。例如在数组{2, 4, 1, 16, 7, 5, 11, 9}中,数对之差的最大值是11,是16减去5的结果。
思路:这又是一道动态规划的题目,时间复杂度为O(n)。假设f[i]表示数组中前i+1个数的解,前i+1个数的最大值为m[i]。则有下列式子。
f[i] = max(f[i-1], m[i-1] - a[i]), m[i] = max(m[i-1],a[i])。问题的解为f[n-1]。

1.  int MaxDiff_Solution2(int *pArray, int nLen)  2.  {  3.      if(pArray == NULL || nLen <= 1)  4.          return 0;  5.      int maxDiff = 0;  6.      int maxElem = pArray[0];  7.      for(int i = 1; i < nLen; i++)  8.      {  9.          maxDiff = max(maxDiff, maxElem - pArray[i]);  10.         maxElem = max(maxElem, pArray[i]);  11.     }  12.     return maxDiff;  13. }

4. 数组中只出现1次的两个数字

设题目中这两个只出现1次的数字分别为A和B,如果能将A,B分开到二个数组中,那显然符合“异或”解法的关键点了。因此这个题目的关键点就是将A,B分开到二个数组中。由于A,B肯定是不相等的,因此在二进制上必定有一位是不同的。根据这一位是0还是1可以将A,B分开到A组和B组。而这个数组中其它数字要么就属于A组,要么就属于B组。再对A组和B组分别执行“异或”解法就可以得到A,B了。而要判断A,B在哪一位上不相同,只要根据A异或B的结果就可以知道了,这个结果在二进制上为1的位都说明A,B在这一位上是不相同的。
比如int a[] = {1, 1, 3, 5, 2, 2}
整个数组异或的结果为3^5即 0x0011 ^ 0x0101 = 0x0110
对0x0110,第1位(由低向高,从0开始)就是1。因此整个数组根据第1位是0还是1分成两组。
a[0] =1 0x0001 第一组
a[1] =1 0x0001 第一组
a[2] =3 0x0011 第二组
a[3] =5 0x0101 第一组
a[4] =2 0x0010 第二组
a[5] =2 0x0010 第二组
第一组有{1, 1, 5},第二组有{3, 2, 3},明显对这二组分别执行“异或”解法就可以得到5和3了。

1.  void FindTwoNotRepeatNumberInArray(int *a, int n, int *pN1, int *pN2)  2.  {  3.      int i, j, temp;  4.        5.      //计算这两个数的异或结果  6.      temp = 0;  7.      for (i = 0; i < n; i++)  8.          temp ^= a[i];  9.        10.     // 找第一个为1的位  11.     for (j = 0; j < sizeof(int) * 8; j++)  12.         if (((temp >> j) & 1) == 1)  13.             break;  14.   15.     // 第j位为1,说明这两个数字在第j位上是不相同的  16.     // 由此将整个数组分组即可  17.     *pN1 = 0, *pN2 = 0;  18.     for (i = 0; i < n; i++)  19.         if (((a[i] >> j) & 1) == 0)  20.             *pN1 ^= a[i];  21.         else  22.             *pN2 ^= a[i];  23. }

5. 数组中只出现1次的三个数字

假设x y z为只出现一次的数,其他出现偶数次。lowbit为某个数从右往左扫描第一次出现1的位置,则x^y、 x^z、 y^z 这三个值的lowbit有一个规律,其中肯定两个是一样的,另外一个是不一样的。令flips为上述三个值的异或,即flips=lowbit(a^b)^lowbit(a^c)^lowbit(b^c)。因此,可以利用此条件获得某个x(或者y,或者z),循环判断的条件是a[i]^xors的lowbit==flips(其中xors为所有数的异或值)
解释:a[i]^xors即可划分为两组,一组是lowbit与flips不同,一组是lowbit与flips相同。这样就能找到某个x,y,z,找出后,将其与数组最后一个值交换,在利用上题思路,在前面n-1个数中找出剩余两个。

1.  // lowbit为某个数从右往左扫描第一次出现1的位置2.  int lowbit(int x)3.  {4.      return x & ~(x - 1);5.  }6.  //三个数两两的异或后lowbit有两个相同,一个不同,可以分为两组7.  void Find3(int seq[], int n, int& a, int& b, int& c)8.  {9.      int i, xors = 0;10.     for(i = 0; i < n; i++)11.         xors ^= seq[i];12. 13.     int flips = 0;14.     for(i = 0; i < n; i++) //因为出现偶数次的seq[i]和xors的异或,异或结果不改变15.         flips ^= lowbit(xors ^ seq[i]); //表示的是:flips = lowbit(a^b) ^ lowbit(a^c) ^ lowbit(b^c)16. 17.     //三个数两两异或后lowbit有两个相同,一个不同,可以分为两组18.     //所以flips的值为:lowbit(a^b) 或 lowbit(a^c) 或 lowbit(b^c)19. 20.     //得到三个数中的一个21.     a = 0;22.     for(i = 0; i < n; i++)23.     {24.         if(lowbit(seq[i] ^ xors) == flips)     //找出三个数两两异或后的lowbit与另外两个lowbit不同的那个数25.             a ^= seq[i];26.     }27. 28.     //找出后,与数组中最后一个值交换,利用Find2,找出剩余的两个29.     for(i = 0; i < n; i++)30.     {31.         if(a == seq[i])32.         {33.             int temp = seq[i];34.             seq[i] = seq[n - 1];35.             seq[n - 1] = temp;36.         }37.     }38. 39.     //利用Find2,找出剩余的两个40.     Find2(seq, n - 1, b, c);41. }42. //假设数组中只有2010)、3011)、5101)三个数,23异或后为00125异或后为11135异或后为11043. //则flips的值为lowbit(001)^lowbit(111)^lowbit(110)= 2 ,当异或结果xors与第一个数2异或的时候,得到的就是35异或的结果110,其lowbit值等于flips,所以最先找出来的是三个数中的第一个数:244. 

6. 数组中出现一次的数,其他数字出现3次

如果数组中没有x,那么数组中所有的数字都出现了3次,在二进制上,每位上1的个数肯定也能被3整除。而再对该数组添加任何一个数,如果这个数在二进制的某位上为1都将导致该位上1的个数不能被3整除。因此通过统计二进制上每位1的个数就可以推断出x在该位置上是0还是1了,这样就能计算出x了。推广一下,所有其他数字出现N(N>=2)次,而一个数字出现1次都可以用这种解法来推导出这个出现1次的数字。

1.  int FindNumber(int a[], int n)  2.  {  3.    int bits[32];  //32=sizeof(int)*84.    int i, j;  5.    // 累加数组中所有数字的二进制位  6.    memset(bits, 0, 32 * sizeof(int));  7.    for (i = 0; i < n; i++)  8.      for (j = 0; j < 32; j++)  9.        bits[j] += ((a[i] >> j) & 1);  10.   // 如果某位上的结果不能被整除,则肯定目标数字在这一位上为1  11.   int result = 0;  12.   for (j = 0; j < 32; j++)  13.     if (bits[j] % 3 != 0)  14.       result += (1 << j); //1<<j即第j位为1 15.   return result;  16. }

7. 把数组排成最小的数

输入一个正整数数组,将它们连接起来排成一个数,输出能排出的所有数字中最小的一个。例如输入数组{32, 321},则输出这两个能排成的最小数字32132。请给出解决问题的算法,并证明该算法。
思路:先将整数数组转为字符串数组,然后字符串数组进行排序,最后依次输出字符串数组即可。这里注意的是字符串的比较函数需要重新定义,不是比较a和b,而是比较ab与 ba。如果ab < ba,则a < b;如果ab > ba,则a > b;如果ab = ba,则a = b。比较函数的定义是本解决方案的关键。

1.  //重新定义比较函数对象  2.  struct compare  3.  {  4.      bool operator() (const string &src1, const string &src2)  5.      {  6.          string s1 = src1 + src2;  7.          string s2 = src2 + src1;  8.          return s1 < s2;   //升序排列,如果改为s1 > s2则为逆序排列  9.      }  10. };  11. //函数功能 : 把数组排成最小的数  12. //函数参数 : pArray为数组,num为数组元素个数    13. //返回值 :   无  14. void ComArrayMin(int *pArray, int num)  15. {  16.     int i;  17.     string *pStrArray = new string[num];  18.   19.     for(i = 0; i < num; i++) //将数字转换为字符串  20.     {     21.         stringstream stream;  22.         stream<<pArray[i];  23.         stream>>pStrArray[i];  24.     }  25.   26.     sort(pStrArray, pStrArray + num, compare()); //字符串数组排序  27.   28.     for(i = 0; i < num; i++) //打印字符串数组  29.         cout<<pStrArray[i];  30.     cout<<endl;  31.   32.     delete [] pStrArray;  33. } 

8. 将二个有序数列合并

1.  //将有序数组a[]和b[]合并到c[]中  2.  void MemeryArray(int a[], int n, int b[], int m, int c[])  3.  {  4.      int i, j, k;  5.    6.      i = j = k = 0;  7.      while (i < n && j < m)  8.      {  9.          if (a[i] < b[j])  10.             c[k++] = a[i++];  11.         else  12.             c[k++] = b[j++];   13.     }  14.   15.     while (i < n)  16.         c[k++] = a[i++];  17.   18.     while (j < m)  19.         c[k++] = b[j++];  20. } 

9. 找数组中的特定元素

问题描述:一个int数组,里面数据无任何限制,要求求出所有这样的数a[i],其左边的数都小于等于它,右边的数都大于等于它。能否只用一个额外数组和少量其它空间实现。
思路:如果能用两个辅助数组,那么相对来说简单一点,可定义数组Min和数组Max,其中Min[i]表示自a[i]之后的最小值(包括a[i]),Max[i]表示自a[i]之前元素的最大值。有了这两个辅助数组后,对于a[i],如果它大于Max[i-1]并且小于Min[i+1],那么就符合要求。
但是题目要求是只用一个额外数组,其实Max数组可以省去,完全可以边判断边计算,这是因为Max[i]是自左往右计算的,而判断时也是自左往右,两个过程正好可以合起来。只需用一个变量Max保存一下当前的最大值即可。下面给出两种方法的代码实现。

1.  //函数功能 : 找元素  2.  //函数参数 : pArray指向数组,len为数组的元素个数  3.  //返回值 : 无  4.  void FindElements_Solution1(int *pArray, int len)  5.  {  6.      if(pArray == NULL || len <= 0 )  7.          return ;  8.    9.      int *pMin = new int[len];  10.     int *pMax = new int[len];  11.     int i;  12.   13.     pMax[0] = pArray[0];  14.     for(i = 1; i < len; i++)       //计算自i往前最大值的辅助数组  15.         pMax[i] = (pMax[i-1] >= pArray[i])? pMax[i-1]: pArray[i];  16.     pMin[len-1] = pArray[len-1];  //必须从后往前遍历17.     for(i = len - 2; i >= 0; i--) //计算自i开始最小值的辅助数组  18.         pMin[i] = (pMin[i+1] <= pArray[i])? pMin[i+1]: pArray[i];  19.   20.     if(pArray[0] <= pMin[0])     //检查第1个元素是否满足条件  21.         cout<<pArray[0]<<' ';  22.     for(i = 1; i < len - 1; i++)  23.     {  24.         if(pArray[i] >= pMax[i-1] && pArray[i] <=pMin[i+1]) //满足这个关系式的元素符合要求  25.             cout<<pArray[i]<<' ';  26.     }  27.     if(pArray[len-1] >= pMax[len-1]) //检查第len个元素是否满足条件  28.         cout<<pArray[i];  29.     cout<<endl;  30.   31.     delete [] pMin;  32.     delete [] pMax;  33.     pMin = pMax = NULL;  34. }  1.  void FindElements_Solution2(int *pArray, int len)  2.  {  3.      if(pArray == NULL || len <= 0 )  4.          return ;  5.    6.      int *pMin = new int[len];  7.      int Max;  8.      int i;  9.    10.     Max = pArray[0];  11.     pMin[len-1] = pArray[len-1];  12.     for(i = len - 2; i >= 0; i--) //计算自i开始最小值的辅助数组  13.         pMin[i] = (pMin[i+1] <= pArray[i])? pMin[i+1]: pArray[i];  14.   15.     if(pArray[0] <= pMin[0])     //检查第1个元素是否满足条件  16.         cout<<pArray[0]<<' ';  17.   18.     for(i = 1; i < len - 1; i++)  19.     {  20.         if(pArray[i] >= Max && pArray[i] <=pMin[i+1]) //满足这个关系式的元素符合要求  21.             cout<<pArray[i]<<' ';  22.         Max = (Max < pArray[i])? pArray[i]: Max; //更新当前最大值  23.     }  24.     if(pArray[len-1] >= Max) //检查第len个元素是否满足条件  25.         cout<<pArray[i];  26.     cout<<endl;  27.   28.     delete [] pMin;  29.     pMin = NULL;  30. }

10. 从数列1,2…n中随意取几个数,使其和等于m

输入两个整数n和m,从数列1,2…….n中随意取几个数,使其和等于m,要求将其中所有的可能组合列出来。
思路:这个问题其实背包问题的变形,本文给出两种解法。
解法一:用递归,效率可能低了点。假设问题的解为F(n, m),可分解为两个子问题 F(n-1, m-n)和F(n-1, m)。对这两个问题递归求解,求解过程中,如果找到了符合条件的数字组合,则打印出来。
解法二:用循环,其实就是枚举所有组合。对于n ,组合数应该为2^n。我们可以用一个数字 i 来表示组合。如果i = 5,其二进制形式为101,相应的组合为{1, 3}。也就是说,二进制的每一位都代表一个数字,bit0代表数字1,bit1代表数字2,依次类推。当某位为1,表示选中了该位所表示的数字。

1.  //函数功能 : 从数列1,2...n中随意取几个数,使其和等于m  2.  //函数参数 : n为当前最大值,m为剩余值,flag标记选中与否,len为flag的容量  3.  //返回值 :   无  4.  void BagProblem_Solution1(int n, int m, int *flag, int len)  5.  {  6.      if(n < 1 || m < 1)  7.          return;  8.    9.      if(n < m)  10.     {  11.         flag[n-1] = 1;  12.         BagProblem_Solution1(n-1, m-n, flag, len); //选了n  13.         flag[n-1] = 0;  14.         BagProblem_Solution1(n-1, m, flag, len);   //不选n  15.     }  16.     else  17.     {  18.         flag[m-1] = 1;  //n>=m,选中m即可  19.         for(int i = 0; i < len; i++)  20.         {  21.             if(flag[i] == 1)  22.                 cout<<i+1<<' ';  23.         }  24.         cout<<endl;  25.         flag[m-1] = 0; //不选m,继续递归。比如n = 10,m = 8,求出{1, 7}后,仍需继续,{1,3,4} {1,2,5}都是解  26.         BagProblem_Solution1(m-1, m, flag, len);  27.     }  28. }  1.  //函数功能 : 从数列1,2...n中随意取几个数,使其和等于m  2.  //函数参数 : n为当前最大值,m为剩余值  3.  //返回值 :   无  4.  void BagProblem_Solution2(int n, int m)  5.  {  6.      if(n < 1|| m < 1)  7.          return;  8.      if(n > m)  9.          n = m;  10.   11.     int num = 1<<n;               //枚举次数  12.     for(int i = 1; i < num; i++)  //枚举所有情况  13.     {  14.         int sum = 0;  15.         int j, k;  16.         for(j = i, k = 1; j != 0; j>>=1, k++) //针对每种情况求和,判断是否满足条件 k记录bit位为1的位置17.         {  18.             if(j&1)  19.                 sum += k;  20.         }  21.         if(sum == m) //如果满足,打印结果  22.         {  23.             for(j = i, k = 1; j != 0; j>>=1, k++)  24.             {  25.                 if(j&1)  26.                     cout<<k<<' ';  27.             }  28.             cout<<endl;  29.         }  30.     }  31. }  

11. 旋转数组中的最小元素

把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个排好序的数组的一个旋转,输出旋转数组的最小元素。例如数组{3, 4, 5, 1, 2}为{1, 2, 3, 4, 5}的一个旋转,该数组的最小值为1。
思路:这道题最直观的解法并不难。从头到尾遍历数组一次,就能找出最小的元素,时间复杂度显然是O(n)。但这个思路没有利用输入数组的特性。既然有时间复杂度更小的算法,我们容易想到二分查找,因为它的时间复杂度为O(logn)。这个问题是否可以运用二分查找呢?答案是肯定的。观察一下数组的特性,首先递增(称为递增a),然后突然下降到最小值,然后再递增(称为递增b)。当然还有一种特殊情况,就是数组递增,中间没有下降,即旋转元素个数为0。
对于一般的情况,假设A为输入数组,left 和 right 为数组左右边界的坐标,考察中间位置的值A[mid] ,如果A[mid] <= A[right],表明处于递增b,调整右边界 right = mid;如果A[mid] >= A[left],表明处于递增a,因此调整左边界left = mid。当左右边界相邻时,较小的一个就是数组的最小值。其实,对于一般情况,右边界所指的元素为最小值。
对于特殊情况,即旋转个数为0。按照上述算法,右边界会不断减少,直到与左边界相邻。这时左边界所指的元素为最小值。下面给出几组测试案例:
1. //{1,2,3,4,5,6,7,8,9,10} 1
2. //{4,5,6,7,8,9,10,1,2,3} 1
3. //{1,1,1,1,1,1,1,1,1,1} 1
4. //{1,9,10,1,1,1,1,1,1,1} 1
5. //{9,9,9,9,9,9,9,10,1,9} 9 错误
第五组的结果是错误的。其实,上述算法适用于严格递增的数组,对于非严格递增,用二分法无法保证正确解。有兴趣的读者,可以试试,对于非严格递增的序列,是否可以用二分法得到正确解。

1.  //函数功能 : 旋转数组的最小元素    2.  //函数参数 : pArray指向数组,len为数组长度  3.  //返回值 :   最小元素  4.  int FindMin(int *pArray, int len)  5.  {  6.      if(pArray == NULL || len <= 0)  7.          return 0;  8.      int left = 0, right = len - 1, mid;  9.      while(right - left != 1)  10.     {  11.          mid = left + ((right - left)>>1);  12.          if(pArray[right] >= pArray[mid])   13.              right = mid;  14.          else if(pArray[left] <= pArray[mid])         15.              left = mid;  16.     }  17.     return pArray[right] > pArray[left] ? pArray[left]: pArray[right];  18. }  

12. 求最长单调递减子序列

问题描述:求一个数组的最长递减子序列 比如{9,4,3,2,5,4,3,2}的最长递减子序列为{9,5,4,3,2}。
思路:这是很经典的一个问题,用动态规划解决。假设源数组为A,定义一个辅助数组为B,B[i]表示以A[i]结尾的最长递减序列的长度。举个简单的例子,如果A[i]大于之前的所有元素,那么B[i] = 1。
有了这个辅助数组后,可以推出下面这个递推式子。B[i] = max{B[k] + 1, A[k]>A[i]&&0=

1.  //函数功能 : 打印最长递减子序列  2.  //函数参数 : pArray指向源数组,pB指向辅助数组,k表示最长子序列的末尾元素  3.  //返回值 :   无  4.  void Print(int *pArray, int *pB, int k)  5.  {  6.      for (int i = k - 1; i >= 0; i--)  7.      {  8.          if(pB[k] == pB[i] + 1 && pArray[i] > pArray[k]) //再现动态规划求解的过程,只不过是逆向  9.          {  10.             Print(pArray, pB, i);  11.             break;  12.         }  13.     }  14.     cout<<pArray[k]<<' ';  15. }  16.   17. //函数功能 : 一个数组的最长递减子序列  18. //函数参数 : pArray指向源数组,len表示数组长度  19. //返回值 :   无  20. void FindMDS(int *pArray, int len)  21. {  22.     int i, j, maxi = 0;        //maxi用来记录最长递减序列的末尾元素  23.     int *pB = new int [len];   //辅助空间,pB[i]表示以pAray[i]结尾的最长递减序列长度  24.     for(i = 0 ; i < len; i++)  //初始化  25.         pB[i] = 0;  26.   27.     for(i = 0; i < len; i++)   //计算以pAray[i]结尾的最长递减序列  28.     {  29.         pB[i] = 1;  30.         for(j = 0; j < i; j++)  31.         {  32.             if(pArray[j] > pArray[i] && pB[j] + 1 > pB[i]) //这个判断式是关键  33.             {  34.                 pB[i] = pB[j] + 1;  35.                 if(pB[i] > pB[maxi]) //更新当前找到的最长递减序列  36.                     maxi = i;  37.             }  38.         }  39.     }  40.     Print(pArray, pB, maxi); //打印目标序列  41.     delete [] pB;  42. }

13. 查找最小的k个元素

题目是:输入n 个整数,输出其中最小的k 个。例如输入1,2,3,4,5,6,7 和8 这8 个数字,则最小的4 个数字为1,2,3 和4。
(1)看到题目的时候我第一反应,这题很简单,使用任何方式的排序将数列按顺序存储,之后遍历需要的k个元素即可,于是自己动手很容易就完成了。
(2)咱们想到了用选择或交换排序,即遍历n个数,先把最先遍历到的k个数存入大小为k的数组之中,对这k个数,利用选择或交换排序,找到k个数中的最大数kmax(kmax设为k个元素的数组中最大元素),用时O(k)(你应该知道,插入或选择排序查找操作需要O(k)的时间),后再继续遍历后n-k个数,x与kmax比较:如果x

1.  public static void FindKMin(int[] sort, int k)2.  {3.        int[] heap = sort;4.        int rootIndex = k / 2 - 1;5.        while (rootIndex >= 0)6.        {7.            reheap(heap, rootIndex, k - 1);8.            rootIndex--;9.        }10.   11.      for (int i = k, len=heap.Length; i < len; i++)12.      {13.          if (heap[i]<heap[0])14.          {15.              heap[0] = heap[i];16.              reheap(heap, 0, k - 1);17.          }18.      }19.   20.      Console.WriteLine("The {0} min element =",k);21.      for (int i = 0; i < k; i++)22.      {23.          Console.Write(heap[i] + " ");24.      }25.  }26.   27.  private static void reheap(int[] heap, int rootIndex, int lastInddex)28.  {29.      int orphan = heap[rootIndex];30.      bool done = false;31.      int leftIndex = rootIndex * 2 + 1;32.      while (!done && leftIndex <= lastInddex)33.      {34.          int largerIndex = leftIndex;35.          if (leftIndex+1 <= lastInddex)36.          {37.              int rightIndex = leftIndex + 1;38.              if (heap[rightIndex] > heap[leftIndex])39.              {40.                  largerIndex = rightIndex;41.              }42.          }43.   44.          if (orphan < heap[largerIndex])45.          {46.              heap[rootIndex] = heap[largerIndex];47.              rootIndex = largerIndex;48.              leftIndex = rootIndex * 2 + 1;49.          }50.          else51.          {52.              done = true;53.          }54.      }55.   56.      heap[rootIndex] = orphan;57. }

14. 顺时针打印矩阵

题目:输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字。
例如:如果输入如下矩阵:
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
则依次打印出数字1, 2, 3, 4, 8, 12, 16, 15, 14, 13, 9, 5, 6, 7, 11, 10。
解题思路(借鉴 迷宫问题):1)在矩阵周围 添加一堵墙 (-1);
2)分为四个方向运动,向右,向下,向左,向右。
3)在碰到墙 或者 已经走过的点, 则改变方向,方向的改变依赖上条的四个方向,依次循环找下一个方向。(而具体方向的执行,表现在 下标的改动)。
4)用printCount计数打印了的点数,也就是 走过的路径长度,而总路径长度是size*size的,如果大于它了,则不需要在往下执行

1.  // ClockWisePrintMatrix_顺时针打印矩阵.cpp : Defines the entry point for the console application.  2.  //  3.  #include "stdafx.h"  4.  #define MAX_SIZE 100  5.  int Matrix[MAX_SIZE][MAX_SIZE];  6.  int size;  7.  #define START_X 1  8.  #define START_Y 0  9.  int END_X,END_Y;  10. typedef enum Direction{  11.     RIGHT=0,  12.     DOWN=1,  13.     LEFT=2,  14.     UP=3,  15. };  16. //wall is -1, if has walked also change value to -1  17. void BuildOutsideWall()  18. {  19.     for(int i=0;i<size+2;i++)  20.     {  21.         Matrix[0][i]=-1;  22.         Matrix[size+1][i]=-1;  23.     }  24.     for(int i=1;i<size+2;i++)  25.     {  26.         Matrix[i][0]=-1;  27.         Matrix[i][size+1]=-1;  28.     }  29.       30. }  31. Direction  ChangeDirection(int dir)  32. {  33.     switch (dir)  34.     {  35.     case RIGHT:  36.         return DOWN;  37.     case DOWN:  38.         return LEFT;  39.     case LEFT:  40.         return UP;  41.     case UP:  42.         return RIGHT;  43.     }  44. }  45. void PrintClockWiseMatrix()  46. {  47.     int i=START_X,j=START_Y;  48.     Direction dir=RIGHT;  49.     int printCount=0;  50.     while(printCount<=size*size)  51.     {  52.         switch(dir)  53.         {  54.         case RIGHT:  55.              if(Matrix[i][j+1]!=-1)  56.              {  57.                  j++;  58.                  printf("%d  ",Matrix[i][j]);  59.                  Matrix[i][j]=-1;  //已输出的元素置为-160.                  printCount++;  //控制循环的次数n*n61.              }  62.              else  63.              {  64.                 dir=ChangeDirection(dir);  65.              }  66.              break;  67.         case DOWN:  68.             if(Matrix[i+1][j]!=-1)  69.             {  70.                 i++;  71.                 printf("%d  ",Matrix[i][j]);  72.                 Matrix[i][j]=-1;  73.                  printCount++;  74.             }  75.             else  76.             {  77.                 dir=ChangeDirection(dir);  78.             }  79.                   80.             break;  81.         case LEFT:  82.             if(Matrix[i][j-1]!=-1)  83.             {  84.                 j--;  85.                 printf("%d  ",Matrix[i][j]);  86.                 Matrix[i][j]=-1;  87.                 printCount++;  88.             }  89.             else  90.             {  91.                 dir=ChangeDirection(dir);  92.             }  93.             break;  94.         case UP:  95.             if(Matrix[i-1][j]!=-1)  96.             {  97.                 i--;  98.                 printf("%d  ",Matrix[i][j]);  99.                 Matrix[i][j]=-1;  100.                    printCount++;  101.                }  102.                else  103.                {  104.                    dir=ChangeDirection(dir);  105.                }  106.                break;  107.            }  108.        }  109.            110.    }  111.    int _tmain(int argc, _TCHAR* argv[])  112.    {  113.        scanf("%d",&size);  114.        END_X=END_Y=size;  115.        BuildOutsideWall();  116.        for(int i=1;i<=size;i++)  117.            for(int j=1;j<=size;j++)  118.            {  119.                scanf("%d",&Matrix[i][j]);  120.            }  121.        PrintClockWiseMatrix();  122.        return 0;  123.    } 

15. 寻找和为给定值的两个数

输入一个数组和一个数字,在数组中查找两个数,使得它们的和正好是输入的那个数
字。要求时间复杂度是 O(n)。如果有多对数字的和等于输入的数字,输出任意一对即可。
例如输入数组 1、2、4、7、11、15 和数字 15。由于 4+11=15,因此输出 4 和 11。
不论原序列是有序还是无序,解决这类题有以下三种办法:
1)、二分(若无序,先排序后二分),时间复杂度总为 O(n*logn),空间复杂度为 O(1);
对每个a[i],查找sum-a[i]是否也在原始序列中。
2)、扫描一遍,X-S[i]映射到一个数组或构造hash表(大小由和决定,在没有负数的情况下),时间复杂度为O(n),空间复杂度为O(n);
3)、两个指针两端扫描(若无序,先排序后扫描),时间复杂度最后为:有序O(n),无序O(n*logn+n)=O(n*logn),空间复杂度都为O(1)。然后用两个指针 i,j,各自指向数组的首尾两端,令i=0,j=n-1,然后i++,j–,逐次判断a[i]+a[j]?=sum,如果某一刻a[i]+a[j]>sum,则要想办法让sum的值减小,所以此刻i不动,j–,如果某一刻a[i]+a[j]

1.  bool findNum(int data[], int len, int sum, int &firstNum, int &secondNum)2.  {3.      if(len < 1)4.          return false;5.      6.      int begin = 0;7.      int end = len – 1;8.   9.      while(begin < end)10.     {11.         int curSum = data[begin] + data[end];12.         if(curSum == sum)13.         {14.              firstNum = data[begin];15.             secondNum = data[end];16.             return true;17.         }18.         else if(curSum > sum)19.             end--;20.         else21.             begin++;22.     }23.     return false;24. }  

16. 进制之间的转换

(1)十进制二进制
整数部分:除2取余,商继续除2,直到商为0,从最后一个余数读起直到第一个余数
小数部分:乘2取整,剩下的小数部分继续乘2,直到小数部分为0;如果永远不能为0,就利用0舍1入。读数时从前面得到的整数读到后面的整数。
(2)二进制十进制
不分整数和小数部分,按权相加法,即将二进制每位上的数乘以权,然后相加之和即是结果。
(3)二进制八进制
取三合一法,即从二进制的小数点为分界点,向左(向右)每三位取成一位,接着将这三位二进制按权相加,得到的数就是一位八位二进制数,然后,按顺序进行排列,小数点的位置不变。大家在做添0和去0的时候要注意,是在小数点最左边或者小数点的最右边(即整数的最高位和小数的最低位)才能添0或者去0,否则将产生错误 。1101.1 –> 15.4
(1) 八进制二进制
取一分三法,即将一位八进制数分解成三位二进制,用三位二进制按权相加去凑这位八进制数,小数点位置照旧。67.54转换为二进制数为110111.101100,即110111.1011
(5)二进制十六进制
取四合一法,即从二进制的小数点为分界点,向左(向右)每四位取成一位,接着将这四位二进制按权相加,得到的数就是一位十六位二进制数,然后,按顺序进行排列,小数点的位置不变,得到的数字就是我们所求的十六进制数。如果向左(向右)取四位后,取到最高(最低)位时候,如果无法凑足四位,可以在小数点最左边(最右边),即整数的最高位(最低位)添0,凑足四位。 将二进制11101001.1011转换为十六进制
(6)十进制转换为八进制
1)间接法:先将十进制转换成二进制,然后将二进制又转换成八进制
2)直接法:前面我们讲过,八进制是由二进制衍生而来的,因此我们可以采用与十进制转换为二进制相类似的方法,还是整数部分的转换和小数部分的转换,下面来具体讲解一下:
①整数部分
方法:除8取余法,即每次将整数部分除以8,余数为该位权上的数,而商继续除以8,余数又为上一个位权上的数,这个步骤一直持续下去,直到商为0为止,最后读数时候,从最后一个余数起,一直到最前面的一个余数。
②小数部分
方法:乘8取整法,即将小数部分乘以8,然后取整数部分,剩下的小数部分继续乘以8,然后取整数部分,剩下的小数部分又乘以8,一直取到小数部分为零为止。如果永远不能为零,就同十进制数的四舍五入一样,暂取个名字叫3舍4入。
例:将十进制数796.703125转换为八进制数
解:先将这个数字分为整数部分796和小数部分0.703125


0 0