LeetCode -- 力扣算法题解题心得 -- (个人笔记记录)持续更新~~

一、前言

正式开启数据结构+算法研究的历程,准备好一年后的面试。下面的解法不一定是最优解,只求能力提升,会定期更新~~

二、目录

1 2 19 20 21 24
35 83 86 94 100 101
102 103 104 108 110 111
112
122 136 141 142 144 155
160
191 202 203 206 226 231
235 237 257 268 371 876
938 5673

三、题解部分

1.两数之和

(暴力算法)
此题目类似冒泡排序法,使用暴力算法解题,双重循环遍历求得目标值,每次循环判断是否满足条件,如果满足,则记录下标。(返回结果的时候注意返回returnSize)。
LeetCode -- 力扣算法题解题心得 -- (个人笔记记录)持续更新~~_第1张图片

/**
 1. Note: The returned array must be malloced, assume caller calls free().
 */
int* twoSum(int* nums, int numsSize, int target, int* returnSize){
     
    int *a = (int *)malloc(sizeof(int)*2);
    for (int i = 0; i < numsSize-1; i++) {
     
        for (int j = i + 1; j < numsSize; j++) {
     
            if (nums[j] + nums[i] == target) {
     
                a[0] = i;
                a[1] = j;
                *returnSize = 2;
                return a;
            }
        }
    }
    *returnSize = 0;
    return 0;
}

2.两数相加

代码可能写的比较啰嗦,但是逻辑是没问题的,每位相加记录进位数,直到两个都结束,结束后检查进位填补结点。
LeetCode -- 力扣算法题解题心得 -- (个人笔记记录)持续更新~~_第2张图片

class Solution {
     
public:
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
     
        ListNode* res = new ListNode();
        ListNode rest;
        rest.next = res;
        int memo = 0;
        while(l1 != NULL && l2 != NULL) {
     
            int temp = memo + l1->val + l2->val;
            if(temp > 9){
     
                memo = 1;
            }else {
     
                memo = 0;
            }
            ListNode* kk = new ListNode();
            kk->val = (temp) % 10;
            res->next = kk;
            res = res->next;
            l1 = l1->next;
            l2 = l2->next;
        }

        while(l1 != NULL){
     
            int temp = memo + l1->val;
            if(temp > 9){
     
                memo = 1;
            }else {
     
                memo = 0;
            }
            ListNode* kk = new ListNode();
            kk->val = (temp) % 10;
            res->next = kk;
            res = res->next;
            l1 = l1->next;
        }
        while(l2 != NULL){
     
            int temp = memo + l2->val;
            if(temp > 9){
     
                memo = 1;
            }else {
     
                memo = 0;
            }
            ListNode* kk = new ListNode();
            kk->val = (temp) % 10;
            res->next = kk;
            res = res->next;
            l2 = l2->next;
        }
        if(memo == 1){
     
            ListNode* kk = new ListNode();
            kk->val = 1;
            kk->next = NULL;
            res->next = kk;
        }
        return rest.next->next;
    }
};

19.删除链表的倒数第N个结点

这道题用暴力的方法,注意要添加一个虚拟头结点来处理链表为空或者为一个结点的情况。
这里也可以用双指针的方法一遍过,让两个间距为n的指针平行移动找到要删除的即可,这里就不实现了。睡觉了,晚安~
LeetCode -- 力扣算法题解题心得 -- (个人笔记记录)持续更新~~_第3张图片

struct ListNode* removeNthFromEnd(struct ListNode* head, int n){
       

    struct ListNode* test = (struct ListNode*)malloc(sizeof(struct ListNode));
    test->next = head;

    struct ListNode p;          // 用一个结点p来记录链表
    p.next = test; 
    int num = 0;
    
    while(head!=NULL){
     
        num++;
        head = head->next;
    }
    
    for(int i=0;i<num-n;i++){
     
        test = test->next;
    }

    if(test->next!=NULL){
     
        test->next = test->next->next;
    }
    return p.next->next;
}

20.有效的括号

这里用了线性栈–一个数组来表示栈,将左括号放入栈中,计数器加一,当遇到右括号的时候进行匹配,并且使计数器的值减一,最终判断计数器的值是否被清空。
LeetCode -- 力扣算法题解题心得 -- (个人笔记记录)持续更新~~_第4张图片

bool isValid(char * s){
     
    int n = strlen(s);
    char *arr = (char *)malloc(sizeof(char)*n+1);
    memset(arr,0,n);
    int j = 1;
    for(int i = 0;i<n;i++){
     
        if(s[i] == '{' || s[i] == '(' || s[i] == '['){
     
            arr[j] = s[i];
            j++;
        }else if((s[i] == '}' && arr[j-1] == '{') || (s[i] == ')' && arr[j-1] == '(') || (s[i] == ']' && arr[j-1] == '[')){
     
                j--;
        }else{
     
            return false;
        }
    }

    if(j == 1){
     
        return true;
    }

    return false;
}

