LeetCode数据结构_C语言题解系列-数组II&动态规划

题目一.两个数组的交集

两个数组的交集 IIhttps://leetcode.cn/problems/intersection-of-two-arrays-ii/

        给你两个整数数组 nums1 和 nums2 ,请你以数组形式返回两数组的交集。返回结果中每个元素出现的次数,应与元素在两个数组中都出现的次数一致(如果出现次数不一致,则考虑取较小值)。可以不考虑输出结果的顺序。

示例 :

输入:nums1 = [1,2,2,1], nums2 = [2,2]
输出:[2,2]

1.思路分析:

由于要取两个数组的交集,首先想到的方法应该是遍历法,遍历两个数组内相同元素,并且将其送入新数组repty内,返回数组指针repty。其中需要注意以下问题:

1.因为交集数组大小不确定,最大可能为较小数组的长度。repty数组的大小size可设置大一些,重新定义一个int型数据lenth来确定交集范围,否则数组内将会残留未赋值的脏数据;如下图多了一个数:

2.同一数据X出现多次时,交集为min{Xquantity(nums1),Xquantity(nums2)}。即由出现次数少的一个数组决定。特点为:X少的一边必然能在多的一边找到唯一对应。如下图:故在遍历时设置一个标志数组flag即可解决:遍历数组时,当且仅当数据相同且flag==0才为未找过的交集元素,写flag标志位为1,同时break此次循环。

2.AC代码

/**
 * Note: The returned array must be malloced, assume caller calls free().
 */
 int Max(int input1,int input2){
     if(input1>=input2) return input1;
     else return input2;
 }
int* intersect(int* nums1, int nums1Size, int* nums2, int nums2Size, int* returnSize){
    int size= Max(nums1Size,nums2Size);
    int* repty =(int *)malloc(sizeof(int )*Max(nums1Size,nums2Size));
    bool* flag =(bool *)malloc(sizeof(bool)*nums2Size);
    for(int t=0;t<nums2Size;t++){
        flag[t]=0;
    }
    int k=0;
         for(int i=0;i<nums1Size;i++)
        {
            for(int j=0;j<nums2Size;j++)
            {

            if(nums1[i]==nums2[j]&&flag[j]==0) {
                    if(k<size){
                    repty[k]=nums2[j];
                    k++;  
                    flag[j]=1;
                    break;
                    }
               
                }
            }
        }   
    

    *returnSize=k;
    return repty;
}

题目二.买卖股票的最佳时机

121. 买卖股票的最佳时机https://leetcode.cn/problems/best-time-to-buy-and-sell-stock/

        给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。

你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。

返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0 。

示例 :

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

1.思路分析:

本题为典型的动态规划问题,数据结构使用数组即可。

思路a.暴力遍历

        最简单的思路为二重循环遍历,即设置初始盈利值为一个极小的数-99999,i角标指向当前购买的股票价格,j角标指向卖出股票价格,当prices[j]-prices[i]大于当前盈利值时,刷新当前盈利值。要注意j取值范围为[i+1,pricesSize-1],因为不可以在买入前卖出。

但是该方法在第201个测试用例上会出现超出时间限制问题。如下图所示,该方法不可行。

虽然不能通过该题,但还是将代码给出,以便交流参考。

#define low_price -100000
int maxProfit(int* prices, int pricesSize){
int price_cont=low_price;
for(int i=0;i<pricesSize;i++){
    for(int j=i+1;j<pricesSize;j++){
        if(prices[j]-prices[i]>=price_cont) {
            price_cont=prices[j]-prices[i];
        }
    }
}
if(price_cont>0)
return price_cont;
else return 0;
}

思路b.动态规划

动态规划 前i天的最大收益 = max{前i-1天的最大收益,第i天的价格-前i-1天中的最小价格},即将第i天前的部分看做一个动态数组,选取其中最小值,与新加入动态数组的元素求利润。当差值大于当前盈利值时,刷新当前盈利值。但是在数组的[0,i-1]范围内选最小值的子函数还是要使用一层循环,本方法同样无法通过第201个测试用例,如下图所示:

虽然不能通过该题,但还是将代码给出,以便交流参考。

#define now_price -99999
#define start     999999
int mins(int* nums,int tail){
    int reg=0;
    int min=start;
    for(int i=0;i<tail;i++){
        if(nums[i]<min){
            min=nums[i];
            reg=i;
        }
    }
    return reg;
}
int maxs(int a,int b){
    if(a>=b) return a;
    else return b;
}
int maxProfit(int* prices, int pricesSize){
int price_cont=0;

for(int i=0;i<pricesSize;i++){
price_cont=maxs(price_cont,prices[i]-prices[mins(prices,i)]);
}
return price_cont;

}

