关于数组的问题(连续子数组的最大和、数组中出现次数超过一半的数字、调整数组顺序使奇数位于偶数之前)

题目一:连续子数组的最大和

题目描述:在古老的一维模式识别中,常常需要计算连续子向量的最大和,当向量全为正数的时候,问题很好解决。但是,如果向量中包含负数,是否应该包含某个负数,并期望旁边的正数会弥补它呢?例如:{6,-3,-2,7,-15,1,2,2},连续子向量的最大和为8(从第0个开始,到第3个为止)。(子向量的长度至少是1)

应用动态规划法解题:

1、当数组的和sum<0时,则将下一个数字重新赋值给sum,

2、如果sum>0与目前保存的最大和进行判断,更新一下最大和,这种方法时间复杂度为o(n)

具体代码如下:

class Solution {
public:   
    int FindGreatestSumOfSubArray(vector array) {
        vector totalNum;
        int sum = 0;
        int maxValue = array[0];
        if(array.size() == 0)return 0;       
        for(int i = 0;i < array.size(); i++) 
        {
            if(sum < 0){//如果和小于,则将下一个值重新赋值给sum
                sum = array[i];
            }else{
                sum = sum + array[i]; 
            }if(sum > maxValue){
                maxValue = sum;//如果sum大于现在的最大值
            }
        }
        return maxValue;    
    }
};

另一种方法很容易理解,三重循环,取尽数组的子数组的所有可能的和,然后求出这些和中的最大值,但是时间复杂度为o(n*n*n)

具体代码如下所示:

class Solution {
public:   
    int FindGreatestSumOfSubArray(vector array) {
        vector totalNum;
        int sum = 0;
        int maxValue = array[0];
        //采用三重循环,第一层表示自向量的长度间隔,1个向量间隔为0,2个向量间隔为1
        //第二层表示,每次取间隔的起始位置,从0到array.size()-1
        //第三层表示,自向量有几个值相加,与第一层有关
        for(int i = 0;i < array.size(); i++)
        { 
             for(int j = 0;j < array.size(); j++)
             {  
                sum = 0;
                if((j+i) > array.size()-1) break;//如果起始位置加上向量的个数大于数组的长度,则直接退出
                for(int k = 0; k <= i;k++)
                {   
                   sum = sum + array[j+k];
                }
                totalNum.push_back(sum);
             }              
        }
        //找出这些向量和中的最大值
        int m = 0;
        while(m < totalNum.size())
        {
            if(totalNum[m] > maxValue){maxValue = totalNum[m];}
            m++;
        }
        return maxValue;    
    }
};

题目二:数组中出现次数超过一半的数字

题目描述:数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。

解题思路:这个题目的思路与题目一的方法一很相似;

数组中一个数字出现的次数超过数组长度的一半,也就是说它出现的次数比其他所有数字出现次数的和还要多。

所以在遍历数组时保留2个数,一个是数字的值,另一个是次数,

      1、如果下一个数字和保留的数字相同,次数加1,数字不同,次数减1,次数为0,需要保存下一个数字并把次数设为1,
      2、由于我们要找的数字出现的次数比其他所有数字出现的次数之和还要多,要找的数字则是最后一次设为1的数字
      3、在这个过程后要判断这个最后设为1的数是否存在超过数组一半的数字

具体代码如下所示:

class Solution {
public:    
    int MoreThanHalfNum_Solution(vector numbers) {
        int length = numbers.size();
        if(length <= 0) return 0;
        int result;
        int times = 0;
        for(int i = 0; i < length; ++i)
        {
            if(times == 0){result = numbers[i]; times = 1;}
            else if(result == numbers[i]){times++;}
            else {times--;}
        }
        //判断这个数是否超过数组的一半的数字        
        for(int i = 0;i < length; ++i)
        {
            if(numbers[i] == result)
            {
                times++;
            }
        }
        if(times*2 <= length){return 0;}
        return result;               
    }
};

题目三:最小的k个数

题目描述:输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,。

题目解析:最简单直接的方法就是采用排序,排除前k个最小的值,然后输出

这种解法是最直观的方法,时间复杂度为O(nk),有时间复杂度为O(n)的方法,但是这两种方法都需要修改数组,
用最小堆的方法不用修改数组,适合海量数据时间复杂度为O(nlog(n))但是这两种方法我都不太会。。。。。

采用冒泡排序,具体代码如下所示:

class Solution {
public:
    vector GetLeastNumbers_Solution(vector input, int k) {
        vector minNumbers;
        int minValue = 0;
        if(k > input.size())return minNumbers;
        //采用冒泡排序,但是只需排前k个数字即可
        for(int i = 0;i < k; i++)
        {
            for(int j = i+1;j < input.size(); j++)
            {
                if(input[i] > input[j])
                {
                    minValue = input[j];
                    input[j] = input[i];
                    input[i] = minValue;
                }
            }
           minNumbers.push_back(input[i]);
        }      
        return minNumbers;
    }
};

题目四:调整数组顺序使奇数位于偶数之前

题目描述:输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。

题目解析:只需扫描一下数组,按顺序将奇数提取出来放到数组中,按顺序将偶数提取出来放到数组中,并将偶数数组链接到奇数数组的后边,则达到题目要求,但是这种方法需要新增O(N)的空间,另一种方法可以减少空间的使用,按顺序扫描一下数组,遇到偶数将偶数提取出来放到另一个数组中,并将原数组中的偶数删除。最后将偶数数组添加到原数组中。

class Solution {
public:
    void reOrderArray(vector &array) {
        vector evenArray;
        for(int i = 0;i < array.size(); i++)
        {
            if(!(array[i] & 0x1))
            {                
                evenArray.push_back(array[i]);
                //把array数组中的值删去
                array.erase(array.begin() + i--);//为什么要i--呢,因为少了一个数,如果不减的话,就跳过一个值了
            }            
        }
        array.insert(array.end(),evenArray.begin(),evenArray.end());
    }
};



你可能感兴趣的:(剑指offer)