数组中子数组和为固定值的题目汇总

开头附件一部分数组去重的知识

 

C++中数组/Vector中去除重复元素

unique函数是一个去重函数,去除相邻中的重复元素(只留一个)。

其中,最关键的是:并不是删除并不是把重复的元素删除,而是全部放倒数组的后面。

因为,unique只是去除(相邻)的重复元素,因此,为了去除重复的元素,应该,首先对数组/Vector进行排序,这样保证重复元素在相邻的位置。

unique函数,返回的是去重后的尾地址。

因此对于一个内容为{2, 2, 5, 5, 6}的vector,执行unique函数以后,vector大小并没有改变,只不过顺序变成了{2, 5, 6, 2, 5},并且函数的返回值为:3。

此时需要删除重复元素,只需要将后面的数据全部删除即可。

排序函数(sort)和去重函数都在<algorithm>头文件中。

复制代码
 1 #include <iostream>
 2 #include <algorithm>
 3 #include <vector>
 4 using namespace std;
 5 
 6 
 7 int main() {
 8     vector<int> v;
 9     cout << "Number of vector's element : " << endl;
10     int number;
11     cin >> number;
12     for (int i = 0; i < number; i++) {
13         int temp;
14         cin >> temp;
15         v.push_back(temp);
16     }
17     sort(v.begin(),v.end());
18     v.erase(unique(v.begin(), v.end()), v.end());
19     for (int i = 0; i < v.size(); i++) {
20         cout << v[i] << " ";
21     }
22     cout << endl;
23     return 0;
24 }
复制代码

unique()函数将重复的元素放到vector的尾部然后返回指向第一个重复元素的迭代器再用erase函数擦除从这个元素到最后元素的所有的元素

自己写的去重函数!

int QuChong(int *nums, int len)
{
    sort(nums, nums + len);
    int i = 0, j = 0;
    for ( i = 0; i < len-1; i++)
    {
        while (nums[i] == nums[i + 1])
        {
            i++;
        }
        nums[j++] = nums[i];
    }
    return j;
}
 int main()
 {
     int nums[10] = { 1, 1,8,2, 3, 4, 5, 6, 7, 8 };
     cout << QuChong(nums,10) << endl;
     cout << unique(nums, nums + 10)-nums << endl;;
     system("pause");
     return 0;
 } 

题目表

1)输入一个递增排序的数组和一个数字S,在数组中查找两个数,使得他们的和正好是S,如果有多对,输出任意一对既可。

2)排序不重复的数组求所有对数和为固定值sum的所有对数!

3)排序不重复的数组求所有对数差值为固定值的所有对数!

3-1)给出n和k,然后给出n个数,求出数组里面两两数的差为k有几对,数组排序及是否重复不限制。

4)输入一个非递增非排序的数组(可能有重复数字)和一个数字S,在数组中查找两个数,使得他们的和正好是S,如果有多对,输出所有可能对数,不能重复。

5)输入一个正数S,打印出所有和为S的连续正数序列,至少包含两个数;例如输入15,应该输出(1,2,3,4,5)(4,5,6)(7,8)。

6)回溯法求数组中和为定值的子数组的组合!

7)求连续子数组的最大和问题!

8)股票最大收益问题,求数组中后面最大值(卖出)减去前面最小值(买入)的最大收益差值(2020-12-10)

 

 

 

 

文章正式开始!!

 

1)输入一个递增排序的数组和一个数字S,在数组中查找两个数,使得他们的和正好是S,如果有多对,输出任意一对既可。

java版本:

public class Test1 {
    public static ArrayList<Integer> FindNumbersWithSum(int[] array, int sum) {
        ArrayList<Integer> list = new ArrayList<>();
        if (array == null || array.length < 2) {
            return list;
        }
        int begin = 0, end = array.length - 1;
        while (begin < end) {
            if ((array[begin] + array[end]) == sum) {
                list.add(array[begin]);
                list.add(array[end]);
                break;
            } else if ((array[begin] + array[end]) > sum) {
                end--;
            } else {
                begin++;
            }
        }
        return list;
    }

    public static void main(String[] args) {
        int[] str ={1,2,3,4};
        System.out.println(FindNumbersWithSum(str, 5));

    }
}

c++版本:

bool FindTwoNumsWithSum(int *nums, int sum, int len, vector<int> &res)
{
    bool found = false;
    if (len < 1 || nums == NULL)
        return found;
    int begin = 0, end = len - 1;
    while (begin < end)
    {
        long long cursum = nums[begin] + nums[end];
        if (cursum == sum)
        {
            res.push_back(nums[begin]);
            res.push_back(nums[end]);
            found = true;
            break;
        }
        if (cursum>sum)
        {
            end--;
        }
        else
            begin++;
    }
    return found;
}

 int main()
 {
     int nums[8] = { 1, 2, 3, 4, 5, 6, 7, 8 };
     int len = 8;
     int sum = 9;
     vector<int> res;
     FindTwoNumsWithSum(nums, sum, len, res);
     cout << res[0] << res[1] << endl;
    // MainFun(nums, len,  sum);
     system("pause");
     return 0;
 }

