zoukankan      html  css  js  c++  java
  • 数组中的趣味题二

    1.找出数组中唯一的重复元素


    问题描述:给定包含101个元素的数组arr,数组中元素一定属于[1,100],并且[1,100]之间的每个数都在arr中出现过。

    解决方案:分析,数组中有101个元素,如果[1,100]之间的每个数出现一次,那就是100个元素了,剩下的那个元素就是唯一的重复出现的元素。我们可以通过遍历arr,得到arr中所有元素的总和,然后既然[1,100]之间的每个数出现一次,那么我们减去1+2+……+99+100的和,结果就是我们需要的唯一的重复出现的元素了。时间复杂度是O(n)。

    代码:


     1 //找到数组中唯一的重复元素
    2 int FindOnlyRepeat(int *arr)
    3 {
    4     int tmp_sum = 0;//记录1~100的和
    5     int total_sum = 0;//数组中所有树的和
    6     int i = 0;
    7     while(i < 101)
    8     {
    9         tmp_sum += i+1;
    10         total_sum += arr[i++];
    11     }
    12     tmp_sum-=101;
    13     return total_sum - tmp_sum;
    14 }

    2.找出数组中出现奇数次的元素


    问题描述:现在有一个整数数组arr,其中的元素只有一个元素出现奇数次,请找出这个元素。

    解决方案:对于任意一个数k,有k^k = 0,k^0 = k,所以将arr中所有元素进行异或,那么出现次数为偶数的元素异或后都变成了0,出现次数为奇数的元素异或后得到元素本身。下面写代码就很容易了~~时间复杂度是O(n)。

    代码:

     1 //找出数组唯一的出现次数是奇数的元素
     2 int Find(int *arr,int n)
     3 {
     4     int ans = arr[0];
     5     for(int i = 1 ; i < n ; i++)
     6     {
     7         ans^=arr[i];
     8     }
     9     return ans;
    10 }

    3.找出两个数组中满足给定和的数对

    问题描述:有两个数组arr1和arr2,两个数组均已经排好序,现在要找出这样的x和y使得x+y=sum,其中sum已知,x是arr1中某个元素,y是arr2中的某个元素。

    解决方案:既然数组arr1和arr2中的元素已经排好序了,那么问题就简单了不少。假设arr1[i] + arr2[j] > sum,若arr1下标不变,那么要找到满足条件的x和y,只能取arr2中下标< j 的元素和arr1[i]相加,结果才可能等于sum;假设arr1[i] + arr2[j] < sum,若arr2的下标不变,那么要找到满足条件的x和y,只能取arr1中下标 > i 的元素和arr2[j]相加,结果才可能等于sum。因此我们可以设置两个指针 i 和 j ,分别指向arr1的开始位置和结束位置,这时 i 只能不断变大,j 只能不断变小,直到超过了数组的范围。通过代码更好理解,看代码吧~~时间复杂度是O(n+m),n和m分别是arr1和arr2的大小。

    代码:


     1 //找出数组中两个数的和是固定值
    2 void FindTheSum(int *arr1,int *arr2,int n,int m,int sum)
    3 {
    4     int i = 0 , j = m-1;
    5     while(i < n && j >= 0)
    6     {
    7         if(arr1[i] + arr2[j] > sum)
    8         {
    9             j--;
    10         }
    11         else if(arr1[i] + arr2[j] < sum)
    12         {       
    13             i++;
    14         }
    15         else
    16         {
    17             cout<<arr1[i]<<" + "<<arr2[j]<<" = "<<sum<<endl;
    18             i++;
    19             j--;
    20         }
    21     }
    22 }

    4.最大子段和


    问题描述:对于整数数组arr,求出最大连续子段之和,字段和是这样的: i 和 j 是数组下标并且i <= j ,那么sub_sum = arr[i] + arr[i+1]……+arr[j],就是一段子段和,我们的目的是找到最大的子段和。如果和为负数,按0计算。

    解决方案:这个算法,可是算得上是比较经典的算法了,对照着代码,理解一下思路吧:MAX是记录在搜索过程中出现的最大值,也就是最终的最大值保存的地方,而对于tmp的话,tmp > 0,就说明如果tmp继续和后面的数(假设是arr[i])相加,就能继续使得以a[i]结尾的子段和变大,而当tmp < 0 ,就说明这个值不能加到a[i]上,这一定会导致总和不是最大的,tmp的意图比较像是获得“最大前缀和”!!我就说这么多吧,这个东西还是看代码理解吧!!时间复杂度是O(n)。

    代码:

    //求最大子段和
     2 int MaxSubSum(int *arr,int n)
     3 {
     4     int tmp = 0;
     5     int MAX = arr[0];
     6     for(int i = 0 ; i < n ; i++)
     7     {
     8         tmp += arr[i];
     9         if(tmp < 0)
    10         {
    11             tmp = 0;
    12         }
    13         if(MAX < tmp)
    14         {
    15             MAX = tmp;
    16         }
    17     }
    18     return MAX;
    19 }

    5.最大子段积


    问题描述:对于整数数组arr,求出最大连续子段积。具体什么是最大连续子段积,我想参考最大字段和应该能知道。

    解决方案:和最大子段和的思想和很相似,看代码!时间复杂度是O(n)

    代码:

     1 int MaxSubMult(int *arr,int n)
     2 {
     3     int min_Mult = 1;
     4     int max_Mult = 1;
     5     int ans = arr[0];
     6     for(int i = 0 ; i < n ; i++)
     7     {
     8         if(arr[i] > 0)
     9         {
    10             max_Mult *= arr[i];
    11             min_Mult = min_Mult*arr[i] < 1 ? min_Mult*arr[i] : 1;
    12         }
    13         else if(arr[i] < 0)
    14         {
    15             int tmp = max_Mult;
    16             max_Mult = min_Mult*arr[i] > 1 ? min_Mult*arr[i] : 1;
    17             min_Mult = tmp*arr[i];
    18         }
    19         else //arr[i] = 0
    20         {
    21             max_Mult = 1;
    22             min_Mult = 1;
    23         }
    24         if(max_Mult > ans)
    25         {
    26             ans = max_Mult;
    27         }
    28     }
    29     return ans;
    30 }

    6.一种特殊的排序(重排问题)


    问题描述: 对于整数数组arr中包含0和非0元素,现在要对数组进行处理,使得处理后的结果满足:(1)0都排在数组的前面(2)非0元素都在数组的后面,并且相对顺序不能变化。例如arr[] = {3,0,1,0},经处理后的结果应为:{0,0,3,1}。

    解决方案:要完成这个要求,只需要从后向前遍历数组arr,遇到一个非0的数就将其放到数组的后面,遇到的第一个非0元素放在数组的第n-1位置,遇到的第二个非0元素放在数组的第n-2位置(其中n是数组的大小)。这样就完成了题目的要求!!!时间复杂度是O(n)

    代码:

     void Deal(int *arr,int n)
     2 {
     3     int tmp = n-1;
     4     for(int i = n-1 ; i >= 0 ; i--)
     5     {
     6         if(arr[i])
     7         {
     8             if(!arr[tmp])
     9             {
    10                 arr[tmp] = arr[i];
    11                 arr[i] = 0;
    12             }
    13             tmp--;
    14         }
    15     }        
    16 }

    7.找出绝对值最小的数


    问题描述:整数数组arr已经排好序,其中包含正数,0负数,数组大小是n,要求找到绝对值最小的数。

    解决方案:通过分析有几种情况:(1)若arr[0]和arr[n-1]同号且arr[0]>=0,则绝对值最小的数是arr[0];(2)若arr[0]和arr[n-1]同号且arr[0]<=0,则绝对值最小的数是arr[n-1];(3)若arr[0]和arr[n-1]不同号,则绝对值最小数应该是“最小的正整数”和“最大的负整数”中的一个。关键就是找到这“最小的正整数”和“最大的负整数”。既然数组是已经排好序了,那么可以利用二分。

    代码:

    1 int MinAbs(int *arr, int n)
     2 {    
     3     if(n == 1) //只有一个元素  
     4     {        
     5         return arr[0] ;    
     6     }
     7     if(arr[0]*arr[n-1] >= 0)    
     8     {        
     9         return arr[0] >=0 ? arr[0] : arr[n -1] ;    
    10     }
    11     int l =0 ;    
    12     int r = n - 1;    
    13     while(l < r)    
    14     {        
    15         cout<<l<<" "<<r<<endl;
    16         if(l + 1 == r)//出口,只剩下两个元素,可以得到结果了       
    17         {            
    18             return abs(arr[l]) < abs(arr[r]) ? abs(arr[l]) : abs(arr[r]);        
    19         }        
    20         int m = (l + r) / 2;        
    21         if(arr[m] * arr[r] >= 0)        
    22         {            
    23             r = m;            
    24             continue;        
    25         }        
    26         if(arr[l] * arr[m] >= 0)        
    27         {            
    28             l = m;            
    29             continue;       
    30         }    
    31     }
    32 }

    参考资料:

    【1】博文http://www.cnblogs.com/graphics/archive/2010/08/24/1761620.html#link13

    【2】《编程之美》

  • 相关阅读:
    springcloud组件梳理之hystrix
    springcloud组件梳理之Feign
    React Native startReactApplication 方法简析
    FREE OFFER
    修改docker默认目录
    使用云效进行自动化构建和部署
    Git同时推送到多个远端仓库【转】
    OneNote出现we're sorry. OneNote is cleanning up from the last time it was open.
    【数学基础】数据科学的概率基础
    【摄影后期基础教程】Lightroom_秋凉视频教程
  • 原文地址:https://www.cnblogs.com/hoobey/p/5247512.html
Copyright © 2011-2022 走看看