目录
感觉所有算法里面掌握最好的还是回溯,其他的都是半吊子。
1、反转链表
反转链表
双指针法
class Solution {
public:
ListNode* ReverseList(ListNode* pHead) {
ListNode* cur = pHead;
ListNode* prev = nullptr;
while(cur != nullptr)
{
ListNode* tmp = cur->next;
cur->next = prev;
prev = cur;
cur = tmp;
}
return prev;
}
};
2、排序
排序
这里我们选择使用快速排序来求解:
class Solution {
public:
void Quicksort(vector<int>& a, int s, int t)
{
int i, j;
if (s < t)
{
//【1】设置两个变量i、j.分别指向首元素和尾元素,设定i指向的首元素为基准元素
i = s;
j = t + 1;
while (1)
{
do i++;
while (!(a[s] <= a[i] || i == t)); //【2】重复i++操作,直到i指向的元素>=基准元素,或者i指向尾部
do j--;
while (!(a[s] >= a[j] || j == s)); //【3】反复执行j--,直到指向的元素<基准元素,或者j指向头部
if (i < j) //【5】若此时i<j,将i和j指向的元素进行交换。(大的元素在后面)
{
swap(a[j], a[i]);
}
else break; //【5】完成第一次交换后,重复执行步骤1、2,直到i>=j位置
}
//【6】此时i>=j,然后将基准元素与j指向的元素交换位置,至此完成了原序列的第一次划分
swap(a[s], a[j]);
//【7】接下来分别对基准元素前后的子序列中长度大于1的子序列重复执行上述操作。
Quicksort(a, s, j - 1); //前半序列
Quicksort(a, j + 1, t); //后半序列
}
}
vector<int> MySort(vector<int>& arr) {
// write code here
Quicksort(arr,0,arr.size()-1);
return arr;
}
};
3、先序中序后序遍历
递归法:
class Solution {
public:
/**
*
* @param root TreeNode类 the root of binary tree
* @return int整型vector<vector<>>
*/
vector<int> pre;
vector<int> mid;
vector<int> post;
void preorder(TreeNode* root)
{
if(root == nullptr) return;
pre.push_back(root->val);
preorder(root->left);
preorder(root->right);
}
void midorder(TreeNode* root)
{
if(root == nullptr) return;
midorder(root->left);
mid.push_back(root->val);
midorder(root->right);
}
void postorder(TreeNode* root)
{
if(root == nullptr) return;
postorder(root->left);
postorder(root->right);
post.push_back(root->val);
}
vector<vector<int> > threeOrders(TreeNode* root) {
// write code here
pre.clear();
mid.clear();
post.clear();
preorder(root);
midorder(root);
postorder(root);
return {
pre,mid,post};
}
};
4、最小的k个数
sort + 取值
class Solution {
public:
vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
if(k > input.size()) return {
};
vector<int> result(k,0);
sort(input.begin(),input.end());
for(int i = 0; i < k; i++)
result[i] = input[i];
return result;
}
};
方法二:堆
我们用一个大根堆实时维护数组的前 k 小值。首先将前 k个数插入大根堆中,随后从第 k+1 个数开始遍历,如果当前遍历到的数比大根堆的堆顶的数要小,就把堆顶的数弹出,再插入当前遍历到的数。最后将大根堆里的数存入数组返回即可。在下面的代码中,由于 C++ 语言中的堆(即优先队列)为大根堆,我们可以这么做。
class Solution {
public:
vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
if(k > input.size()) return {
};
if(k == 0) return {
};
priority_queue<int> que;
for(int i = 0; i < k; i++)
{
que.push(input[i]);
}
int size = (int)input.size();
for(int i = k; i < size; i++)
{
if(input[i] < que.top())
{
que.pop();
que.push(input[i]);
}
}
vector<int> res(k,0);
for(int i = 0; i < k; i++)
{
res[i] = que.top();
que.pop();
}
return res;
}
};
如果是要求最大的k个数,就用小根堆
5、子数组的最大累加和
https://leetcode-cn.com/problems/lian-xu-zi-shu-zu-de-zui-da-he-lcof/
class Solution {
public:
int maxSubArray(vector<int>& nums) {
if(nums.empty()) return 0;
int res =INT_MIN;
int sum = 0;
for(int i = 0; i < nums.size(); i++)
{
sum += nums[i];
if(sum > res) res = sum;
if(sum < 0) sum = 0;
}
return res;
}
};
6、 用两个栈实现队列
用两个栈实现队列
一个输入栈,一个输出栈。
push数据的时候,只要把数据放进输入栈即可。
pop的时候:
1、输出栈如果为空,就将进栈的数据全部导入,再出栈弹出数据。
2、如果栈不为空,直接从出栈弹出数据
class Solution
{
public:
void push(int x) {
stIn.push(x);
}
int pop() {
if(stOut.empty())
{
while(!stIn.empty())
{
stOut.push(stIn.top());
stIn.pop();
}
}
//out有元素了,那么就pop
int result = stOut.top();
stOut.pop();
return result;
}
private:
stack<int> stIn;
stack<int> stOut;
};
7、142. 环形链表 II
环形链表 II
使用快慢指针:
通过数学证明,x = z;
即:从头节点出发一个index,从相遇地点出发一个index,每次移动一点,直到两者相遇,相遇地点就是入口
这里给出牛客网同样题目的代码:
https://www.nowcoder.com/practice/6e630519bf86480296d0f1c868d425ad?tpId=117&tqId=37713&companyId=134&rp=1&ru=%2Fcompany%2Fhome%2Fcode%2F134&qru=%2Fta%2Fjob-code-high%2Fquestion-ranking&tab=answerKey

