写代码的时候要认真,一旦出错了,debug是很痛苦的,这次是叹号又没加队,而且初始赋值错了
class Solution {
private:
int len1;
int len2;
public:
void dfs(int i, int j, vector<vector<char>>& biggrid)
{
if (biggrid[i][j] == '0')return;
biggrid[i][j] = '0';
dfs(i + 1, j, biggrid);
dfs(i - 1, j, biggrid);
dfs(i, j + 1, biggrid);
dfs(i, j - 1, biggrid);
}
int numIslands(vector<vector<char>>& grid) {
if (!grid.size()) return 0;
len1 = grid.size();
len2 = grid[0].size();
vector<vector<char>> biggrid(len1 + 2, vector<char>(len2 + 2,'0'));
for (int i = 1; i < len1 + 1; i++)
{
for (int j = 1; j < len2 + 1; j++)
{
biggrid[i][j] = grid[i - 1][j - 1];
}
}
int n=0;
for (int i = 1; i < len1 + 1; i++)
{
for (int j = 1; j < len2 + 1; j++)
{
if (biggrid[i][j] == '1')
{
dfs(i, j, biggrid); n++;
}
}
}
return n;
}
};
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* removeElements(ListNode* head, int val) {
auto head1 = new ListNode(0);
head1->next = head;
auto temp = head1;
while(temp->next)
{
if(temp->next->val==val)
{
temp->next = temp->next->next;
}
else
{
temp = temp->next;
}
}
return head1->next;
}
};
class Solution {
public:
bool judge(int n)
{
for(int i = 2;i*i<=n;i++)
{
if(n%i==0)return false;
}
return true;
}
int countPrimes(int n) {
int count = 0;
for(int i = 2; i<n;i++)
{
if(judge(i))count++;
}
return count;
}
};
class Solution {
public:
bool isIsomorphic(string s, string t) {
int lens = s.size();
int lent = t.size();
if(lens!=lent)return false;
unordered_map<char,char> mp;
unordered_map<char,char>::iterator iter;
for(int i = 0 ; i<lens ;i++)
{
char s1 = s[i];
if(mp.find(s1)==mp.end())
{
for(iter = mp.begin() ;iter != mp.end();iter++)
{
if(iter->second==t[i])return false;
}
mp[s1] = t[i];
}
else
{
if(mp[s1]!=t[i])return false;
}
}
return true;
}
};
下面这种做法看似正确,但是是不对的,因为这里其实是浅拷贝,复制了以后如果直接对其进行修改,会导致原来的也发生变化,可以重新进行浅拷贝赋值但是不能进行值和指针的修改
/**
* 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) {
auto head1 = head;
head1->next = NULL;
head = head->next;
while(head)
{
auto temp = head;
head = head->next;
temp->next = head1;
head1 = temp;
}
return head1;
}
};
当新建一个空节点的时候,不能使用auto
/**
* 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* pre = NULL;
auto cur = head;
while(cur)
{
auto temp = cur->next;
cur->next = pre;
pre = cur;
cur = temp;
}
return pre;
}
};
class Solution {
public:
bool dfs(vector<vector<int>>& board, vector<int>& vt, int i)
{
if(vt[i]==-1) return true;//已经访问过
else if (vt[i]==1)return false;//正在访问
else
{
vt[i]=1;
for(auto j : board[i])//这里必须用auto
{
if(!dfs(board, vt, j))return false;
}
vt[i]=-1;
return true;
}
//return true;
}
bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
//0表示未访问,1表示正在访问,-1表示已经访问过
vector<vector<int>> board(numCourses);
for(auto p:prerequisites)//这里必须用auto因为不知道有多少个
{
board[p[1]].push_back(p[0]);//注意方向
}
vector<int> vt(numCourses,0);
for(int i = 0 ;i<numCourses;i++)
{
if(!dfs(board,vt,i))return false;
}
return true;
}
};
/*
* 应用:自动补全、给字符串按字典序排序
* 优势:1、找到具有同一前缀的全部键值。2、按词典序枚举字符串的数据集。
*/
class Trie {
private:
// 最多R个指向子节点的链接,其中每个链接对应字母表数据集中的一个字母,这里取26个英文字母,R=26。
Trie *child[26];
// 指定节点是对应键的结尾还是只是键前缀
bool isWord;
public:
/** Initialize your data structure here. */
// 构造函数
Trie() {
isWord = false;
for (int i=0;i<26;i++) {
child[i] = nullptr;
}
}
/** Inserts a word into the trie. */
// 插入键 时间复杂度O(m),m为键长。空间复杂度O(m),最坏的情况下新插入的键没有公共前缀。
// 通过搜索Trie树来插入键。从根开始搜索它对应于第一个键字符的链接。
void insert(string word) {
// 用于指向每一层节点,进行搜索的操作。
Trie *t = this;
// 遍历插入键的每一个字符
for(char c: word){
// 如果链接不存在,创建一个新节点,并将它与父节点的链接相连,该链接与当前的键字符相匹配
if (!t -> child[c-'a']) {
t->child[c-'a'] = new Trie();
}
// 链接存在,沿着链接移动到树的下一个子层。算法继续搜索下一个键字符
t = t->child[c-'a'];
}
// 直到到达键的最后一个字符,然后将当前节点标记为结束节点。此时的当前节点已经移动到键的最后字符所在的节点
t->isWord = true;
}
/** Returns if the word is in the trie. */
// 查找键 时间复杂度O(m),最坏的情况下m为键长。空间复杂度O(1)
bool search(string word) {
// 用于指向每一层节点,进行搜索的操作。
Trie *t = this;
// 遍历查找键的每一个字符
for (char c:word) {
// 如果链接不存在,查找失败
if (!t -> child[c - 'a']) {
return false;
}
// 链接存在,沿着链接移动到树的下一个子层。算法接续查找下一个键字符。
t = t->child[c - 'a'];
}
// 直到到达最后一个字符,返回该键字符节点的isWord,如果为false,待查键是Trie树中另一个键的前缀。
return t->isWord;
}
/** Returns if there is any word in the trie that starts with the given prefix. */
// 查找Trie树中的键前缀
bool startsWith(string prefix) {
// 用于指向每一层节点,进行搜索的操作。
Trie *t = this;
// 遍历查找前缀的每一个字符
for (char c:prefix) {
// 如果链接不存在,查找失败
if (!t->child[c-'a']) {
return false;
}
// 链接存在,沿着链接移动到树的下一个子层。算法接续查找下一个键字符。
t = t->child[c - 'a'];
}
// 直到到达最后一个字符,由于是查找前缀,而不是整个键,所以返回true
return true;
}
};
作者:ichhYTTtiU
链接:https://leetcode-cn.com/problems/implement-trie-prefix-tree/solution/qian-zhui-shu-c-shu-ju-jie-gou-by-ichhytttiu/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
class Solution {
public:
int minSubArrayLen(int s, vector<int>& nums) {
if(nums.empty())return 0;
int sum = 0,res = INT_MAX,start = 0;
for(int i = 0 ;i<(int)nums.size() ;i++)
{
sum += nums[i];
while(sum>=s)
{
res = min(res, i-start+1);
sum -= nums[start];
start++;
}
}
return (res==INT_MAX)?0:res;
}
};
对于1的情况分类讨论,一次算,一次不算,dp表达式不变
class Solution {
public:
int rob(vector<int>& nums) {
//分两种情况,计算1的和不计算1的
//计算1的情况,这样最后一个不能要了
int len = nums.size();
if(len==0) return 0;
if(len == 1)return nums[0];
if(len ==2)return max(nums[0],nums[1]);
if(len==3)return max(nums[0],max(nums[1],nums[2]));
vector<int> dp1 = nums;
dp1[0] = nums[0];
dp1[1] = nums[0];
dp1[2] = max(nums[1],nums[0]+nums[2]);
for(int i = 3; i<len-1 ;i++ )
{
dp1[i] = max(dp1[i]+dp1[i-2],dp1[i-1]);
}
//不要第一个
vector<int> dp2 = nums;
dp2[0] = 0;
dp2[1] = nums[1];
dp2[2] = max(nums[1],nums[2]);
for(int i =3 ; i<len ; i++)
{
dp2[i] = max(dp2[i]+dp2[i-2],dp2[i-1]);
}
return max(dp1[len-2],dp2[len-1]);
}
};
class Solution {
public:
vector<vector<int>> res;
vector<int> path;
void dfs(int k,int n, vector<int>& ref,int sum,int p)
{
if(sum>n)return;
if(path.size()==k)
{
if(sum==n){res.push_back(path);}
return;
}
for(int i =p;i<=9;i++)
{
if(ref[i-1]==0)
{
ref[i-1]=1;
sum += i;
path.push_back(i);
dfs(k,n,ref,sum,i+1);
path.pop_back();
sum -=i;
ref[i-1]=0;
}
}
}
vector<vector<int>> combinationSum3(int k, int n) {
vector<int> ref(9,0);
dfs(k,n,ref,0,1);
return res;
}
};
class Solution {
public:
bool containsDuplicate(vector<int>& nums) {
unordered_map<int,int> m;
for(auto i:nums)
{
if( m[i]>=1 )return true;
else m[i]=1;
}
return false;
}
};
class Solution {
public:
vector<vector<int>> getSkyline(vector<vector<int>>& buildings) {
vector<pair<int,int>> h;
multiset<int> m;
vector<vector<int>> res;
//1、将每一个建筑分成“两个部分”,例如:[2,9,10]可以转换成[2,-10][9,10],我们用负值来表示左边界
for(const auto& b:buildings)
{
h.push_back({b[0], -b[2]});
h.push_back({b[1], b[2]});
}
//2、根据x值对分段进行排序
sort(h.begin(),h.end());
int prev = 0, cur = 0;
m.insert(0);
//3、遍历
for (auto i:h)
{
if (i.second < 0) m.insert(-i.second); //左端点,高度入堆
else m.erase(m.find(i.second)); //右端点,高度出堆
cur = *m.rbegin(); //当前最大高度高度
if (cur != prev) { //当前最大高度不等于最大高度perv表示这是一个转折点
res.push_back({i.first, cur}); //添加坐标
prev = cur; //更新最大高度
}
}
return res;
}
};
class Solution {
public:
bool containsNearbyDuplicate(vector<int>& nums, int k) {
unordered_map<int,vector<int>> mp;
for(int i = 0 ;i<nums.size();i++)
{
if(mp.find(nums[i])==mp.end())
{
vector<int> temp = {i};
mp[nums[i]]=temp;
}
else
{
if(mp[nums[i]].size()>=1 && i-mp[nums[i]].back()<=k)return true;
mp[nums[i]].push_back(i);
}
}
return false;
}
};
class Solution {
public:
int maximalSquare(vector<vector<char>>& matrix) {
if (matrix.size() == 0 || matrix[0].size() == 0) {
return 0;
}
int maxSide = 0;
int rows = matrix.size(), columns = matrix[0].size();
vector<vector<int>> dp(rows, vector<int>(columns));
for (int i = 0; i < rows; i++) {
for (int j = 0; j < columns; j++) {
if (matrix[i][j] == '1') {
if (i == 0 || j == 0) {
dp[i][j] = 1;
} else {
dp[i][j] = min(min(dp[i - 1][j], dp[i][j - 1]), dp[i - 1][j - 1]) + 1;
}
maxSide = max(maxSide, dp[i][j]);
}
}
}
int maxSquare = maxSide * maxSide;
return maxSquare;
}
};
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/maximal-square/solution/zui-da-zheng-fang-xing-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
和求最大深度的方法类似,直接递归
/**
* 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 countNodes(TreeNode* root) {
if(!root)return 0;
return countNodes(root->left)+countNodes(root->right)+1;
}
};
class Solution {
public:
int computeArea(int A, int B, int C, int D, int E, int F, int G, int H) {
int s1 = (C-A)*(D-B);
int s2 = (G-E)*(H-F);
int left = max(A,E);
int right = min(C,G);
int up = min(D,H);
int down = max(B,F);
if(left>right || up<down)return s1+s2;
return s1+s2-(right-left)*(up-down);
}
};
class Solution {
public:
int calculate(string s) {
stack<string> st;
int i = 0,j=0;
while (i<s.size())
{
string s1;
if (s[i] >= '0')
{
while (s[i] >= '0')
{
s1 += s[i++];
}
}
else
{
s1 = s[i++];
}
if (s1 == "(")
{
st.push("(");
}
else if (s1 == ")")
{
int temp = stoi(st.top());
st.pop(); st.pop();
if (!st.empty() && st.top() == "+")
{
st.pop();
int t = stoi(st.top()) + temp;
st.pop();
st.push(to_string(t));
}
else if (!st.empty() && st.top() == "-")
{
st.pop();
int t = stoi(st.top()) - temp;
st.pop();
st.push(to_string(t ));
}
else st.push(to_string(temp));
}
else if (s1 == "+")
{
st.push("+");
}
else if (s1 == "-")
{
st.push("-");
}
else if (s1 == " ")
{
continue;
}
else
{
if (st.empty() || st.top() == "(")st.push(s1);
else if (st.top() == "+")
{
st.pop();
int temp = (stoi(st.top())) + stoi(s1);
st.pop();
st.push(to_string(temp));
}
else if (st.top() == "-")
{
st.pop();
int temp = (stoi(st.top())) - stoi(s1);
st.pop();
st.push(to_string(temp));
}
}
}
return stoi(st.top());
}
};
class MyStack {
public:
//用一个队列实现
queue<int> qt;
/** Initialize your data structure here. */
MyStack() {
}
/** Push element x onto stack. */
void push(int x) {
qt.push(x);
}
/** Removes the element on top of the stack and returns that element. */
int pop() {
int len = qt.size();
while(len-1)
{
len--;
qt.push(qt.front());
qt.pop();
}
int temp = qt.front();
qt.pop();
return temp;
}
/** Get the top element. */
int top() {
return qt.back();
}
/** Returns whether the stack is empty. */
bool empty() {
return qt.empty();
}
};
/**
* Your MyStack object will be instantiated and called as such:
* MyStack* obj = new MyStack();
* obj->push(x);
* int param_2 = obj->pop();
* int param_3 = obj->top();
* bool param_4 = obj->empty();
*/
/**
* 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* invertTree(TreeNode* root) {
if(!root)return NULL;
auto r = invertTree(root->right);
auto l = invertTree(root->left);
root->right = l;
root->left = r;
return root;
}
};
递归就是把大问题最后递归成小问题,只要使二叉树的每个节点的左右子节点交换,最后整个树的就翻转了
class Solution {
public:
TreeNode* invertTree(TreeNode* root) {
dfs(root);
return root;
}
private:
void dfs(TreeNode* root){ //这是先序遍历,每一个节点,然后将这个节点的左右子节点翻转
if(root){
swap(root->left, root->right);
dfs(root->left);
dfs(root->right);
}
}
};
作者:zuo-10
链接:https://leetcode-cn.com/problems/invert-binary-tree/solution/c-shi-yong-swapdi-gui-die-dai-by-zuo-10/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
在vs上能运行通
class Solution {
public:
int calculate(string s) {
vector<string> st;
int i = 0;
while (i < s.size())
{
string s1;
if (s[i] >= '0')
{
while (s[i] >= '0')
{
s1 += s[i++];
}
}
else
{
s1 = s[i++];
}
if (st.empty() || s1 == "+" || s1 == "-" || s1 == "*" || s1 == "/") { st.push_back(s1); }
else if (s1 == " ") {}
else
{
if (st.back() == "*")
{
st.pop_back();
int temp = stoi(st.back())*stoi(s1);
st.pop_back();
st.push_back(to_string(temp));
}
else if(st.back()=="/")
{
st.pop_back();
int temp = stoi(st.back()) / stoi(s1);
st.pop_back();
st.push_back(to_string(temp));
}
else
{
st.push_back(s1);
}
}
}
int res = stoi(st[0]);
for (i = 1; i < st.size(); i++)
{
if (st[i - 1] == "+")
{
res += stoi(st[i]);
}
else if (st[i - 1] == "-")
{
res -= stoi(st[i]);
}
}
return res;
}
};
特别注意里面溢出的情况,最好的解决方式就换个表达方式,尽量不要产生大的数
class Solution {
public:
vector<string> summaryRanges(vector<int>& nums) {
//for(int i = 0;i(nums[i]);
int i=1,j=0;
vector<string> res;
while(i<nums.size())
{
//while(i
while(i<nums.size() && nums[i]-1==nums[i-1])i++;
if(j==i-1)
{
res.push_back(to_string(nums[j++]));i++;
}
else
{
res.push_back(to_string(nums[j])+"->"+to_string(nums[i-1]));j=i;i++;
}
}
if(j==nums.size()-1)res.push_back(to_string(nums[j]));
return res;
}
};
/**
* 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 count = 0;
int res = 0;
void dfs(TreeNode* root, int k)
{
if(!root)return;
dfs(root->left,k);
count++;if(count==k){res = root->val;return;}
dfs(root->right,k);
}
int kthSmallest(TreeNode* root, int k) {
dfs(root,k);
return res;
}
};
class Solution {
public:
bool isPowerOfTwo(int n) {
if(n==1)return true;
if(n<=0)return false;
if(n>0 && n<1)
{
n = 1/n;
}
while(n>2)
{
if(n%2!=0)return false;
n /=2;
}
return true;
}
};
自己写的不仅复杂而且有检查不出的错误,因为peek和pop会导致栈的元素全部移到另一个栈中会颠倒顺序,所以每次进行这两个操作的时候都需要再重新倒回来,这会十分的复杂
下面这个实现非常简单,一个栈就用来进,一个就用来出,当要出的时候就从出站里面弹,如果出栈为空就把入栈的所有元素再放入出栈,而且pop操作时比peek多加了一步,pop里面还能再使用peek
class MyQueue {
public:
/** Initialize your data structure here. */
MyQueue() {
}
/** Push element x to the back of queue. */
void push(int x) {
input.push(x);
}
/** Removes the element from in front of queue and returns that element. */
int pop() {
int temp = peek();
output.pop();
return temp;
}
/** Get the front element. */
int peek() {
if(output.empty()){
while(input.size()){
output.push(input.top());
input.pop();
}
}
return output.top();
}
/** Returns whether the queue is empty. */
bool empty() {
return input.empty() &&output.empty();
}
stack<int> input, output;
};
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
bool isPalindrome(ListNode* head) {
int count = 0;
auto slow = head;
auto fast = head;
auto temp = head;
while(temp){count++;temp=temp->next;}
while(fast && fast->next)
{
slow= slow->next;
fast = fast->next->next;
}
if(count%2==1){slow =slow->next;}
ListNode* pre = NULL;
auto cur = slow;
while(cur)
{
temp = cur->next;
cur->next = pre;
pre = cur;
cur = temp;
}
slow = pre;
while(head && slow)
{
if(head->val != slow->val)return false;
head = head->next;
slow = slow->next;
}
return true;
}
};
利用二叉搜索树的性质
/**
* 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* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
if(!root)return root;
if((root->val>=p->val && root->val<=q->val)||(root->val<=p->val && root->val>=q->val))return root;
if(root->val<=p->val && root->val<=q->val)return lowestCommonAncestor(root->right,p,q);
if(root->val>=p->val && root->val>=q->val)return lowestCommonAncestor(root->left,p,q);
return root;
}
};
当我们用递归去做这个题时不要被题目误导,应该要明确一点
这个函数的功能有三个:给定两个节点 p 和 q
如果 p 和 q 都存在,则返回它们的公共祖先;
如果只存在一个,则返回存在的一个;
如果 p 和 q 都不存在,则返回NULL
具体思路:
(1) 如果当前结点 root等于 NULL,则直接返回 NULL
(2) 如果 root 等于 p 或者 q ,那这棵树一定返回 pp 或者 qq
(3) 然后递归左右子树,因为是递归,使用函数后可认为左右子树已经算出结果,用 left和 right表示
(4) 此时若leftleft为空,那最终结果只要看 rightright;若 rightright 为空,那最终结果只要看 leftleft
(5) 如果 leftleft 和 rightright 都非空,因为只给了 pp 和 qq 两个结点,都非空,说明一边一个,因此 rootroot 是他们的最近公共祖先
(6) 如果 leftleft 和 rightright 都为空,则返回空(其实已经包含在前面的情况中了)
时间复杂度是 O(n)O(n):每个结点最多遍历一次或用主定理,空间复杂度是 O(n)O(n):需要系统栈空间
作者:Wilson79
链接:https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-tree/solution/c-jing-dian-di-gui-si-lu-fei-chang-hao-li-jie-shi-/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
if(root == NULL)
return NULL;
if(root == p || root == q)
return root;
TreeNode* left = lowestCommonAncestor(root->left, p, q);
TreeNode* right = lowestCommonAncestor(root->right, p, q);
if(left == NULL)
return right;
if(right == NULL)
return left;
if(left && right) // p和q在两侧
return root;
return NULL; // 必须有返回值
}
};
作者:Wilson79
链接:https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-tree/solution/c-jing-dian-di-gui-si-lu-fei-chang-hao-li-jie-shi-/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
这道题本来开始想的是遍历一次求所有位置的左积,再遍历一次求所有位置的右积,再遍历一次求左积*右积
大概是O(3n),但是其实可以一次遍历完成,每个值先不着急乘是左右的乘机乘积,可以先左边乘到这里,等一会右边再乘到这里,十分巧妙
class Solution {
public:
vector<int> productExceptSelf(vector<int>& nums) {
int n=nums.size();
int left=1,right=1; //left:从左边累乘,right:从右边累乘
vector<int> res(n,1);
for(int i=0;i<n;++i) //最终每个元素其左右乘积进行相乘得出结果
{
res[i]*=left; //乘以其左边的乘积
left*=nums[i];
res[n-1-i]*=right; //乘以其右边的乘积
right*=nums[n-1-i];
}
return res;
}
};
作者:ooolize-2
链接:https://leetcode-cn.com/problems/product-of-array-except-self/solution/yi-ci-bian-li-qiao-miao-cun-chu-he-ji-suan-zuo-ji-/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
vector<int> res;
if(k == 0) return res;
deque<int> window; //双端队列,从队头到队尾 依次存 窗口内最大元素的index ~ 最小元素的index
int right = 0;
while(right < nums.size()){ //后续,窗口每右移一次,都会产生一个最大值[队列头位置的元素]
if(!window.empty() && window.front() <= right - k){ //队头不在窗口范围内
window.pop_front();
}
while(!window.empty() && nums[right] > nums[window.back()]){ //待入队元素比队尾元素大
window.pop_back();
}
window.push_back(right);
right++;
if(right >= k) res.push_back(nums[window.front()]);
}
return res;
}
class Solution {
public:
bool searchMatrix(vector<vector<int>>& matrix, int target) {
if(matrix.empty())return false;
int len1 = matrix.size();
int len2 = matrix[0].size();
int i=len1-1,j=0;
while(i>=0 && j<len2)
{
if(target==matrix[i][j])return true;
else if(target<matrix[i][j])
{
i--;
}
else
{
j++;
}
}
return false;
}
};
class Solution {
public:
bool isAnagram(string s, string t) {
unordered_map<char,int> ms,mt;
for(auto s1:s)ms[s1]++;
for(auto t1:t)mt[t1]++;
return ms==mt;
}
};
这道题一看结果,其实就是写出所有路径的结果再变个形式,所以可以先dfs,然后变结果,常用的二叉树dfs就那几种
括号里是否加!始终没有弄清,浪费了好多时间,判断是否为叶节点时应该用!left&&!right代表叶节点,而left本身就代表部位空了。另外string里面也有pop_back的方法
/**
* 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 {
private:
vector<vector<int> > r;
vector<int> path;
public:
void dfs(TreeNode* root)
{
if(!root->left && !root->right)
{
path.push_back(root->val);
r.push_back(path);
path.pop_back();
return;
}
if(root->left)
{
path.push_back(root->val);
dfs(root->left);
path.pop_back();
}
if(root->right)
{
path.push_back(root->val);
dfs(root->right);
path.pop_back();
}
}
vector<string> binaryTreePaths(TreeNode* root) {
vector<string> res;
if(!root)return res;
dfs(root);
for(auto i:r)
{
string s;
for(auto j:i)
{
s = s + to_string(j)+"->";
}
s.pop_back();
s.pop_back();
res.push_back(s);
}
return res;
}
};
class Solution {
public:
int addDigits(int num) {
string s=to_string(num);
while(s.size()>1)
{
int temp = 0;
for(auto s1:s)
{
temp += s1-'0';
}
s = to_string(temp);
}
return stoi(s);
}
};
class Solution {
public:
bool isUgly(int num) {
if(num==0)return false;
while(1)
{
while(num%2==0)num=num/2;
while(num%3==0)num=num/3;
while(num%5==0)num=num/5;
if(num==1)return true;
if(num%2!=0 && num%3!=0 && num%5!=0)return false;
}
return true;
}
};
class Solution {
public:
int nthUglyNumber(int n) {
vector<int> dp(n, 0);
dp[0] = 1;
int p2 = 0, p3 = 0, p5 = 0;
for(int i = 1; i < n; i ++){
dp[i] = min(min(dp[p2]*2, dp[p3]*3), dp[p5]*5);
if(dp[i] == dp[p2]*2) p2++;
if(dp[i] == dp[p3]*3) p3++;
if(dp[i] == dp[p5]*5) p5++;
}
return dp[n - 1];
}
};
作者:yizhe-shi
链接:https://leetcode-cn.com/problems/ugly-number-ii/solution/c-onjie-fa-by-yizhe-shi-2/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
class Solution {
public:
int missingNumber(vector<int>& nums) {
int len = nums.size();
sort(nums.begin(),nums.end());
if(nums[0]!=0) return 0;
for(int i= 1 ; i<len ;i++)
{
if(nums[i]-nums[i-1]>1)return nums[i-1]+1;
}
return nums[len-1]+1;
}
};
class Solution {
public:
int hIndex(vector<int>& citations) {
if(citations.empty())return 0;
sort(citations.begin(),citations.end());
for(int i = citations.back();i>=0;i--)
{
int t = lower_bound(citations.begin(),citations.end(),i)-citations.begin();
if(citations.size() - t >= i){return i;}
}
return 0;
}
};
素组有序,让我们在O(log n)的时间内完成计算。看到这个时间复杂度,应该有很敏锐的意识应该用二分查找法,我们最先初始化left和right为0和数组长度len-1,然后取中间值mid,比较citations[mid]和len-mid做比较,如果前者大,则right移到mid之前,反之right移到mid之后,终止条件是left>right,最后返回len-left即可。
————————————————
版权声明:本文为CSDN博主「pushup8」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/pushup8/article/details/85200248
里面特殊情况总是判断不清楚,对这个h定义比较模糊
class Solution {
public:
int hIndex(vector<int>& nums) {
int n = nums.size(), low = 0, high = n - 1, mid = 0;
while(low <= high){
mid = low + (high - low) / 2;
int target = n - mid;
if(nums[mid] < target) low = mid + 1;
else if(nums[mid] > target) high = mid - 1;
else return n - mid;
}
return n - low;
}
};
class Solution {
public:
bool judge(vector<int> citations, int mid)
{
int temp = lower_bound( citations.begin(),citations.end(),mid) -citations.begin();
return citations.size()-temp >= mid;
}
int hIndex(vector<int>& citations) {
int len = citations.size();
if(len==0)return len;
int left = 0,right = citations.back();
while(left<=right)
{
int mid=left +(right-left)/2;
if(judge(citations, mid))
{left=mid+1;}
else
{right=mid-1;}
}
return left>=1?left-1:0;
}
};
并不是mid值一定要加1,不同的情况不一样
// The API isBadVersion is defined for you.
// bool isBadVersion(int version);
class Solution {
public:
int firstBadVersion(int n) {
long left = 1;
long right = n;
while(left<right)
{
long mid= (left+right)/2;
if(isBadVersion(mid))
{
right = mid;
}
else
{
left = mid+1;
}
}
return left;
}
};
dfs超时,应该用bfs`在这里插入代码片
注意剪枝操作,而且当里面会有重复元素时,最好用一个无序set,这样做反而会使时间复杂度降低,因为unordered的查找复杂度是极低的
class Solution {
public:
int numSquares(int n) {
if(n==0)return 0;
if(n==1)return 1;
int num = 0;
queue<int> qt; qt.push(0);
unordered_set<int> st; st.insert(0);
int m = sqrt(n);
while(!qt.empty())
{
int len = qt.size();
for(int i = 0;i<len ;i++)
{
auto temp = qt.front();qt.pop();
if(temp==n)return num;
for(int j = m;j>=0;j--)
{
int x = temp+j*j;
if(x>n)continue;//
if(st.find(x)==st.end()){qt.push(x);st.insert(x);}
}
}
num++;
}
return num;
}
};
class Solution
{
public:
/*返回小于n的平方序列: 1, 4, 9...*/
vector<int> getSquares(int n)
{
vector<int> res;
for(int i = 1; i*i <= n; ++i)
{
res.push_back(i*i);
}
return res;
}
int numSquares(int n)
{
vector<int> squares = getSquares(n);
vector<bool> visited(n+1); //记录已访问过的节点
queue<int> q;
q.push(n);
int res = 0;
visited[n] = true;
while(!q.empty())
{
int size = q.size();
res++;
while(size--)
{
int curr = q.front();
q.pop();
/*每次跨越的间隔为平方数*/
for(int num: squares)
{
int next = curr - num;
if(next < 0)
{
break;
}
if(next == 0)
{
return res;
}
if(visited[next])
{
continue;
}
visited[next] = true;
q.push(next);
}
}
}
return n;
}
};
作者:yu-mu-20
链接:https://leetcode-cn.com/problems/perfect-squares/solution/dong-tai-gui-hua-bfsliang-chong-fang-fa-by-yu-mu-2/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
class Solution {
public:
int res = INT_MAX;
vector<int> path;
void dfs(int target,int l,int sum,int p)
{
if(sum>target){return;}
if(sum==target){res = min(res,(int)path.size());return;}
for(int i = p;i<=l;i++)
{
if(path.size()>res)continue;//
sum += i*i;
path.push_back(i*i);
dfs(target,l,sum,p);
path.pop_back();
sum -= i*i;
}
}
int numSquares(int n) {
if(n==0)return 0;
if(n==1)return 1;
int l = sqrt(n);
dfs(n,l,0,1);
return res;
}
};
按照前后双指针的思路很快做出来,但是改变了顺序,不符合题目的要求
class Solution {
public:
void moveZeroes(vector<int>& nums) {
int len = nums.size();
int i = 0;
int j = len -1;
while(i<=j)
{
while(i<=j && nums[i]!=0)i++;
while(i<j && nums[j]==0)j--;
if(i<=j)
{
swap(nums[i++],nums[j--]);
}
}
return;
}
};
改一下双指针的遍历方式,两个都是从前往后遍历
class Solution {
public:
void moveZeroes(vector<int>& nums) {
int len = nums.size();
int i = 0;
int j = 0;
while(i<len)
{
while(i<len && nums[i]==0)i++;
if(i<len)
{
swap(nums[i++],nums[j++]);
}
}
return;
}
};
哈希和排序都不满足要求,这道题用链表有环的方法最好,一样的思路
本题要符合时间复杂度小于n2,空间复杂度1的话,官方解答的前两种方法都不满足,只有循环检测的方法能够满足,代码也非常简单。
但我认为官方解释没有写的非常完整,这里来试图写的完整一点。
首先,如果从nums[0]开始沿着下标的方式来走,如果没有重复的数字,可能可以走出一条线,因为不可能回到0,所以最后一个节点应该的值应该是n,而不存在索引号为n的节点(因为是从0开始),所以中断了,就退出了。
但是这里的情况是,存在重复的节点,所以这样沿着nums[0]走会发生什么呢?
首先,必定不可能回到0,因为没有值是0的节点,其次,不可能像刚刚一样中断。
这是为什么呢,因为要中断,必然需要节点的值大于最大的索引,但因为有重复,节点的最大值小于等于索引的最大值,所以没有办法中断,所以必定是在一个循环之中。
也就是通过这条路,走着走着进入了一个循环。
可以举个例子,[1,2,3,4,5,3]这样,也就是会 1-2-3-4-5-3-4-5-3-4-5……也就是3-4-5-3这部分陷入了循环,可以发现,重复的地方也就是循环的起始点,也就是3,因为这个3有2个不同的点到达了它,所以造成了循环,它也就是2条路的交叉口。
接下来,用乌龟和兔的方法,假如乌龟一次走1步,兔一次走2步。
所有的情况都可以抽象成先经过i个节点到达重复节点,再进入到长度为S的循环圈中。
那么,如果乌龟和兔同时出发,他们会在哪里相遇呢?
一定是在这个圈中的某点,因为兔的速度是2,乌龟是1,相对速度是1,所以兔子一定能追上乌龟,在圈里的某处。
当乌龟走了距离i到达圈起始点时,兔子已经走了2i,那么兔子相对于乌龟来说是多远呢?也就是i-kS,也就是去掉兔子额外走的k圈。
这时,还是兔子追乌龟,它需要追多远呢?应该是圈剩下的距离,也就是S-(i-ks),也就是(k+1)S-i,也就是乌龟再走这么久,会被追上,这个位置非常巧妙,可以发现这里再经过i就会回到圈的起点,这就让我们想到,在这个地方让另一个乌龟从起点爬起,当起点的乌龟爬到圈起始点时,刚好原来的乌龟也会达到圈起始点,这样就能够得到圈起始点了,也就是重复的元素。
作者:jie-ju-wei-ming-ming
链接:https://leetcode-cn.com/problems/find-the-duplicate-number/solution/xun-huan-jian-ce-fang-fa-xi-shuo-by-jie-ju-wei-min/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
class Solution {
public:
int findDuplicate(vector<int>& nums) {
int fast = 0, slow = 0;
while(true){
fast = nums[nums[fast]]; //相当于走两步
slow = nums[slow];
if(fast == slow)
break;
}
int finder = 0; //新建一个慢指针重新回到起点开始走
while(true){
finder = nums[finder];
slow = nums[slow];
if(slow == finder)
break;
}
return slow;
}
};
作者:zjczxz
链接:https://leetcode-cn.com/problems/find-the-duplicate-number/solution/kuai-man-zhi-zhen-de-jie-shi-cong-damien_undoxie-d/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
class Solution {
public:
void func(vector<vector<int>>& board,int i,int j)
{
int count = 0;
if(i-1>=0 && j-1>=0 && (board[i-1][j-1]==1||board[i-1][j-1]==3))count++;
if(i-1>=0 && (board[i-1][j]==1||board[i-1][j]==3))count++;
if( j-1>=0 && (board[i][j-1]==1||board[i][j-1]==3))count++;
if(i+1<board.size() && j-1>=0 && (board[i+1][j-1]==1||board[i+1][j-1]==3))count++;
if(i-1>=0 && j+1<board[0].size() && (board[i-1][j+1]==1||board[i-1][j+1]==3))count++;
if(i+1<board.size() && j+1<board[0].size() && (board[i+1][j+1]==1||board[i+1][j+1]==3))count++;
if(i+1<board.size() && (board[i+1][j]==1||board[i+1][j]==3))count++;
if( j+1<board[0].size() && (board[i][j+1]==1||board[i][j+1]==3))count++;
if(board[i][j]==1 && count<2) board[i][j]=3;
//else if(board[i][j]=1&&count<2)board[i]][j]=3;
else if(board[i][j]==1&&count>3)board[i][j]=3;
else if(board[i][j]==0&&count==3)board[i][j]=2;
}
void gameOfLife(vector<vector<int>>& board) {
//不允许使用额外的数组进行储存
for(int i = 0;i<board.size();i++)
{
for(int j = 0;j<board[0].size();j++)
{
func(board,i,j);
}
}
for(int i = 0;i<board.size();i++)
{
for(int j = 0;j<board[0].size();j++)
{
if(board[i][j]==2)board[i][j]=1;
else if(board[i][j]==3)board[i][j]=0;
}
}
return;
}
};
里面有几点:
1.从一段话中提取单词没有现成的函数,需要用空格为标志采用双指针法写一个
2.里面还有一个要求是不同的p中的字母对应的string不能一样,所以当要增加新的时候,要对之前进行遍历,防止之前已经有这个value了,再遍历哈希的时候,需要使用复杂的迭代器法
class Solution {
public:
bool wordPattern(string pattern, string str) {
unordered_map<char, string> mp;
unordered_map<char, string>::iterator iter;
int len = str.size();
int i = 0, j = 0;
vector<string> ss;
while (i < len)
{
if (str[i] != ' ')
{
i++;
}
else
{
ss.push_back(str.substr(j, i - j)); i++; j = i;
}
}
ss.push_back(str.substr(j,i-j));
len = pattern.size();
if(ss.size()!=len)return false;
for (int i = 0; i < len; i++)
{
if (mp.find(pattern[i]) == mp.end())
{
for(iter = mp.begin() ;iter!=mp.end();iter++)
{if(iter->second==ss[i])return false;}
mp[pattern[i]] = ss[i];
}
else
{
if (mp[pattern[i]] != ss[i])return false;
}
}
return true;
}
};
class Solution {
public:
bool canWinNim(int n) {
return n%4!=0;
}
};
注意是子序列而不是子串,所以这里递归的办法要变一下
注意是求dp里面的最大值,而不是某位的值,因为不一定最大
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
int len = nums.size();
if(len==0)return 0;
vector<int> dp(len,0);
dp[0]=1;
int res=0;
for(int i = 0 ; i< len ;i++)
{
int m = 1;
for(int j = 0 ; j< i ; j++)
{
if(nums[j]<nums[i]){m = max(m,dp[j]+1);}
}
dp[i] = m;
if(m>res) res = m;
}
return res;
}
};
class NumArray {
private:
vector<int> data;
public:
NumArray(vector<int>& nums) {
data = nums;
}
int sumRange(int i, int j) {
int sum=0;
//NumArray();
for(int c = i ;c<=j ;c++)
{
sum +=data[c];
}
return sum;
}
};
/**
* Your NumArray object will be instantiated and called as such:
* NumArray* obj = new NumArray(nums);
* int param_1 = obj->sumRange(i,j);
*/
int coinChange(vector<int>& coins, int amount) {
// 数组大小为 amount + 1,初始值也为 amount + 1
vector<int> dp(amount + 1, amount + 1);
// base case
dp[0] = 0;
for (int i = 0; i < dp.size(); i++) {
// 内层 for 在求所有子问题 + 1 的最小值
for (int coin : coins) {
// 子问题无解,跳过
if (i - coin < 0) continue;
dp[i] = min(dp[i], 1 + dp[i - coin]);
}
}
return (dp[amount] == amount + 1) ? -1 : dp[amount];
}
作者:labuladong
链接:https://leetcode-cn.com/problems/coin-change/solution/dong-tai-gui-hua-tao-lu-xiang-jie-by-wei-lai-bu-ke/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
双指针是没有问题的,但是问题是当双指针取值到最后试,可能会有到中间的值和中间值是相等的,面对这种情况,需要把最特殊的单独考虑一下,将级数的情况变换成偶数的情况来
排序后用双指针,如果数组元素个数为偶数n则一个指针指向中间一个指针指向最后(例如 1 2 3 4 5 6则一个指向3 一个指向6)然后依次填数即可(先填左指针的数再填右指针的数保证增减增减的顺序)
若为奇数个,仔细分析可以发现序列的倒数第二个元素到最后一个元素必然是递减的所以可以考虑将排序后的第一元素放到最后,这样就又变成了元素个数为偶数的问题了。
作者:wf_csu
链接:https://leetcode-cn.com/problems/wiggle-sort-ii/solution/fei-chang-jian-ji-by-docker-2/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
class Solution {
public:
void wiggleSort(vector<int>& nums) {
sort(nums.begin(),nums.end());
int len = nums.size();
vector<int> res;
if(len%2==0)
{
int i=len/2-1,j =len-1;
while(i>=0)
{
res.push_back(nums[i--] );
res.push_back(nums[j--]);
}
}
else
{
int i = len/2,j = len-1;
while(i>=1)
{
res.push_back(nums[i--]);
res.push_back(nums[j--]);
}
res.push_back(nums[0]);
}
nums=res;
return;
}
};
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* oddEvenList(ListNode* head) {
if(!head || !head->next)return head;
auto temp = head;
auto o = new ListNode(0);
auto head1 = o;
auto e = new ListNode(0);
auto head2 = e;
while(temp)
{
o->next = temp;
o = temp;
temp = temp->next;
if(temp)
{
e->next = temp;
e = temp;
temp = temp->next;
}
}
e->next = NULL;
o->next = head2->next;
return head1->next;
}
};
状态数组dp[i]表示:数字 i 拆分为至少两个正整数之和的最大乘积。为了方便计算,dp 的长度是 n + 1,值初始化为 1。
显然dp[2]等于 1,外层循环从 3 开始遍历,一直到 n 停止。内层循环 j 从 1 开始遍历,一直到 i 之前停止,它代表着数字 i 可以拆分成 j + (i - j)。但 j * (i - j)不一定是最大乘积,因为i-j不一定大于dp[i - j](数字i-j拆分成整数之和的最大乘积),这里要选择最大的值作为 dp[i] 的结果。
作者:xin-tan
链接:https://leetcode-cn.com/problems/integer-break/solution/shuang-jie-fa-dong-tai-gui-hua-tan-xin-fa-fu-zhao-/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
class Solution {
public:
int numberOfArithmeticSlices(vector<int>& A) {
// 求的是子区间而不是子序列构成的区间,这样只需要计算每次新加入的对之前的影响就行
int len = A.size();
vector<int> dp(len,0);
for(int i = 2; i<len ;i++)
{
if(A[i]-A[i-1]==A[i-1]-A[i-2])
{dp[i] = dp[i-1] +1;}
}
int sum = 0;
for(auto i:dp){sum +=i;}
return sum;
}
};
class Solution {
public:
void reverseString(vector<char>& s) {
//reverse(s.begin(),s.end());
int i = 0;
int j = s.size()-1;
while(i<j)
{
swap(s[i++],s[j--]);
}
return ;
}
};
由于是有序矩阵,那么左上角的数字一定是最小的,而右下角的数字一定是最大的,所以这个是我们搜索的范围,然后我们算出中间数字mid,由于矩阵中不同行之间的元素并不是严格有序的,所以我们要在每一行都查找一下mid,我们使用upper_bound,这个函数是查找第一个大于目标数的元素,如果目标数在比该行的尾元素大,则upper_bound返回该行元素的个数,如果目标数比该行首元素小,则upper_bound返回0, 我们遍历完所有的行可以找出中间数是第几小的数,然后k比较,进行二分查找,left和right最终会相等,并且会变成数组中第k小的数字。(方便理解,我们没有直接使用upper_bound函数,但道理一样)。
————————————————
版权声明:本文为CSDN博主「pushup8」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/pushup8/article/details/85200248
class Solution {
public:
int kthSmallest(vector<vector<int>>& matrix, int k) {
int row = matrix.size(), col = matrix[0].size();
int low = matrix[0][0], high = matrix[row - 1][col - 1];
while(low < high){
int mid = (low + high) / 2, j = col - 1, cnt = 0;
for(int i = 0; i < row; i++){
while(j >=0 && matrix[i][j] > mid)j--;
cnt +=(j + 1);
}
if(cnt < k) low = mid + 1;
else high = mid;
}
return low;
}
};
这里面有一个很关键的问题是,可能直接等于k的那个数不在矩阵中下面是解释看到通过二分法在矩阵元素的最大值和最小值之间查找恰好使小于等于该值的矩阵元素为k个的值,这个值即为所求结果的方法,觉得有可能查到的值不在矩阵元素中,但后来发现如果并不是一查到符合条件的值(小于等于该值的矩阵元素有k个)就返回,而是继续二分,直到上下界相等,然后返回此时的下界/上界,由于矩阵中均为整数,是可以保证查到的值在矩阵内且小于等于该值的矩阵元素恰好有k个的。
作者:shimura233
链接:https://leetcode-cn.com/problems/kth-smallest-element-in-a-sorted-matrix/solution/guan-yu-wei-shi-yao-er-fen-cha-zhao-zui-hou-fan-hu/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
关于对哈希里面的value排序的整个过程1.将哈希的pair放到一个向量中去2.重写sort函数,对向量进行排序3.从向量中提取结果
class Solution {
public:
static bool func(pair<int,int>& p1, pair<int,int>& p2)
{
return (p1.second>p2.second)?true:false;
}
vector<int> topKFrequent(vector<int>& nums, int k) {
unordered_map<int,int> mp;
for(auto num:nums)mp[num]++;
vector<pair<int,int>> v(mp.begin(),mp.end());
sort(v.begin(),v.end(),func);
vector<int> res;
//unordered_map::iterator iter;
//for(auto iter=mp.begin();iter!=mp.begin()+k;iter++)res.push_back(iter->first);
for(int i = 0;i<k;i++)res.push_back(v[i].first);
return res;
}
};
class Solution {
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
set<int> st1(nums1.begin(),nums1.end());
set<int> st2(nums2.begin(),nums2.end());
vector<int> res;
for(auto s1:st1)
{
if(st2.find(s1)!=st2.end())
{res.push_back(s1);}
}
return res;
}
};
class Solution {
public:
vector<int> intersect(vector<int>& nums1, vector<int>& nums2) {
unordered_map<int,int> mp;
for(auto num:nums1)
{
if(mp.find(num)!=mp.end())
{mp[num]++;}
else
{mp[num]=1;}
}
vector<int> res;
for(auto num:nums2)
{
if(mp.find(num)!=mp.end() && mp[num]>=1)
{res.push_back(num);mp[num]--;}
}
return res;
}
};
这是第一种做法,原理是对整体进行升序排序,然后,动态规划计算套娃信封的个数,然而这种方法在某种情况下会出现错误:某个位置不应该套,例如这个例子:
[[2,100],[3,200],[4,300],[5,500],[5,400],[5,250],[6,370],[6,360],[7,380]]
死三个信封其实可以套,但是套上就不是最大值了这里介绍一种新的思路,先对0位置进行升序,再对1位置进行降序,这样的话就成为了求最长递增系序列的问题了,现在的关键是如何实现升序加降序的操作
class Solution {
public:
int maxEnvelopes(vector<vector<int>>& envelopes) {
int len = envelopes.size();
if(len==0)return 0;
sort(envelopes.begin(), envelopes.end());
vector<int> dp(len,0);
dp[0] = 1;
int j=0;
for(int i = 1 ; i< len ;i++)
{
if(envelopes[i][0]>envelopes[j][0] && envelopes[i][1]>envelopes[j][1])
{dp[i] = dp[j]+1;j=i;}
else{dp[i]=dp[j];}
}
return dp[len-1];
}
};
void sort (RandomAccessIterator first, RandomAccessIterator last, Compare comp);
(1)第一个参数first:是要排序的数组的起始地址。
(2)第二个参数last:是结束的地址(最后一个数据的后一个数据的地址)
(3)第三个参数comp是排序的方法:可以是从升序也可是降序。如果第三个参数不写,则默认的排序方法是从小到大排序。
比较时sort函数根据comp函数进行判断输的大小,系统默认ab时返回为真,那么最终得到的排序结果也相应的从小到大变成从大到小
sort(envelopes.begin(),envelopes.end(),[](const vector<int>& a,const vector<int>& b){
return a[0]<b[0]||(a[0]==b[0]&&a[1]>b[1]);
});
或者单独写出来
static bool myfunc(vector<int> a, vector<int> b)
{
if(a[0] < b[0] && a[1] && b[1])
return true;
else
return a[0] < b[0];
}
作者:EL1S
链接:https://leetcode-cn.com/problems/russian-doll-envelopes/solution/354-e-luo-si-tao-wa-xin-feng-wen-ti-dp-zui-chang-s/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
class Solution {
public:
//题解1:动态规划,时间复杂度O(n^2),空间复杂度O(n)
int maxEnvelopes_1(vector<vector<int>>& envelopes) {
if(envelopes.empty())return 0;
//先按w排序,若w相同,则按h由高到低排序;若w不同,则按w由小到大排序
sort(envelopes.begin(),envelopes.end(),[](const vector<int>& a,const vector<int>& b){
return a[0]<b[0]||(a[0]==b[0]&&a[1]>b[1]);
});
int n=envelopes.size(),res=0;
vector<int> dp(n,1);
for(int i=0;i<n;++i){
for(int j=0;j<i;++j){
if(envelopes[j][1]<envelopes[i][1]){
dp[i]=max(dp[i],dp[j]+1);
}
}
res=max(res,dp[i]);
}
return res;
}
//优化:动态规划+二分法,时间复杂度O(nlogn),空间复杂度O(n)
int maxEnvelopes(vector<vector<int>>& envelopes){
if(envelopes.empty())return 0;
//先按w排序,若w相同,则按h由高到低排序;若w不同,则按w由小到大排序
sort(envelopes.begin(),envelopes.end(),[](const auto& a,const auto& b){
return a[0]<b[0]||(a[0]==b[0]&&a[1]>b[1]);
});
vector<int> dp;
for(auto& en:envelopes){
int idx=lower_bound(dp.begin(),dp.end(),en[1])-dp.begin();
if(idx>=dp.size()){
dp.emplace_back(en[1]);
}
else{
dp[idx]=en[1];
}
}
return dp.size();
}
};
作者:xiaoneng
链接:https://leetcode-cn.com/problems/russian-doll-envelopes/solution/cdong-tai-gui-hua-jiang-er-wei-shu-zu-jiang-wei-ch/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
class Twitter {
public:
deque<pair<int,int>> cache;
unordered_map<int,vector<int>> mp;
/** Initialize your data structure here. */
Twitter() {
}
/** Compose a new tweet. */
void postTweet(int userId, int tweetId) {
cache.push_front(make_pair(userId,tweetId));
return;
}
/** Retrieve the 10 most recent tweet ids in the user's news feed. Each item in the news feed must be posted by users who the user followed or by the user herself. Tweets must be ordered from most recent to least recent. */
vector<int> getNewsFeed(int userId) {
vector<int> res;
vector<int> ID;
ID.push_back(userId);
if(mp.find(userId)!=mp.end())
{
for(auto i:mp[userId])ID.push_back(i);
}
for(int i =0;i<cache.size();i++)
{
if(find(ID.begin(),ID.end(),cache[i].first)!=ID.end()){res.push_back(cache[i].second);}
if(res.size()==10)break;
}
return res;
}
/** Follower follows a followee. If the operation is invalid, it should be a no-op. */
void follow(int followerId, int followeeId) {
mp[followerId].push_back(followeeId);
return;
}
/** Follower unfollows a followee. If the operation is invalid, it should be a no-op. */
void unfollow(int followerId, int followeeId) {
for(auto iter=mp[followerId].begin();iter!=mp[followerId].end();iter++)
{
if(*iter==followeeId){mp[followerId].erase(iter);break;}
}
return;
}
};
/**
* Your Twitter object will be instantiated and called as such:
* Twitter* obj = new Twitter();
* obj->postTweet(userId,tweetId);
* vector param_2 = obj->getNewsFeed(userId);
* obj->follow(followerId,followeeId);
* obj->unfollow(followerId,followeeId);
*/
/*
一位数时 10
二位数时 9*9(首位可选1~9 = 9种可能 ;第二位0~10 - 首位的值 = 9种可能)
三位数时 9*9*8
对于n 把以上加起来就是答案了
*/
int countNumbersWithUniqueDigits(int n) {
if(n==0) return 1;
int res = 10,num = 9*9;
for(int i = 2; i <= min(n,10); i++) res += num, num = num*(10-i);
return res;
}
作者:zeroac
链接:https://leetcode-cn.com/problems/count-numbers-with-unique-digits/solution/c-gui-lu-by-zeroac/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
注意溢出的处理,乘变除还要转换类型
class Solution {
public:
bool isPerfectSquare(int num) {
if(num==1)return true;
int left = 1,right = num/2+1;
while(left<right)
{
int mid = left+(right-left)/2;
if((double)num/mid==mid)return true;
if((double)num/mid>mid)
{
left = mid+1;
}
else
{
right = mid;
}
}
return false;
}
};
while (b)
{
auto carry = ((unsigned int ) (a & b))<<1 ; // 记录a+b的进位,直到进位为0是退出
a = a^b; //结果相加
b = carry; //循环
}
return a;
作者:zi-lun
链接:https://leetcode-cn.com/problems/sum-of-two-integers/solution/cshi-xian-xiang-jie-by-zi-lun/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
一开始考虑的是建立一个哈希表,但是发现key不能是pair,所以这里不能使用哈希,但是优先队列里面是可以放pair结构的,先将前k个放入,之后如果小于栈顶,则将其放入,维护一个自定义的大顶堆
class Solution {
public:
struct cmp{
bool operator ()(pair<int, int> &a, pair<int, int> &b) {
return a.first+a.second<b.first+b.second;
}
};
vector<vector<int>> kSmallestPairs(vector<int>& nums1, vector<int>& nums2, int k) {
priority_queue<pair<int,int>,vector<pair<int,int>>,cmp>q;
vector<vector<int>>res;
for(int i=0;i<nums1.size();i++){
for(int j=0;j<nums2.size();j++){
if(q.size()<k)
q.push({nums1[i],nums2[j]});
else if(nums1[i]+nums2[j]<q.top().first+q.top().second){
q.pop();
q.push({nums1[i],nums2[j]});
}
}
}
while(!q.empty()){
pair<int,int> top=q.top();
res.push_back({top.first,top.second});
q.pop();
}
return res;
}
};
作者:user3350r
链接:https://leetcode-cn.com/problems/find-k-pairs-with-smallest-sums/solution/c-you-xian-dui-lie-da-ding-dui-by-user3350r/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
上面这个不转向量的优先队列有几点要注意的地方
1.不写成向量直接写cmp函数要先写一个结果体,里面套一个bool的operator函数
2.这道题是要建一个大顶堆,把最大的放在堆顶,要注意写cmp的时候要写成小于好,因为是求前k个最小,要按更大的一个逻辑来
这道题统计频率意义不大,所以不用哈希,如果用堆排序的话用的也是自动排序的功能,如果在写堆排序的时候像哈希那样转成向量再实现的话既无法实现也没意义,不如直接就放到vector里并重写sort函数,所以这道题要么直接使用vector要么就使用堆,然后注意不转向量的堆排序需要把cmp函数写成一个结果体的形式
下面是直接使用vector的做法,可能这才是最简单的方式
class Solution {
public:
vector<vector<int>> kSmallestPairs(vector<int>& nums1, vector<int>& nums2, int k) {
vector<vector<int>> sums;
for(size_t i=0;i<nums1.size();++i){
for(size_t j=0;j<nums2.size();++j){
sums.push_back(vector<int>{nums1[i],nums2[j]});
}
}
std::sort(sums.begin(), sums.end(), [](vector<int>& l, vector<int>& r){
return ((l[0]+l[1]) < (r[0]+r[1]));
});
if(static_cast<size_t>(k) > sums.size()) return sums;
vector<vector<int>> sums_truc(sums.begin(), sums.begin()+k);
return sums_truc;
}
};
作者:user2473E
链接:https://leetcode-cn.com/problems/find-k-pairs-with-smallest-sums/solution/cun-chu-pai-xu-jie-qu-by-user2473e/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
这是对需要对复杂结构进行排序的用法总结
1.需要统计次数只能用哈希的就先用哈希,排序时可以直接用结构体cmp排序也可以转成向量再用函数cmp排序
2.如果不是一定要使用哈希功能的,能使用vector排序的都建议使用vector因为这是能容纳类型较多的容器,而且可能其他类型的参数比较难写
/**
* Forward declaration of guess API.
* @param num your guess
* @return -1 if num is lower than the guess number
* 1 if num is higher than the guess number
* otherwise return 0
* int guess(int num);
*/
class Solution {
public:
int guessNumber(int n) {
int left =1,right = n;
while(left<right)
{
long mid = left+(right-left)/2;
if(guess(mid)==0)return mid;
else if(guess(mid)==1)
{left=mid+1;}
else
{right=mid;}
}
return left;
}
};
class Solution {
public:
int wiggleMaxLength(vector<int>& nums) {
if(nums.size() == 0){
return 0;
}
vector<int> up(nums.size(), 1); // 所有元素, 单独也构成一个摆动序列, 并且长度为 1
vector<int> down(nums.size(), 1);
for(int i = 1; i < nums.size(); i++)
for(int j = 0; j < i; j++)
if(nums[j] > nums[i]) // 说明 nums[j] -> nums[i] 是一个下降的过程, 那么只有在最长摆动序列中 nums[i] 位置的元素属于上升元素时, 此处的 nums[i] 才可以把它给延长, 并且延长后 nums[i] 位置本身是属于下降的元素
down[i] = max(down[i], up[j] + 1); //
else if(nums[j] < nums[i])
up[i] = max(up[i], down[j] + 1);
// 相同的元素直接跳过
int ret = 1;
for(int i = 0; i < nums.size(); i++){ // 从记录子找到最长的, 这部分代码也可以融入前面的动态规划中, 动态及更新全局最大值
ret = max(ret, down[i]);
ret = max(ret, up[i]);
}
return ret;
}
};
作者:mrsate
链接:https://leetcode-cn.com/problems/wiggle-subsequence/solution/dong-tai-gui-hua-de-guo-cheng-by-mrsate/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
使用dfs会超时,但是属于典型的dfs思路
class Solution {
private:
int res=0;
int sum = 0;
public:
void dfs(vector<int>& nums, int target, int& sum,int& res)
{
if (sum == target) { res++; return; }
if (sum > target)return;
for (int i = 0; i < nums.size(); i++)
{
sum += nums[i];
dfs(nums, target, sum,res);
sum -= nums[i];
}
}
int combinationSum4(vector<int>& nums, int target) {
dfs(nums, target, sum, res);
return res;
}
};
dp
class Solution {
public int combinationSum4(int[] nums, int target) {
//dfs会超时
//使用dp数组,dp[i]代表组合数为i时使用nums中的数能组成的组合数的个数
//别怪我写的这么完整
//dp[i]=dp[i-nums[0]]+dp[i-nums[1]]+dp[i=nums[2]]+...
//举个例子比如nums=[1,3,4],target=7;
//dp[7]=dp[6]+dp[4]+dp[3]
//其实就是说7的组合数可以由三部分组成,1和dp[6],3和dp[4],4和dp[3];
int[]dp=new int[target+1];
//是为了算上自己的情况,比如dp[1]可以由dp【0】和1这个数的这种情况组成。
dp[0]=1;
for(int i=1;i<=target;i++)
{
for(int num:nums)
{
if(i>=num)
{
dp[i]+=dp[i-num];
}
}
}
return dp[target];
}
}
注意的问题是背包比当前的大才可以,小的话不行,然后要注意初值,
class Solution {
public:
int combinationSum4(vector<int>& nums, int target) {
//完全背包,而且计算顺序,则物品在里面
vector<long long> dp(target+1,0);
dp[0]=1;
for(int i = 1; i<= target ;i++)
{
for(auto num:nums)
{
if(i>=num)
{dp[i] = dp[i] + dp[i-num];}
}
}
return dp[target];
}
};
class Solution {
public:
bool canConstruct(string ransomNote, string magazine) {
unordered_map<char,int> mp;
for(auto m:magazine)
{
if(mp.find(m)==mp.end())
{mp[m]=1;}
else
{mp[m]++;}
}
for(auto r:ransomNote)
{
if(mp.find(r)==mp.end())
{return false;}
else
{
if(mp[r]==0){return false;}
else{mp[r]--;}
}
}
return true;
}
};
class Solution {
public:
bool isSubsequence(string s, string t) {
//转变为求公共子序列问题
string r = s;
s = t;
t = r;
int lent = t.size();
int lens = s.size();
vector<vector<int>> vt(lent+1, vector<int>(lens+1,0));
for(int i = 1 ;i<=lent ;i++)
{
for( int j = 1 ; j<=lens ;j++)
{
if(t[i-1]==s[j-1])vt[i][j] = vt[i-1][j-1]+1;
else vt[i][j]=max(vt[i-1][j],vt[i][j-1]);
}
}
return lent==vt[lent][lens];
}
};
双指针确实更好
代码块class Solution
{
public:
bool isSubsequence(string s, string t)
{
int tag = 0;
//如果s为空,也是对的
if(s.empty())
return true;
//一个个扫描
for(int i = 0; i < t.size(); i++)
{
if(t[i] == s[tag])
{
tag++;
if(tag >= s.size())
return true;
}
}
return false;
}
};
作者:lu-guo-de-feng-2
链接:https://leetcode-cn.com/problems/is-subsequence/solution/zui-jian-ji-de-c-by-lu-guo-de-feng-2/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
写的有问题,在dfs部分如何遍历所有的结果成为问题
bool dfs(vector<int>& time, int n)
{
if ((8 * time[0] + 4 * time[1] + 2 * time[2] + time[3]) > 11 || 32 * time[4] + 16 * time[5] + 8 * time[6] + 4 * time[7] + 2 * time[8] + 1 * time[9] > 59)
{
return false;
}
if (accumulate(time.begin(), time.end(), 0) == n)
{
return true;
}
bool flag;
while (i < n)
{
for (int j = 0 ; j<10 ; j++)
{
time[j] = 1;
bool k = dfs(time, n);
if (k)
{
string s;
s = to_string(8 * time[0] + 4 * time[1] + 2 * time[2] + time[3]) + ":";
if ((32 * time[4] + 16 * time[5] + 8 * time[6] + 4 * time[7] + 2 * time[8] + 1 * time[9]) < 10)
{
s = s + "0" + to_string(32 * time[4] + 16 * time[5] + 8 * time[6] + 4 * time[7] + 2 * time[8] + 1 * time[9]);
}
else
{
s = s + to_string(32 * time[4] + 16 * time[5] + 8 * time[6] + 4 * time[7] + 2 * time[8] + 1 * time[9]);
}
res.push_back(s);
}
else
{
time[j]=0;
}
}
}
}
vector<string> readBinaryWatch(int num) {
vector<string> v;
if (num == 0) { return v; }
n = num;
i = 0;
vector<int>time(10, 0);
dfs(time, n);
return res;
}
vector<string> ans;
vector<string> readBinaryWatch(int num) {
DFS(num, 0, vector<int>(10));
return ans;
}
void DFS(int num, int pos, vector<int>time) {
if (num == 0) {
int hour = time[0] + 2 * time[1] + 4 * time[2] + 8 * time[3];
int minute = time[4] + 2 * time[5] + 4 * time[6] + 8 * time[7] + 16 * time[8] + 32 * time[9];
if (hour < 12 && minute < 60) {
char buffer[6];
sprintf_s(buffer, "%d:%.2d", hour, minute);
ans.push_back(buffer);
}
return;
}
for (int i = pos; i <= 10 - num; i++) {
time[i]++;
DFS(num-1, i + 1, time);
time[i]--;
}
}
作者:pris_bupt
链接:https://leetcode-cn.com/problems/binary-watch/solution/c-dfsfa-yu-tui-jian-yi-ge-bie-ren-de-da-an-by-pris/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
之前判断字母的题最终目的是判断是否存在,所以dfs设置成了bool型,但是这题最终让输出一个变量,这种的设置一个全局变量就可以,下面是伪代码:
主函数(num)
{
执行dfs;
返回结果
}
dfs(num,pos,)
{
如果尝试到底了:成功则输出,然后和不成功一样返回
遍历所有的情况:(因为不能重复,所以这里要有一个pos专门记录位置,不是从0开始的,这与可重复时不同,并将此pos作为参数)
递归调用(这里由于有次数,次数作为一个参数,当作为参数时,无形中递归减一,不用再设置成全局变量了)
}
子数组是连续的,是属于求最大相同子串问题中的最大回文子串中的求数组中回文子串个数同级的问题,试着用同样的方法做;
这里的dp,其实实质就是双指针,遍历半个二维数组,在遍历的过程中新写一个函数对这个函数进行判断,虽然可能超时但是使记忆太多的dp规律容易出错
class Solution {
public:
bool is(vector<int> nums)
{
int len = nums.size();
int a = nums[1]-nums[0];
for(int i = 2; i<len ;i++ )
{
if(nums[i]-nums[i-1]!=a)return false;
}
return true;
}
int numberOfArithmeticSlices(vector<int>& A) {
//子数组是连续的,是属于求最大相同子串问题中的最大回文子串中的求数组中回文子串个数同级的问题,试着用同样的方法做
vector<vector<bool>> v;
int len = A.size();
int res = 0;
for(int i = len-1 ; i>=0 ;i--)
{
for(int j = i ; j< len ; j++)
{
vector<int> temp(A.begin()+i, A.begin()+j+1);
if( j-i>=2 && is(temp)) res++;
}
}
return res;
}
};
如果前面三个是等差的,那么新加入的这个会增加前面加1个,最后将所有数组相加,直接硬写出总和的dp是有难度的
class Solution {
public:
int numberOfArithmeticSlices(vector<int>& A) {
// 求的是子区间而不是子序列构成的区间,这样只需要计算每次新加入的对之前的影响就行
int len = A.size();
vector<int> dp(len,0);
for(int i = 2; i<len ;i++)
{
if(A[i]-A[i-1]==A[i-1]-A[i-2])
{dp[i] = dp[i-1] +1;}
}
int sum = 0;
for(auto i:dp){sum +=i;}
return sum;
}
};
class Solution {
public:
bool canPartition(vector<int>& nums) {
int sum = 0;
for(auto n:nums)sum+=n;
if(sum%2==1)return false;
//容量为sum/2,物品容量和价值都为nums
int N=nums.size();
vector<vector<int>> dp(N+1,vector<int>(sum/2+1,0));
for(int i = 1;i<=N;i++)
{
for(int j =1;j<=sum/2;j++)
{
if(j<nums[i-1]) {dp[i][j]=dp[i-1][j];}
else
{
dp[i][j]=max( dp[i-1][j], dp[i-1][j-nums[i-1]] + nums[i-1] );
}
}
}
return dp[N][sum/2]==sum/2;
}
};
dfs超时
class Solution {
public:
bool flag = false;
void dfs(vector<int> nums, int sum,int target,int p)
{
if(flag)return;
if(sum==target/2){flag=true;return;}
if(sum>target/2)
{
return;
}
for(int i = p;i<nums.size();i++)
{
sum += nums[i];
dfs(nums,sum,target,i+1);
sum -= nums[i];
}
}
bool canPartition(vector<int>& nums) {
int sum = 0;
for(auto n:nums)sum+=n;
if(sum%2==1)return false;;
dfs(nums,0,sum,0);
return flag;
}
};
dfs优化
优化一;降序排列2.判断是否有大于一半的元素,有的话直接false
class Solution {
public:
bool flag = false;
void dfs(vector<int> nums, int sum,int target,int p)
{
if(flag)return;
if(sum==target/2){flag=true;return;}
if(sum>target/2)
{
return;
}
for(int i = p;i<nums.size();i++)
{
sum += nums[i];
dfs(nums,sum,target,i+1);
sum -= nums[i];
}
}
inline static bool cmp(int a,int b){return a>b;}
bool canPartition(vector<int>& nums) {
int sum = 0;
for(auto n:nums)sum+=n;
if(sum%2==1)return false;;
sort(nums.begin(),nums.end(),cmp);
for(auto n:nums){if(n>sum/2)return false;}
dfs(nums,0,sum,0);
return flag;
}
};
没想出来应该怎么做
解答看不太懂,但是知道了原来可以直接在容器中定义键值对pair
构建一个状态矩阵:
用第一个bit存储太平洋是否能达到此点
用第二个bit存储大西洋是否能达到此点
最终查询点状态为3(二进制为11)的点即可。
class Solution {
public:
int dirs[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
bool valid(int r, int c, int R, int C) {
return r >= 0 && r < R && c >= 0 && c < C;
}
vector<vector<int>> pacificAtlantic(vector<vector<int>>& matrix) {
vector<vector<int> > res;
if (matrix.empty()) return res;//以后用这个判断了
int R = matrix.size();
int C = matrix[0].size();
vector<vector<int> > status(R, vector<int>(C, 0));
queue<pair<int, int> > q; //存放键值对的队列
for (int i = 0; i < R; ++i) { //最左边和最右边
q.push({i, 0});
status[i][0] |= 1;
q.push({i, C - 1});
status[i][C - 1] |= 2;
}
for (int i = 0; i < C; ++i) {
q.push({0, i});
status[0][i] |= 1;
q.push({R - 1, i});
status[R - 1][i] |= 2;
}
while (!q.empty()) {
auto p = q.front();
q.pop();
for (int i = 0; i < 4; ++i) {
int r = p.first + dirs[i][0];
int c = p.second + dirs[i][1];
if (valid(r, c, R, C) && matrix[r][c] >= matrix[p.first][p.second]) {
if (status[r][c] != status[p.first][p.second]) {
status[r][c] |= status[p.first][p.second];
q.push({r, c});
}
}
}
}
for (int i = 0; i < R; ++i) {
for (int j = 0; j < C; ++j) {
if (status[i][j] == 3) {
res.push_back({i, j});
}
}
}
return res;
}
};
作者:da-li-wang
链接:https://leetcode-cn.com/problems/pacific-atlantic-water-flow/solution/c-yan-du-you-xian-bian-li-by-da-li-wang/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
class Solution {
public:
vector<int> findDuplicates(vector<int>& nums) {
sort(nums.begin(),nums.end());
int len =nums.size();
vector<int> res;
for(int i =1 ;i<len ;i++)
{
if(nums[i]==nums[i-1])res.push_back(nums[i]);
}
return res;
}
};
更简洁的做法
class Solution {
public:
vector<int> findDuplicates(vector<int>& nums) {
vector<int> res;
for(int i = 0; i < nums.size(); i++){
if(nums[i] != nums[nums[i] - 1]){
swap(nums[i], nums[nums[i] - 1]);
--i;
}
}
for(int i = 0; i < nums.size(); i++){
if(nums[i] != i + 1){
res.push_back(nums[i]);
}
}
return res;
}
};
class Solution {
public:
int eraseOverlapIntervals(vector<vector<int>>& intervals) {
if (intervals.empty()) return 0;
sort(intervals.begin(), intervals.end());
int left = intervals[0][1];
int res = 0;
for (int i = 1; i < intervals.size(); ++i) {
if (intervals[i][0] < left) {
++res;
left = min(left, intervals[i][1]);
} else {
left = intervals[i][1];
}
}
return res;
}
};
作者:da-li-wang
链接:https://leetcode-cn.com/problems/non-overlapping-intervals/solution/c-pai-xu-hou-tan-xin-fa-ti-jie-by-da-li-wang/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
class Solution {
public:
//sort()必须时静态成员函数
static bool cmp(vector<int>a,vector<int>b){
return a[1]<b[1];
}
int eraseOverlapIntervals(vector<vector<int>>& intervals) {
if (intervals.empty()) return 0;
//按照区间终结点,从小到大排序
sort(intervals.begin(), intervals.end(),cmp);
//获取最小的,区间终结点
int end = intervals[0][1];
int res = 0;
for (int i = 1; i < intervals.size(); ++i) {
//如果区间的起点,小于上一个区间的终点,说明有交集,要删除
if (intervals[i][0] < end) {
++res;
} else {
//没有交集,更新end
end = intervals[i][1];
}
}
return res;
}
};
作者:liu-wen-tao-2
链接:https://leetcode-cn.com/problems/non-overlapping-intervals/solution/ctan-xin-suan-fa-by-liu-wen-tao-2/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
stack<ListNode*> s1;
stack<ListNode*> s2;
while(l1){s1.push(l1);l1 = l1->next;}
while(l2){s2.push(l2);l2 = l2->next;}
int b = 0;
auto head= new ListNode(0);
while(!s1.empty() && !s2.empty())
{
int x = s1.top()->val+s2.top()->val; s1.pop(); s2.pop();
auto temp = new ListNode((x+b)%10);
temp->next = head->next;
head->next = temp;
b = ((x+b)>=10)?1:0;
}
while(!s1.empty())
{
int x = s1.top()->val; s1.pop();
auto temp = new ListNode((x+b)%10);
temp->next = head->next;
head->next = temp;
b = ((x+b)>=10)?1:0;
}
while(!s2.empty())
{
int x = s2.top()->val; s2.pop();
auto temp = new ListNode((x+b)%10);
temp->next = head->next;
head->next = temp;
b = ((x+b)>=10)?1:0;
}
if(b)
{
head->val=1;return head;
}
else
{
auto head1 = head->next;
delete head;
return head1;
}
}
};
class Solution {
public:
vector<int> findDisappearedNumbers(vector<int>& nums) {
vector<int> res;
unordered_map<int,int> mp;
int len = nums.size();
for(int i = 1 ;i<=len;i++)mp[i]=0;
for(auto num:nums)mp[num]++;
for(auto iter=mp.begin();iter!=mp.end();iter++)
{
if(iter->second==0)res.push_back(iter->first);
}
return res;
}
};
更简单的做法
class Solution {
public:
vector<int> findDisappearedNumbers(vector<int>& nums) {
vector<int> res;
for(int i = 0; i < nums.size(); i++){
if(nums[i] != nums[nums[i] - 1]){
swap(nums[i], nums[nums[i] - 1]);
--i;
}
}
for(int i = 0; i < nums.size(); i++){
if(nums[i] != i + 1){
res.push_back(i + 1);
}
}
return res;
}
};
这道题是一道典型的sort重写题:
1.如果要对哈希表写排序,还是最好先将整个pair放到向量中进行排序,对于pai取值要使用。来取值,什么时候用-》需要再留意
2.重写func函数时记住函数的参数是要比较的元素的引用,而且整个函数要设置为一个静态函数类型
static bool value_compare(const pair<char, int>& p1, const pair<char, int>& p2)
{
return p1.second > p2.second;
}
string frequencySort(string s) {
map<char, int> m;
for(int i = 0;i < s.size(); ++i)
{
++m[s.at(i)];
}
vector<pair<char, int>> v(m.begin(), m.end());
sort(v.begin(), v.end(), value_compare);
string s1;
s1.reserve(s.capacity());
for(int i = 0; i < v.size(); ++i)
{
for(int j = 0; j < v.at(i).second; ++j)
s1.push_back(v.at(i).first);
}
return s1;
}
template<typename T, typename U>
struct value_less
{
bool operator()(const pair<T, U>& left, const pair<T, U>& right) const
{
return left.second < right.second;
}
};
//2.1、map + 最大堆
string frequencySort(string s) {
map<char, int> m;
for (int i = 0; i < s.size(); ++i)
{
++m[s.at(i)];
}
priority_queue<pair<int, char>> queue; //使用默认的pair operator<() 比较 也满足题意
for (auto iter = m.begin(); iter != m.end(); ++iter)
{
queue.push(pair<int, char>(iter->second, iter->first));
}
string s1;
s1.reserve(s.capacity());
while (!queue.empty())
{
for (int i = 0; i < queue.top().first; ++i)
{
s1.push_back(queue.top().second);
}
queue.pop();
}
return s1;
}
作者:eric-345
链接:https://leetcode-cn.com/problems/sort-characters-by-frequency/solution/c-san-chong-fang-fa-by-eric-345-2/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
还可以直接对字符串进行排序,然后排序的时候利用哈希表
class Solution {
public:
string frequencySort(string s) {
unordered_map<char, int> hash;
for(auto ch : s) hash[ch]++;
sort(s.begin(), s.end(), [&](char& a, char& b){
return hash[a] > hash[b] || (hash[a] == hash[b] && a < b);
});
return s;
}
};
好像最大最小没有区别,值得注意的仅仅是边界重合问题
class Solution {
public:
int findMinArrowShots(vector<vector<int>>& points) {
if(points.empty())return 0;
sort(points.begin(),points.end());
int dp = points[0][1], res = 0;
for(int i =1 ;i<(int)points.size() ;i++)
{
if(points[i][0]<=dp)
{res++;dp=min(dp,points[i][1]);}
else {dp=points[i][1];}
}
return (int)points.size()-res;
}
};
用了两个哈希表分别记录AB和CD的两两之和出现次数,然后遍历其中一个哈希表,并在另一个哈希表中找和的相反数出现的次数。
class Solution {
public:
int fourSumCount(vector<int>& A, vector<int>& B, vector<int>& C, vector<int>& D) {
int n = A.size(), res = 0;
unordered_map<int, int>hash1, hash2;
for(int i = 0; i < n; i++){
for(int j = 0; j < n; j++){
hash1[A[i] + B[j]]++;
hash2[C[i] + D[j]]++;
}
}
for(auto m : hash1) res += m.second * (hash2[-m.first]);
return res;
}
};
之前一直不懂。和-》取数的区别,下面是几点说明1.对哈希遍历可以不适用迭代器,而直接使用auto这样出来的其实是一个pair类型,对于这种类型采用点取值2,如果采用迭代器迭代的方式,得到的是迭代器,迭代器在这时取值采用的是-》符号,如果是向量中的迭代器取值采用的是&
/*
for(auto iter = mp1.begin();iter!=mp1.end();iter++)
{
res += mp2[-iter->first]*iter->second;
}
*/
int findMaxForm(vector<string>& strs, int m, int n ) {
vector<vector<int>> nums (strs.size() , vector<int>(2 , 0));
for(int i = 0 ; i < strs.size() ; i++)
{
for(auto ch : strs[i])
{
if(ch == '0') (nums[i][0])++;
else (nums[i][1])++;
}
}
vector<vector<vector<int>>> dp(strs.size() + 1, vector<vector<int>>
(m + 1 , vector<int>(n + 1 , 0)));
for(int i = 1 ; i < strs.size() + 1; i ++ )
for(int cap_0 = 0 ; cap_0 < m + 1 ; cap_0++ )
for(int cap_1 = 0 ; cap_1 < n + 1 ; cap_1++)
{
if(cap_0 - nums[i - 1][0] >= 0 && cap_1 - nums[i - 1][1] >= 0)
dp[i][cap_0][cap_1] =
max(dp[i - 1][cap_0][cap_1] , dp[i - 1][cap_0 - nums[i -1][0]][cap_1 - nums[i - 1][1]] + 1 );
else dp[i][cap_0][cap_1] = dp[i - 1][cap_0][cap_1];
}
return dp[strs.size()][m][n];
}
作者:rocky-12
链接:https://leetcode-cn.com/problems/ones-and-zeroes/solution/duo-wei-bei-bao-wen-ti-wei-jian-hua-ban-ben-by-roc/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
01背包问题,但是是二维背包,但是思路是一样的
class Solution {
public:
int findMaxForm(vector<string>& strs, int m, int n) {
//01背包,两个背包,需要用二维的情况
vector<vector<int>> dp(m+1,vector<int>(n+1,0));
for(auto str:strs)
{
int zeros = 0 , ones = 0;
for(auto c:str)
{
if(c=='0')zeros++;
else ones++;
}
for(int i = m; i>= zeros ;i--)
{
for(int j = n ; j>= ones ;j--)
{
dp[i][j] = max (dp[i][j], dp[i-zeros][j-ones]+1);
}
}
}
return dp[m][n];
}
};
还是dfs主体没搞清楚,
class Solution {
private:
int num;
int len;
public:
void dfs(int pos, int sum, vector<int>& nums, int S)
{
if(pos == len)
{
if(sum==S){num++;}
return;
}
for(int i = pos ; i< len ;i++)
{
sum = sum+nums[i];
dfs(pos+1,sum,nums,S);
sum=sum-nums[i]*2;
dfs(pos+1,sum,nums,S);
}
}
int findTargetSumWays(vector<int>& nums, int S) {
len = nums.size();
num = 0;
dfs(0,0,nums,S);
return num;
}
};
在dfs的地方不用遍历,直接传递那个,那个值每次加1就可以起到遍历的作用了,但是上一道题又需要进行遍历,现在什么时候需要遍历什么时候不需要还没有弄得很清楚
class Solution {
public:
int findTargetSumWays(vector<int>& nums, int S) {
int res = 0, sum = 0;
dfs(nums, S, 0, sum, res);
return res;
}
void dfs(vector<int>& nums, int S, int i, int sum, int& res) {
if (i == nums.size()) {
if (sum == S) {
++res;
}
return;
}
dfs(nums, S, i + 1, sum + nums[i], res);//这里i传递位置,不进行遍历
dfs(nums, S, i + 1, sum - nums[i], res);
}
};
作者:guohaoding
链接:https://leetcode-cn.com/problems/target-sum/solution/494-mu-biao-he-liang-chong-fang-fa-dfsji-yi-hua-so/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
动态规划
背包问题01背包不可重复,背包在外,进行逆序
class Solution {
public:
int findTargetSumWays(vector<int>& nums, int S) {
int sum = 0;
for(auto num:nums){sum +=num;}
if(sum<S || (sum+S)%2==1)return 0;
int w = (S+sum)/2;
vector<int> dp(w+1,0);
dp[0]=1;
for(auto num:nums)
{
for(int i = w ; i>=num ;i--)
{
dp[i] = dp[i] + dp[i-num];
}
}
return dp[w];
}
};
class Solution {
public:
vector<int> nextGreaterElement(vector<int>& nums1, vector<int>& nums2) {
vector<int> vt;
vector<int> res(nums1.size(),-1);
unordered_map<int,int> mp;
for(int i = 0; i<nums2.size() ;i++)
{
while(!vt.empty() && nums2[i]>vt.back())
{
mp[vt.back()]=nums2[i];
vt.pop_back();
}
vt.push_back(nums2[i]);
}
for(int i = 0;i<nums1.size();i++)
{
if(mp.find(nums1[i])!=mp.end())res[i]=mp[nums1[i]];
}
return res;
}
};