刷题笔记:LeetCode精选TOP面试题(2)

#101.对称二叉树

递归法:

class Solution {
public:
    bool check(TreeNode *p, TreeNode *q) {
        if (!p && !q) return true;
        if (!p || !q) return false;
        return p->val == q->val && check(p->left, q->right) && check(p->right, q->left);
    }

    bool isSymmetric(TreeNode* root) {
        return check(root, root);
    }
};

迭代法:

/**
 * 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 {
public:
    bool isSymmetric(TreeNode* root) {
        queue<TreeNode*> Q;
        Q.push(root);
        Q.push(root);
        TreeNode *p,*q;
        while(!Q.empty()){
            p=Q.front();
            Q.pop();
            q=Q.front();
            Q.pop();
            if(!p&&!q){
                continue;
            }
            if( (!p || !q)||(p->val!=q->val)){
                return false;
            }
            Q.push(p->left);
            Q.push(q->right);

            Q.push(p->right);
            Q.push(q->left);
        }
        return true;
    }
};

#102.二叉树的层序遍历

/**
 * 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 {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        if(root==NULL){
            return {};
        }
        vector<vector<int>> result;
        vector<int> temp;
        queue<pair<TreeNode* ,int>> Q;
        Q.push(make_pair(root,1));
        int last=1;
        while(!Q.empty()){
            TreeNode* node=Q.front().first;
            int depth=Q.front().second;
            if(last==depth){
                temp.push_back(node->val);
            }
            else{
                result.push_back(temp);
                temp.clear();
                temp.push_back(node->val);
            }
            last=depth;
            Q.pop();
            if(node->left)
                Q.push(make_pair(node->left,depth+1));
            if(node->right)
                Q.push(make_pair(node->right,depth+1));
            
        }
        result.push_back(temp);
        return result;

    }
};

#103.二叉树的锯齿形层次遍历

这道题面试时遇到了原题,当时我是用一个queue一个stack解决的,但这次刷到发现可以用一个dequeue节省空间复杂度!

/**
 * 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 {
public:
    vector<vector<int>> zigzagLevelOrder(TreeNode* root) {
        if(root==NULL) return {};
        vector<vector<int>> result;
        deque<TreeNode*> Q;
        Q.push_front(root);
        //是否是奇数行
        bool isOdd=true;
        while(!Q.empty()){
            vector<int> layer;
            //每次直接把这一层的都执行完
            for(int i=Q.size()-1;i>=0;i--){
                TreeNode *cur;
                //奇数行从前往后取节点,孩子从左向右进队尾
                if(isOdd){
                    cur =Q.front();Q.pop_front();
                    layer.push_back(cur->val);
                    if(cur->left)  Q.push_back(cur->left);
                    if(cur->right) Q.push_back(cur->right);
                }
                else{//偶数行从后往前取节点,孩子从右向左进队首 
                    cur=Q.back();Q.pop_back();
                    layer.push_back(cur->val);
                    if(cur->right) Q.push_front(cur->right);
                    if(cur->left)  Q.push_front(cur->left);
                }
            }
            //每一层遍历完 奇偶数交换,并把该层加入结果中
            isOdd=!isOdd;
            result.push_back(layer);
        }
        return result;
    }
};

#104.二叉树的最大深度

怎么遍历都可以,我写了个递归的深搜

/**
 * 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 {
public:
    int maxDepth(TreeNode* root) {
        if(root==NULL){
            return 0;
        }
        int ldepth=maxDepth(root->left);
        int rdepth=maxDepth(root->right);
        return (max(ldepth,rdepth)+1) ;
    }
};

#105.从前序与中序遍历构造二叉树

自己写了一个用递归,但速度和内存消耗都不太理想!!

/**
 * 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 {
public:
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        int m=preorder.size();
        if(m==0) return NULL;
        //根就是先根序遍历得根
        TreeNode* root=new TreeNode(preorder[0]);
        //定义向下传递得vector
        vector<int> preorder_left,inorder_left,preorder_right,inorder_right;
        int index;
        //把左右子树得中序遍历数组求好
        for(index=0;index<m;index++){
            if(inorder[index]==preorder[0]) break;
            inorder_left.push_back(inorder[index]);
        }
        for(index=index+1;index<m;index++){
            inorder_right.push_back(inorder[index]);
        }
        //计算左右子树前序遍历得俩数组
        for(index=1;index<m;index++){
            //构造左子树前序遍历
            if(index<=inorder_left.size()){
                preorder_left.push_back(preorder[index]);
            }
            else{//构造右子树前序遍历
                preorder_right.push_back(preorder[index]);
            }
        }
        //把当前节点关系创建好
        root->left=buildTree(preorder_left,inorder_left);
        root->right=buildTree(preorder_right,inorder_right);
        return root;

    }
};


#108.将有序数组转换为二叉搜索树

递归就好!!!  发现了嘛?只要让你构造二叉树,就很可能用递归就可以解决呦!!

/**
 * 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 {
public:
    TreeNode* sortedArrayToBST(vector<int>& nums) {
        return construct(nums,0,nums.size()-1);
    }

    TreeNode* construct(vector<int>& nums,int left,int right){
        if(left>right){
            return NULL;
        }
        //总是选择中间位置左边数字为根
        int mid=(left+right)/2;
        TreeNode *root=new TreeNode(nums[mid]);
        root->left=construct(nums,left,mid-1);
        root->right=construct(nums,mid+1,right);
        return root;
    }
};

 

#116.填充每个节点的下一个右侧节点指针

又是层次遍历的变形!!

/*
// Definition for a Node.
class Node {
public:
    int val;
    Node* left;
    Node* right;
    Node* next;

    Node() : val(0), left(NULL), right(NULL), next(NULL) {}

    Node(int _val) : val(_val), left(NULL), right(NULL), next(NULL) {}

    Node(int _val, Node* _left, Node* _right, Node* _next)
        : val(_val), left(_left), right(_right), next(_next) {}
};
*/