2)排序不重复的数组求所有对数和为固定值sum的所有对数!

java版本:

public class TwoTuple<A, B> {

    public final A first;

    public final B second;

    public TwoTuple(A a, B b){
        first = a;
        second = b;
    }

    public String toString(){
        return "(" + first + ", " + second + ")";
    }

}
public class Test1 {
    public static ArrayList<TwoTuple> FindAllNumbersWithSum(int[] array, int sum) {
        ArrayList<TwoTuple> list = new ArrayList<>();
        if (array == null || array.length < 2) {
            return list;
        }
        int begin = 0, end = array.length - 1;
        while (begin < end) {
            if ((array[begin] + array[end]) == sum) {
                TwoTuple<Integer, Integer> tuple = new TwoTuple<>(array[begin], array[end]);
                list.add(tuple);
                begin++;
                end--;
            } else if ((array[begin] + array[end]) > sum) {
                end--;
            } else {
                begin++;
            }
        }
        return list;
    }

    public static void main(String[] args) {
        int[] str ={1,2,3,4};
        ArrayList<TwoTuple> twoTuples = FindAllNumbersWithSum(str, 5);
        for(TwoTuple var:twoTuples){
            System.out.println(var.first+"  "+var.second);
        }
    }
}

c++版本:

void dualSum(int arr[], int len, int sum)
{
    int low = 0;
    int high = len - 1;

    while (low<high)
    {
        while (arr[high] >= sum)
        {
            high--;
        }

        if (arr[low] + arr[high]>sum)
            high--;
        else if (arr[low] + arr[high]<sum)
            low++;
        else
        {
            cout << arr[low] << " + " << arr[high] << " = " << sum << endl;
            high--; low++;//仅仅是如果题目要求数组没有重复元素的时候才会成立!
        }
    }
}
int main()
{  
    int arr2[] = { 1,2,3,4,5,6 };
    int len = 6;
    int sum = 7;
    dualSum(arr2, len, sum);
    system("pause");
    return 0;
}

3)排序不重复的数组求所有对数差值为固定值的所有对数!

void dualSum(int arr[], int len, int k)
{
    int low = 0;
    int high = 0;
    while (low<len)
    {        
        if (arr[high] -arr[low]>k)
            low++;
        else if (arr[high] - arr[low]<k)
            high++;
        else
        {
            cout << arr[low] << " chavalue" << arr[high] << " = " << k << endl;
            high++;//仅仅是如果题目要求数组没有重复元素的时候才会成立!
        }
    }
}
int main()
{
    int arr[] = { 1, 3, 5, 7, 9, 10 };
    int len = 6;
    int k = 2;
    dualSum(arr, len, k);
    system("pause");
    return 0;

}

3-1)给出n和k,然后给出n个数,求出数组里面两两数的差为k有几对,数组排序及是否重复不限制。

public static int findPairs2(int[] nums, int k) {
    // k小于0无意义
    int count = 0;
    if (nums == null || nums.length == 0 || k < 0)
        return 0;
    //这里使用了HashMap可以达到去重的目的
    Map<Integer, Integer> map = new HashMap<>();
    for (int num : nums){
        if(map.containsKey(num)){
            map.put(num,map.get(num)+1);
        }else{
            map.put(num,1);
        }
    }
    for(Integer key:map.keySet()){
        if(k==0&&map.get(key)>=2){
            count++;
        }
        if(k>0&&map.containsKey(key+k)){
            count++;
        }
    }
    return count;
}

int NumChaValue(int * arr,int num, int k)
{
    multiset<int> all;
    for (int i = 0; i < num; i++)
    {
        all.insert(arr[i]);
    }
    multiset<int>::iterator ite = all.begin();
    int res = 0;
    for (; ite != all.end(); ite++)
    {
        if (all.count((*ite) + k)>0)
        {
            res += all.count((*ite) + k);
        }
    }
    return res;
}


int main() {
    int arr[] = {1,3,3,3 ,5};
    //cout << sizeof(arr) / sizeof(arr[0]) << endl;
    int num = sizeof(arr) / sizeof(arr[0]);
    int k = 2;
    cout << NumChaValue( arr,  num, k) << endl;
    system("pause");
    return 0;
}