21.合并两个有序链表

1.自用的方法是暴力算法,性能很低下。。。最古老的办法进行链表的逐个排序放入,注意操作链表的写法。
LeetCode -- 力扣算法题解题心得 -- (个人笔记记录)持续更新~~_第5张图片

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */


struct ListNode* mergeTwoLists(struct ListNode* l1, struct ListNode* l2){
     
    struct ListNode *temp = (struct ListNode *)malloc(sizeof(struct ListNode));
    struct ListNode *Head = (struct ListNode *)malloc(sizeof(struct ListNode));
    temp->next = NULL; 

    if(l1->val < l2->val){
     
        struct ListNode *swap = (struct ListNode *)malloc(sizeof(struct ListNode));
        swap->val = l1->val;
        temp->next = swap;
        temp = temp->next;
    }else if(l1->val >= l2->val){
     
        struct ListNode *swap = (struct ListNode *)malloc(sizeof(struct ListNode));
        swap->val = l2->val;
        temp->next = swap;
        temp = temp->next;
    }

    return Head;
}

24.两两交换链表中的结点

题目不是很难,但是反映的问题比较多,首先要记住虚拟头结点的重要性,然后链表换顺序需要一个虚拟头结点记住初始位置。
LeetCode -- 力扣算法题解题心得 -- (个人笔记记录)持续更新~~_第6张图片

struct ListNode* swapPairs(struct ListNode* head){
     
    struct ListNode p;
	p.next = head;
	struct ListNode* temp = &p;
    while((temp->next!=NULL)&&(temp->next->next!=NULL)){
     
    	struct ListNode* s1 = temp->next;
    	struct ListNode* s2 = temp->next->next;
    	temp->next = s2;
    	s1->next = s2->next;
    	s2->next = s1;
		temp = temp->next->next;
	} 
	return p.next;
}

35.搜索插入位置

一道简单题,用普通的搜索方法就可以做出;
可用来复习二分法查找。
LeetCode -- 力扣算法题解题心得 -- (个人笔记记录)持续更新~~_第7张图片

int searchInsert(int* nums, int numsSize, int target){
     
    int i;
    for(i = 0;i<numsSize;i++){
     
        if(nums[i] == target){
     
            return i;
        }
        if(nums[i] > target){
     
            return i;
        }
    }
    
    return i;
}

83.删除排序链表中的重复元素

遍历每个结点,判断是否重复。
LeetCode -- 力扣算法题解题心得 -- (个人笔记记录)持续更新~~_第8张图片

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */

struct ListNode* deleteDuplicates(struct ListNode* head){
     
    struct ListNode* cur = head;
    while(cur != NULL){
     
        struct ListNode* rear = cur->next;
        if(rear == NULL){
     
            return head;
        }
        if(cur->val == rear->val){
     
            cur->next = rear->next;
        }
        else{
     
            cur = cur->next;
        }
    }
    return head;
}

86.分隔链表

这题实现起来比较麻烦,需要不停地维护两个结点,并且需要一个标志来记录是否出现大于等于特殊值的结点。代码最终实现效果很好,几乎都是超过所有人。
LeetCode -- 力扣算法题解题心得 -- (个人笔记记录)持续更新~~_第9张图片

struct ListNode* partition(struct ListNode* head, int x){
     
    struct ListNode* temp = (struct ListNode*)malloc(sizeof(struct ListNode));
    temp->next = head;
    struct ListNode p;
    p.next = temp;
    
    bool flag = false;		// 用来标志是否出现大于等于特殊值的结点,若没出现,前面不用动
    struct ListNode* ram;	// 用来标志前面最新的小节点,即下一次前移要插进该结点的后面
    struct ListNode* rbm;	// 用来标志第一次出现的大于等于特殊值的结点
    ram = temp;				// 排除链表结点个数少的情况
    
    while(temp->next != NULL){
     
        if((temp->next->val<x)&&!flag){
     		
        	// 未出现大于等于特殊值的结点,一直往后推进,同时不断更新ram
            ram = temp->next;
            temp = temp->next;
        }else if(temp->next->val>=x){
     
        	// 出现了特殊结点,修改标志,记录rbm
			// 后续再出现,不做任何改动
            if(!flag){
     
                flag = true;
                rbm = temp->next;
            }
            temp = temp->next;
        }else if((temp->next->val<x)&&flag){
     
        	// 已出现特殊结点且当前结点小于特殊值,做顺序修改,具体过程建议画图
            ram->next = temp->next;
            temp->next = temp->next->next;
            ram->next->next = rbm;
            ram = ram->next;
        }
    }
    return p.next->next;
}

