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;
    }
};