class Solution {
public:
    Node* connect(Node* root) {
        if(root==NULL){
            return root;
        }
        queue<Node*> Q;
        Q.push(root);
        while(!Q.empty()){
            int length=Q.size();
            for(int i=0;i<length-1;i++){
                Node* cur=Q.front();
                Q.pop();
                if(cur->left) Q.push(cur->left);
                if(cur->right) Q.push(cur->right);
                cur->next=Q.front();
            }
            Node* cur=Q.front();
            Q.pop();
            cur->next=NULL;
            if(cur->left) Q.push(cur->left);
            if(cur->right) Q.push(cur->right);
        }
        return root;
    }
};


 

#118.杨辉三角

算是动态规划吧!!!

class Solution {
public:
    vector<vector<int>> generate(int numRows) {
        vector<vector<int>> result;
        if(numRows==0){
            return result;
        }
        result.push_back({1});
        if(numRows==1){
            return result;
        }
        for(int i=2;i<=numRows;i++){
            result.push_back(vector<int>(i,1));
            for(int j=1;j<i-1;j++){
                result[i-1][j]=result[i-2][j-1]+result[i-2][j];
            }
        }
        return result;
    }
};

#121.买卖股票的最佳时机

动态规划即可

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        if(prices.size()==0){
            return 0;
        }
        vector<int> dp(prices.size(),0);
        int min=prices[0];
        int max=prices[0];
        for(int i=1;i<prices.size();i++){
            if(prices[i]-min>dp[i-1]){
                dp[i]=prices[i]-min;
            }
            else{
                dp[i]=dp[i-1];
            }
            if(prices[i]>max){
                max=prices[i];
            }
            if(prices[i]<min){
                min=prices[i];
            }
        }
        return dp.back();
    }
};

#122.买卖股票的最佳时机 II

贪心算法

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int result=0;
        for(int i=1;i<prices.size();i++){
            if(prices[i]>prices[i-1]){
                result+=prices[i]-prices[i-1];
            }
        }
        return result;
    }
};

#125.验证回文串

要记得 isalnum()判断是否是字母和数字,tolower()变小写这些常用的库函数

class Solution {
public:
    bool isPalindrome(string s) {
        if(s.size()<2){
            return true;
        }
        int l=0;
        int r=s.size()-1;
        while(l<r){
            if(!isalnum(s[l])){
                l++;
                continue;
            }
            if(!isalnum(s[r])){
                r--;
                continue;
            }
            if(tolower(s[l])==tolower(s[r]) ){
                l++;
                r--;
            }
            else{
                return false;
            }
        }
        return true;
    }
};

#127.单词接龙

很重要的一道题,双向BFS,BFS的搜索过程是金字塔型的,随着搜索深度的增加塔基会越来越大。而使用双向BFS可以有效的优化这种问题!

// Time 68ms, 13.4MB
class Solution {
public:
	int ladderLength(string beginWord, string endWord, vector<string>& wordList) {
        //
		unordered_map<string,int> freqs;
		for(const auto &word:wordList)
			freqs[word]=0;
        //压根没有目标直接返回0
		if(freqs.count(endWord)==0) return 0;
        //双向BFS,所以需要两个队列
		queue<string> q1({beginWord}), q2({endWord});
		int step=1;
		for(freqs[beginWord]|=1,freqs[endWord]|=2; q1.size() && q2.size(); ++step){
			//拿到短的队列
            bool first=q1.size()<q2.size();
			queue<string> &q=first?q1:q2;
			int flag=first?1:2;
            //当前层全部搜一遍
			for(int size=q.size(); size--; q.pop()){
				string &word=q.front();
                //相遇时停止
				if(freqs[word]==3) return step;
                //找下一个词
				for(int i=0; i<word.length(); ++i){
					for(char ch='a'; ch<='z'; ++ch){
						string s=word;
						if(s[i]==ch) continue;
						s[i]=ch;
                        //没有,或者前面在当前队列中已经搜过了就跳过
						if(freqs.count(s)==0 || freqs[s]&flag) continue;
                        //标记为搜索到
						freqs[s]|=flag;
						q.push(s);
					}
				}
			}
		}
		return 0;
	}
};

 

#128.最长连续序列

这道题是困难难度的,因为他想考察并查集,但用哈希表来做其实不太难

