LeetCode 刷题汇总(第一阶段,随机游走)

Posted 陆嵩

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LeetCode 刷题汇总(第一阶段,随机游走)相关的知识,希望对你有一定的参考价值。

从 0 开始 LeetCode刷题

面临毕业,为了谋求一份工作,不得已走上了刷题之路。不追求解法的性能和代码的优雅,只追求在最短的时间内写出来。

很多人喜欢给各种各样的方法起一个奇奇怪怪的名字,比如说“回溯”、“滑动窗口”等等,不懂这些,也可以做呀。你最后自己想了一个方法做出来了,其实默默地也就用了这些所谓的方法。这些题目我做完了,别人和我聊起什么回溯,我也不懂什么意思。我只知道,暴力出奇迹,干就完了。

我们做计算数学的人的长处不在于刷题,奈何这个世界这么无奈。

其实,我一直在思考,用这些小算法题去考验一个人的才能,是不是一个合理的事情。我认为,算法题做得好不好,和个人的工作能力,没有什么相关性,用这个来考察一个人的算法能力,是有失公允的。刷题刷得好,不代表你真的就算法做得好,很多人都是面向答案做题的,每天刷题基本就做做阅读,然后复现一下。这样,即使你题目刷得再多,当给你一道没答案的题目的时候,你该不会还是不会。

文章目录

入门练习

1.两数之和
class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) 
    {
        for(int i=0;i<nums.size();i++)
        {
            for(int j=i+1;j<nums.size();j++)
            {
                if(nums[i]+nums[j]==target)
                {
                   vector<int> result = {i,j}; 
                   return result;
                }
            }
        }
        return {};

    }
};
28.实现strStr
class Solution {
public:
    int strStr(string haystack, string needle) {
        if(needle.length()==0)
        {return 0;}
        else
        {
            int pos = haystack.find(needle);
            if(pos == haystack.npos)
            {
                return -1;
            }
            else
            return pos;
        }
        

    }
};
78.子集
class Solution {
public:
    vector<vector<int>> subsets(vector<int>& nums) {
        sort(nums.begin(), nums.end());
        int numsSize = nums.size();
        vector<vector<int>> result = {{}};
        for(int i=0;i<result.size();++i)
        {
            for(int j=0;j<numsSize;++j)
            {
                vector<int> tmp(result[i]);
                if(tmp.size()==0||nums[j]>tmp.back())
                {
                    int tail = nums[j];
                    tmp.push_back(tail);
                    vector<int> newSet = tmp;
                    result.push_back(newSet);
                }
            }           
        }
        return result;

    }
    
};

数据结构

二叉树

104.二叉树的最大深度
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    int maxD = 1;
    int maxDepth(TreeNode* root) {
        if(root==NULL)
        {
            return 0;
        }
        int depth = 1;
        TreeNode* curRoot = root;
        getDepth(curRoot,depth);
        return maxD;
    }
    int getDepth(TreeNode* curRoot,int &depth)
    {
        TreeNode* tmp1 = curRoot->left;
        TreeNode* tmp2 = curRoot->right;
        if(tmp1!=NULL)
        {
            depth++; 
            getDepth(tmp1,depth);
        }
        if(tmp2!=NULL)
        {
            depth++; 
            getDepth(tmp2,depth);

        } 
        maxD = max(maxD,depth);
        depth--;
        return depth;
    }
};

何时用递归?每个节点拎起来都是一个崭新的开始。每个节点拎起来要做的事情就是递归要做的事情。不能多做,不能少做。多拎几个点看看就知道做多少了。