思路c.极值法

上述两种方法虽然都可以解决问题,但是都使用了二重循环,时间复杂度过高,通不过测试用例。为了压缩用时,回归问题本质:

本质上是买入点越便宜,卖出点越贵越好,即最好是极小值与极大值之差。

故设置变量min=prices[0],如果遍历过程中发现比min小的数据prices[i],刷新min的值,同时记录prices[i]-min,当差值大于当前盈利值时,刷新当前盈利值。这两个步骤可以安排在一层循环内进行,由于min为prices[i]之前(或相同)的值,也保证了“先买后卖”的原则。

2.AC代码

#define now_price -99999
#define start     999999
int maxProfit(int* prices, int pricesSize){
    int mincout=prices[0],maxprice=0;
    for(int i=0;i<pricesSize;++i)
    {
        if(prices[i]<mincout)       mincout=prices[i];
        if(prices[i]-mincout>maxprice)   maxprice=prices[i]-mincout;
    }
    return maxprice;
}

 题目三.重塑矩阵

566. 重塑矩阵icon-default.png?t=N7T8https://leetcode.cn/problems/reshape-the-matrix/

        在 MATLAB 中,有一个非常有用的函数 reshape ,它可以将一个 m x n 矩阵重塑为另一个大小不同(r x c)的新矩阵,但保留其原始数据。给你一个由二维数组 mat 表示的 m x n 矩阵,以及两个正整数 rc ,分别表示想要的重构的矩阵的行数和列数。重构后的矩阵需要将原始矩阵的所有元素以相同的 行遍历顺序 填充。如果具有给定参数的 reshape 操作是可行且合理的,则输出新的重塑矩阵;否则,输出原始矩阵。

示例 :

566. 重塑矩阵

在 MATLAB 中,有一个非常有用的函数 reshape ,它可以将一个 m x n 矩阵重塑为另一个大小不同(r x c)的新矩阵,但保留其原始数据。

给你一个由二维数组 mat 表示的 m x n 矩阵,以及两个正整数 rc ,分别表示想要的重构的矩阵的行数和列数。

重构后的矩阵需要将原始矩阵的所有元素以相同的 行遍历顺序 填充。

如果具有给定参数的 reshape 操作是可行且合理的,则输出新的重塑矩阵;否则,输出原始矩阵。

示例 1:

输入:mat = [[1,2],[3,4]], r = 1, c = 4
输出:[[1,2,3,4]]

1.思路分析:

        首先要理解题目函数框架内入参的含义:如下图所示:二级指针指向一个指针型数组,每一个数组元素指向一个矩阵行,此外还有一个数组matColSize用于表示每一个行有多少数据(列数),在此统一设置为相同值列数即可。

 

 思路非常简单:首先进行判断,若要求输出的矩阵元素个数与原矩阵不相等,返回原数组指针,否则按行优先排序:排序方法有很多,可以通过计算角标的方式得到。但是笔者在这里采用的方法是将行列用新的计数变量k,t表示:新矩阵为row[k][t],数据填满一行时,k++,t置0,未满一行时t++,k不变。由于之前分支考虑过数据不一样多的情况,进入这个分支表示两个矩阵总元素个数必然相同。

2.AC代码

/**
 * Return an array of arrays of size *returnSize.
 * The sizes of the arrays are returned as *returnColumnSizes array.
 * Note: Both returned array and *columnSizes array must be malloced, assume caller calls free().
 */
int** matrixReshape(int** mat, int matSize, int* matColSize, int r, int c, int* returnSize, int** returnColumnSizes){
    int t=0;
    int k=0;
if(r*c!=(*matColSize)*matSize) {
    *returnSize=matSize;
    *returnColumnSizes=matColSize;
    return mat;
    }
else {
    *returnSize=r;
    *returnColumnSizes=(int*)malloc(r*sizeof(int));
    for(int i=0;i<r;i++) (*returnColumnSizes)[i]=c;
    
    int** row=(int**)malloc(r*sizeof(int*));
    for(int i=0;i<r;i++){
        row[i]=(int*)malloc(c*sizeof(int));
    }
    for(int i=0;i<matSize;i++){
        for(int j=0;j<*matColSize;j++){
        row[k][t]=mat[i][j];
        if(t<c-1) t++;
        else {
            k++;
            t=0;
        }
        }
    }
return row;
}
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

物质波波波

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值