4)输入一个非递增非排序的数组(可能有重复数字)和一个数字S,在数组中查找两个数,使得他们的和正好是S,如果有多对,输出所有可能对数,不能重复。

方法一思路: 用N减去每个元素得到另一个数组b,嵌套循环找到a与b中值相同而位置不同的元素对;空间复杂度2N,时间复杂度O(N^2)。(时间复杂度较高,相当于暴力解法)

void CalcTwoSum(int *nums, int len, int sum, vector<vector<int>> &vec)
{
    int *numsB= new int[len];
    for (int i = 0; i < len; i++)
    {
        numsB[i] = sum - nums[i];
    }
    int index = 0;
    for (int i = 0; i < len; i++)
    {
        int find = numsB[i];
        for (int j = i + 1; j < len; j++)
        {
            if (nums[j] == find)
            {
                cout << numsB[i] << " + " << nums[i] << endl;
                vector<int> tmp;
                tmp.push_back(numsB[i]);
                tmp.push_back(nums[i]);
                vec.push_back(tmp);//注意vector<vector<int>>的赋值方法,不能像二维数组那样单独赋值,需要建一个临时vector<int>tmp来赋值处理!!
            }
                
        }
    }
}


int QuChong(int *nums, int len)
{
    sort(nums, nums + len);
    int i = 0, j = 0;
    for ( i = 0; i < len-1; i++)
    {
        while (nums[i] == nums[i + 1])
        {
            i++;
        }
        nums[j++] = nums[i];
    }
    return j;
}
 int main()
 {
     int nums[10] = { 1, 1,8,2, 3, 4, 5, 6, 7, 8 };
     int len = QuChong(nums, 10);
     int sum = 9;
     vector<vector<int>> vec;
     CalcTwoSum(nums, len, sum,vec);

     system("pause");
     return 0;
 }

 

5)输入一个正数S,打印出所有和为S的连续正数序列,至少包含两个数;例如输入15,应该输出(1,2,3,4,5)(4,5,6)(7,8)。

我的做法,好理解一些

void PrintContinuousSequence(int small, int big);

void FindContinuousSequence(int sum)
{
    if (sum < 3)
        return;

    int small = 1;
    int big = 2;
    int middle = (1 + sum) / 2;
    int curSum = small + big;

    while (small < middle)
    {
        if (curSum == sum)
        {
            PrintContinuousSequence(small, big);
            big++;
            curSum += big;//这个千万不要漏掉,因为要求满足和为sum的所有组合,否则就停掉了!
        }
        else if (curSum > sum)
        {
            curSum -= small;
            small++;
        }
        else
        {
            big++;
            curSum += big;
        }
        
    }
}

void PrintContinuousSequence(int small, int big)
{
    for (int i = small; i <= big; ++i)
        printf("%d ", i);

    printf("\n");
}
int main()
{

    FindContinuousSequence(15);


    system("pause");
    return 0;
}

剑指offer做法

void PrintContinuousSequence(int small, int big);

void FindContinuousSequence(int sum)
{
    if(sum < 3)
        return;

    int small = 1;
    int big = 2;
    int middle = (1 + sum) / 2;
    int curSum = small + big;

    while(small < middle)
    {
        if(curSum == sum)
            PrintContinuousSequence(small, big);

        while(curSum > sum && small < middle)
        {
            curSum -= small;
            small ++;

            if(curSum == sum)
                PrintContinuousSequence(small, big);
        }

        big ++;
        curSum += big;
    }
}

void PrintContinuousSequence(int small, int big)
{
    for(int i = small; i <= big; ++ i)
        printf("%d ", i);

    printf("\n");
}

6)回溯法求数组中和为定值的组合(方法2 感觉好理解一些)

方法1

void sumn(vector<int> &A, int start, int end, int sum, vector<int> &tmp, vector<vector<int>> &res);
void MainFun(int *nums, int len, int sum)
{
    vector<int> A;
    int start = 0,end=len-1;
    for (int i = 0; i < len; i++)
        A.push_back(nums[i]);
    vector<int> tmp;
    vector<vector<int>> res;
    sumn(A, start, end, sum, tmp, res);
    for (int i = 0; i < res.size(); i++)
    {
        for (unsigned int j = 0; j < res[i].size(); j++)
        {
            cout << res[i][j] << " ";
        }
        cout << endl;
    }
}


void sumn(vector<int> &A, int start, int end, int sum, vector<int> &tmp, vector<vector<int>> &res){
    if (start == end && sum == 0)
    {
        res.push_back(tmp);
    }
    else if (start == end)
        return;
    else
    {
        if (sum >= A[start])
        {
            tmp.push_back(A[start]);
            sumn(A, start + 1, end, sum - A[start], tmp, res);//求start后面和为sum - A[start]的组合
            tmp.pop_back();//需要将tmp临时数组恢复原样
        }
        sumn(A, start + 1, end, sum, tmp, res);//依次递增start求数组后面除了含有start前面数字的子数组组合。
    }
}

 int main()
 {
     int nums[8] = { 1, 2, 3, 4, 5, 6, 7, 8 };
     int len = 8;
     int sum = 15;
     MainFun(nums, len,  sum);
     system("pause");
     return 0;
 }

