给定一个整数数组 nums
,找出一个序列中乘积最大的连续子序列(该序列至少包含一个数)。
示例 1:
输入: [2,3,-2,4]
输出: 6
解释: 子数组 [2,3] 有最大乘积 6。
示例 2:
输入: [-2,0,-1]
输出: 0
解释: 结果不能为 2, 因为 [-2,-1] 不是子数组。
使用动态规划的方法,因为数组中由负数的出现,所以要考虑负负得正的情况,要保存最大值和最小值。
class Solution {
public:
//会出现负数乘负数得正数的情况,使用动态规划的方法
int maxProduct(vector& nums) {
int len=nums.size();
vector>dp;
dp.resize(2);
dp[0].resize(len); //dp[0][i]存放以i为结尾的子数组的最大乘积
dp[1].resize(len); //dp[1][i] 最小乘积
int result=nums[0];
dp[0][0]=nums[0];
dp[1][0]=nums[0];
for(int i=1;itemp)
temp=b;
if(c>temp)
temp=c;
return temp;
}
int min(int a,int b,int c){
int temp=a;
if(b
给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数。
示例 1:
输入: [1,2,3,4,5,6,7] 和 k = 3
输出: [5,6,7,1,2,3,4]
解释:
向右旋转 1 步: [7,1,2,3,4,5,6]
向右旋转 2 步: [6,7,1,2,3,4,5]
向右旋转 3 步: [5,6,7,1,2,3,4]
示例 2:
输入: [-1,-100,3,99] 和 k = 2
输出: [3,99,-1,-100]
解释:
向右旋转 1 步: [99,-1,-100,3]
向右旋转 2 步: [3,99,-1,-100]
说明:
尽可能想出更多的解决方案,至少有三种不同的方法可以解决这个问题。
要求使用空间复杂度为 O(1) 的原地算法。
第一个方法,空间复杂度不为 o(1)
class Solution {
public:
void rotate(vector& nums, int k) {
vector res(nums.size());
for(int i=0;i
第二种方法就是从网上看到的方法,观察旋转时候的数组会发现最终的结果是先旋转前n-k个元素,然后旋转后n个元素,最后旋转整个数组得到的。
1 2 3 4 5 6 7 k=3
4 3 2 1 5 6 7
4 3 2 1 7 6 5
5 6 7 1 2 3 4
class Solution {
public:
void rotate(vector& nums, int k) {
//先把前n-k个数翻转一下,再把后k个数翻转一下,再把整个数组翻转一下
k=k%nums.size(); //可能会出现要旋转的长度比数组要长,例如 nums=[-1],k=2
reverse(nums.begin(),nums.begin()+(nums.size()-k));
reverse(nums.begin()+(nums.size()-k),nums.end());
reverse(nums.begin(),nums.end());
}
};
第三种方法,旋转相当于是把最前面的元素插入到最后面,最后显示超时了,不知道为什么,可能是插入删除操作太费时了?
class Solution {
public:
void rotate(vector& nums, int k) {
k=k%nums.size();
for(int i=0;i
给定一个整数数组,判断是否存在重复元素。
如果任何值在数组中出现至少两次,函数返回 true。如果数组中每个元素都不相同,则返回 false。
示例 1:
输入: [1,2,3,1]
输出: true
示例 2:
输入: [1,2,3,4]
输出: false
示例 3:
输入: [1,1,1,3,3,4,3,2,4,2]
输出: true
第一种非常直接的思路,将数组排序,速度还不错
class Solution {
public:
bool containsDuplicate(vector& nums) {
if(nums.size()==1||nums.size()==0)
return false;
sort(nums.begin(),nums.end());
for(int i=1;i
给定一个数组 nums
,编写一个函数将所有 0
移动到数组的末尾,同时保持非零元素的相对顺序。
示例:
输入: [0,1,0,3,12]
输出: [1,3,12,0,0]
说明:
必须在原数组上操作,不能拷贝额外的数组。
尽量减少操作次数
最初的暴力的想法是直接将数组遍历,将0向后移动。但是总是觉得有些暴力,记录0的个数,似乎也行不通。还是选择用最暴力的方式。
也很清晰,写算法首先是要把它写出来吧,之后再要求效率之类的。不要将自己陷在一种马上要找出很好的算法的情况下。
class Solution {
public:
void moveZeroes(vector& nums) {
//如果实在是想不出其他方法就先用暴力方法算一下
int count=0;
for(int i=0;i
看到另一种解法,但实际上感觉操作的次数实际上一样的。
class Solution {
public:
void moveZeroes(vector& nums) {
int k = 0; //数组中索引为[0,k)的均为非零元素
for(int i = 0; i < nums.size(); i++){
if(nums[i] != 0){
if(k != i)
swap(nums[i],nums[k]);
k++;
}
}
}
};
打乱一个没有重复元素的数组。
示例:
// 以数字集合 1, 2 和 3 初始化数组。
int[] nums = {1,2,3};
Solution solution = new Solution(nums);
// 打乱数组 [1,2,3] 并返回结果。任何 [1,2,3]的排列返回的概率应该相同。
solution.shuffle();
// 重设数组到它的初始状态[1,2,3]。
solution.reset();
// 随机返回数组[1,2,3]打乱后的结果。
solution.shuffle();
class Solution {
private:
//会出现连续执行很多遍shuffle的情况,所以在每次shuffle之后都需要恢复
vector numsstatic;
vector nums2;
public:
Solution(vector& nums) {
nums2=nums;
numsstatic=nums;
}
int random(int num){
//定义产生指定范围的随机数的函数
return rand()%num;
}
/** Resets the array to its original configuration and return it. */
vector reset() {
//printf("reset");
nums2=numsstatic;
return numsstatic;
}
/** Returns a random shuffling of the array. */
vector shuffle() {
vector res;
for(int i=nums2.size();i>0;i--){
int rand=random(i);
res.insert(res.begin(),nums2[rand]);
//printf("%d",&nums2[rand]);
nums2.erase(nums2.begin()+rand);
}
nums2=numsstatic;
return res;
}
};
/**
* Your Solution object will be instantiated and called as such:
* Solution* obj = new Solution(nums);
* vector param_1 = obj->reset();
* vector param_2 = obj->shuffle();
*/
看了一下其他的解答,发现自己对这个题目的理解有些偏差,题目要求的是生成的结果要有完全的随机性,(可能需要数学证明吧,菜鸟只能是凭感觉了QAQ),如果应用在抽奖等基数很大的情况下,不是完全随机的话,是很有问题的。
解决这个问题的经典的方法是 Fisher–Yates shuffle 洗牌算法,思路和自己之前写的是相同的,但是直接往对应的位置放就可以了,不需要单独占用空间来存。
参考:https://www.zhihu.com/question/68330851/answer/266506621
class Solution {
private:
vector nochange;
vector change;
public:
Solution(vector& nums) {
nochange=nums;
change=nums;
}
int random(int num){
//定义产生指定范围的随机数的函数
//C++中产生随机数的方式是rand(),需要 #include
//产生0 ~ num-1的随机数
return rand()%num;
}
/** Resets the array to its original configuration and return it. */
vector reset() {
return nochange;
}
/** Returns a random shuffling of the array. */
vector shuffle() {
change=nochange;
for(int i=change.size()-1;i>0;i--){
int index=random(i+1); //需要从最后一个开始,否则还依旧不具有随机性
int temp=change[i];
change[i]=change[index];
change[index]=temp;
}
return change;
}
};
/**
* Your Solution object will be instantiated and called as such:
* Solution* obj = new Solution(nums);
* vector param_1 = obj->reset();
* vector param_2 = obj->shuffle();
*/
给定两个数组,编写一个函数来计算它们的交集。
示例 1:
输入: nums1 = [1,2,2,1], nums2 = [2,2]
输出: [2,2]
示例 2:
输入: nums1 = [4,9,5], nums2 = [9,4,9,8,4]
输出: [4,9]
说明:
输出结果中每个元素出现的次数,应与元素在两个数组中出现的次数一致。
我们可以不考虑输出结果的顺序。
进阶:
如果给定的数组已经排好序呢?你将如何优化你的算法?
如果 nums1 的大小比 nums2 小很多,哪种方法更优?
如果 nums2 的元素存储在磁盘上,磁盘内存是有限的,并且你不能一次加载所有的元素到内存中,你该怎么办?
#include
class Solution {
public:
vector intersect(vector& nums1, vector& nums2) {
vector res;
sort(nums1.begin(),nums1.begin()+nums1.size());
sort(nums2.begin(),nums2.begin()+nums2.size());
int i1=0;
int i2=0;
while(i1!=nums1.size()&&i2!=nums2.size()){
if(nums1[i1]==nums2[i2]){
res.insert(res.begin(),nums1[i1]);
i1++;
i2++;
}
else if(nums1[i1]nums2[i2]){
i2++;
}
}
return res;
}
};
另一种方法,使用map,或许题目中的对顺序没有要求就暗示了使用map呢,在一些元素要/不要同时出现之类的情况中可以考虑以下使用map是否可以。
#include
class Solution {
public:
vector intersect(vector& nums1, vector& nums2) {
vector res;
map container;
for(int i=0;i
给定一个未排序的数组,判断这个数组中是否存在长度为 3 的递增子序列。
数学表达式如下:
如果存在这样的 i, j, k, 且满足 0 ≤ i < j < k ≤ n-1,
使得 arr[i] < arr[j] < arr[k] ,返回 true ; 否则返回 false 。
说明: 要求算法的时间复杂度为 O(n),空间复杂度为 O(1) 。
示例 1:
输入: [1,2,3,4,5]
输出: true
示例 2:
输入: [5,4,3,2,1]
输出: false
题目的难点在于时间和空间复杂性的限制,同时否定了暴力遍历和动态规划的方式。
设置2个变量,分别记录遍历过程中的第一小和出现在第一小之后的第二小。
感叹一下,解法相当巧妙~
class Solution {
public:
bool increasingTriplet(vector& nums) {
//空间复杂度为1,直接否定掉了动态规划
//C++取最大值
int min1=INT_MAX;
int min2=INT_MAX;
for(int i=0;imin1&&nums[i]min2)
return true;
}
return false;
}
};
编写一个高效的算法来搜索 m x n 矩阵 matrix 中的一个目标值 target。该矩阵具有以下特性:
示例:
现有矩阵 matrix 如下:
[
[1, 4, 7, 11, 15],
[2, 5, 8, 12, 19],
[3, 6, 9, 16, 22],
[10, 13, 14, 17, 24],
[18, 21, 23, 26, 30]
]
给定 target = 5,返回 true。
给定 target = 20,返回 false。
看到题目最初的想法是使用递归,但是用递归的话长度大一些就会超时。
在网上看到的方法是:
1.由于数组中是有序的,所以对每一行进行二分查找
class Solution {
public:
bool find(vector>& matrix,int target,int row){
printf("find\n");
int low=0;
int high=matrix[0].size()-1; //从0到尺寸减1
int mid;
while(low<=high){
mid=(low+high)/2;
if(target==matrix[row][mid])
return true;
else if(target>matrix[row][mid])
low=mid+1;
else
high=mid-1;
}
return false;
}
bool searchMatrix(vector>& matrix, int target) {
if(matrix.size()<1)
return false;
if(matrix[0].size()<1)
return false;
for(int i=0;i
2.从最后一行开始,不断向右上角缩小数组。要充分利用好数组已经排好序的这个条件
class Solution {
public:
bool searchMatrix(vector>& matrix, int target) {
if(matrix.size()<1)
return false;
if(matrix[0].size()<1)
return false;
int i=matrix.size()-1;
int j=0;
while(i>=0&&j<=matrix[0].size()-1){
//while(i!=0&&j!=matrix[0].size()-1){ 最开始是这样写的,但是如果说只有一个数字的话就是不行的
//输入为 [[-5]],-5 的时候 结果就是错的,不要偷懒哦
if(matrix[i][j]==target)
return true;
else if(matrix[i][j]>target){
i--;
}
else if(matrix[i][j]
给定长度为 n 的整数数组 nums,其中 n > 1,返回输出数组 output ,其中 output[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积。
示例:
输入: [1,2,3,4]
输出: [24,12,8,6]
说明: 请不要使用除法,且在 O(n) 时间复杂度内完成此题。
进阶:
你可以在常数空间复杂度内完成这个题目吗?( 出于对空间复杂度分析的目的,输出数组不被视为额外空间。)
没有想出来,在网上找的解法,很笨了
联想到了高数里的夹逼定理(虽然他们之间并没有什么关联orz
有了思路之后这道题写起来还是蛮快的
class Solution {
public:
vector productExceptSelf(vector& nums) {
///很有意思哎。从右往左,从左往右,夹了中间的
vector left(nums.size());
vector right(nums.size());
int temp=1;
for(int i=0;i=0;i--){
temp=temp*nums[i];
//right.insert(right.begin(),temp);
right[i]=temp;
printf("right %d:%d\n",i,temp);
}
vectorres(nums.size());
for(int i=0;i=0&&i+1=nums.size()){
res[i]=left[i-1];
}
}
return res;
}
};