94.二叉树的中序遍历

本题有两种做法,一种是中规中矩的递归,另一种是看官方题解给的方法,叫做Mirrors方法,代码附在下面,目前还没有办法能写出这个算法。。。。加油。
LeetCode -- 力扣算法题解题心得 -- (个人笔记记录)持续更新~~_第10张图片

void inorder(struct TreeNode* root,int *arr,int *num){
     
    if(root == NULL){
     
        return;
    }
    inorder(root->left,arr,num);
    arr[(*num)++] = root->val;
    inorder(root->right,arr,num);
}

/**
 * Note: The returned array must be malloced, assume caller calls free().
 */
int* inorderTraversal(struct TreeNode* root, int* returnSize){
     
    int *arr = malloc(sizeof(int)*500);
    *returnSize = 0;
    inorder(root,arr,returnSize);    
    return arr;
}
int* inorderTraversal(struct TreeNode* root, int* returnSize) {
     
    int* res = malloc(sizeof(int) * 501);
    *returnSize = 0;
    struct TreeNode* predecessor = NULL;

    while (root != NULL) {
     
        if (root->left != NULL) {
     
            // predecessor 节点就是当前 root 节点向左走一步,然后一直向右走至无法走为止
            predecessor = root->left;
            while (predecessor->right != NULL && predecessor->right != root) {
     
                predecessor = predecessor->right;
            }

            // 让 predecessor 的右指针指向 root,继续遍历左子树
            if (predecessor->right == NULL) {
     
                predecessor->right = root;
                root = root->left;
            }
            // 说明左子树已经访问完了,我们需要断开链接
            else {
     
                res[(*returnSize)++] = root->val;
                predecessor->right = NULL;
                root = root->right;
            }
        }
        // 如果没有左孩子,则直接访问右孩子
        else {
     
            res[(*returnSize)++] = root->val;
            root = root->right;
        }
    }
    return res;
}

100.相同的树

(递归算法)
1.先判断节点是否拥有左右孩子,同时为空则返回true,只有一个则返回false
2.如果两个节点的值不相等,则返回false
3.如果没有return,函数最终利用递归法,将对应的左孩子和右孩子进行递归返回值。
LeetCode -- 力扣算法题解题心得 -- (个人笔记记录)持续更新~~_第11张图片

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     struct TreeNode *left;
 *     struct TreeNode *right;
 * };
 */

bool isSameTree(struct TreeNode* p, struct TreeNode* q){
     
    if(p == NULL && q == NULL){
     
        return true;
    }
    
    if(p == NULL || q == NULL){
     
        return false;
    }
    
    if(p->val != q->val){
     
        return false;
    }
    return isSameTree(p->left,q->left)&&isSameTree(p->right,q->right);
}

101.对称二叉树

(递归算法)
此题应该特别写一个函数,函数含有两个参数,左子树和右子树,函数内部使用递归。
1.先判断传入的两个节点是否同时为空,或者其中一个为空,前者return true,后者return false
2.如果上述过程没有return,则判断左节点的右孩子和右节点的左孩子&&右节点的右孩子和左节点的左孩
最重要的是找到递归点。
LeetCode -- 力扣算法题解题心得 -- (个人笔记记录)持续更新~~_第12张图片

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     struct TreeNode *left;
 *     struct TreeNode *right;
 * };
 */

bool checkSymmetric(struct TreeNode* lroot,struct TreeNode* rroot){
     
    if(lroot == NULL && rroot == NULL){
     
        return true;
    }

    if(lroot == NULL || rroot == NULL){
     
        return false;
    }

    if(lroot->val == rroot->val){
     
        return checkSymmetric(lroot->left,rroot->right)&&checkSymmetric(lroot->right,rroot->left);
    }

    return false;
}

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

102.二叉树的层序遍历①

肝了两天,解决了这个层序遍历的个人解法!
我的思路是递归遍历层数的时候带上一个层数记录器,利用这个记录器将结点信息保存在二维容器对应层。先是用C语言做,很不理想,因为C没有动态容器这种东西,后来使用了C++的vector,很轻松的解决了,算法速度很快,比队列快了一丢丢,优点在于,思路极其简单!
LeetCode -- 力扣算法题解题心得 -- (个人笔记记录)持续更新~~_第13张图片

// 个人解法:
class Solution {
     
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
     
		vector<vector<int>> res;
		int pos = 0;
		Tranverse(root,pos,res);
		return res;
    }

	void Tranverse(TreeNode* root,int pos,vector<vector<int>> &arr){
     
		if(root == NULL){
     
			return;
		}
		if(pos>=arr.size()){
     
			arr.push_back(vector<int> ());
		}
		arr[pos].push_back(root->val);
		Tranverse(root->left,pos+1,arr);
		Tranverse(root->right,pos+1,arr);
	}
};

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

