Letbook Cookbook题单——数组3
创始人
2024-03-24 22:47:10
0

Letbook Cookbook题单——数组3

48. 旋转图像

难度中等

给定一个 n × n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。

你必须在 原地 旋转图像,这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。

示例 1:

img

输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]
输出:[[7,4,1],[8,5,2],[9,6,3]]

示例 2:

img

输入:matrix = [[5,1,9,11],[2,4,8,10],[13,3,6,7],[15,14,12,16]]
输出:[[15,13,2,5],[14,3,4,1],[12,6,8,9],[16,7,10,11]]

提示:

  • n == matrix.length == matrix[i].length
  • 1 <= n <= 20
  • -1000 <= matrix[i][j] <= 1000

先把矩阵主对角线翻折再沿中间翻折

class Solution {
public:void rotate(vector>& matrix) {for(int i=1;iswap(matrix[i][j],matrix[j][i]);}for(int i=0;iswap(matrix[i][matrix.size()-j-1],matrix[i][j]);}}
};

53. 最大子数组和

难度中等

给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

子数组 是数组中的一个连续部分。

示例 1:

输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
输出:6
解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。

示例 2:

输入:nums = [1]
输出:1

示例 3:

输入:nums = [5,4,-1,7,8]
输出:23

提示:

  • 1 <= nums.length <= 105
  • -104 <= nums[i] <= 10^4

**进阶:**如果你已经实现复杂度为 O(n) 的解法,尝试使用更为精妙的 分治法 求解。

这题,我只能说经典中的经典,四种解法

暴力

前缀和预处理,然后枚举每个子数组,超时

class Solution
{
public:int maxSubArray(vector &nums){vectorsum(nums.size()+1);for(int i=1;i<=nums.size();i++)sum[i]=sum[i-1]+nums[i-1];int ans=INT_MIN;for(int i=1;i<=nums.size();i++)for(int j=i;j<=nums.size();j++)ans=max(ans,sum[j]-sum[i-1]);return ans;}
};

贪心

连续的数组,当前一个子数组和为负数,则显然会丢弃
初始化数组和为0,最大值为第一个元素值
遍历数组,更新数组和,并且更新最大值,当数组和<0,则丢弃数组,数组和置零

class Solution
{
public:
int maxSubArray(vector&nums){
int max=INT_MIN;
int sum=0;
for(int i=0;isum+=nums[i];if(sum>max)max=sum;if(sum<0)sum=0;
}
return max;
}
};

动态规划

dp[i]代表必然选择第i个元素且以第i个元素为子数组最后一个元素的最大子数组和,那么状态转移方程就是dp[i]=dp[i-1]>=0?dp[i-1]+nums[i]:nums[i],和贪心一样,如果前面出现负数就没必要加进来

class Solution
{
public:int maxSubArray(vector &nums){vectordp(nums.size()+1);int ans=INT_MIN;for(int i=1;i<=nums.size();i++){if(dp[i-1]>=0)dp[i]=dp[i-1]+nums[i-1];elsedp[i]=nums[i-1];ans=max(ans,dp[i]);}return ans;}
};

分治法

分治法虽然效率没有前面两者好,但是它的思想极其深刻,详细解释可以参考算法导论

假定我们要寻找子数组nums[low… high]的最大子数组。使用分治技术意味着我们要将子数组划分为两个规模尽量相等的子数组。也就是说,找到子数组的中央位置,比如mid,然后考虑求解两个子数组nums[low. . mid]和 nums[mid+1…high]。如图所示,nums[low. . high]的任何连续子数组nums[i…j]所处的位置必然是以下三种情况之一:

完全位于子数组nums[low. . mid]中,因此low<=i<=mid。

完全位于子数组nums[mid+1…high]中,因此mid

跨越了中点,因此low<=i<=mid

在这里插入图片描述

因此,nums[low… high]的一个最大子数组所处的位置必然是这三种情况之一。实际上,A[low. . high]的一个最大子数组必然是完全位于nums[low. . mid]中、完全位于nums[mid+1…high]中或者跨越中点的所有子数组中和最大者。

**我们可以递归地求解nums[low. . mid]和 nums[mid+1…high]的最大子数组,因为这两个子问题仍是最大子数组问题,只是规模更小。**因此,剩下的全部工作就是寻找跨越中点的最大子数组,然后在三种情况中选取和最大者。

我们可以很容易地在线性时间(相对于子数组 nums[low. . high]的规模)内求出跨越中点的最大子数组。

此问题并非原问题规模更小的实例,因为它加人了限制——求出的子数组必须跨越中点。

