记录自己刷算法题遇见的美妙解法
动态规划(dynamic programming)的programming指的是一种表格法,而非编写计算机程序
【leetcode 104】二叉树最大深度
int maxDepth(TreeNode* root) {
if(root==nullptr){
return 0;
}
int left = maxDepth(root->left);
int right = maxDepth(root->right);
return (left>right?left:right)+1;
}
【leetcode 100】判断二叉树是否相同,好简单,好美妙的解法
/**
* 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 isSameTree(TreeNode* p, TreeNode* q) {
if (p == NULL) return q == NULL;
return q != NULL && p->val == q->val && isSameTree(p->left, q->left) && isSameTree(p->right, q->right);
}
};
反转链表
// 递归版本
ListNode* reverseList(ListNode* head) {
if(head == NULL || head->next == NULL){
return head;
}
ListNode* last = reverseList(head->next);
head->next->next=head;
head->next = NULL;
return last;
}
// 迭代版本
ListNode* reverseList(ListNode* head) {
if(head == nullptr || head->next==nullptr) return head;
ListNode *pre = nullptr, *cur = head;
while(cur){
ListNode *next = cur->next;
cur->next = pre;
pre = cur;
cur = next;
}
return pre;
}
是否为环形链表,除了使用哈希表来判断,也可以使用快慢指针,如果快慢指针相遇,即代表链表有环
class Solution {
public:
bool hasCycle(ListNode* head) {
if (head == nullptr || head->next == nullptr) {
return false;
}
ListNode* slow = head;
ListNode* fast = head->next;
while (slow != fast) {
if (fast == nullptr || fast->next == nullptr) {
return false;
}
slow = slow->next;
fast = fast->next->next;
}
return true;
}
};
判断s是否为t的子序列,
字符串的一个子序列是原始字符串删除一些(也可以不删除)字符而不改变剩余字符相对位置形成的新字符串。(例如,"ace"是"abcde"的一个子序列,而"aec"不是)。
class Solution {
public:
bool isSubsequence(string s, string t) {
int n = s.length(), m = t.length();
int i = 0, j = 0;
while (i < n && j < m) {
if (s[i] == t[j]) {
i++;
}
j++;
}
return i == n;
}
};
解数独:本质上就是穷举,不过要使用回溯法,运用计算机递归调用机制
class Solution {
public:
bool isValid(vector<vector<char>>& board, int r,int c,char n){
for(int i=0;i<9;i++){
if(board[r][i] == n) return false;
if(board[i][c] == n) return false;
if(board[(r/3)*3+i/3][(c/3)*3+i%3] == n) return false;
}
return true;
}
bool backtrack(vector<vector<char>>& board, int i, int j){
int m=9,n=9;
if(j==n){
return backtrack(board, i+1, 0);
}
if(i==m){
return true;
}
if(board[i][j]!='.'){
return backtrack(board, i,j+1);
}
for(char ch = '1';ch<='9';ch++){
if(!isValid(board, i, j, ch)) continue;
board[i][j] = ch;
if(backtrack(board,i,j+1)){
return true;
}
board[i][j]='.';
}
return false;
}
void solveSudoku(vector<vector<char>>& board) {
backtrack(board, 0, 0);
}
};
求最大公约数,欧几里得算法,这也许是世界上已知的最古老的算法之一,上次B站崩溃就是因为使用Lua语言计算gcd时,出现了NAN错误,即not a number,我想如果使用静态语言就不会出现这种情况了吧
int gcd(int a, int b){
int tmp;
while(b){
tmp = b;
b = a % b;
a = tmp;
}
return a;
}
224 基本计算器
class Solution {
public:
int calculate(string s) {
stack<int> ops;
ops.push(1);
int sign = 1;
int ret = 0;
int n = s.length();
int i = 0;
while (i < n) {
if (s[i] == ' ') {
i++;
} else if (s[i] == '+') {
sign = ops.top();
i++;
} else if (s[i] == '-') {
sign = -ops.top();
i++;
} else if (s[i] == '(') {
ops.push(sign);
i++;
} else if (s[i] == ')') {
ops.pop();
i++;
} else {
long num = 0;
while (i < n && s[i] >= '0' && s[i] <= '9') {
num = num * 10 + (s[i] - '0');
i++;
}
ret += sign * num;
}
}
return ret;
}
};
二叉树的层序遍历
/**
* 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>> levelOrder(TreeNode* root) {
vector<vector<int>> res;
if(root==NULL)
return res;
queue<TreeNode *> nodes;
nodes.push(root);
while(!nodes.empty()){
int size = nodes.size();
vector<int> layer;
for(int i=0;i<size;i++){
TreeNode* tmp = nodes.front();
nodes.pop();
layer.push_back(tmp->val);
if(tmp->left!=NULL)
nodes.push(tmp->left);
if(tmp->right!=NULL)
nodes.push(tmp->right);
}
res.push_back(layer);
}
return res;
}
};
合并K个有序链表,先看怎么合并两个有序链表,然后k个直接新建一个空指针,然后依次合并。
合并两个有序链表时,新建一个虚拟头结点,然后指向两个链表中的最小值,最后再让当前指针指向未遍历完的链表。
/**
* 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* mergeKLists(vector<ListNode*>& lists) {
ListNode *head = nullptr;
for(int i=0;i<lists.size();i++){
head = mergetTwoLists(head, lists[i]);
}
return head;
}
ListNode *mergetTwoLists(ListNode *l1, ListNode *l2){
if(!l1 || !l2) return l1?l1:l2;
ListNode head ;
ListNode *cur = &head;
while(l1 && l2){
if(l1->val < l2->val){
cur->next = l1;
l1=l1->next;
}
else{
cur->next = l2;
l2=l2->next;
}
cur = cur->next;
}
cur->next = l1?l1:l2;
return head.next;
}
};