110.平衡二叉树
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    bool flag = true;
    bool isBalanced(TreeNode* root) {
        if(root==NULL)
        {
            return true;
        }
        root -> val = 0;
        maxHeight(root);
        cout<<root->val<<endl;
        judge(root);
        return flag;

    }
    int judge(TreeNode* curRoot)
    {
        TreeNode* left = curRoot->left;
        TreeNode* right = curRoot -> right;
        if(left!=NULL && right!=NULL)
        {
            int diffH = abs(left->val-right->val);
            cout<<diffH<<endl;
            if(diffH>1)
            {
                flag = false;
            }
        }
        if(left==NULL&&right!=NULL)
        {
            int diffH = abs(right->val);
            if(diffH>1)
            {
                flag = false;
            }
            cout<<"right is not NULL:"<<diffH<<endl;
        }
        if(right==NULL&&left!=NULL)
        {
            int diffH = abs(left->val);
            if(diffH>1)
            {
                flag = false;
            }
            cout<<diffH<<endl;
        }
        if(left!=NULL)
        {
            judge(left);
        }
        if(right!=NULL)
        {
            judge(right);
        }
    return 0;
    }
    int maxHeight(TreeNode* curRoot)
    {
        TreeNode* left = curRoot -> left;
        TreeNode* right = curRoot -> right;
        if(left!=NULL)
        {
            maxHeight(left);
        }
        if(right!=NULL)
        {
            maxHeight(right);
        }
        if(left==NULL&&right==NULL)
        {
            curRoot->val=1;
        }
        else
        {
            if(left!=NULL&&right==NULL)
            {
                curRoot->val = left->val+1;
            }
            if(left==NULL&&right!=NULL)
            {
                curRoot->val = right->val+1;
            }
            if(left!=NULL&&right!=NULL)
            {
                curRoot->val = max(left->val,right->val)+1;
            }
            
        } 
        return 0;    
    }
};

树的深度应该从1开始比较合理。

124.二叉树中的最大路径和
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution
{
public:
	void rec(TreeNode* root,int &maxSum)
	{
		int originVal= root->val;
		int maxLeftDepth = root->val;
		int maxRightDepth = root->val;
		TreeNode* left = root->left;
		TreeNode* right = root->right;
		if(left!=NULL)
		{
			cout<<maxLeftDepth<<endl;
			rec(left,maxSum);
			maxLeftDepth = max(originVal,maxLeftDepth+left->val);

		}

		if(right!=NULL)
		{

			cout<<maxRightDepth<<endl;
			rec(right,maxSum);
			maxRightDepth = max(originVal,maxRightDepth+right->val);

		}
		root->val = max(maxLeftDepth,maxRightDepth);
		root->val = max(originVal,root->val);
		maxSum = max(maxSum,maxLeftDepth+maxRightDepth-originVal);
		maxSum = max(maxSum,originVal);

	}

	int maxPathSum(TreeNode* root)
	{
		int maxSum = -999999999;
		rec(root,maxSum);
		return maxSum;
	}
};

搞清楚哪些是需要递归两层以上的量,我们将其作为返回参数进行传递。两层内的变量,看看是否能用树节点结构里面自带的变量。

236.二叉树的最近公共祖先
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
    TreeNode* commonAncestor;
    int recursion(TreeNode*root, TreeNode* p, TreeNode* q)
    {    
        TreeNode* left = root->left;
        TreeNode* right = root->right;
        int val = root->val;    
        int numHavePQ = 0;
        int leftNumHavePQ = 0;
        int rightNumHavePQ = 0;
        if(left!=NULL)
        {
            leftNumHavePQ = recursion(left,p,q);
        }
        if(right!=NULL)
        {
            rightNumHavePQ = recursion(right,p,q);
        }
        if(val==p->val||val==q->val)
        {
            numHavePQ++;
        }     
        numHavePQ = numHavePQ+leftNumHavePQ+rightNumHavePQ;
        cout<<"node:"<<val<<",numHavePQ:"<<numHavePQ<<endl;
        if(numHavePQ==2)
        {
            commonAncestor = root;
            return 0;
        }
        return numHavePQ;
    }
public:

    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        recursion(root,p,q);
        return commonAncestor;
    }
};

1、这里提供了一个二叉树递归的范式模板:
int recursion(TreeNoderoot, TreeNode p, TreeNode* q)
{
TreeNode* left = root->left;
TreeNode* right = root->right;
int val = root->val;
if(left!=NULL)
{
leftNumHavePQ = recursion(left,p,q);
}
if(right!=NULL)
{
rightNumHavePQ = recursion(right,p,q);
}
2、如有需要,可以设置每个递归层的私有变量,以及程序全局变量。但无法改变链表自带的变量个数。

102.二叉树的层序遍历
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
    //vector<int> r(10,0);
    vector<vector<int>> result;
    int recursion(TreeNode* root,int recursionLevel)
    {
        if(root==NULL)
        {
            return 0;
        }
        TreeNode* left = root->left;
        TreeNode* right = root->right;
        int val = root->val;
        int recursionLevelCur = recursionLevel+1;
        if(result.size()<recursionLevelCur+1)
        {
            vector<int> tmp;
            result.push_back(tmp);

        }
        result[recursionLevelCur].push_back(val);
        if(left!=NULL)
        {
            recursion(left,recursionLevelCur);
        }
        if(right!=NULL)
        {
            recursion(right,recursionLevelCur);
        }
        
        return 0;
    }
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        recursion(root,-1);
        return result;
    }
};