和上面几个层序遍历类似,这题的思路是增加一个层数指示器,按照正常的顺序存进队列,然后按层存入容器,偶数层逆序存入容器。
LeetCode -- 力扣算法题解题心得 -- (个人笔记记录)持续更新~~_第14张图片

class Solution {
     
public:
    vector<vector<int>> zigzagLevelOrder(TreeNode* root) {
     
        vector<vector<int>> res;
        queue<TreeNode*> q;
        int level = 0;

        if(root == NULL){
     
            return res;
        }

        q.push(root);
        while(!q.empty()){
     
            vector<int> newbar;
            int size = q.size();
            for(int i=0;i<size;i++){
     
                TreeNode* cur = q.front();
                q.pop();
                newbar.push_back(cur->val);
                if(cur->left != NULL){
     
                    q.push(cur->left);
                }
                if(cur->right != NULL){
     
                    q.push(cur->right);
                }
            }
            if(level++ % 2 == 1){
     
                reverse(newbar.begin(),newbar.end());
            }
            res.push_back(newbar);
        }
        return res;
    }
};

104.二叉树的最大深度

定义一个max函数,递归遍历每一个叶子节点,经过一个就加一,return最大的数。
LeetCode -- 力扣算法题解题心得 -- (个人笔记记录)持续更新~~_第15张图片

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     struct TreeNode *left;
 *     struct TreeNode *right;
 * };
 */

int max(int a,int b){
     
    if(a>b){
     
        return a;
    }else{
     
        return b;
    }
}

int maxDepth(struct TreeNode* root){
     
    if(root == NULL){
     
        return 0;
    }

    return 1 + max(maxDepth(root->left),maxDepth(root->right));
}

107.二叉树的层序遍历②

本题类似102题,102题我用的是自己的方法,那么这题用的就是基础的队列方法,没啥好说的看代码。
LeetCode -- 力扣算法题解题心得 -- (个人笔记记录)持续更新~~_第16张图片

class Solution {
     
public:
    vector<vector<int>> levelOrderBottom(TreeNode* root) {
     
        queue<TreeNode*> q;
        q.push(root);
        vector<vector<int>> smallv;
        
        if(root == NULL){
     
            return smallv;
        }

        while(!q.empty()){
     
            int size = q.size();
            vector<int> newv;
            for(int i=0;i<size;i++){
     
                struct TreeNode* cur = q.front();
                q.pop();
                newv.push_back(cur->val);
                if(cur->left != NULL){
     
                    q.push(cur->left);
                }
                if(cur->right != NULL){
     
                    q.push(cur->right);
                }
            }
            smallv.push_back(newv);
        }
        reverse(smallv.begin(),smallv.end());
        return smallv;
    }
};

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

先看题目,这道题给出的是一个有序数组,所以我们只要每次选择最中间的元素视为根结点返回即可,过程中需要控制边界。
LeetCode -- 力扣算法题解题心得 -- (个人笔记记录)持续更新~~_第17张图片

struct TreeNode* constructor(int* nums,int left,int right){
     
    if(left > right){
     
        return NULL;
    }

    struct TreeNode* root = (struct TreeNode*)malloc(sizeof(struct TreeNode));
    int mid = (left + right + 1)/2;

    root->val = nums[mid];
    root->left = constructor(nums,left,mid-1);
    root->right = constructor(nums,mid+1,right);

    return root;
}


struct TreeNode* sortedArrayToBST(int* nums, int numsSize){
     
    return constructor(nums,0,numsSize-1);
}

110.平衡二叉树

思路比较简单,平衡二叉树的每一棵子树都是平衡二叉树。使用双重递归的方法,目前比较复杂,等待以后优化。
LeetCode -- 力扣算法题解题心得 -- (个人笔记记录)持续更新~~_第18张图片

int height(struct TreeNode* root){
     
    if(root == NULL){
     
        return 0;
    }
    return fmax(height(root->left),height(root->right))+1;
}

bool isBalanced(struct TreeNode* root){
     
    if(root == NULL){
     
        return true;
    }
    return (fabs(height(root->left)-height(root->right)) <= 1)&&(isBalanced(root->left))&&(isBalanced(root->right)); 
}

111.二叉树的最小深度

LeetCode -- 力扣算法题解题心得 -- (个人笔记记录)持续更新~~_第19张图片

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     struct TreeNode *left;
 *     struct TreeNode *right;
 * };
 */