方法2

void Combination_helper(vector<int> array, int begin, int &current, int target, vector<int>&path)
{
    if (begin >= array.size())
        return;
    current += array[begin];
    path.push_back(array[begin]);
    if (current == target)
    {
        for (int i = 0; i < path.size(); i++)
            cout << path[i] << ' ';
        cout << endl;
    }
    Combination_helper(array, begin + 1, current, target, path);
    path.pop_back();
    current -= array[begin];

    /*
    int j;
    for (j = begin + 1; j < array.size();)
    {
        if (array[j] == array[begin])
            j++;
        else
            break;
    }
    Combination_helper(array, j, current, target, path);
    *///这个是去掉重复值的作用,看看要求里面有没有去重的题目要求
}
int main()
{
    vector<int>array({ 1, 2, 2, 3, 4, 4, 5, 5, 6, 6, 7 });
    //vector<int>array({ 1, 2, 3});
    vector<int>path;
    int current = 0;
    Combination_helper(array, 0, current, 10, path);
    system("pause");
    return 0;

}

 

7)求连续子数组的最大和问题(剑指offer T31)并且输出这个最大的子数组ResMaxInt

java版本

public class LCS {
    public static List<Integer> getLCSList(List<Integer> arr) {
        ArrayList<Integer> maxArr = new ArrayList<>();
        ArrayList<Integer> tmpArr = new ArrayList<>();
        int max = 0, currSum = 0;
        if (null == arr || arr.size() <= 0)
            return maxArr;
        for (int i = 0; i < arr.size(); i++) {
            if(currSum <= 0){
                currSum = arr.get(i);
                tmpArr.clear();
                tmpArr.add(arr.get(i));
            }else{
                currSum+=arr.get(i);
                tmpArr.add(arr.get(i));
            }
            if(currSum>=max){
                max = currSum;
                maxArr.clear();
                maxArr = (ArrayList<Integer>)tmpArr.clone();//也可以单个循环赋值给maxArr
            }
        }
        return maxArr;
    }

    public static void main(String[] args) {
        ArrayList<Integer> arr = new ArrayList<>();
        arr.add(1);
        arr.add(2);
        arr.add(3);
        arr.add(-100);
        arr.add(100);
        arr.add(1);
        List<Integer> lcsList = getLCSList(arr);
        System.out.println(lcsList);
    }
}

c++版本

int maxSubInt(int arr[], int length, vector<int> &ResMaxInt)
{
    if (NULL == arr || length <= 0)
        return 0;
    int TmpSum = 0;
    vector<int> TmpMaxInt;
    int ResSum = 0;
    for (int i = 0; i < length; i++)
    {
        if (TmpSum <= 0)
        {
            TmpSum = arr[i];
            vector<int> TmporaryMaxInt;
            TmporaryMaxInt.push_back(arr[i]);
            TmpMaxInt = TmporaryMaxInt;
        }
        else
        {
            TmpSum += arr[i];
            TmpMaxInt.push_back(arr[i]);
        }
        if (TmpSum>ResSum)
        {
            ResSum = TmpSum;
            ResMaxInt = TmpMaxInt;
        }
    }
    return ResSum;
}
int main() {
    int arr[] = { 1, -2, 3, 10, -4, 7, 2, -5 };
    int length = sizeof(arr) / sizeof(arr[0]);
    vector<int> ResMaxInt;
    cout << maxSubInt(arr,  length, ResMaxInt) << endl;
    system("pause");
    return 0;
}
 

8)股票最大收益问题,求数组中后面最大值(卖出)减去前面最小值(买入)的最大收益差值(2020-12-10)

示例 1:

输入: [7,1,5,3,6,4]
输出: 5
解释: 在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。
注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格。
示例 2:

输入: [7,6,4,3,1]
输出: 0
解释: 在这种情况下, 没有交易完成, 所以最大利润为 0

 

class Solution {
    public int maxProfit(int[] prices) {
        int len;
        if(prices == null || (len=prices.length) <= 1)
            return 0;
        int max_profit = 0;
        int base_num = prices[0];
        for(int i = 1;i < len;i++) {
            if(prices[i] > base_num)
                max_profit = Math.max(max_profit,prices[i] - base_num);
            else 
                base_num = prices[i];
        }
        return max_profit;
    }
}

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值