二叉树的遍历可以从前往后遍历,也可以从后往前遍历。
类内的成员变量无法在定义的时候就初始化。

107.二叉树的层序遍历II
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
    vector<vector<int>> result;
    int recursion(TreeNode* root,int level)
    {
        if(root==NULL)
        {
            return 0;
        }
        int currentLevel = level+1;
        TreeNode* left = root->left;
        TreeNode* right = root->right;
        int value = root->val;
        if(result.size()<currentLevel)
        {
            vector<int> tmp;
            result.insert(result.begin(),tmp);
        }
        result[result.size()-currentLevel].push_back(value);
        if(left!=NULL)
        {
            recursion(left,currentLevel);
        }
        if(right!=NULL)
        {
            recursion(right,currentLevel);
        }
        return 0;
    }
public:
    vector<vector<int>> levelOrderBottom(TreeNode* root) {
        recursion(root,0);
        return result;
    }
};

巧用 C++ STL 容器的灵活性,前插后插都可以。

103.二叉树的锯齿形层序遍历
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    vector<vector<int>> zigzagLevelOrder(TreeNode* root) {
        vector<vector<int>> result;
        if(root==NULL) return result;
        TreeNode* left = root->left;
        TreeNode* right = root->right;
        int value = root->val;
        
        vector<TreeNode*> from;
        vector<TreeNode*> to;
        from.push_back(root);
        int i = 0;
        while(1)
        {
            vector<int> tmp;
            for(auto &it:from)
            {
                tmp.push_back(it->val);
                if(it->left!=NULL)
                {
                    to.push_back(it->left);
                    cout<<it->left->val<<endl;
                }
                if(it->right!=NULL)
                {
                    to.push_back(it->right);
                    cout<<it->right->val<<endl;

                }
                
            }
            if(i%2==1)
            {
                reverse(tmp.begin(),tmp.end());
            }
            result.push_back(tmp);
            if(to.empty()) break;
            from = to;
            to.clear();
            i++;
            //cout<<i<<endl;

        }
        return result;
    }
        
};

while 循环,最好写成 while(1) xxx break;的形式,更加灵活。
写这种 while 跳出型的循环,最开始先不写 while,先按自己脑子里的逻辑写一遍这个流程,直到重复点,最后在适当的地方补上这个 while。

98.验证二叉搜索树
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
    int getMax(TreeNode* root)//HACK
    {
        if(root==NULL)
        {
            return 99999999;
        }
        int maxValue = root->val;
        if(root->left!=NULL)
        {
            maxValue = max(maxValue,getMax(root->left));
        }
        if(root->right!=NULL)
        {
            maxValue = max(maxValue,getMax(root->right));
        }
        return maxValue;
        
    }
    int getMin(TreeNode* root)//HACK
    {
        if(root==NULL)
        {
            return -99999999;
        }
        int minValue = root->val;
        if(root->left!=NULL)
        {
            minValue = min(minValue,getMin(root->left));
        }
        if(root->right!=NULL)
        {
            minValue = min(minValue,getMin(root->right));
        }
        return minValue;
        
    }
    bool recursion(TreeNode* root)
    {
        TreeNode* left = root->left;
        TreeNode* right = root->right;
        int value = root->val;
        int leftMax;
        int rightMin;
        leftMax = getMax(left);//todo
        rightMin = getMin(right);
        bool leftIsValid = true;
        bool rightIsValid = true;
        if(left!=NULL)
        {
            leftIsValid = recursion(left)&&(value>leftMax);
        }
        if(right!=NULL)
        {
            rightIsValid = recursion(right)&&(value<rightMin);
        }
        return leftIsValid&&rightIsValid;
    }
public:
    bool isValidBST(TreeNode* root) {
        return recursion(root);

    }
};

当你想利用节点的新的属性辅助你的程序的时候,首先可以利用递归的返回变量,如果递归的返回变量已经被使用,可以考虑在递归里面再利用一次递归来实时地求得这个值。
递归根节点总是用 root 来表示,返回总是先看看主程序的返回。