int minDepth(struct TreeNode* root){
     
    if(root == NULL){
     
        return 0;
    }

    if(root->left == NULL && root->right == NULL){
     
        return 1;
    }

    if(root->left != NULL && root->right == NULL){
     
        return 1+minDepth(root->left);
    }

    if(root->left == NULL && root->right != NULL){
     
        return 1+minDepth(root->right);
    }

    return 1+(minDepth(root->left)<minDepth(root->right)?minDepth(root->left):minDepth(root->right));
}

112.路径总和

LeetCode -- 力扣算法题解题心得 -- (个人笔记记录)持续更新~~_第20张图片

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     struct TreeNode *left;
 *     struct TreeNode *right;
 * };
 */

bool hasPathSum(struct TreeNode* root, int sum){
     
    if(root == NULL){
     
        return false;
    }
    
    if(root->left == NULL && root->right == NULL){
     
        return root->val == sum;
    }

    return hasPathSum(root->left,sum-root->val) || hasPathSum(root->right,sum-root->val);
}

122.买卖股票的最佳时机

使用贪心算法,sum每符合条件的两天之间的差值。
LeetCode -- 力扣算法题解题心得 -- (个人笔记记录)持续更新~~_第21张图片

int maxProfit(int* prices, int pricesSize){
     
    if(pricesSize == 0){
     
        return 0;
    }
    int sum = 0;
    for(int i = 0;i < pricesSize - 1;i++){
     
        if(prices[i]<prices[i+1]){
     
            sum += prices[i+1] - prices[i];
        }
    }
    return sum;
}

136.只出现一次的数字

第一次使用位运算,还用到了异或^,太骚了,这三行代码解决。
任何数与0异或结果为本身,
任何数与自身异或结果为0;
LeetCode -- 力扣算法题解题心得 -- (个人笔记记录)持续更新~~_第22张图片

class Solution {
     
public:
    int singleNumber(vector<int>& nums) {
     
        int res = 0;
        for(auto i:nums) res ^= i;
        return res;
    }
};

141.环形链表

本题适合使用快慢指针来求解,如果存在环,快指针总会撞到慢指针。
LeetCode -- 力扣算法题解题心得 -- (个人笔记记录)持续更新~~_第23张图片

bool hasCycle(struct ListNode *head) {
     
    if(head == NULL || head->next == NULL){
     
        return false;
    }
    struct ListNode *slow = head;
    struct ListNode *fast = head->next;
    while((fast != NULL) && (fast->next != NULL)){
     
        slow = slow->next;
        fast = fast->next->next;
        if(fast==slow){
     
            return true;
        }
    }
    return false;
}

142.环形链表②

本题较此题的母题加大了难度,母题判断是否有环,本题则返回环的入口结点。
同样是使用快慢指针的思路,快指针一次走两步,慢指针一次走一步,在环内有一个相遇点。
先进行数学归纳推导:
如图所示,A为环前表长,B为相遇点前的长度,C为相遇点到入口点的长度。
假设n为在圈内循环的次数,则:
先分析快指针步数:
Step1 = A + n × ( B + C ) + B = A + ( n + 1 ) × B + n × C
再分析慢指针步数:
Step2 = A + B
两者数量关系为2倍: Step2 × 2 = Step1
则 2 ×( A + B ) = A + ( n + 1 ) × B + n × C
得到
A =( n - 1 )× ( B + C )+ C
即入口前长度A等于从n圈后加C,初始位置为相遇点,则n圈后加C的位置为入环结点。
于是我们让一个新的结点从head开始和slow一起跑,最终相遇在入环结点。
LeetCode -- 力扣算法题解题心得 -- (个人笔记记录)持续更新~~_第24张图片

LeetCode -- 力扣算法题解题心得 -- (个人笔记记录)持续更新~~_第25张图片

struct ListNode *detectCycle(struct ListNode *head) {
     
    struct ListNode *slow = head;
    struct ListNode *fast = head;
    while(fast!=NULL){
     
        if(fast->next == NULL) return NULL;
        slow = slow->next;
        fast = fast->next->next;
        if(slow == fast){
        
            struct ListNode *extra = head;
            while(extra!=slow){
     
                slow = slow->next;
                extra = extra->next;
            }
            return extra;
        }
    }
    return NULL;
}

144.二叉树的前序遍历

nnd,好不容易会了递归,还有迭代。。。好不容易会了迭代,还有Morris。。。。。
LeetCode -- 力扣算法题解题心得 -- (个人笔记记录)持续更新~~_第26张图片

class Solution {
     
public:
    void Tranverse(TreeNode* root,vector<int> &res) {
     
        if(root == nullptr) {
     
            return;
        }
        res.push_back(root->val);    
        Tranverse(root->left,res);
        Tranverse(root->right,res);
    }

    vector<int> preorderTraversal(TreeNode* root) {
     
        vector<int> res;
        Tranverse(root,res);
        return res;
    }   
};