class Solution {
public:
    int longestConsecutive(vector<int>& nums) {
        unordered_set<int> st;
        for(int n:nums) st.insert(n);
        int ans=0;
        for(int i:st){
            if(i!=INT_MIN && st.count(i-1)){
                continue;
            }
            int cnt=1;
            while(i!=INT_MAX && st.count(i+1)){
                cnt++;
                i++;
            }
            ans=max(ans,cnt);
        }
        return ans;
    }
};

#130.被围绕的区域

非常巧妙的反向思维,把搜索内部O变成从边界的O开始深搜!!!

class Solution {
public:
    void solve(vector<vector<char>>& board) {
        if(board.size()<=1 || board[0].size()<=1){
            return;
        }
        int row=board.size();
        int col=board[0].size();
        for(int i=0;i<row;i++){
            for(int j=0;j<col;j++){
                if((i==0 || j==0 || i==row-1 || j==col-1) && board[i][j]=='O'){
                    DFS(board,i,j);
                }
            }
        }

        for(int i=0;i<row;i++){
            for(int j=0;j<col;j++){
                if(board[i][j]=='O'){
                    board[i][j]='X';
                }
                else if(board[i][j]=='#'){
                    board[i][j]='O';
                }
            }
        }
    }
private:
    void DFS(vector<vector<char>> &board,int i,int j){
        static const int dx[]={1,-1,0,0};
        static const int dy[]={0,0,1,-1};
        board[i][j]='#';
        for(int k=0;k<4;k++){
            int newx=dx[k]+i;
            int newy=dy[k]+j;
            if(newx>=0 && newx<board.size() && newy>=0 && newy<board[0].size() &&  board[newx][newy]=='O' ){
                DFS(board,newx,newy);
            }
        }

    }
};

#131.分割回文串

这种要求返回所有可能的题目基本就是回溯法

class Solution {
    vector<vector<string>> res;
    int size;
    //检查是否是回文串
    bool check(const string&s, int i, int j) {
        if (j < i) return true;
        if (s[i++] == s[j--]) return check(s, i, j);
        else return false;
    }
    void backtrack(const string& s, int ps, vector<string>& temp) {
        if (ps >= size) {
            res.push_back(temp);
            return;
        }
        //递归树分支:以当前ps位置为开始分割所有的回文串,后面部分递归进行处理
        for (int i = ps; i < size; ++i) {
            if (check(s, ps, i)) {
                temp.push_back(s.substr(ps, i-ps+1));
                backtrack(s, i+1, temp);
                temp.pop_back();
            }
        }
    }
public:
    vector<vector<string>> partition(const string& s) {
        size = s.size();
        if (size == 0) return res;
        vector<string> temp;
        backtrack(s, 0, temp);
        return res;
    }
};

#132.分割回文串II

看到要求返回最少次数之类问题,就可以考虑动态规划!!

class Solution {
public:
    int minCut(string s) {
        int len=s.length();

        // 状态定义:dp[i]:前缀子串 s[0:i] (包括索引 i 处的字符)符合要求的最少分割次数
        int dp[len];

        // 1 个字符最多分割 0 次;
        // 2 个字符最多分割 1 次;
        // 3 个字符最多分割 2 次
        // 初始化的时候,设置成为这个最多分割次数
        for(int i=0;i<len;i++){
            dp[i]=i;
        }

        //创建二维数组用于记录子串s[a:b]是否为回文串,且一开始全部初始化为false(可以发现a<=b)
        vector<vector<bool>> checkPalindrome(len, vector<bool>(len, false));
        
        //根据所给的字符串s,遍历,记录子串s[a:b]是否为回文串
        for(int right=0;right<len;right++){
            for(int left=0;left<=right;left++){
                if(s[left]==s[right] && (right-left<=2 || checkPalindrome[left+1][right-1])){ // "right-left<=2" 和 "checkPalindrome[left+1][right-1]"位置不可换
                    checkPalindrome[left][right]=true;
                }
            }
        }

        // 状态转移方程:
        // dp[i] = min(dp[j] + 1 if s[j + 1: i] 是回文 for j in range(i))
        for(int i=0;i<len;i++){
            if(checkPalindrome[0][i]){
                dp[i]=0;
                continue;
            }
            for(int j=0;j<i;j++){
                if(checkPalindrome[j+1][i]){
                    dp[i]=min(dp[i],dp[j]+1);
                }
            }
        }

        return dp[len-1];
    }
};

自己写的一个会超出时间,因为判断是否是回文数的算法用的双指针,是线性时间复杂度


class Solution {
public:
    int minCut(string s) {
        if(s.size()<2){
            return 0;
        }
        vector<int> dp(s.size());
        //初始化
        for(int i=0;i<dp.size();i++){
            dp[i]=i;
        }

        for(int i=0;i<s.size();i++){
            //自己本身就是的话就不用分割
            if(check(s,0,i)){
                dp[i]=0;
            }
            else{
                for(int j=0;j<i;j++){
                    if(check(s,j+1,i)){
                        dp[i]=min(dp[i],dp[j]+1);
                    }
                }
            }
        }

        return dp[s.size()-1];
    }