701.二叉搜索树中的插入操作
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
    int recursion(TreeNode* &root,int val)
    {
        if(root==NULL)
        {
            cout<<"root is null"<<endl;
            TreeNode* append = new TreeNode(val);
            root = append;
            cout<<root->val<<endl;
            return 0;
        }
        TreeNode* left=root->left;
        TreeNode* right=root->right;
        int value = root->val;
        if(val<value)
        {
            if(left==NULL)
            {
                TreeNode* append = new TreeNode(val);
                root->left = append;
            }
            else
                recursion(left,val);
        }
        else{
            if(right==NULL)
            {
                TreeNode* append = new TreeNode(val);
                root->right = append;

            }
            else
                recursion(right,val); 
            
        }
        return 0;
    }
    
public:
    TreeNode* insertIntoBST(TreeNode* root, int val) {
        recursion(root,val);
        return root;
    }
};

从前往后走,看看是插入左子树还是右子树,直到叶子节点,new 一个对象,让叶子节点的左边或者右边指向它。如果 root 就是空节点,直接 new 一个对象,让 root 指向它即可。
神奇的是,官方给出的第二张图似乎不是二解吧。问了几个人,似乎没人直到什么叫搜索树的插入。

链表

83.删除排序链表中的重复元素
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
    int printListNode(ListNode* root)
    {
        ListNode* cur = root;
        while(cur!=NULL)
        {
           cout<<cur->val<<endl;
           cur = (cur->next);
        }
        return 0;

    }
    int unique(ListNode* head)
    {
        while(1)
        {
        ListNode* next = head->next;
        if(next==NULL) break;
        if((head->val)==(next->val))
        {

            head->next = next->next;
        }
        else
            break;

        }
        return 0;
    }

public:
    ListNode* deleteDuplicates(ListNode* head) {
        ListNode* cur = head;
        //printListNode(head);
        while(cur!=NULL)
        {
            //cout<<cur->val<<endl;
            unique(cur);
            cur = cur->next;
        }
        return head;
    }
};

判断的时候最好以当前点为核心,而不是 next。NULL 不存在值的,这点要注意。

82.删除排序链表中的重复元素II
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* deleteDuplicates(ListNode* head) {
        ListNode* vitualNode = new ListNode;
        vitualNode->next = head;
        ListNode* cur = vitualNode;
        while(1)
        {
            if( cur->next==NULL) return vitualNode->next;
            cout<<"cur:"<<cur->val<<endl;
            ListNode* left = cur->next;
            ListNode* right = cur->next;
            while(1)
            {
                if(right==NULL||left->val!=right->val) break;
                cout<<"left:"<<left->val<<endl;
                cout<<"right:"<<right->val<<endl;
                right = right->next;
            }
            if(right!=left->next)
            {
                cur->next = right;

            }
            else
            {
                cur = cur->next;
            }

        }
        cout<<"vituralNode:"<<vitualNode->next->val<<endl;
        return vitualNode->next;    
    }
};

1、虚拟节点技术,因为 head 有可能就是重复的,所以要新增一个虚拟节点指向 head。
2、搞三个游标,一个游标在重复段前,表示要越过重复段的链。另外两个游标,用来标识重复段。即 a->b->b->c类型的,需要把第一个游标放在 a 位置,第二、第三个游标放在第一个 b 的位置,移动第三个游标,直到其挪到了 c 位置,然后让 a 指向 c 即可。

206.反转链表
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        if(head==NULL) return head;
        ListNode* last = NULL;
        ListNode* cur = head;
        while(1)
        {
            ListNode* next = cur->next;
            cur->next=last;
            last = cur;
            cur = next;
            if(cur==NULL) break;
        }
        return last;
    }
};

1、在 head 前面添加 NULL,然后实现箭头从右边到左边的翻转。
2、翻转前,要找个中间变量存下下一个点,方便当前点到下一点的迭代。

92.反转链表II
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* reverseBetween(ListNode* head, int left, int right) {
        ListNode* cur = head;
        ListNode* from = NULL;
        ListNode* to = NULL;
        ListNode* curr;
        int count = 1;
        while(1){
            if(count==left)
            {

                ListNode* last = NULL;
                curr = cur;
                while(1)
                {
                ListNode* next = curr->next;
                curr->next = last;
                if(count==right) {to=next;break;}
                last = curr;
                curr = next;
                count++;
                }
                break;
            }
            else
            {
                from = cur;
                cur=cur->next;
                count++;
               
            }
        }
        if(from!=NULL)
        {
            from->next=curr;
        }
        else
        {
            head = curr;
        }
        
        cur->next = to; 
        return head;



    }
};