155.最小栈

在栈中使用到了辅助栈,负责记录主栈的最小值,起到用空间换取时间的效果。如果不用辅助栈,算法性能总体都很差。
LeetCode -- 力扣算法题解题心得 -- (个人笔记记录)持续更新~~_第27张图片

typedef struct {
     
    int arr[7700];
    int top;
    struct numstack *stack;
}MinStack;

typedef struct numstack{
     
    int arr[3000];
    int top;
}numstack;

/** initialize your data structure here. */

MinStack* minStackCreate() {
     
    MinStack *st = (MinStack *)malloc(sizeof(MinStack));
    st->stack = (numstack *)malloc(sizeof(numstack));
    st->top = -1;
    st->stack->top = -1;
    return st;
}

void minStackPush(MinStack* obj, int x) {
     
    obj->top ++;
    obj->arr[obj->top] = x;
    if(obj->top == 0){
     
        obj->stack->top++;
        obj->stack->arr[obj->stack->top] = x;
    }else{
     
        if(x<=obj->stack->arr[obj->stack->top]){
     
            obj->stack->top++;
            obj->stack->arr[obj->stack->top] = x;
        }
    }
}

void minStackPop(MinStack* obj) {
     
    if(obj->arr[obj->top] == obj->stack->arr[obj->stack->top]){
     
        obj->stack->top--;
    }
    obj->top--;
}

int minStackTop(MinStack* obj) {
     
    int i = obj->top;
    return obj->arr[obj->top];
}

int minStackGetMin(MinStack* obj) {
     
    if(obj->stack->top == -1){
     
        return NULL;
    }
    return obj->stack->arr[obj->stack->top];
}

void minStackFree(MinStack* obj) {
     
    free(obj);
}

/**
 * Your MinStack struct will be instantiated and called as such:
 * MinStack* obj = minStackCreate();
 * minStackPush(obj, x);
 
 * minStackPop(obj);
 
 * int param_3 = minStackTop(obj);
 
 * int param_4 = minStackGetMin(obj);
 
 * minStackFree(obj);
*/

160.相交链表

本题比较浪漫的解法,类似快慢指针寻找环,本题是两个指针错位移动寻找共同节点。
正所谓:错的人终将走散,对的人终将重逢。
LeetCode -- 力扣算法题解题心得 -- (个人笔记记录)持续更新~~_第28张图片

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
     
    struct ListNode *work1 = headA;
    struct ListNode *work2 = headB;
    while(work1!=work2)
    {
     
        if(work1)
            work1 = work1->next;
        else
            work1 = headB;
        if(work2)
            work2 = work2->next;
        else
            work2 = headA;
    }
    return work2;
}

190.颠倒二进制位

本题使用位运算,从右往左将每个位赋值给新的变量。
LeetCode -- 力扣算法题解题心得 -- (个人笔记记录)持续更新~~_第29张图片

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

191.位1的个数

趁热打铁,学了使用位运算,真的快活!下面给出两种方法,第一种是自己想出来的,第二种是官网优化算法。只能说,太巧妙了,将n与n-1进行或运算总会将最小的1位变为0。
LeetCode -- 力扣算法题解题心得 -- (个人笔记记录)持续更新~~_第30张图片

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

202.快乐数

有三种做法:1.自己的解法,贪心算法;2.哈希表解法;3.快慢指针的解法。
我的解法有两个判断条件:根据观察,递归时:1.若某次递归初始数为1,则返回 true ;2.若某次递归时初始数为4,则陷入死循环,不快乐了,返回 false 。
其中我的解法要注意的知识点是:未知位数的 int 型变量取出每位的数,用%从小往大取比较方便。
LeetCode -- 力扣算法题解题心得 -- (个人笔记记录)持续更新~~_第31张图片

bool isHappy(int n){
     
    if(n==1){
     
        return true;
    }

	if(n==4){
     
		return false;
	}

    int j=0;
    int temp = n;
    while(temp>0){
     
        temp = temp/10;
        j++;
    }
	
    int k=0;
	for(int i=0;i<j;i++){
     
		k = k + (n%10) * (n%10);
		n = n / 10; 
	}

    return isHappy(k);
}

203.移除链表元素

LeetCode -- 力扣算法题解题心得 -- (个人笔记记录)持续更新~~_第32张图片

struct ListNode* removeElements(struct ListNode* head, int val){
     
    struct ListNode p;
	p.next = head;	

    struct ListNode* cur = &p;
    while (cur->next != NULL) {
     
        if (cur->next->val == val) {
     
            cur->next = cur->next->next;
        } else {
     
            cur = cur->next;
        }
    }
    return p.next;
}

206.翻转链表链表