    bool check(string s,int begin,int end){
        int i=begin;
        int j=end;
        while(i<j){
            if(s[i]!=s[j]){
                return false;
            }
            else{
                i++;
                j--;
            }
        }
        return true;
    }
};

#134.加油站

先判断能不能走一圈,如果能就用双指针来走一遍!!!

class Solution {
public:
    int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
	if (gas.size() == 1)
		return gas[0] >= cost[0] ? 0 : -1;
	int gas_sum = accumulate(gas.begin(), gas.end(),0);//0为累加的初值
	int cost_sum = accumulate(cost.begin(), cost.end(), 0);
    //这里进行初始判断,如果总汽油量小于总花费量直接返回-1.
	if (gas_sum < cost_sum )
		return -1;
    
	int left = 0;//由于条件以满足,故left可以任意赋初值。
	int right = 1;
	int temp = gas[left]-cost[left];
    int N=gas.size();
	while (right != left)
	{
		if (temp >= 0)
		{
            //走到right处,right右移
			temp += gas[right] - cost[right];
			right = right == N - 1 ? 0 : right + 1;
		}
		else
		{   //向左找加油站
			left = left == 0 ? N - 1 : left - 1;//这里要先改left再加。
			temp += gas[left] - cost[left];
		}
	}
	return left;
}
};

 

#136.只出现一次的数字

记得位运算可以巧妙解决问题呀!!!!!!!!!!!!!

class Solution {
public:
    int singleNumber(vector<int>& nums) {
        int result=0;
        for(int i=0;i<nums.size();i++){
            result=result^nums[i];
        }
        return result;
    }
};

#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) {
        map<Node*,int> map1;
        vector<Node*> map2;
        Node* head1=head;
        if(!head1)
        {
            return NULL;
        }
        int i=0;
        while(head1)
        {
            //新增结点
            map2.push_back(new Node(head1->val));
            //原链表对应关系存入map1
            map1[head1]=i; 
            head1=head1->next;    
            i++;
        }
        head1=head;
        i=0;
        map2.push_back(0);
        while(head1)
        {
            map2[i]->next=map2[i+1];   
            if(head1->random)
            {
                map2[i]->random=map2[map1[head1->random]];
            }     
            head1=head1->next;
            i++;   
        }
        return map2[0];

    }
};

#139.单词拆分

不是特别容易想到的一个动态规划

class Solution {
public:
    bool wordBreak(string s, vector<string>& wordDict) {
        unordered_set<string> wordDictSet;
        for(auto i:wordDict){
            wordDictSet.insert(i);
        }
        vector<bool> dp(s.size()+1,false);
        dp[0]=true;
        for(int i=1;i<=s.size();i++){
            for(int j=0;j<i;j++){
                //前面j个字串可以,j到i也可以
                if(dp[j] && wordDictSet.find(s.substr(j,i-j))!=wordDictSet.end() ){
                    dp[i]=true;
                    break;
                }
            }
        }
        return dp.back();
    }
};

#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){
            return false;
        }
        ListNode *fast=head;
        ListNode *slow=head;
        while(fast){
            fast=fast->next;
            if(!fast) return false;
            fast=fast->next;
            slow=slow->next;
            if(fast==slow){
                return true;
            }
        }
        return false;
    }
};

#146.LRU缓存机制

考察数据结构能力!!自己没想出来,直接放官方代码吧

---------------题目内容--------------------------------------------------

运用你所掌握的数据结构,设计和实现一个  LRU (最近最少使用) 缓存机制。它应该支持以下操作: 获取数据 get 和 写入数据 put 。

获取数据 get(key) - 如果关键字 (key) 存在于缓存中,则获取关键字的值(总是正数),否则返回 -1。
写入数据 put(key, value) - 如果关键字已经存在,则变更其数据值;如果关键字不存在,则插入该组「关键字/值」。当缓存容量达到上限时,它应该在写入新数据之前删除最久未使用的数据值,从而为新的数据值留出空间。

//哈希双链表
struct DLinkNode{
    int key,value;
    DLinkNode *prev;
    DLinkNode *next;
    DLinkNode():key(0),value(0),prev(nullptr),next(nullptr){}
    DLinkNode(int _key,int _value):key(_key),value(_value),prev(nullptr),next(nullptr){}
};


class LRUCache {
private:
    unordered_map<int,DLinkNode*> cache;
    DLinkNode *head;
    DLinkNode *tail;
    int size;
    int capacity;
public:
    LRUCache(int capacity) {
        this->size=0;
        this->capacity=capacity;
        head=new DLinkNode();
        tail=new DLinkNode();
        head->next=tail;
        tail->prev=head;
    }
    
    int get(int key) {
        //如果没有返回-1
        if(!cache.count(key)){
            return -1;
        }
        //如果有的话先拿到结点然后放到队首
        DLinkNode *node=cache[key];
        moveToHead(node);
        return node->value;
    }
    