如图所示,任何跨越中点的子数组都由两个子数组nums[i…mid]和nums[mid+1…j组成,其中 low≤i≤mid且mid

在这里插入图片描述

函数find_max_max接收数组nums和下标low、mid和high为输人,返回一个下标元组划定跨越中点的最大子数组的边界,并返回最大子数组中值的和。

早期刷letcode用c语言写的

double find_max_mid(int *nums,int l,int r,int mid)
{double lmax=-1e10,rmax=-1e10,maxl,maxr;double sum=0;for(int i=mid;i>=l;i--){sum+=nums[i];if(lmaxmaxl=i;lmax=sum;}}sum=0;for(int i=mid+1;i<=r;i++){sum+=nums[i];if(rmaxmaxr=i;rmax=sum;}}return lmax+rmax;
}
double find_max(int *nums,int l,int r)
{if(l==r)return nums[l];else{int mid=(l+r)/2;double lmax=find_max(nums,l,mid);double rmax=find_max(nums,mid+1,r);double midmax=find_max_mid(nums,l,r,mid);if(lmax>=rmax&&lmax>=midmax)return lmax;else if(rmax>=lmax&&rmax>=midmax)return rmax;elsereturn midmax;}
}
int maxSubArray(int* nums, int numsSize){
return find_max(nums,0,numsSize-1);
}

54. 螺旋矩阵

难度中等

给你一个 mn 列的矩阵 matrix ,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素。

示例 1:

输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]
输出:[1,2,3,6,9,8,7,4,5]

示例 2:

输入:matrix = [[1,2,3,4],[5,6,7,8],[9,10,11,12]]
输出:[1,2,3,4,8,12,11,10,9,5,6,7]

提示:

  • m == matrix.length
  • n == matrix[i].length
  • 1 <= m, n <= 10
  • -100 <= matrix[i][j] <= 100

按照题意模拟,可以用递归写法

class Solution {
public:vector spiralOrder(vector>& matrix) {if(matrix.empty() || matrix[0].empty()) return {};vector res;int m = matrix.size(), n = matrix[0].size();// 确定上下左右四条边的位置int up = 0, down = m - 1, left = 0, right = n - 1;while (true){ for (int i = left; i <= right; i++) res.push_back(matrix[up][i]);if (++up > down) break;for (int i = up; i <= down; i++) res.push_back(matrix[i][right]);if (--right < left) break;for (int i = right; i >= left; i--) res.push_back(matrix[down][i]);if (--down < up) break;for (int i = down; i >= up; i--) res.push_back(matrix[i][left]);if (++left > right) break;}return res;}
};

55. 跳跃游戏

难度中等

给定一个非负整数数组 nums ,你最初位于数组的 第一个下标

数组中的每个元素代表你在该位置可以跳跃的最大长度。

判断你是否能够到达最后一个下标。

示例 1:

输入:nums = [2,3,1,1,4]
输出:true
解释:可以先跳 1 步,从下标 0 到达下标 1, 然后再从下标 1 跳 3 步到达最后一个下标。

示例 2:

输入:nums = [3,2,1,0,4]
输出:false
解释:无论怎样,总会到达下标为 3 的位置。但该下标的最大跳跃长度是 0 , 所以永远不可能到达最后一个下标。

提示:

  • 1 <= nums.length <= 3 * 10^4
  • 0 <= nums[i] <= 10^5

尽可能到达最远位置(贪心)。
如果能到达某个位置,那一定能到达它前面的所有位置。

初始化最远位置为 0,然后遍历数组,如果当前位置能到达,并且当前位置+跳数>最远位置,就更新最远位置。最后比较最远位置和数组长度。

class Solution {
public:bool canJump(vector& nums) {int r=nums[0];for(int i=1;iif(i>r)return false;else{r=max(r,nums[i]+i);}}return true;}
};

12.7每日一题

1775. 通过最少操作次数使数组的和相等

难度中等127收藏分享切换为英文接收动态反馈

给你两个长度可能不等的整数数组 nums1nums2 。两个数组中的所有值都在 16 之间(包含 16)。

每次操作中,你可以选择 任意 数组中的任意一个整数,将它变成 16 之间 任意 的值(包含 16)。

请你返回使 nums1 中所有数的和与 nums2 中所有数的和相等的最少操作次数。如果无法使两个数组的和相等,请返回 -1

示例 1:

输入:nums1 = [1,2,3,4,5,6], nums2 = [1,1,2,2,2,2]
输出:3
解释:你可以通过 3 次操作使 nums1 中所有数的和与 nums2 中所有数的和相等。以下数组下标都从 0 开始。
- 将 nums2[0] 变为 6 。 nums1 = [1,2,3,4,5,6], nums2 = [6,1,2,2,2,2] 。
- 将 nums1[5] 变为 1 。 nums1 = [1,2,3,4,5,1], nums2 = [6,1,2,2,2,2] 。
- 将 nums1[2] 变为 2 。 nums1 = [1,2,2,4,5,1], nums2 = [6,1,2,2,2,2] 。

示例 2:

输入:nums1 = [1,1,1,1,1,1,1], nums2 = [6]
输出:-1
解释:没有办法减少 nums1 的和或者增加 nums2 的和使二者相等。

示例 3:

输入:nums1 = [6,6], nums2 = [1]
输出:3
解释:你可以通过 3 次操作使 nums1 中所有数的和与 nums2 中所有数的和相等。以下数组下标都从 0 开始。
- 将 nums1[0] 变为 2 。 nums1 = [2,6], nums2 = [1] 。
- 将 nums1[1] 变为 2 。 nums1 = [2,2], nums2 = [1] 。
- 将 nums2[0] 变为 4 。 nums1 = [2,2], nums2 = [4] 。

提示:

  • 1 <= nums1.length, nums2.length <= 105
  • 1 <= nums1[i], nums2[i] <= 6

这题的贪心挺有意思,后面还可以用哈希优化

首先,根据题意,我们需要计算出数组nums1和nums2之间,最小的操作次数,使得nums1的总和:sum(nums1)与nums2的总和:sum(nums2)两个值相等。那么我们可以根据如下4个步骤来解决这个问题:

  • 步骤1:分别计算sum(nums1)和sum(nums2)的值,确定两个数组加和的差值diff,以及sum(nums1)和sum(nums2)之间的大小关系。
  • 步骤2将总和较小的数组赋值为int[] smaller,将总和较大的数组赋值为int[] bigger。
  • 对于smaller数组中的每个值,我们要执行变大操作,其中:由于最大值是6,所以每个元素s变大的最大跨度是:6 - s;
    对于bigger数组中的每个值,我们要执行变小操作,其中:由于最小值是1,所以每个元素b变大的最大跨度是:b - 1;

贪心

class Solution {
public:int minOperations(vector& nums1, vector& nums2) {if (nums1.size() > nums2.size() * 6 && nums1.size() * 6 < nums2.size())return -1;int sum1 = 0, sum2 = 0;;for (auto i : nums1)sum1 += i;for (auto i : nums2)sum2 += i;vectornums(nums1.size() + nums2.size());int x = 0,dif;if (sum1 < sum2)swap(nums1, nums2), dif = sum2 - sum1;else if(sum1==sum2)return 0;elsedif = sum1 - sum2;for (auto& i : nums1)nums[x++] =i-1;for (auto& i : nums2)nums[x++]=6-i;sort(nums.begin(), nums.end());for (int i = nums.size() - 1; i >= 0; i--){dif -= nums[i];if (dif <= 0)return nums.size() - i;}return -1;}
};

贪心+哈希

class Solution {
public:int minOperations(vector& nums1, vector& nums2) {if (nums1.size() > nums2.size() * 6 && nums1.size() * 6 < nums2.size())return -1;int sum1 = 0, sum2 = 0;;for (auto i : nums1)sum1 += i;for (auto i : nums2)sum2 += i;int x = 0,dif;if (sum1 < sum2)swap(nums1, nums2), dif = sum2 - sum1;else if(sum1==sum2)return 0;elsedif = sum1 - sum2;int a[6]={0};for (auto i : nums1)a[i-1]++;for (auto i : nums2)a[6-i]++;int ans=0;for(int i=5;i>0;i--)for(int j=0;jdif-=i;ans++;if(dif<=0)return ans;}return -1;}
};

相关内容

热门资讯

用心做好每一块电池的欣旺达,因... 这两天国内动力电池生产厂商欣旺达遇到麻烦事了,因其所生产的电芯存在质量问题被威睿电动汽车技术(宁波)...
以案为鉴筑防线 以审促廉扬清风... 为充分发挥以案释法、以案说纪的警示教育作用,进一步加强党风廉政建设,提高党员干部的法纪意识和廉洁意识...
新加坡国立大学东亚研究所高级研... 由三亚市人民政府主办,《财经》杂志、财经网、《财经智库》、三亚中央商务区管理局、三亚经济研究院承办的...
原创 全... 在国家有关调查力量进驻南京之后,一个并不显眼、却耐人寻味的现象悄然出现了。 短时间内,全国多地博物馆...
跨境金融研究院院长王志毅:离岸... 由三亚市人民政府主办,《财经》杂志、财经网、《财经智库》、三亚中央商务区管理局、三亚经济研究院承办的...
原告向法官出示证据,右下角赫然... 近日,湖北孝感大悟法院民二庭在审理一起房屋租赁合同纠纷案时,精准识破原告方利用AI技术伪造证据的行为...
美国纽约州出台法律约束“成瘾性... 美国纽约州州长凯茜·霍楚尔26日宣布,根据该州新出台的一项法律,具备无限刷新、自动播放和算法推送功能...
富安娜理财纠纷一审落槌,中信证... 乐居财经 李兰经历近三年后,富安娜(002327.SZ)理财纠纷有了新进展。 12月25日,富安娜发...
从合作伙伴到对簿公堂:威睿起诉... 12月26日,欣旺达发布公告,其全资子公司欣旺达动力科技股份有限公司(下称“欣旺达动力”)因买卖合同...
突发!俄称已控制库皮扬斯克;泽... 俄乌,突传大消息! 俄国防部称已控制库皮扬斯克 俄罗斯国防部12月27日在每日例行通报中说,库皮扬斯...