让链表中每个结点回指向前一个结点。
LeetCode -- 力扣算法题解题心得 -- (个人笔记记录)持续更新~~_第33张图片

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */

struct ListNode* reverseList(struct ListNode* head){
     
    struct ListNode* pre = NULL;
    struct ListNode* current = head;
    struct ListNode* temp;
    while(current != NULL){
     
        temp = current->next;
        current->next = pre;
        pre = current;
        current = temp;
    }
    return pre;
}

226. 翻转二叉树

利用递归思想很简单就可以解决。
LeetCode -- 力扣算法题解题心得 -- (个人笔记记录)持续更新~~_第34张图片

/**
 1. Definition for a binary tree node.
 2. struct TreeNode {
 3.     int val;
 4.     struct TreeNode *left;
 5.     struct TreeNode *right;
 6. };
 */
 
struct TreeNode* invertTree(struct TreeNode* root){
     
    if(root == NULL){
        
        return NULL;
    }

    struct TreeNode* temp = root->left;
    root->left = root->right;
    root->right = temp;
    invertTree(root->left);
    invertTree(root->right);
    return root;
}

231.2的幂

这题给的测试数据太坑了,题目也没有说清楚,需要注意数据类型和长度,然后要学会使用n&n-1。
LeetCode -- 力扣算法题解题心得 -- (个人笔记记录)持续更新~~_第35张图片

class Solution {
     
public:
    bool isPowerOfTwo(int n) {
     
        if(n == 0){
     
            return false;
        }
        long x = n;
        return ((x-1) & x) == 0;
    }
};

235.二叉搜索树的最近公共祖先

此题有两种解法,一种是两遍遍历得到两个结点的访问路径,然后逐个比较筛选;
另一种解法是:
有三种情况:

  1. 当前结点的值大于两个结点的值,则访问左子树;
  2. 当前结点的值小于两个结点的值,则访问右子树;
  3. 当前结点的值在两个结点值中间,则为分歧点,直接跳出循环返回。
    LeetCode -- 力扣算法题解题心得 -- (个人笔记记录)持续更新~~_第36张图片
struct TreeNode* lowestCommonAncestor(struct TreeNode* root, struct TreeNode* p, struct TreeNode* q) {
     
    while(true){
     
        if(root->val>p->val&&root->val>q->val){
     
            root = root->left;
        }else if(root->val<p->val&&root->val<q->val){
     
            root = root->right;
        }else{
     
            break;
        }
    }
    return root;
}

237.删除链表中的节点

此题较为简单,直接把节点拉出来斩了就行。
LeetCode -- 力扣算法题解题心得 -- (个人笔记记录)持续更新~~_第37张图片

void deleteNode(struct ListNode* node) {
     
    node->val = node->next->val;
    node->next = node->next->next;
}

257.二叉树的所有路径

采用深度遍历算法,用一个数组记录非叶结点,当访问到叶结点时将相应的序列放进数组。
LeetCode -- 力扣算法题解题心得 -- (个人笔记记录)持续更新~~_第38张图片

void Tranverse(struct TreeNode* root,int num,int *arr,int *returnSize,char** res){
     
    if(root == NULL){
     
        return ;
    }
    if(root->left == NULL && root->right == NULL){
     
        char* temp = (char*)malloc(sizeof(char)*1000);
        int len = 0;
        for(int i=0;i<num;i++){
     
            len += sprintf(temp+len,"%d->",arr[i]);
        }
        sprintf(temp+len,"%d",root->val);
        res[(*returnSize)++] = temp;
    }else{
     
        arr[num++] = root->val;
        Tranverse(root->left,num,arr,returnSize,res);
        Tranverse(root->right,num,arr,returnSize,res);
    }
}

char ** binaryTreePaths(struct TreeNode* root, int* returnSize){
     
    char** res = (char**)malloc(sizeof(char*)*1000);
    int* arr = (int*)malloc(sizeof(int)*1000);
    *returnSize = 0;
    Tranverse(root,0,arr,returnSize,res);
    return res;
}

268.缺失数字

一种做法是付出额外的空间,申请一个额外的数组来存放数字,然后改变值,通过值来判断是否缺失。
LeetCode -- 力扣算法题解题心得 -- (个人笔记记录)持续更新~~_第39张图片

int missingNumber(int* nums, int numsSize){
     
    int *arr = (int*)malloc(sizeof(int)*(numsSize+1));
    int ans;
    for(int i=0;i<numsSize+1;i++){
     
        arr[i] = -1;
    }
    for(int i=0;i<numsSize;i++){
     
        arr[nums[i]] += 1;
    }
    for(int j=0;j<numsSize+1;j++){
     
        if(arr[j] != 0){
     
            ans = j;
            break;
        }
    }
    return ans;
}