    void put(int key, int value) {
        //如果不存在key
        if(!cache.count(key)){
            //创建结点
            DLinkNode *node=new DLinkNode(key,value);
            //添加到哈希表
            cache[key]=node;
            //添加至队首
            addToHead(node);
            size++;
            //容量不够时删除队尾的元素
            if(size>capacity){
                DLinkNode *removed=removeTail();
                //删除哈希表中的对应项
                cache.erase(removed->key);
                //避免内存泄漏
                delete removed;
                size--;
            }
        }
        else{
            //如果存在则修改value并移动到队首
            DLinkNode *node=cache[key];
            node->value=value;
            moveToHead(node);
        }
    }

private:
    //移除结点
    void remove(DLinkNode *node){
        node->next->prev=node->prev;
        node->prev->next=node->next;
    }
    //在队首添加结点
    void addToHead(DLinkNode *node){
        node->prev=head;
        node->next=head->next;
        head->next->prev=node;
        head->next=node;
    }
    //移动到队首
    void moveToHead(DLinkNode *node){
        remove(node);
        addToHead(node);
    }
    //删除队尾结点
    DLinkNode* removeTail(){
        DLinkNode *removed=tail->prev;
        remove(removed);
        return removed;
    }
};

/**
 * Your LRUCache object will be instantiated and called as such:
 * LRUCache* obj = new LRUCache(capacity);
 * int param_1 = obj->get(key);
 * obj->put(key,value);
 */

#148.排序链表

在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序。

二路归并

class Solution {
public:
    ListNode* sortList(ListNode* head) {
        if (head == NULL || head->next == NULL)
        {
            return head;
        }
        ListNode* pmid;
        ListNode* mid = head;
        ListNode* trail = head;
        while (trail && trail->next)
        {
            pmid = mid;
            mid = mid->next;
            trail = trail->next->next;
        }
        pmid->next = NULL;

        return twoWayMerge(sortList(head), sortList(mid));
    }

    ListNode* twoWayMerge(ListNode* l1, ListNode* l2) {
        ListNode header(-1);
        ListNode *p = &header;
        while (l1 && l2)
        {
            if (l1->val < l2->val)
            {
                p->next = l1;
                l1 = l1->next;
            }
            else
            {
                p->next = l2;
                l2 = l2->next;
            }
            p = p->next;
        }

        p->next = l1 == NULL ? l2 : l1;

        return header.next;
    }
};

#149.直线上最多的点数

把求斜率的除法变成乘法

class Solution {
public:
    int maxPoints(vector<vector<int>>& points) 
    {
        //两点确定一条直线
        const int size = points.size();
        if(size<3)
            return size;
        
        int Max=0;
        for(int i=0;i< size;i++)//i表示数组中的第i+1个点
        {
            //same用来表示和i一样的点
            int same=1;
            for(int j=i+1;j < size;j++)//j表示数组中的第j+1个点
            {
                int count=0;
                // i、j在数组中是重复点,计数
                if(points[i][0]==points[j][0]&&points[i][1]==points[j][1])
                    same++;
                else//i和j不是重复点,则计算和直线ij在一条直线上的点
                {
                    count++;
                    long long xDiff = (long long)(points[i][0] - points[j][0]);//Δx1
                    long long yDiff = (long long)(points[i][1] - points[j][1]);//Δy1
                    
//Δy1/Δx1=Δy2/Δx2 => Δx1*Δy2=Δy1*Δx2,计算和直线ji在一条直线上的点
                    for (int k = j + 1; k < size; ++k)
                    {
                        if (xDiff * (points[i][1] - points[k][1]) == yDiff *                                (points[i][0] - points[k][0]))
                            count++;
                    }
                }
                Max=max(Max,same+count);
            }
            if(Max> size /2)
                return Max;//若某次最大个数超过所有点的一半,则不可能存在其他直线通过更多的点
        }
        return Max;
    }
};

#150.逆波兰表达式求值

记得可以用stringstream来直接进行atoi的操作


class Solution {
public:
    int evalRPN(vector<string>& tokens) {
        if(tokens.empty()) return 0;
        stack<int> numst;
        stringstream ss; 

        for(int i = 0;i<tokens.size();++i)
        {
            string c = tokens[i] ;
            if(c == "+"||c == "-"||c == "*"||c == "/" ) 
            {
                int temp1 = numst.top(); numst.pop();
                int temp2 = numst.top(); numst.pop();
                int temp3 = 0;
                if(c == "+") {temp3 = temp1+temp2; numst.push(temp3);}
                else if(c == "-") {temp3 = temp2-temp1; numst.push(temp3);}
                else if(c == "*") {temp3 = temp1*temp2; numst.push(temp3);}
                else{temp3 = temp2/temp1; numst.push(temp3);}
            }
            else
            {
            int number;
            ss.clear();
            ss<<c;
            ss>>number;
            numst.push(number);
            }
        }
        return numst.top();

        

    }
};

#152.乘积最大子数组

非常经典的一个动态规划思想,要借助两个动态规划数组!

class Solution {
public:
    int maxProduct(vector<int>& nums) {
        vector<int> maxDP(nums.size());
        vector<int> minDP(nums.size());
        maxDP[0]=nums[0];
        minDP[0]=nums[0];
        int result=maxDP[0];
        for(int i=1;i<nums.size();i++){
            maxDP[i]=max(maxDP[i-1]*nums[i],max(nums[i],minDP[i-1]*nums[i]));
            minDP[i]=min(minDP[i-1]*nums[i],min(nums[i],maxDP[i-1]*nums[i]));
            result=max(result,maxDP[i]);
        }
        return result;
    }
};

