力扣数据结构刷题Day1-4
文章目录
前言
小小记录下数据结构的学习过程(花了365开极速判题通道 小小哭个穷呜呜呜)
一、小试牛刀
存在重复元素(L217)
给你一个整数数组 nums 。如果任一值在数组中出现 至少两次 ,返回 true ;如果数组中每个元素互不相同,返回 false 。
bool containsDuplicate(vector<int>&nums){
int len=nums.size();
sort(nums.begin(),nums.end());
for(int i=0;i<len-1;++i){
if(nums[i]==nums[i+1]){
return true;
}
}
return false;
}
最大子数组和(L53)
给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
子数组 是数组中的一个连续部分。
动态规划法
int maxSubArray(vector<int>& nums) {
int a=nums[0],b=0;
for(int i=0;i<nums.size();i++){
b=fmax(nums[i]+b,nums[i]);
a=fmax(a,b);
}
return a;
}
设f(i)为第i个数结尾的连续子数组的最大和
动态规划转移方程:f(i) = max{f(i-1)+nums[i],nums[i]}
贪心法
int sum=0;
for(int i=0;i<numsSize;i++){
sum+=nums[i];
result=max(result,sum);
if(sum<0) sum=0;
}
return result;
分治法
int maxSubArray(vector<int> &nums)
{
//类似寻找最大最小值的题目,初始值一定要定义成理论上的最小最大值
int result = INT_MIN;
int numsSize = int(nums.size());
result = maxSubArrayHelper(nums, 0, numsSize - 1);
return result;
}
int maxSubArrayHelper(vector<int> &nums, int left, int right)
{
if (left == right)
{
return nums[left];
}
int mid = (left + right) / 2;
int leftSum = maxSubArrayHelper(nums, left, mid);
//注意这里应是mid + 1,否则left + 1 = right时,会无线循环
int rightSum = maxSubArrayHelper(nums, mid + 1, right);
int midSum = findMaxCrossingSubarray(nums, left, mid, right);
int result = max(leftSum, rightSum);
result = max(result, midSum);
return result;
}
int findMaxCrossingSubarray(vector<int> &nums, int left, int mid, int right)
{
int leftSum = INT_MIN;
int sum = 0;
for (int i = mid; i >= left; i--)
{
sum += nums[i];
leftSum = max(leftSum, sum);
}
int rightSum = INT_MIN;
sum = 0;
//注意这里i = mid + 1,避免重复用到nums[i]
for (int i = mid + 1; i <= right; i++)
{
sum += nums[i];
rightSum = max(rightSum, sum);
}
return (leftSum + rightSum);
}
作者:pinku-2
链接:https://leetcode-cn.com/problems/maximum-subarray/solution/zui-da-zi-xu-he-cshi-xian-si-chong-jie-fa-bao-li-f/
来源:力扣(LeetCode)
两数之和(L1)
给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
vector<int> twoSum(vector<int>& nums, int target) {
int n=nums.size();
int i,j;
for(i=0;i<n-1;i++){
for(j=i+1;j<n;j++){
if(nums[i]+nums[j]==target){
return {i,j};
}
}
}
return {};
}
或使用哈希表如下
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int, int> hashtable;
for (int i = 0; i < nums.size(); ++i) {
auto it = hashtable.find(target - nums[i]);
if (it != hashtable.end()) {
return {it->second, i};
}
hashtable[nums[i]] = i;
}
return {};
}
作者:LeetCode-Solution
合并两个有序数组 (L88)
给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2 中的元素数目。
请你 合并 nums2 到 nums1 中,使合并后的数组同样按 非递减顺序 排列。
注意:最终,合并后数组不应由函数返回,而是存储在数组 nums1 中。为了应对这种情况,nums1 的初始长度为 m + n,其中前 m 个元素表示应合并的元素,后 n 个元素为 0 ,应忽略。nums2 的长度为 n 。
双指针easy
以下代码使用逆向双指针
void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
int p1 = m - 1, p2 = n - 1;
int tail = m + n - 1;
int cur;
while (p1 >= 0 || p2 >= 0) {
if (p1 == -1) {
cur = nums2[p2--];
} else if (p2 == -1) {
cur = nums1[p1--];
} else if (nums1[p1] > nums2[p2]) {
cur = nums1[p1--];
} else {
cur = nums2[p2--];
}
nums1[tail--] = cur;
}
}
作者:LeetCode-Solution
买卖股票的最佳时机(L121)
给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。
你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。
返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0 。
最重要的是要想到用二维数组!
int maxProfit(vector<int>& prices) {
int len=prices.size();
if(len<2) return 0;
int dp[len][2];
dp[0][0]=0;
dp[0][1]=-prices[0];
for(int i=1;i<len;i++){
dp[i][0]=max(dp[i-1][1]+prices[i],dp[i-1][0]);
dp[i][1]=max(-prices[i],dp[i-1][1]);
}
return dp[len-1][0];
}
两个数组的交集(L350)
给你两个整数数组 nums1 和 nums2 ,请你以数组形式返回两数组的交集。返回结果中每个元素出现的次数,应与元素在两个数组中都出现的次数一致(如果出现次数不一致,则考虑取较小值)。
可以不考虑输出结果的顺序。
使用哈希表
vector<int> intersect(vector<int>& nums1, vector<int>& nums2) {
if (nums1.size() > nums2.size()) {
return intersect(nums2, nums1);
}
unordered_map <int, int> m;
for (int num : nums1) {
++m[num];
}
vector<int> intersection;
for (int num : nums2) {
if (m.count(num)) {
intersection.push_back(num);
--m[num];
if (m[num] == 0) {
m.erase(num);
}
}
}
return intersection;
}
作者:LeetCode-Solution
排序+双指针
(方便之处在于有一个数组被便利完后可直接结束)
vector<int> intersect(vector<int>& nums1, vector<int>& nums2) {
sort(nums1.begin(), nums1.end());
sort(nums2.begin(), nums2.end());
int length1 = nums1.size(), length2 = nums2.size();
vector<int> intersection;
int index1 = 0, index2 = 0;
while (index1 < length1 && index2 < length2) {
if (nums1[index1] < nums2[index2]) {
index1++;
} else if (nums1[index1] > nums2[index2]) {
index2++;
} else {
intersection.push_back(nums1[index1]);
index1++;
index2++;
}
}
return intersection;
}
作者:LeetCode-Solution
重塑矩阵(L566)
在 MATLAB 中,有一个非常有用的函数 reshape ,它可以将一个 m x n 矩阵重塑为另一个大小不同(r x c)的新矩阵,但保留其原始数据。
给你一个由二维数组 mat 表示的 m x n 矩阵,以及两个正整数 r 和 c ,分别表示想要的重构的矩阵的行数和列数。
重构后的矩阵需要将原始矩阵的所有元素以相同的 行遍历顺序 填充。
如果具有给定参数的 reshape 操作是可行且合理的,则输出新的重塑矩阵;否则,输出原始矩阵。
将二维数组用一维形式遍历;构建的二维数组录入时行数和列数运用当前数的序数与列数的商和余数。
vector<vector<int>> matrixReshape(vector<vector<int>>& mat, int r, int c) {
int m=mat.size();
int n=mat[0].size();
if(r*c!=m*n){
return mat;
}
vector<vector<int>> ans(r,vector<int>(c));
for(int i=0;i<m*n;++i){
ans[i/c][i%c]=mat[i/n][i%n];
}
return ans;
}
杨辉三角(L118)
堪称最简单的动态规划了。
重点是用resize保证输出的每一行的容量变化!
vector<vector<int>> generate(int numRows) {
vector<vector<int>> dp(numRows);
for(int i=0;i<numRows;++i){
dp[i].resize(i+1);
dp[i][0]=1;
dp[i][i]=1;
}
for(int a=2;a<numRows;++a){
for(int b=1;b<a;++b){
dp[a][b]=dp[a-1][b-1]+dp[a-1][b];
}
}
return dp;
}