342.4的幂

该题目是2的幂的变题,只需要在辨别2的幂的基础上区分2和4,两种思路,一是用该数异运算0xaaaaaaaa,得到一的为4的幂,可以发散至其他的题目。但是也可用%3 == 1 的方法。
LeetCode -- 力扣算法题解题心得 -- (个人笔记记录)持续更新~~_第40张图片

class Solution {
     
public:
    bool isPowerOfFour(int n) {
     
        long x = n;
        if(n <= 0) return false;
        return ((n-1 & n) == 0) && (n%3==1);
    }
};

371.两整数之和

利用加法器的原理,先用异或算加过的位数,再用或算出进位,循环,直到为零。
LeetCode -- 力扣算法题解题心得 -- (个人笔记记录)持续更新~~_第41张图片

class Solution {
     
public:
    int getSum(int a, int b) {
     
        unsigned long x = a,y = b;
        while(x != 0){
     
            long temp = x^y;
            x = (x&y) << 1;
            y = temp;
        }
        return y;
    }
};

876.链表的中间结点

本题两种思路,一种是暴力求解,先得到链表长度,再返回一半的链表;
另一种是用快慢指针,慢指针走到一半快指针走到头。下面给出了两种方法的代码。原则上两种方法的性能是一样的,但第二种方法更加巧妙,且快慢指针可以处理其他很多问题。
LeetCode -- 力扣算法题解题心得 -- (个人笔记记录)持续更新~~_第42张图片

// 暴力求解
struct ListNode* middleNode(struct ListNode* head){
     
    int num = 0;
    struct ListNode* test = head;
    while(test!=NULL){
     
        num++;
        test = test->next;
    }
    for(int i=0;i<num/2;i++){
     
        head = head->next;
    }
    return head;
}

// 快慢指针
struct ListNode* middleNode(struct ListNode* head){
     
    struct ListNode* slow = head;
    struct ListNode* fast = head;
    while((fast != NULL)&&(fast->next != NULL)){
     
        slow = slow->next;
        fast = fast->next->next;
    }
    return slow;
}

938.二叉搜索树的范围和

第一次没好好读题,做成了普通二叉树的解法,给出代码,蛮简单的,然后又改成二叉搜索树的代码。结果显示,性能还不如暴力解法。
LeetCode -- 力扣算法题解题心得 -- (个人笔记记录)持续更新~~_第43张图片


int Tranverse(struct TreeNode* root,int low,int high){
     
    if(root == NULL){
     
        return 0;
    }

    int k = 0;
    if(root->val >= low && root->val <= high){
     
       k = root->val;
    }

    return k + Tranverse(root->left,low,high) + Tranverse(root->right,low,high);
}

int rangeSumBST(struct TreeNode* root, int low, int high){
     
    int k = Tranverse(root,low,high);
    return k;
}

int Tranverse(struct TreeNode* root,int low,int high){
     
    if(root == NULL){
     
        return 0;
    }

    // 进行三重选择判断
    if(root->val < low){
     
        return 0 + Tranverse(root->right,low,high);
    }else if(root->val > high){
     
        return 0 + Tranverse(root->left,low,high);
    }
    
    return root->val + Tranverse(root->left,low,high) + Tranverse(root->right,low,high);

}

int rangeSumBST(struct TreeNode* root,int low,int high){
     
    int k = Tranverse(root,low,high);
    return k;
}

5672.检查数组是否经排序和轮换得到

这题思路就是将数组进行n次轮转,每次从后往前挪动一个元素,然后检查是否升序排列。
LeetCode -- 力扣算法题解题心得 -- (个人笔记记录)持续更新~~_第44张图片

bool check(int* nums, int numsSize){
     
    int i;
    for(int j=0;j<numsSize;j++){
     
    	int num =0;
        int k = nums[numsSize-1];
        for(int m = numsSize-2;m>=0;m--){
     
            nums[m+1] = nums[m];
        }
        nums[0] = k;
		for(i=0;i<numsSize-1;i++){
     
            if(nums[i]<=nums[i+1]){
     
                num++;
            }
        }
        if(num == numsSize-1){
     
            return true;
        }
    }
    return false;
}

5673.移除石子的最大得分

第一次参加力扣周赛,肝了两题还都是暴力,害,事后来诸葛亮了。
LeetCode -- 力扣算法题解题心得 -- (个人笔记记录)持续更新~~_第45张图片

int maximumScore(int a, int b, int c){
     
        if(a+b<=c)
            return a+b;
        else if(a+c<=b)
            return a+c;
        else if(b+c<=a)
            return b+c;
        return (a+b+c)/2;
}

你可能感兴趣的:(算法笔记,leetcode,算法,数据结构)