#155.最小栈

class MinStack {
public:
    /** initialize your data structure here. */
    MinStack() {
        
    }
    
    void push(int x) {
        if(_data.empty())
        {
            _data.push(x);
            _min.push(x);
            return;
        }
        _data.push(x);
        if(x<_min.top())
        {
            _min.push(x);
        }
        else
        {
            _min.push(_min.top());
        }
    }
    
    void pop() {
        _data.pop();
        _min.pop();
    }
    
    int top() {
        return _data.top();
    }
    
    int getMin() {
        return _min.top();
    }
private:
    stack<int> _data;
    stack<int> _min;
};

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

#160.相交链表

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        int lengthA=0;
        int lengthB=0;
        ListNode *pA=headA;
        ListNode *pB=headB;
        while(pA){
            lengthA++;
            pA=pA->next;
        }
        while(pB){
            lengthB++;
            pB=pB->next;
        }
        if(lengthA>lengthB){
            for(int i=0;i<(lengthA-lengthB);i++){
                headA=headA->next;
            }
        }
        else if(lengthB>lengthA){
            for(int i=0;i<(lengthB-lengthA);i++){
                headB=headB->next;
            }
        }
        //开始找
        while(headA && headB){
            if(headA==headB){
                return headA;
            }
            headA=headA->next;
            headB=headB->next;
        }
        return NULL;
    }
};

#162.寻找峰值

只要遇到找某个有特点的值,优先考虑二分查找!!!

class Solution {
public:
    int findPeakElement(vector<int>& nums) {
        if(nums.size()==1){
            return 0;
        }
        return bsearch(nums,0,nums.size()-1);
    }

    int bsearch(vector<int>& nums,int l,int r){
        if(l==r){
            return l;
        }
        int mid=(l+r)/2;
        if(nums[mid]>nums[mid+1]){
            return bsearch(nums,l,mid);
        }
        return bsearch(nums,mid+1,r);
    }
};

#166.分数小数

这道题不难,但是有很多细节要考虑全面!!

class Solution {
public:
    //小数部分如果余数重复出现两次就表示该小数是循环小数了
    string fractionToDecimal(int numerator, int denominator) {
        if(denominator==0) return "";//边界条件,分母为0
        if(numerator==0) return "0";//边界条件,分子为0
        string result;
        //转换为longlong防止溢出
        long long num = static_cast<long long>(numerator);
        long long denom = static_cast<long long>(denominator);
        //处理正负号,一正一负取负号
        if((num>0)^(denom>0))result.push_back('-');
        //分子分母全部转换为正数
        num=llabs(num);denom=llabs(denom);
        //处理整数部分
        result.append(to_string(num/denom));
        //处理小数部分
        num%=denom;                         //获得余数
        if(num==0)return result;             //余数为0,表示整除了,直接返回结果
        result.push_back('.');              //余数不为0,添加小数点
        int index=result.size()-1;          //获得小数点的下标
        unordered_map<int,int> record;      //map用来记录出现重复数的下标,然后将'('插入到重复数前面就好了
        while(num&&record.count(num)==0){   //小数部分:余数不为0且余数还没有出现重复数字
            record[num]=++index;
            num*=10;                        //余数扩大10倍,然后求商,和草稿本上运算方法是一样的
            result+=to_string(num/denom);
            num%=denom;
        }
        if(record.count(num)==1){           //出现循环余数,我们直接在重复数字前面添加'(',字符串末尾添加')'
            result.insert(record[num],"(");
            result.push_back(')');
        }
        return result;
    }
};

#169.多数元素

class Solution {
public:
    int majorityElement(vector<int>& nums) {
        unordered_map<int,int> hash;
        for(int i=0;i<nums.size();i++){
            if(hash.count(nums[i])==0){
                hash[nums[i]]=1;
            }
            else{
                hash[nums[i]]++;
            }
        }
        unordered_map<int,int>::iterator iter=hash.begin();
        int result;
        while(iter!=hash.end()){
            if(iter->second>(nums.size()/2) ){
                result=iter->first;
                break;
            }
            else{
                iter++;
            }
        }
        return result;
    }
};

#171.Excel表列序号

class Solution {
public:
    int titleToNumber(string s) {
        int result=0;
        int _pow=0;
        for(int i=s.size()-1;i>=0;i--){
            result+=pow(26,_pow)*(s[i]-'A'+1);
            _pow++;
        }
        return result;
    }
};

#172.阶乘后的零

class Solution {
public:
    int trailingZeroes(int n) {
        if(n<5){
            return 0;
        }
        return (n/5 +trailingZeroes(n/5));
    }
};

#179.最大数

class Solution {
public:
    string largestNumber(vector<int>& nums) {
        if(nums.empty()) return "";
        if(nums.size() == 1) return to_string(nums[0]);

        sort(nums.begin(), nums.end(), cmp()); // 调用STL中的sort函数
        string result = "";
        for(int i : nums)
        {
            result += to_string(i);
        }
        // 特殊case,全是0的时候应该输出0而不是00000
        if(result[0] == '0') return "0"; 
        return result;
    }