1、注意审题:left 和 right 表示的是位置,而不是链表的值。
2、注意标记好短点的四个位置,便于最后的三段链接。
3、用 cout 计数,找到 left 对应的位置开始翻转,一直到 right 结束翻转。重调两端的链接即可。

21.合并两个有序链表
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution
{
public:
	ListNode* mergeTwoLists(ListNode* l1, ListNode* l2)
	{
        if(l1==NULL) return l2;
        if(l2==NULL) return l1;
		ListNode* cur1;
		ListNode* cur2;
        ListNode* cur;
		ListNode* head;
		if(l1->val<=l2->val)
		{
			cur = l1;
            cur1 = cur->next;
            cur2 = l2;
		}
		else
		{
			cur = l2;
            cur1 = cur->next;
            cur2 = l1;

		}
		head = cur;

		while(1)
		{	
           if(cur1==NULL)
           {
               cur->next=cur2;break;

           }
           if(cur2==NULL)
           {
               cur->next=cur1;break;
           }
           cout<<"cur:"<<cur->val<<endl;
            cout<<"cur1:"<<cur1->val<<endl;
            cout<<"cur2:"<<cur2->val<<endl;
                
			if(cur1->val<=cur2->val)
			{
                cur->next = cur1;
				cur = cur1;
                cur1 = cur1->next;
			}
			else
			{
                cur->next = cur2;
                cur = cur2;
                cur2 = cur2->next;
			}	
			if(cur1==NULL&&cur2==NULL)
				break;
		}
		return head;

	};
};

宁愿多写一些代码也别把程序逻辑搞得太复杂。
动手前先想清楚,想好用几个游标。太多太乱,太少不够。
边界的判断要想清楚,最好单独写。

86.分隔链表
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:  
    ListNode* partition(ListNode* head, int x) {
        ListNode* small = new ListNode;
        ListNode* large = new ListNode;
        ListNode* curSmall = small;
        ListNode* curLarge = large;
        ListNode* cur = head;
        ListNode* curNext;

        while(cur!=NULL)
        {
            //cout<<cur->val<<endl;
        
        if(cur->val<x)
        {
            curSmall->next = cur;
            curSmall = cur;
            //cout<<curSmall->val<<endl<<endl;
        }
        else
        {
            curLarge->next = cur;
            curLarge = cur;
            cout<<curLarge->val<<endl<<endl;
        }
        curNext = cur->next;
        cur->next = NULL;
        cur= curNext;
        }
        //cout<<endl<<curSmall->val<<endl;
        (curSmall->next) = (large->next);
        return small->next;
        //return head;
    }
};

1、报==42==ERROR: AddressSanitizer: heap-use-after-free on address的错误,可能是返回的链表打结了,得仔细地看看哪里有bug。
2、指针赋值是以为,指针 next 赋值,是改变指向。
3、学会添加虚拟的链表节点。

128.排序链表
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2)
	{
        if(l1==NULL) return l2;
        if(l2==NULL) return l1;
		ListNode* cur1;
		ListNode* cur2;
        ListNode* cur;
		ListNode* head;
		if(l1->val<=l2->val)
		{
			cur = l1;
            cur1 = cur->next;
            cur2 = l2;
		}
		else
		{
			cur = l2;
            cur1 = cur->next;
            cur2 = l1;

		}
		head = cur;

		while(1)
		{	
           if(cur1==NULL)
           {
               cur->next=cur2;break;

           }
           if(cur2==NULL)
           {
               cur->next=cur1;break;
           }
          // cout<<"cur:"<<cur->val<<endl;
          //  cout<<"cur1:"<<cur1->val<<endl;
          //  cout<<"cur2:"<<cur2->val<<endl;
                
			if(cur1->val<=cur2->val)
			{
                cur->next = cur1;
				cur = cur1;
                cur1 = cur1->next;
			}
			else
			{
                cur->next = cur2;
                cur = cur2;
                cur2 = cur2->next;
			}	
			if(cur1==NULL&&cur2==NULL)
				break;
		}
		return head;

	};

    ListNode* divide(ListNode* head)
    {
        if(head->next==NULL) return head;
        ListNode* quick;
        ListNode* slow;
        ListNode* last = new ListNode;
        quick = head;
        slow = head;
        last->next = slow;
        while(1)//快慢指针二分链表
        {
           // if(quick!=NULL)
            //    cout<<"slow:"<<slow->val<<"quick:"<<quick->val<<endl;
            if(quick==NULL||quick->next==NULL) 
            {
                last->next = NULL;//切断
                break;
            }
            last = slow;
            slow = slow ->next;
            quick = quick->next->next;       
        }//头小尾轻,慢指针之后的为第二部分,被分成了两部分
        head = divide(head);
        //if(head->next!=NULL)
        //cout<<head->val<<"\\n"<<head->next->val<<endl;
        slow = divide(slow);
        //cout<<slow->val<<"\\n"<<slow->next->val<<endl;
        head = mergeTwoLists(head,slow);
        return head;

    }