class Solution {
public:
ListNode *detectCycle(ListNode *head) {
ListNode* fast = head;
ListNode* slow = head;
while(fast != nullptr && fast->next != nullptr)
{
slow = slow->next;
fast = fast->next->next;
//当两者相遇的时候,开始计算入口地点
while(slow == fast)
{
ListNode* index1 = slow;
ListNode* index2 = head;
while(index1 != index2)
{
index1 = index1->next;
index2 = index2->next;
}
return index1;
}
}
//如果遇到nullptr,说明没有环
return nullptr;
}
};
8、20. 有效的括号
https://leetcode-cn.com/problems/valid-parentheses/
使用栈的时候三者对应到的栈的情况;
1、已经遍历完字符串,但是栈不为空
2、遍历字符串匹配的过程中,栈已经为空了
3、再遍历字符串匹配的过程中,发现栈中没有要匹配的字符。
class Solution {
public:
bool isValid(string s) {
stack<char> st;
for(int i = 0; i < s.size(); i++)
{
if(s[i] == '(') st.push(')');
else if(s[i] == '[') st.push(']');
else if(s[i] == '{') st.push('}');
//接下来就是判断,这个是1、3情况
else if(st.empty() || st.top() != s[i])
{
return false;
}
//如果匹配,那么出栈
else
{
st.pop();
}
}
//第2种情况,遍历完字符串,栈不为空
return st.empty();
}
};
9、最长公共子串(动态规划),磕磕绊绊
给定两个字符串str1和str2,输出两个字符串的最长公共子串
题目保证str1和str2的最长公共子串存在且唯一。
1≤∣str1∣,∣str2∣≤5000
“1AB2345CD”,“12345EF”
“2345”
1、把两个字符串分别以行和列组成一个二维矩阵。
2、比较二维矩阵中每个点对应行列字符中否相等,相等的话值设置为1,否则设置为0。
3、通过查找出值为1的最长对角线就能找到最长公共子串。
string LCS(string str1, string str2) {
// write code here
int len1 = str1.size();
int len2 = str2.size();
int start_index = 0;
int res_length = 0;
if(len1 == 0 || len2 == 0) return "";
vector<vector<int>> f(len1+1,vector<int>(len2+1,0));
for(int i=0;i < len1;i++) //防止数组越界
{
for(int j=0;j < len2;j++)
{
//i-1:text中的第i个字符
if(str1[i] == str2[j])
{
if( i == 0 || j == 0)
{
f[i][j] = 1;
}
else
{
f[i][j] = f[i-1][j-1] + 1;
}
}
else f[i][j] = 0;
//更新坐标
if(f[i][j] >= res_length)
{
start_index = i - res_length;
res_length = f[i][j];
}
}
}
// cout << start_index << endl;
// cout << res_length << endl;
return str1.substr(start_index,res_length);
}
10、二叉树之字形层序遍历
层序遍历+flag标志即可
vector<vector<int> > zigzagLevelOrder(TreeNode* root) {
// write code here
queue<TreeNode*> que;
if(root != nullptr) que.push(root);
vector<vector<int>> result;
int flag = 0;
while(!que.empty())
{
int size = que.size();
vector<int> vec;
for(int i = 0; i < size; i++)
{
TreeNode* node = que.front();
que.pop();
vec.push_back(node->val);
if(node->left) que.push(node->left);
if(node->right) que.push(node->right);
}
if(flag == 0)
{
result.push_back(vec);
flag = 1;
}
else
{
reverse(vec.begin(),vec.end());
result.push_back(vec);
flag = 0;
}
}
return result;
}
11、重建二叉树
https://leetcode-cn.com/problems/zhong-jian-er-cha-shu-lcof/
/**
* 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* traversal(vector<int>& preorder,int prestart,int preend,vector<int>& inorder,int instart,int inend)
{
//首先,检查先序数组大小,根据下标
if(prestart == preend)
{
return nullptr;
}
//先序数组中第一个节点就是当前中间节点,new一个节点
int rootval = preorder[prestart];
TreeNode* root = new TreeNode(rootval);
//如果是叶子节点,就不需要分割了,直接返回该节点
if(preend - prestart == 1)
{
return root;
}
//中序数组找切割点
int splitIndex = instart;
//注意,区间是左闭右开的
for(splitIndex = instart; splitIndex < inend; splitIndex++)
{
if(inorder[splitIndex] == rootval) break;
}
//切割中序数组
int leftInbegin = instart;
int leftInend = splitIndex;
int rightInbegin = splitIndex + 1;
int rightInend = inend;
//切割先序数组
int leftPrebegin = prestart + 1;
int leftPreend = prestart + leftInend - leftInbegin;
int rightPrebegin = leftPreend;
int rightPreend = preend;
//递归处理左区间和右区间
root->left = traversal(preorder,leftPrebegin,leftPreend,inorder,leftInbegin,leftInend);
root->right = traversal(preorder,rightPrebegin,rightPreend,inorder,rightInbegin,rightInend);
return root;
}
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
if(preorder.empty() || inorder.empty()) return nullptr;
return traversal(preorder,0,preorder.size(),inorder,0,inorder.size());
}
};
12、LRU缓存
struct DLinkedNode {
public:
int key;
int value;
DLinkedNode* prev;
DLinkedNode* next;
DLinkedNode() : key(0), value(0), prev(nullptr), next(nullptr) {
};
DLinkedNode(int _key, int _value) : key(_key), value(_value), prev(nullptr), next(nullptr) {
};
};
class LRUCache {
private:
unordered_map<int,DLinkedNode*> cache;
//dummyhead and dummytail
DLinkedNode* dummyhead;
DLinkedNode* dummytail;
// now size of cache
int _size;
// capacity of cache
int _capacity;
public:
LRUCache(int capacity) {
_capacity = capacity;
_size = 0;
dummyhead = new DLinkedNode();
dummytail = new DLinkedNode();
dummyhead->next = dummytail;
dummytail->prev = dummyhead;
}
~LRUCache() {
delete dummyhead;
delete dummytail;
}
int get(int key) {
// if not find
if(cache.find(key) == cache.end())
{
return -1;
}
//if find
//haxi
DLinkedNode* node = cache[key];
//move this Node to head
moveHead(node);
return node->value;
}
void put(int key, int value) {
// if key not exist ,create it
if(cache.find(key) == cache.end())
{
// if size > capacity delete tail node
if(_size + 1 > _capacity)
{
DLinkedNode* deleted_node = deleteTail();
cache.erase(deleted_node->key);
delete deleted_node;
_size--;
}
DLinkedNode* newnode = new DLinkedNode(key,value);
cache[key] = newnode;
addHead(newnode);
_size++;
}
else //chage value
{
DLinkedNode* node = cache[key];
node->value = value;
moveHead(node);
}
}
void addHead(DLinkedNode* node)
{
//双向指针操作 + 虚拟头节点
node->prev = dummyhead;
node->next = dummyhead->next;
dummyhead->next->prev = node;
dummyhead->next = node;
}
DLinkedNode* deleteTail()
{
//尾节点是虚拟tail前面一个。
DLinkedNode* node = dummytail->prev;
deleteNode(node);
return node;
}
void deleteNode(DLinkedNode* node)
{
node->prev->next = node->next;
node->next->prev = node->prev;
}
void moveHead(DLinkedNode* node)
{
//先删除当前节点
deleteNode(node);
//然后将它加入头部
addHead(node);
}
};
13、合并两个有序链表
https://leetcode-cn.com/problems/merge-two-sorted-lists/
/**
* 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) {
ListNode* dummyHead = new ListNode(-1);
ListNode* cur = dummyHead;
while(l1 != nullptr && l2 != nullptr)
{
if(l1->val > l2->val)
{
cur->next = l2;
cur = cur->next;
l2 = l2->next;
}
else
{
cur->next = l1;
cur = cur->next;
l1 = l1->next;
}
}
while(l1 != nullptr)
{
cur->next = l1;
cur = cur->next;
l1 = l1->next;
}
while(l2 != nullptr)
{
cur->next = l2;
cur = cur->next;
l2 = l2->next;
}
ListNode* ret = dummyHead->next;
delete dummyHead;
return ret;
}
};
15、大数加法
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
* 计算两个数之和
* @param s string字符串 表示第一个整数
* @param t string字符串 表示第二个整数
* @return string字符串
*/
string solve(string s, string t) {
// write code here
if(s.empty()) return t;
if(t.empty()) return s;
if(s.size()<t.size()) swap(t,s);
int tail = s.size() - t.size();
int tmp = 0;
//补零操作 t是短的那个
while(tail--) t = '0'+t;
//每次只处理1位,从低到高
for(int i=s.size()-1;i>=0;i--){
tmp = s[i]-'0' + t[i] -'0' + tmp;
s[i] = tmp%10 + '0';
tmp/=10;
}
//最高位是否有进位位
if(tmp) s = '1'+s;
return s;
}
};
16、一个二叉树和一个值sum,请找出所有的根节点到叶子节点的节点值之和等于sum 的路径
一个二叉树和一个值sum…
普通的回溯即可。
class Solution {
public:
/**
*
* @param root TreeNode类
* @param sum int整型
* @return int整型vector<vector<>>
*/
vector<vector<int> > result;
vector<int> path;
void traversal(TreeNode* root,int count)
{
if(root->left == nullptr && root->right == nullptr)
{
if(count == 0)
{
result.push_back(path);
}
return ;
}
if(root->left)
{
count -= root->left->val;
path.push_back(root->left->val);
traversal(root->left,count);
path.pop_back();
count += root->left->val;
}
if(root->right)
{
count -= root->right->val;
path.push_back(root->right->val);
traversal(root->right,count);
path.pop_back();
count += root->right->val;
}
return ;
}
vector<vector<int> > pathSum(TreeNode* root, int sum) {
// write code here
path.clear();
result.clear();
if(root == nullptr) return result;
path.push_back(root->val);
traversal(root,sum - root->val);
return result;
}
};
17、寻找第K大
18、买卖股票的最佳时机
int maxProfit(vector<int>& prices) {
// write code here
int n = prices.size();
vector<int> dp(n+1,0);
int minnum = prices[0];
for(int i = 1; i < n; i++)
{
minnum = min(minnum,prices[i]);
dp[i] = max(prices[i] - minnum,dp[i-1]);
}
return dp[n-1];
}
可以使用滚动数组优化:
int maxProfit(vector<int>& prices) {
int n=prices.size();
if(n==0) return 0;
int ans=0;
int minnum =prices[0];
for(int i=1;i<n;i++)
{
minnum=min(minnum,prices[i]);
ans=max(ans,prices[i]-minnum);
}
if(ans<=0)ans=0;
return ans;
}
19、二数之和
https://leetcode-cn.com/problems/two-sum/
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int,int > umap;
for(int i = 0; i < nums.size(); i++)
{
auto iter = umap.find(target - nums[i]);
//如果找到了
if(iter != umap.end())
{
return {
i,iter->second};
}
//否则,进行插入操作
umap.insert(pair<int,int>(nums[i],i));
}
return {
};
}
};
20、合并两个有序数组
void merge(int A[], int m, int B[], int n) {
int l1 = 0;
int l2 = 0;
vector<int> res;
while(l1 < m && l2 < n)
{
if(A[l1] <= B[l2])
{
res.push_back(A[l1]);
l1++;
}
else
{
res.push_back(B[l2]);
l2++;
}
}
while(l1 < m)
{
res.push_back(A[l1]);
l1++;
}
while(l2 < n)
{
res.push_back(B[l2]);
l2++;
}
for(int i = 0; i < res.size(); i++)
A[i] = res[i];
}
21、二叉树的最近公共祖先
int lowestCommonAncestor(TreeNode* root, int o1, int o2) {
// write code here
if(root == nullptr) return -1;
if(o1 == root->val || o2 == root->val) return root->val;
int left = lowestCommonAncestor(root->left,o1,o2);
int right = lowestCommonAncestor(root->right,o1,o2);
if(left == -1) return right;
if(right == -1) return left;
return root->val;
}