1.盛水最多的容器
思路:双指针,一个最左,一个最右,由于容器的高度由最矮的边决定,因此当左面高于右面时,右面往左移;否则左面往右移,用一个res记录最大值,与每次的面积做对比。
class Solution {
public:
int maxArea(vector<int>& height) {
int len=height.size();
if(len<2) return 0;
int left=0;
int right=len-1;//双指针
int res=min(height[right],height[left])*(right-left);
while(left<right)
{
if(height[left]<height[right])
{
left++;
}
else
{
right--;
}
res=max(res,min(height[right],height[left])*(right-left));
}
return res;
}
};2.删除排序数组中的重复项
思路:从头到尾遍历,设一个指针,如果重复,指针不移动,如果不重复,指针移动,记录下不重复的数字。
class Solution {
public:
int removeDuplicates(vector<int>& nums) {
int len=nums.size();
if(len<2) return len;
int i=0;
int j=1;
for(i=1;i<len;i++)
{
if(nums[i]!=nums[i-1])
{
nums[j++]=nums[i];
}
}
return j;
}
};3.三数之和(重点)
思路:先对数组进行排序,从头开始遍历,依次选择一个数,然后利用双指针,一个指针指向所选择数的后一位,另一个指向数组的最后一位,如果相加等于0,那么记录下来,小于0,left++,大于0,right--。此问题要注意去重:如果某数与前一个数相同,则直接跳过,当符合条件时,看left++与right--是否与left和right相同。
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> res;
vector<int> cur;
int len=nums.size();
if(len<3) return res;//小于三不符合条件
sort(nums.begin(),nums.end());
for(int i=0;i<len-2;i++)
{
if(nums[i]>0) break;
if(i>0&&nums[i]==nums[i-1]) continue;//注意这个判断条件,是后和前比,不是前和后(-1,-1,2)说明不能前和后
int left=i+1;
int right=len-1;
while(left<right)
{
int sum=nums[i]+nums[left]+nums[right];
if(sum==0)
{
cur.push_back(nums[i]);
cur.push_back(nums[left]);
cur.push_back(nums[right]);
res.push_back(cur);
cur.clear();
while(left<right&&nums[left]==nums[left+1]) left++;//去重
while(left<right&&nums[right]==nums[right]-1) right--;//去重
left++;
right--;
}
else if(sum<0)
{
left++;
}
else
{
right--;
}
}
}
return res;
}
};4.移动0
思路:引入一个指针,从头到尾开始遍历,如果不为0,指针记录次数,后移一位,最后剩下的位置都补0.
class Solution {
public:
void moveZeroes(vector<int>& nums) {
if(nums.size()<=0) return;
int j=0;
for(int i=0;i<nums.size();i++)
{
if(nums[i]!=0)
{
nums[j++]=nums[i];
}
}
for(int k=j;k<nums.size();k++)
{
nums[k]=0;
}
}
};5.爬楼梯
思路:一个循环一个递归。
class Solution {
public:
int climbStairs(int n) {
//循环代替递归
if(n==1) return 1;
if(n==2) return 2;
int a=1;
int b=2;
int c;
for(int i=3;i<=n;i++)
{
c=a+b;
a=b;
b=c;
}
return c;
}
};6.合并两个有序链表
思路:一个循环一个递归,见程序。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
/*递归
if(l1==nullptr) return l2;
if(l2==nullptr) return l1;
ListNode *p=nullptr;
if(l1->val<l2->val)
{
p=l1;
p->next=mergeTwoLists(l1->next,l2);
}
else
{
p=l2;
p->next=mergeTwoLists(l1,l2->next);
}
return p;*/
ListNode *Head=new ListNode(-1);
ListNode *p=Head;
while(l1!=nullptr&&l2!=nullptr)
{
if(l1->val<=l2->val)
{
p->next=l1;
l1=l1->next;
}
else
{
p->next=l2;
l2=l2->next;
}
p=p->next;
}
if(l1==nullptr)
p->next=l2;
else
p->next=l1;
return Head->next;
}
};7.旋转数组
class Solution {
public:
void rotate(vector<int>& nums, int k) {
int len=nums.size();
k%=len;//重要一步,过长度轮会产生一个循环
reverse(nums,0,len-1);//整体翻转
reverse(nums,0,k-1);//前k个数翻转
reverse(nums,k,len-1);//剩下的数翻转
}
void reverse(vector<int>& nums,int begin,int end)
{
while(begin<end)
{
int temp=nums[begin];
nums[begin]=nums[end];
nums[end]=temp;
begin++;
end--;
}
}
};8.合并两个有序数组
思路:尾结点的双指针。
class Solution {
public:
void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
//尾部双指针
int tail=m+n-1;
int tail1=m-1;
int tail2=n-1;
while(tail1!=tail)//如果第一个数组遍历完了,就把第二个数组剩余的数字全都依次放在前面
{
if(tail1>=0&&nums1[tail1]>nums2[tail2])
{
nums1[tail--]=nums1[tail1--];//从尾开始对比,如果1大于2,就把1放在最末尾
}
else
{
nums1[tail--]=nums2[tail2--];
}
}
}
};9.两两交换链表中的节点
思路:注意新建两个节点,一个用来当前做改变,另一个保持不动用来返回。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution
{
public:
ListNode* swapPairs(ListNode* head)
{
//新建一个空结点,用来指向头节点
ListNode* p = new ListNode(0);
p->next = head;
//新建和p相同一个curr节点,两个相同的节点一个是当前做改变的节点,一个是保持不动用来返回的节点
ListNode* curr = p;
//循环条件为当前节点为NULL或当前的下一个节点为NULL,分别对应偶数和奇数个节点的终止标志
while(head != NULL && head->next != NULL)
{
//为了清晰明了,我们新建两个节点,一节点和二节点
ListNode* firstNode = head;
ListNode* secondNode = head->next;
///把一和二进行交换,并连接前后
//当前curr节点指向二节点
curr->next = secondNode;
//一节点指向二节点此时的下一节点
firstNode->next = secondNode->next;
//二节点指向一节点,即交换位置成功
secondNode->next = firstNode;
//由于每次循环curr节点都指向每次循环的一节点,所以要再次把curr节点指向一节点
curr = firstNode;
//每次移动都是由head节点来赋值操作,所以head应向右移动两格,即新循环的一节点
head = firstNode->next;
}
//返回p的下一个节点即对应整个操作后的链表
return p->next;
}
};10.链表形式的两数相加
思路:利用栈来存储逆序的计算,注意进位标志的保存,以及链表从尾到头生成。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
//逆序想到用栈
stack<int> s1, s2;
while (l1) {
s1.push(l1 -> val);
l1 = l1 -> next;
}
while (l2) {
s2.push(l2 -> val);
l2 = l2 -> next;
}
int carry = 0;
ListNode* ans = nullptr;
while (!s1.empty() || !s2.empty() || carry != 0) {
int a = s1.empty() ? 0 : s1.top();
int b = s2.empty() ? 0 : s2.top();
if (!s1.empty()) s1.pop();
if (!s2.empty()) s2.pop();
int cur = a + b + carry;
carry = cur / 10;//进位
cur %= 10;
auto curnode = new ListNode(cur);
curnode -> next = ans;
ans = curnode;//倒着往回走
}
return ans;
}
};
京公网安备 11010502036488号