public:
    ListNode* sortList(ListNode* head) {
        if(head==NULL)
        {
            return head;
        }
        head = divide(head);
        return head;

    }
};

为了性能,采用了堆排序的分治思想。合并排序的程序直接抄了前面的合并两个有序链表。
一般来说,编译通过的代码有 bug,首先应该通过肉眼去阅读代码发现,而不是急着 cout。
利用快慢指针来找链表的分界点,边界条件需要想好。

143.重排链表
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    void reorderList(ListNode* head) {
        vector<ListNode*> nodes;
        ListNode* cur = head;
        while(cur!=NULL)
        {
            nodes.push_back(cur);
            cur = cur->next;
        }
        int size = nodes.size();
        int halfSize = size/2;
        int i=0,j=size-1;
        ListNode* cur1 = new ListNode;
        cur1->next = head;
        while(1)
        {
            cur1->next = nodes[i];
            cur1->next->next = nodes[j];
            cur1 = cur1->next->next;
            i++;
            j--;
            if(j<i) 
            {
                cur1->next=NULL;
                break;

            }
        }

    }
};

用 vector 来辅助别的数据结构题目,是一个非常明智的选择。
万物皆可 vector,YYDS。

141.环形链表
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    bool hasCycle(ListNode *head) {
        if(head==NULL) return false;
        vector<ListNode*> vec;
        ListNode* cur;
        cur = head;
        while(1)
        {
            //if(cur->pos==-1) return false;
            if(find(vec.begin(),vec.end(),cur)!=vec.end())
            {
                return true;

            }
            vec.push_back(cur);
            cur = cur->next;
            if(cur==NULL) break;

        }
        return false;
        
    }
};

改用 set 性能会好一些。

142.环形链表II
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        vector<ListNode*> vec;
        ListNode* cur = head;
        while(1)
        {
            if(cur==NULL) break;
            auto iter = find(vec.begin(),vec.end(),cur);
            if(iter!=vec.end())
            {
                int ind = iter-vec.begin();
                return vec[ind];
            }
            vec.push_back(cur);
            cur = cur->next;
            if(cur==NULL) break;
        }
        return NULL;

    }
};

用 vector 事半功倍。

234.回文链表
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    bool isPalindrome(ListNode* head) {
        vector<ListNode*> vec;
        ListNode* cur = head;
        while(1)
        {
            if(cur==NULL) break;
            vec.push_back(cur);
            cur = cur->next;
        }
        cout<<vec.size()<<endl;
        for(int i=0;i<vec.size()/2;i++)
        {
            cout<<"a:"<<vec[i]<<"and b:"<<vec[vec.size()-1-i]<<endl;
            if(vec[i]->val!=vec[vec.size()-1-i]->val)
                return false;
        }
        return true;
        
    }
};

搞清楚是值的异同判断还是地址的异同判断。

138.复制带随机指针的链表
/*
// Definition for a Node.
class Node {
public:
    int val;
    Node* next;
    Node* random;
    
    Node(int _val) {
        val = _val;
        next = NULL;
        random = NULL;
    }
};
*/

class Solution {
public:
    Node* copyRandomList(Node* head) {
        if(head==NULL) return NULL;
        unordered_map<Node*,Node*> map;
        Node* cur = head;
        Node* headNew = new Node(0);

        //Node headNewNode(0);
        //Node* headNew = &headNewNode;
        //cout<<"headNew:"<<headNew<<endl;

        Node* temp = headNew;

        while(cur!=NULL)
        {
            //cout<<"cur:"<<cur<<endl;
            //cout<<"temp:"<<temp<<endl;
            map.insert(make_pair(cur,temp));
           // map.insert(pair<Node*,Node*>(cur,temp));
           //cout<<"cur:"<<cur->val<<endl;
           
            temp->val = cur->val;
             //cout<<"temp:"<<temp->val<<endl;
            ///cout<<"temp:"<<temp->val<<endl;
            if(cur->next!=NULL)
            {
                
                Node* tempNew = new Node(0);
                temp-> next = tempNew;



                //cout<<"to here when temp's next = "<<temp->next->val<<endl;

            }
            else{
                temp->next = NULL;
            }
            
            cur = cur->next;
            temp = temp->next;
        }
        cur = head;
        Node* curNew = headNew;
        while(cur!=NULL)
        {

            auto rdm = cur->random;
            if(rdm==NULL)
                curNew->random = NULL;
            else
            {
                curNew->random = map.find(cur->random)->second;

            }
                        cout<<"cur:"<<cur->val<<endl;
            cout<<"curNew:"<<curNew->val<<endl;

            cur = cur->next;
            curNew = curNew->next;
        }
        return headNew;
        //return head;
        
    }
};