    struct cmp{
        bool operator()(const int& a, const int& b){
            string concatenation1 = to_string(a) + to_string(b);
            string concatenation2 = to_string(b) + to_string(a);
            return concatenation1 > concatenation2;
        }   
         
     };
    

};

#189.旋转数组

虽然是道简单题,但环状替代思想还是很值得思考得!!!下面得结论很重要

对于一个长度为 n 的数组,整体移动 k 个位置

当 n 和 k 的最大公约数 等于 1 的时候:1 次遍历就可以完成交换;比如 n = 5, k = 3n=5,k=3
当 n 和 k 的最大公约数 不等于 1 的时候:1 次遍历是无法完成的所有元素归位,需要 mm (最大公约数) 次

class Solution {
public:
    void rotate(vector<int>& nums, int k) {
        if(nums.size()<=1){
            return; 
        }
        int count=0;
        for(int i=0;count<nums.size();i++){
            int cur=i;
            int next=(i+k)%nums.size();
            int pre=nums[cur];
            do{
                int temp=nums[next];
                nums[next]=pre;
                pre=temp;
                cur=next;
                next=(next+k)%nums.size();
                count++;
            }while(cur!=i);
        }
    }
};

#190.颠倒二进制位

位运算!!

class Solution {
public:
    uint32_t reverseBits(uint32_t n) {
        uint32_t result=0;
        int power=31;
        while(n!=0){
            result+=(n&1)<<power;
            n=n>>1;
            power--;
        }
        return result;
    }
};

#191.位1的个数

记住 n=n&(n-1)这个操作会把n最后的那个1置为0

class Solution {
public:
    int hammingWeight(uint32_t n) {
        int ans=0;
        while(n>0){
            n=n&(n-1);
            ans++;
        }
        return ans;
    }
};

#198.打家劫舍

动态规划

class Solution {
public:
    int rob(vector<int>& nums) {
        if(nums.size() ==0 ){
            return 0;
        }
        if(nums.size() ==1){
            return nums[0];
        }
        vector<int> dp(nums.size(),0);
        dp[0]=nums[0];
        dp[1]=std::max(nums[0],nums[1]);
        for(int i=2;i<nums.size();i++){
            dp[i]=std::max(nums[i]+dp[i-2] , dp[i-1]);
        }
        return dp[nums.size()-1];
    }

};

#200.岛屿数量

经典深搜问题

class Solution {
public:
    int numIslands(vector<vector<char>>& grid) {
        if(grid.size()==0){
            return 0;
        }
        int result=0;
        vector<vector<int>> mark(grid.size(),vector<int>(grid[0].size(),0));

        for(int i=0;i<grid.size();i++){
            for(int j=0;j<grid[i].size();j++){
                if(grid[i][j]=='1'&& mark[i][j]==0){
                    result++;
                    BFS(mark,grid,i,j);
                }
            }
        }
        return result;
    }
    void BFS(std::vector<std::vector<int>> &mark, 
    std::vector<std::vector<char>>& grid,int x,int y ){
        static const int dx[] ={-1,1,0,0};
        static const int dy[] ={0,0,-1,1};
        std::queue<std::pair<int ,int>> Q;
        Q.push(std::make_pair(x,y));
        mark[x][y]=1;
        while(!Q.empty()){
            x=Q.front().first;
            y=Q.front().second;
            Q.pop();
            for(int i=0;i<4;i++){
                int newx=dx[i]+x;
                int newy=dy[i]+y;
                if(newx <0 || newx >=mark.size() || newy <0 || newy >=mark[0].size()){
                    continue;
                }
                if(mark[newx][newy]==0 && grid[newx][newy]=='1'){
                    mark[newx][newy]=1;
                    Q.push(make_pair(newx,newy));
                }
            }
        }
    }
};

#202.快乐数

只要判断循环就用快慢指针思想!!

class Solution {
public:
    bool isHappy(int n) {
        if(n==1){
            return true;
        }
        int fast=_change(n);
        int slow=fast;
        do{
            fast=_change(fast);
            fast=_change(fast);
            slow=_change(slow);
            if(fast==1){
                return true;
            }
        }while(fast!=slow);
        return false;
    }

    int _change(int n){
        int result=0;
        while(n!=0){
            result+=(n%10)*(n%10);
            n=n/10;
        }
        return result;
    }
};

#204.计数质数

虽然简单,但这种从低位向上穷举的思想还是挺不错的

class Solution {
public:
    int countPrimes(int n) {
        vector<bool>  prim(n,true);
        for(int i=2;i<n;i++){
            if(prim[i]){
                for(int j=2*i;j<n;j+=i){
                    prim[j]=false;
                }
            }
        }
        int result=0;
        for(int i=2;i<n;i++){
            if(prim[i]){
                result++;
            }
        }

        return result;
    }
};

#206.反转链表

经典必会题,不解释!!

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        ListNode* result=NULL;
        while(head)
        {
            ListNode* temp=head->next;
            head->next=result;
            result=head;
            head=temp;
        }
        return result;
    }
};