1、循环体里面的申请的变量都是临时的,每次循环都要经历一次申请和释放。
2、new 的时候,new 后面的类型的传入参数要符合构造函数的传入方式。Node* temp = new Node(3)
3、new 是个好东西,没东西的时候,可以 new 一个对象。
4、函数体和类方法里面定义的变量生存周期只在函数方法内,如若要求返回一个新造的东西,要用 new,可以保持周期的全局持久。

栈和队列

155.最小栈
class MinStack {
    vector<int> stack;
    int m;
    int size;
public:
    /** initialize your data structure here. */
    MinStack() {
        size = 0;

    }
    
    void push(int val) {
        stack.push_back(val);
        size++;

    }
    
    void pop() {
        stack.pop_back();
        size--;
    }
    
    int top() {
        return stack[size-1];
        

    }
    
    int getMin() {
        m = stack[0];
        for(auto &it:stack)
        {
            m = min(it,m);
        }
        return m;
    }
};

/**
 * Your MinStack object will be instantiated and called as such:
 * MinStack* obj = new MinStack();
 * obj->push(val);
 * obj->pop();
 * int param_3 = obj->top();
 * int param_4 = obj->getMin();
 */

大道至简,用你觉得最快的方法做,不要想太多。
尽可能选择最合适的数据结构,比如说直接用 stack。

150.逆波兰表达式求值
class Solution {
public:
    int evalRPN(vector<string>& tokens) {
        stack<int> v;
        for(string&it:tokens)
        {
            if(it=="+"||it=="-"||it=="*"||it=="/")
            {
                int b = v.top();
                v.pop();
                int a = v.top();
                v.pop();
                switch(it[0])
                {
                    case '+': v.push(a+b);break;
                    case '-': v.push(a-b);break;
                    case '*': v.push(a*b);break;
                    case '/': v.push(a/b);break;
                }

            }
            else
            {
                cout<<it<<endl;
                v.push(atoi(it.c_str()));

            }
        }
        return v.top();


    }
};

1、resize之后有值存在了。
2、有明显尺寸伸缩的用stack来做比较好。
3、尽可能使用熟悉但正确的东西来做。

394.字符串解码
class Solution {
public:
    string decodeString(string s) {
        int len = s.size();
        stack<pair<string,int>> stk;
        stk.push(make_pair("",0));
        int number = 0;
        string sTmp="";
        for(int i=0;i<len;i++)
        {
            char c = s[i];
            if(c>='0'&&c<='9')
            {
                number = 10*number+(c-'0');
            }
            else if((c>='a'&&c<='z')||(c>='A'&&c<='Z'))
            {
                stk.top().first = stk.top().first+c;
            }
            else if(c=='[')
            {  
                stk.top().second = number;
                number = 0; 
                stk.push(make_pair("",0));              

            }
            else if(c==']')
            {
                auto cur = stk.top();
                stk.pop();
                for(int i=0;i<stk.top().second;i++)
                    stk.top().first = stk.top().first+cur.first;
            }
            
        }
        return stk.top().first;
    }
};

1、string 可以当成是字符串数组使用。string[i] 是 char 类型。
2、敢于猜测一些数据结构的用法,错误了再修正。
3、stack 可以直接取值修改。
4、指针类型取不同位置用 ->, 一般用 .
5、做字符问题,最好给变量取一个好一点的名字,这样不会容易混淆。
6、尽可能用简单的数据结构。
7、总结:这种题目如果之前都没有接触过,还是有一定难度的,需要想想。

94.二叉树的中序遍历
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
    int recursion(TreeNode* root,vector<int> &result)
    {
        if(root==NULL) return 0;
        TreeNode* left = root->left;
        TreeNode* right = root->right;
        recursion(left,result);
        result.push_back(root->val);
        recursion(right,result);
        return 0;
    }
public:
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int> result;
        recursion(root,result);
        return result;        
    }
};

按递归的左->中->右的顺序进行遍历取值,自然就是中序遍历了,这可以思考。
用一个 vector 不断进行引用传值即可。

133.克隆图
/*
// Definition for a Node.
class Node {
public:
    int val;
    vector<Node*> neighbors;
    Node() {
        val = 0;
        neighbors = vector<Node*>();
    }
    Node(int _val) {
        val = _val;
        neighbors = vector<Node*>();
    }
    Node(int _val, vector<Node*> _neighbors) {
        val = _val;
        neighbors = _neighbors;
    }
};
*/

class Solution {
    unordered_map<Node*,Node*> map;
    int recursion(Node* node)
    {
        if(map.find(node)!=map.end())
        {
            return 0;
        }
        Node* newNode = new Node(node->val);
        map[node] = newNode;          
        for(auto &it:node->neighbors)
        {
            recursion(it);
            newNode->neighbors.push_back(map[it]);          
        }
        
        return 0;
    }
    
public:
    Node* cloneGraph(Node* node) {
        if(node==NULL) return NULL;
        Node* nodeCopy = new Node(node->val);
        map[node] = nodeCopy;
        if(empty(node->neighbors))
        {
            return nodeCopy;
        }
        for(auto &it:node->neighbors)
        {
            recursion(it);
            nodeCopy->neighbors.push_back(map[it]);

        }   
        return nodeCopy;
    }
};

1、unordered_map 支持中括号建值。
2、深拷贝的题一般可以做一个复制前复制后节点的一个 map。
3、map 有 find 方法。
4、递归容易错,主要是 neighbors.push_back 的点位要找准,一个 neighbor 递归完,就可以 push 它了。

200.岛屿数量
class Solution {
    int m,n;
    int recusion(vector<vector<char>>& grid,int i,int j)
    {
        if(i==-1||j==-1||i==m||j==n||grid[i][j]=='0')    
            return 0;
        grid[i][j] = '0';
        recusion(grid,i-1,j);
        recusion(grid,i,j-1);
        recusion(grid,i,j+1);
        recusion(grid,i+1,j);
        return 0;

    }
public:
    int numIslands(vector<vector<char>>& grid) {
        m = grid.size();
        n = grid[0].size();
        int count = 0;
        for(int i=0;i<m;i++)
        {
            for(int j=0;j<n;j++)
            {
                if(grid[i][j]=='1')
                {
                    count++;
                    recusion(grid,i,j);
                }
            }
        }
        return count;

    }
    
};
84.柱状图中的最大矩形
class Solution {
public:
    int largestRectangleArea(vector<int>& heights) {
        int maxN = 0;
        for(int i=0;i<heights.size();i++)
        {
            int ii = i;
            while(ii!=0&&heights[ii-1]>=heights[i]) 
            {
                ii--;
            }
            int jj = i;
            while(jj!=heights.size()-1&&heights[jj+1]>=heights[i]) 
            {
                jj++;
            }
            maxN = max(maxN,(jj-ii+1)*heights[i]);
            // if(i==4)
            // {
            //     cout<<heights[i]<<endl;
            //     cout<<jj<<endl;
            //     cout<<ii<<endl;

            // }
            
        }
        return maxN;
    }
};

暴力解法超时了。下面是非暴力的栈解法。

class Solution {
public:
    int largestRectangleArea(vector<int>& heights) {
        stack<int> stk;
        int N = heights.size();
        int Max=0;
        vector<int> leftBound(N,-1);

        int i = 0;
        while(1)
        {
            
            // if(i>0)
            // {            cout<<"stk.top()"<<stk.top()<<endl;
            // cout<<"leftBound[stk.top()]"<<leftBound[stk.top()]<<endl;
            // cout<<empty(stk)<<endl;
            // cout<<"heights[i]"<<heights[i]<<endl;
            // }

            
            if(!empty(stk))//对于相等的情况的特殊处理
            {
                if(heights[i]!=heights[stk.top()])
                {
                    //cout<<"i:"<<i<<endl;
                                
           

以上是关于LeetCode 刷题汇总(第一阶段,随机游走)的主要内容,如果未能解决你的问题,请参考以下文章

LeetCode刷题流程

图上随机游走

LeetCode Java刷题笔记汇总

算法刷题-O 时间插入删除和获取随机元素汇总区间

LeetCode 题解汇总

[LeetCode] LeetCode Summary 汇总