#207.课程表

拓扑排序!!!

class Solution {
public:
    struct GraphNode
    {
        int val;
        vector<GraphNode*> neighbers;
        GraphNode(int x):val(x){};
    };

    bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
           vector<GraphNode*> graph;
           //入度数组
           vector<int> degree;
           for(int i=0;i<numCourses;i++){
               degree.push_back(0);
               graph.push_back(new GraphNode(i));
           }
           //初始化,并计算入度
           for(int i=0;i<prerequisites.size();i++){
               GraphNode *from=graph[prerequisites[i][1]];
               GraphNode *to = graph[prerequisites[i][0]];
               from->neighbers.push_back(to);
               degree[to->val]++;
           }
           std::queue<GraphNode*> q;
           for(int i=0;i<numCourses;i++){
                if(degree[i]==0){
                    q.push(graph[i]);
                }
           }
           while(!q.empty()){
               GraphNode* node = q.front();
               q.pop();
               for(int i=0;i<node->neighbers.size();i++){
                   degree[node->neighbers[i]->val]--;
                   if(degree[node->neighbers[i]->val]==0 ){
                       q.push(node->neighbers[i]);
                   }
               }
           }
           for(int i=0;i<graph.size();i++){
               delete graph[i];
           }
           for(int i=0;i<degree.size();i++){
               if(degree[i]){
                   return false;
               }
           }
           return true;
    }
};

#208.实现Trie(前缀树)

class Trie {
public:
    /** Initialize your data structure here. */
    Trie() {
        is_end=false;
        memset(next,0,sizeof(next));
    }
    
    /** Inserts a word into the trie. */
    void insert(string word) {
        Trie *node=this;
        for(char c : word){
            if(node->next[c-'a']==NULL){
                node->next[c-'a']=new Trie();
            }
            node = node->next[c-'a'];
        }
        node->is_end=true;
    }
    
    /** Returns if the word is in the trie. */
    bool search(string word) {
        Trie *node=this;
        for(auto c : word){
            node=node->next[c-'a'];
            if(node==NULL){
                return false;
            }
        }
        return node->is_end;
    }
    
    /** Returns if there is any word in the trie that starts with the given prefix. */
    bool startsWith(string prefix) {
        Trie *node = this;
        for(char c: prefix){
            node=node->next[c-'a'];
            if(node==NULL){
                return false;
            }
        }
        return true;
    }
private:
    Trie* next[26];
    bool is_end;
};

/**
 * Your Trie object will be instantiated and called as such:
 * Trie* obj = new Trie();
 * obj->insert(word);
 * bool param_2 = obj->search(word);
 * bool param_3 = obj->startsWith(prefix);
 */

#210.课程表II

又是拓扑排序!!!

class Solution {
private:
    struct GraphNode{
        int val;
        vector<GraphNode*> neighbers;
        GraphNode(int x):val(x){}
    };

public:
    vector<int> findOrder(int numCourses, vector<vector<int>>& prerequisites) {
        vector<GraphNode*> graph;
        vector<int> degree(numCourses,0);
        //初始化图
        for(int i=0;i<numCourses;i++){
            graph.push_back(new GraphNode(i));
        }
        for(int i=0;i<prerequisites.size();i++){
            GraphNode *from=graph[prerequisites[i][1]];
            GraphNode *to=graph[prerequisites[i][0]];
            degree[to->val]++;
            from->neighbers.push_back(to);
        }
        //初始化队列
        vector<int> result;
        queue<GraphNode*> q;
        for(int i=0;i<numCourses;i++){
            if(degree[i]==0){
                q.push(graph[i]);
                result.push_back(i);
            }
        }
        //开始拓扑排序的剔除
        while(!q.empty()){
            GraphNode *node=q.front();
            q.pop();
            for(int i=0;i<node->neighbers.size();i++){
                degree[node->neighbers[i]->val]--;
                if(degree[node->neighbers[i]->val]==0){
                    result.push_back(node->neighbers[i]->val);
                    q.push(node->neighbers[i]);
                }
            }
        }
        for(int i=0;i<graph.size();i++){
            delete graph[i];
        }
        for(int i=0;i<numCourses;i++){
            if(degree[i]!=0){
                return {};
            }
        }
        return result;


    }
};

#215.数组中的第K个最大元素

遇到第K大这种问题记得考虑优先级队列!!!!

class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) {
        std::priority_queue<int, std::vector<int>,std::greater<int> > small_heap;
        for(int i=0;i<nums.size();i++){
            if(small_heap.size()<k){
                small_heap.push(nums[i]);
            }
            else{
                if(nums[i]>small_heap.top()){
                    small_heap.pop();
                    small_heap.push(nums[i]);
                }
            }
        }
        return small_heap.top();
    }
};

#217.存在重复元素

一行代码解决!!

class Solution {
public:
    bool containsDuplicate(vector<int>& nums) {
        return nums.size() > unordered_set<int>(nums.begin(), nums.end()).size(); 
         //如果原数组的大小>集合的大小,则说明存在重复元素

    }
};

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值