一. 字符串和哈希函数章节
1.力扣
思路:
//eat tea ate用sort排序后都是ate,用ate作key,其他[eat tea ate]做value。 //[eat tea ate]用一个vector装
看下auto的用法,map怎么添加值
class Solution {
public:
vector<vector<string>> groupAnagrams(vector<string>& strs) {
//eat tea ate用sort排序后都是ate,用ate作key,其他[eat tea ate]做value。
//[eat tea ate]用一个vector装
map<string, vector<int>> mymap;
int len = strs.size();
for (int i = 0; i < len; ++i) {
string tmpstr = strs[i];
sort(tmpstr.begin(),tmpstr.end());
mymap[tmpstr].push_back(i);
//mymap.insert(map<string, vector<int>>::value_type(tmpstr, i));
}
vector<vector<string>> res;
for (auto i : mymap) {
vector<string> thisTime;
auto index = i.second;
for (auto i : index) {
thisTime.push_back(strs[i]);
}
res.push_back(thisTime);
}
return res;
}
};
class Solution {
public:
bool isIsomorphic(string s, string t) {
//若两个字符串长度不同,返回false
//建立两个Map,s一个map,t一个map,map里key是s和t的字符,value是对方s的相同位置字符,或者对方t的相同位置字符。题意要求是二者一一对应
//同时遍历两个字符串,如果两个字符串的字符都没出现过,则同时记录到map里;若一个出现过另一个没出现过则返回false,若两个都出现过,则看他们对应的value是否是对方,不相等则返回false.
int lens = s.size();
int lent = t.size();
if (lens != lent) {
return false;
}
map<char, char> maps;
map<char, char> mapt;
for(int i = 0; i < lens; ++i) {
if (maps.find(s[i]) == maps.end() && mapt.find(t[i]) == mapt.end()) {
maps[s[i]] = t[i];
mapt[t[i]] = s[i];
}
if(maps.find(s[i]) == maps.end() || mapt.find(t[i]) == mapt.end()) {
return false;
}
if (maps[s[i]] != t[i] || mapt[t[i]] != s[i]) {
return false;
}
}
return true;
}
};
3. 1816. 截断句子 力扣
class Solution {
public:
void splitStr(string s, vector<string>& all, char ch = ' ') {
int l = 0, r = 0, len = s.length();
while (r < len) {
while (r < len && s[r] != ch) {
r++;
}
all.push_back(s.substr(l, r-l));
l = ++r;
}
} //C++里的spilt
vector<string> res;
string truncateSentence(string s, int k) {
char tmp = ' ';
splitStr(s, res, tmp);
string ret;
for(int i = 0; i < k; ++i) {
ret += res[i];
if (i == k - 1) {
return ret;
}
ret += " ";
}
return ret;
}
};
class Solution {
public:
bool isSubsequence(string s, string t) {
int cur_s = 0;
for (int i = 0; i < t.size(); ++i) {
if (s[cur_s] == t[i]) {
cur_s++;
}
}
if (cur_s == s.size()) {
return true;
}
return false;
}
};
class Solution {
public:
char findTheDifference(string s, string t) {
/* 建立一个26个字母的哈希表,遍历s,每个字符的value减1,遍历t,每个字符的value加1,找出t中value是1 的字符。*/
int len_s = s.size();
vector<int> vec(26, 0);
for (int i = 0; i < len_s; ++i) {
vec[s[i] - 'a']--;
}
for(int i = 0; i < t.size(); ++i) {
vec[t[i] - 'a']++;
if (vec[t[i] - 'a'] == 1) {
return t[i];
}
}
return 'a';
}
};
暴力法+中心扩展法+动态规划
1. 暴力法
class Solution {
public:
int countSubstrings(string s) {
int count = 0;
int len = s.size();
if (len == 0) {
return 0;
}
for (int i = 0; i < len; ++i) {
for(int j = i; j < len; ++j) {
bool flag = true;
int start = i, end = j;
while(start <= end) {
if (s[start++] != s[end--]) {
flag = false;
}
}
if (flag) {
count++;
}
}
}
return count;
}
};
2. 中心扩展法
这是一个比较巧妙的方法,实质的思路和动态规划的思路类似。
比如对一个字符串 ababa,选择最中间的 a 作为中心点,往两边扩散,第一次扩散发现 left 指向的是 b,right 指向的也是 b,所以是回文串,继续扩散,同理 ababa 也是回文串。
这个是确定了一个中心点后的寻找的路径,然后我们只要寻找到所有的中心点,问题就解决了。
中心点一共有多少个呢?看起来像是和字符串长度相等,但你会发现,如果是这样,上面的例子永远也搜不到 abab,想象一下单个字符的哪个中心点扩展可以得到这个子串?似乎不可能。所以中心点不能只有单个字符构成,还要包括两个字符,比如上面这个子串 abab,就可以有中心点 ba 扩展一次得到,所以最终的中心点由 2 * len - 1 个,分别是 len 个单字符和 len - 1 个双字符。
如果上面看不太懂的话,还可以看看下面几个问题:
为什么有 2 * len - 1 个中心点?
aba 有5个中心点,分别是 a、b、c、ab、ba
abba 有7个中心点,分别是 a、b、b、a、ab、bb、ba
什么是中心点?
中心点即 left 指针和 right 指针初始化指向的地方,可能是一个也可能是两个
为什么不可能是三个或者更多?
因为 3 个可以由 1 个扩展一次得到,4 个可以由两个扩展一次得到
class Solution {
public:
int countSubstrings(string s) {
/* 中心扩散法 */
int len = s.size();
int count = 0;
for(int i = 0; i < len; ++i) {
int start = i;
int end = i;
while(start >=0 && end < len && s[start] == s[end]) {
count++;
--start;
++end;
}
start = i;
end = i + 1;
while(start >=0 && end < len && s[start] == s[end]) {
count++;
--start;
++end;
}
}
return count;
}
};
(2) 最长回文子串力扣
中心扩展法
class Solution {
public:
string longestPalindrome(string s) {
int size = s.size();
int res = 1;
if (size == 1 || size== 0) {
return s;
}
int begin = 0;
int tail = 0;
for (int i = 0; i < size; ++i) {
int start = i;
int end = i;
while(start >= 0 && end <= size - 1 && s[start] == s[end]) {
if (end - start + 1 > res) {
res = end - start + 1;
begin = start;
tail = end;
}
start--;
end++;
}
start = i;
end = i + 1;
while(start >= 0 && end <= size - 1 && s[start] == s[end]) {
if (end - start + 1 > res) {
res = end - start + 1;
begin = start;
tail = end;
}
start--;
end++;
}
}
return s.substr(begin, res);
}
};
注意对字符型char a = 'a'; 可以string str = ""; str+='a';
看下题解里有人讲的这种题的模板 力扣
class Solution {
public:
string reorderSpaces(string text) {
vector<string> vecStr;
int spaceNum = 0;
string tmp;
int len = text.size();
for(int i = 0; i < text.size(); ++i) {
if (text[i] == ' ') {
spaceNum++;
}
if (text[i] != ' ') {
tmp += text[i];
}
if ((text[i] != ' ' && (i + 1) < text.size() && text[i + 1] == ' ') || (i == len - 1) && text[i] != ' ' ) {
vecStr.push_back(tmp);
tmp = "";
}
}
int numStr = vecStr.size();
int aver = 0;
string res;
string space = " ";
int tailNum = 0;
if (numStr != 1) {
aver = spaceNum / (numStr - 1);
tailNum = spaceNum - (numStr - 1) * aver;
for (int i = 0; i < numStr - 1; ++i) {
res += vecStr[i];
for(int j = 1; j <= aver; ++j) {
res += space;
}
}
res += vecStr[numStr - 1];
for (int i = 1; i <= tailNum; ++i) {
res += space;
}
} else {
res += vecStr[0];
for (int i = 1; i <= spaceNum; ++i) {
res += space;
}
}
return res;
}
};
class Solution {
public:
string reverseWords(string s) {
string res;
int len = s.size();
string tmpStr;
vector<string> vec;
for(int i = 0; i < len; ++i) {
if (s[i] != ' ') {
tmpStr += s[i];
}
if (s[i] == ' ') {
vec.push_back(tmpStr);
tmpStr = "";
}
if (i == len - 1) {
vec.push_back(tmpStr);
tmpStr = "";
}
}
for(int i = 0; i < vec.size(); ++i) {
reverse(vec[i].begin(), vec[i].end());
res += vec[i];
if (i != vec.size() - 1) {
res += " ";
}
}
return res;
}
};
9. 554 砌砖 力扣
class Solution {
public:
int leastBricks(vector<vector<int>>& wall) {
int rows = wall.size();
int size = 0;
/* for(int i = 0; i < wall[0].size(); ++i) {
size += wall[0][i];
}
vector<int> myVec(size, 0);
[[100000000,100000000],[100000000,100000000]]
如果用vector,这个用例会超时,因为会遍历0~200000000*/
map<int, int> myMap;
for (int m = 0; m < rows; ++m) {
int sum = 0;
for (int n = 0; n < wall[m].size()-1; n++) {
sum += wall[m][n];
myMap[sum]++;
}
}
int max = 0;
map<int,int>::iterator iter = myMap.begin();
for(; iter != myMap.end(); ++iter) {
if (iter -> second > max) {
max = iter -> second;
}
}
return rows - max;
}
};
class Solution {
public:
vector<string> findWords(vector<string>& words) {
map<char, int> myMap;
string str = "qwertyuiop";
vector<string> res;
for (int i = 0; i < str.size(); ++i) {
myMap[str[i]] = 1;
}
str = "asdfghjkl";
for (int i = 0; i < str.size(); ++i) {
myMap[str[i]] = 2;
}
str = "zxcvbnm";
for (int i = 0; i < str.size(); ++i) {
myMap[str[i]] = 3;
}
for(int i = 0; i < words.size(); ++i) {
int tmpRow = myMap[tolower(words[i][0])];
bool flag = true;
for(int j = 1; j < words[i].size(); ++j) {
if (myMap[tolower(words[i][j])] != tmpRow) {
flag = false;
break;
}
}
if (flag) {
res.push_back(words[i]);
}
}
return res;
}
};
class Solution {
public:
/* vector<string> res;
遇到不是"/"的单词把他放用string tmp存放,如果tmp是..则res弹出最顶上的元素,
如果是. 则什么也不做
*/
string simplifyPath(string path) {
int len = path.size();
vector<string> strVec;
string tmpStr;
string res = "/";
int i = 0;
while (i < len) {
while(path[i] == '/' && i < len) {
i++;
}
while (path[i] != '/' && i < len) {
tmpStr += path[i];
i++;
}
if (tmpStr.size() > 0 && tmpStr != "." && tmpStr != "..") {
strVec.push_back(tmpStr);
}
if (tmpStr == ".." && strVec.size() > 0) {
strVec.pop_back();
}
tmpStr = "";
}
for(int i = 0; i < strVec.size(); ++i) {
res += strVec[i];
if (i < strVec.size() - 1) {
res += "/";
}
}
return res;
}
};
二 链表篇
1 . 链表倒置 力扣
/**
* 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* reverseList(ListNode* head) {
/*
if (head == nullptr|| head -> next == nullptr) {
return head;
}
stack<ListNode*> st;
ListNode* cur = head;
while(cur) {
st.push(cur);
cur = cur -> next;
}
ListNode* ret = st.top();
ListNode* res = st.top();
st.pop();
while (!st.empty()) {
ret -> next = st.top();
ret = ret -> next;
st.pop();
}
ret -> next = nullptr;
return res; */
// 调用递推公式反转当前结点之后的所有节点
// 返回的结果是反转后的链表的头结点
/*
if (head == nullptr || head -> next == nullptr) {
return head;
}
ListNode* newHead = reverseList(head->next);
head->next->next = head;
head->next = nullptr;
return newHead;
*/
if (head == nullptr || head -> next == nullptr) {
return head;
}
ListNode* pre = nullptr;
ListNode* now = head;
ListNode* after;
while (now) {
after = now -> next;
now -> next = pre;
pre = now;
now = after;
}
return pre;
}
};
2. 链表的m到n节点这段转置 力扣
/**
* 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* reverseBetween(ListNode* head, int left, int right) {
/*
定位到要反转部分的头节点 2,head = 2;前驱结点 1,pre = 1;
当前节点的下一个节点3调整为前驱节点的下一个节点 1->3->2->4->5,
当前结点仍为2, 前驱结点依然是1,重复上一步操作。。。
1->4->3->2->5.
*/ //通过dummy->next来获得新链表的头结点
ListNode* dummy=new ListNode(-1);
ListNode* pre=dummy;
dummy->next=head;
//找到要翻转的起始节点
for(int i=0;i<left-1;i++)
pre=pre->next;
//cur为当前节点
ListNode* cur=pre->next;
for(int i=left;i<right;i++){
//t为临时节点
ListNode* t=cur->next;
cur->next=t->next;
t->next=pre->next;
pre->next=t;
}
return dummy->next;
}
};
3. 找两个链表相交的节点 力扣
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
/* //把headA的节点依次加入set,再遍历B的所有节点,若B的节点的指针能在set里找到,就是这个节点
set<ListNode*> setA;
if(headA == nullptr || headB == nullptr) {
return nullptr;
}
ListNode* curA = headA;
while(curA != nullptr) {
setA.insert(curA);
curA = curA -> next;
}
ListNode* curB = headB;
while(curB != nullptr) {
if (setA.find(curB) != setA.end()) {
return curB;
}
curB = curB -> next;
}
return nullptr;
*/
//思路二,先计算两个链表长度,若长链表比短链表长x个节点。然后让长链表的指头节点的指针先走x长度,之后二者同时开始走,二者相遇的节点就是要找的
if(headA == nullptr || headB == nullptr) {
return nullptr;
}
int lenA = 0;
int lenB = 0;
ListNode* a = headA;
ListNode* b = headB;
ListNode* x = headA;
ListNode* y = headB;
while(x != nullptr) {
x = x -> next;
++lenA;
}
while(y != nullptr) {
y = y -> next;
++lenB;
}
if (lenA > lenB) {
int x = lenA - lenB;
while (a != nullptr && x > 0) {
a = a -> next;
x --;
}
}
else if (lenA < lenB) {
int x = lenB - lenA;
while (b != nullptr && x > 0) {
b = b -> next;
x--;
}
}
while (a && b) {
if (a == b) {
return a;
}
a = a -> next;
b = b -> next;
}
return nullptr;
}
};
(4)203. 移除链表元素 力扣
/**
* 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* removeElements(ListNode* head, int val) {
/* if (!head) {
return head;
}
ListNode* res = head;
while(res != nullptr && res -> val == val) {
res = res -> next;
}
if (res == nullptr) {
return nullptr;
}
ListNode* cur = res;
while(cur -> next) {
if (cur ->next -> val == val) {
cur -> next = cur -> next -> next;
} else {
cur = cur -> next;
}
}
return res; */
/* 递归 */
if (head == nullptr) {
return nullptr;
}
/* if (head -> val == val) { //如果写再这里,对于7777 会直接返回结果777
return head -> next;
} */
head -> next = removeElements(head -> next, val);
if (head -> val == val) {
return head -> next;
}
return head;
}
};
4. 环形链表找环的入口 力扣
法一:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
//遍历链表,将节点依次放入set容器,边放边查找是否有相同节点,要是找到相同的,这个节点就是结果
set<ListNode*> setA;
if (head == nullptr) {
return nullptr;
}
ListNode* cur = head;
while (cur) {
if (setA.find(cur) == setA.end()) {
setA.insert(cur);
cur = cur ->next;
}
else {
return cur;
}
}
return nullptr;
}
};
法二
//思路二,可以证明,若有环,则快慢指针(快的每次走两步,慢的每次走一步)必在环内某节点相遇,然后再找两个每次走一步的指针,分别从相///遇点和起点一步步的走,则二者相遇点就是环的起点
if (head == nullptr) {
return nullptr;
}
ListNode* slow = head;
ListNode* fast = head;
ListNode* meet = head;
while(fast) { //找相遇i点
slow = slow -> next;
fast = fast -> next;
if (fast == nullptr) {
return nullptr;
}
fast = fast -> next;
if (fast == slow) {
meet = fast;
break;
}
}
if (fast == nullptr) {
return nullptr;
}
fast = meet;
slow = head;
while (slow != fast) {
slow = slow -> next;
fast = fast -> next;
}
return slow;
}
};
5. 分割链表 力扣
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* partition(ListNode* head, int x) {
//建立两个临时节点。遍历head,一个节点的右边放所有小于x的节点,另一个节点右边放所有大于等于x的节点
ListNode lessNode(0);
ListNode moreNode(0);
ListNode* lessPtr = &lessNode;
ListNode* res = lessPtr;
ListNode* morePtr = &moreNode;
if (head == nullptr) {
return nullptr;
}
ListNode* cur = head;
while (cur != nullptr) {
if (cur -> val < x) {
lessPtr -> next = cur;
lessPtr = cur;
}
else {
morePtr -> next = cur;
morePtr = cur;
}
cur = cur -> next;
}
lessPtr -> next = moreNode.next;
morePtr -> next = nullptr;
return res -> next;
}
};
class Solution {
public:
void splitStr(string s, vector<string>& all, char ch = ' ') {
int l = 0, r = 0, len = s.length();
while (r < len) {
while (r < len && s[r] != ch) {
r++;
}
all.push_back(s.substr(l, r-l));
l = ++r;
}
} //C++里的spilt
bool wordPattern(string pattern, string s) {
vector<string> vec;
char space = ' ';
splitStr(s, vec, space);
if (pattern.size() != vec.size()) {
return false;
}
map<string, char> myMap1;
map<char, string> myMap2;
int j = 0;
for (int i = 0; i < pattern.size(); ++i) {
if (myMap2.find(pattern[i]) == myMap2.end() && myMap1.find(vec[j]) == myMap1.end()) {
myMap2[pattern[i]] = vec[j];
myMap1[vec[j]] = pattern[i];
j++;
} else {
if (myMap2[pattern[i]] == vec[j] && myMap1[vec[j]] == pattern[i]) {
j++;
continue;
} else {
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* mergeTwoLists(ListNode* l1, ListNode* l2) {
ListNode* cur1 = l1;
ListNode* cur2 = l2;
ListNode* head = new ListNode(0);
ListNode* res = head;
while(cur1 && cur2) {
if (cur1 -> val <= cur2 -> val) {
head -> next = cur1;
cur1 = cur1 -> next;
head = head -> next;
} else {
head -> next = cur2;
cur2 = cur2 -> next;
head = head -> next;
}
}
while(cur1) {
head -> next = cur1;
head = head -> next;
cur1 = cur1 -> next;
}
while(cur2) {
head -> next = cur2;
head = head -> next;
cur2 = cur2 -> next;
}
return res -> next;
}
};
三 堆,栈。队列
(1)用队列实现栈 https://leetcode-cn.com/problems/implement-stack-using-queues/
class MyStack {
public:
queue<int> store;
queue<int> sta;
/** Initialize your data structure here. */
MyStack() {
}
/** Push element x onto stack. */
void push(int x) {
// 两个队列,A和B,来新元素时候,先放入A,再把B中元素依次出队放入A,A和B再互换内容,再B出队第一个元素就是pop()
store.push(x);
while(!sta.empty()) {
int x = sta.front();
sta.pop();
store.push(x);
}
swap(store, sta);
}
/** Removes the element on top of the stack and returns that element. */
int pop() {
int top;
if (!sta.empty()) {
top = sta.front();
sta.pop();
}
return top;
}
/** Get the top element. */
int top() {
return sta.front();
}
/** Returns whether the stack is empty. */
bool empty() {
return sta.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();
*/
用两个栈实现队列
class MyQueue {
public:
/** Initialize your data structure here. */
//两个栈A和B 来新元素,都放进B 这是push
//pop 如果B不空,则B.pop;若B空,则把A 所以元素放进B,B再pop
stack<int> A;
stack<int> B;
MyQueue() {
}
/** Push element x to the back of queue. */
void push(int x) {
A.push(x);
}
/** Removes the element from in front of queue and returns that element. */
int pop() {
if (B.empty()) {
while(!A.empty()) {
int top = A.top();
A.pop();
B.push(top);
}
}
int ret = B.top();
B.pop();
return ret;
}
/** Get the front element. */
int peek() {
if (B.empty()) {
while(!A.empty()) {
int top = A.top();
A.pop();
B.push(top);
}
}
int ret = B.top();
return ret;
}
/** Returns whether the queue is empty. */
bool empty() {
return A.empty() && B.empty();
}
};
/**
* Your MyQueue object will be instantiated and called as such:
* MyQueue* obj = new MyQueue();
* obj->push(x);
* int param_2 = obj->pop();
* int param_3 = obj->peek();
* bool param_4 = obj->empty();
*/
用两个栈是实现 找最小元素是O(1)时间复杂度
class MinStack {
public:
/** initialize your data structure here. */
MinStack() {
}
void push(int val) {
data.push(val);
if (less.size() == 0) {
less.push(val);
} else {
if (val < less.top()) {
less.push(val);
}
else {
less.push(less.top());
}
}
}
void pop() {
data.pop();
less.pop();
}
int top() {
return data.top();
}
int getMin() {
return less.top();
}
private:
stack<int> data;
stack<int> less;
};
/**
* Your MinStack object will be instantiated and called as such:
* MinStack* obj = new MinStack();
* obj->push(val);
* obj->pop();
* int param_3 = obj->top();
* int param_4 = obj->getMin();
*/
(3) 946. 验证栈序列 力扣
class Solution {
public:
bool validateStackSequences(vector<int>& pushed, vector<int>& popped) {
//先入栈,设临时堆积元素的栈是tmp, popped队头元素和tmp的栈顶元素相同时,把二者同时拿掉,pushed的下一个元素与再入栈,若和popped栈顶元素仍相同,则继续拿掉二者,若push完后 tmp空 则true,
stack<int> tmp;
int size1 = pushed.size();
int size2 = popped.size();
if (size1 == 0 && size2 == 0) {
return true;
}
if (size1 ==0 || size2 == 0) {
return false;
}
int j = 0;
for (int i = 0; i < size1; ++i) {
tmp.push(pushed[i]);
while (tmp.size() != 0 && tmp.top() == popped[j]) {
j++;
tmp.pop();
}
}
return tmp.empty();
}
};
(4)数据流中第k大元素 力扣
思路:用最小堆。top()元素永远是堆中最小的。比如把数组中前5个元素压入堆后,堆顶的元素就是前五个元素的最小值,设做x。后面元素,比x大则再压入堆,比x小则抛弃。最后top()就是第K大的元素
class KthLargest {
public:
priority_queue<int, vector<int>, greater<int>> pbuffer;
int n;
KthLargest(int k, vector<int>& nums) {
n = k;
int size = nums.size();
for (int i = 0; i < size; ++i) {
if (i < k) {
pbuffer.push(nums[i]);
} else {
if (pbuffer.top() < nums[i]) {
pbuffer.pop();
pbuffer.push(nums[i]);
}
}
}
}
int add(int val) {
pbuffer.push(val);
if (pbuffer.size() > n) {
pbuffer.pop();
}
return pbuffer.top();
}
};
/**
* Your KthLargest object will be instantiated and called as such:
* KthLargest* obj = new KthLargest(k, nums);
* int param_1 = obj->add(val);
*/
class Solution {
public:
bool isValid(string s) {
int len = s.size();
if (len % 2 == 1) {
return false;
}
stack<char> sta;
for(int i = 0; i < len; ++i) {
if (s[i] == '(' || s[i] == '{' || s[i] == '[') {
sta.push(s[i]);
}
else {
if (s[i] == ')' && sta.size() != 0 && sta.top() != '(') {
return false;
}
if (s[i] == ']' && sta.size() != 0 && sta.top() != '[') {
return false;
}
if (s[i] == '}' && sta.size() != 0 && sta.top() != '{') {
return false;
}
if (sta.size() == 0) {
return false;
}
else {
sta.pop();
}
}
}
if (sta.size() != 0) {
return false;
}
return true;
}
};
class Solution {
public:
int evalRPN(vector<string>& tokens) {
stack<int> sta;
int size = tokens.size();
int res = 0;
for(int i = 0; i < size; ++i) {
if (tokens[i] == "+" ||tokens[i] == "-" || tokens[i] == "*" || tokens[i] == "/" ) {
int numRight = sta.top();
sta.pop();
int numLeft = sta.top();
sta.pop();
int res;
if (tokens[i] == "+") {
res = numLeft + numRight;
sta.push(res);
}
if (tokens[i] == "-") {
res = numLeft - numRight;
sta.push(res);
}
if (tokens[i] == "*") {
res = numLeft * numRight;
sta.push(res);
}
if (tokens[i] == "/") {
res = numLeft / numRight;
sta.push(res);
}
} else {
sta.push(atoi(tokens[i].c_str()));
}
}
return sta.top();
}
};
(7)优先队列力扣
class Solution {
public:
//求前 k 大,用小根堆(top最小《geater<int>),求前 k 小,用大根堆(top最大,less<int>。
/* struct cmp{
bool operator()(const pair<int, int>& lhs, const pair<int, int>& rhs) {
return lhs.second > rhs.second;
}
}; */
vector<int> topKFrequent(vector<int>& nums, int k) {
unordered_map<int, int> mymap;
using pii = std::pair<int, int>;
int len = nums.size();
for (int i = 0; i < len; ++i) {
mymap[nums[i]]++;
}
/*pair<int, int>放入优先队列,以first去排序
要访问pair里的两个int,用qu.top().first */
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int,int>>> qu;
unordered_map<int, int>::iterator iter = mymap.begin();
for(;iter != mymap.end(); ++iter) {
qu.push(pair<int, int>(iter -> second, iter -> first));
if (qu.size() > k) {
qu.pop();
}
}
vector<int> res;
for(int i = k - 1; i >= 0; --i) {
res.push_back(qu.top().second);
qu.pop();
}
return res;
}
};
class Solution {
public:
int lastStoneWeight(vector<int>& stones) {
priority_queue <int,vector<int>,less<int> > q;
int size = stones.size();
for (int i = 0; i < size; ++i) {
q.push(stones[i]);
}
if (size == 1) {
return stones[0];
}
while(q.size() > 1) {
int top1 = q.top();
q.pop();
int top2 = q.top();
q.pop();
if (top1 > top2) {
q.push(top1 - top2);
}
}
if (q.size() == 1) {
return q.top();
} else {
return 0;
}
}
};
(8)227. 基本计算器 II 力扣
class Solution {
public:
int calculate(string s) {
int len = s.size();
stack<int> st;
int num = 0;
char preTac = '+';
for(int i = 0; i < len; ++i) {
if (s[i] == ' ') {
continue;
}
if (s[i] == '+' || s[i] == '-' || s[i] == '*' || s[i] == '/') {
num = 0;
preTac = s[i];
} else {
while(s[i] >= '0' && s[i] <='9' && i < len) {
num = num * 10 + (s[i] - '0');
i++;
}
i--;
if (preTac == '+') {
st.push(num);
}
if (preTac == '-') {
st.push(num * (-1));
}
if (preTac == '*') {
int top = st.top();
st.pop();
st.push(num * top);
}
if (preTac == '/') {
int top = st.top();
st.pop();
st.push(top / num);
}
}
}
int res = 0;
while(!st.empty()) {
res += st.top();
st.pop();
}
return res;
}
};
(9) 946. 验证栈序列 力扣
class Solution {
public:
bool validateStackSequences(vector<int>& pushed, vector<int>& popped) {
//先入栈,设临时堆积元素的栈是tmp, popped队头元素和tmp的栈顶元素相同时,把二者同时拿掉,pushed的下一个元素与再入栈,若和popped栈顶元素仍相同,则继续拿掉二者,若push完后 tmp空 则true,
stack<int> tmp;
int size1 = pushed.size();
int size2 = popped.size();
if (size1 == 0 && size2 == 0) {
return true;
}
if (size1 ==0 || size2 == 0) {
return false;
}
int j = 0;
for (int i = 0; i < size1; ++i) {
tmp.push(pushed[i]);
while (tmp.size() != 0 && tmp.top() == popped[j]) {
j++;
tmp.pop();
}
}
return tmp.empty();
}
};
(10)496. 下一个更大元素 I 力扣
class Solution {
public:
vector<int> nextGreaterElement(vector<int>& nums1, vector<int>& nums2) {
/* 创建一个临时栈,一个哈希表,然后遍历 nums2nums2。
若当前栈无数据,则当前数字入栈备用。
若当前栈有数据,则用当前数字与栈顶比较:
3.1 当前数字 > 栈顶,代表栈顶对应下一个更大的数字就是当前数字,则将该组数字对应关系,记录到哈希表。
3.2 当前数字 < 栈顶,当前数字压入栈,供后续数字判断使用。
这样,我们就可以看到哈希表中存在部分 nums2nums2 数字的对应关系了,而栈中留下的数字,代表无下一个更大的数字,我们 全部赋值为 -1 ,然后存入哈希表即可。
遍历 nums1,直接询问哈希表拿对应关系即可。
作者:demigodliu
链接:https://leetcode-cn.com/problems/next-greater-element-i/solution/zhan-xia-yi-ge-geng-da-yuan-su-i-by-demi-cumj/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
*/
int len1 = nums1.size();
int len2 = nums2.size();
unordered_map<int, int> tab;
stack<int> st;
for(int i = 0; i < len2; ++i) {
while(!st.empty() && st.top() < nums2[i]) {
tab[st.top()] = nums2[i];
st.pop();
}
if (st.empty() || nums2[i] < st.top()) {
st.push(nums2[i]);
}
}
while(!st.empty()) {
tab[st.top()] = -1;
st.pop();
}
vector<int> res;
for(int i = 0; i < len1; ++i) {
res.push_back(tab[nums1[i]]);
}
return res;
}
};
(1)暴力法
class Solution {
public:
vector<int> nextGreaterElement(vector<int>& nums1, vector<int>& nums2) {
int len1 = nums1.size();
int len2 = nums2.size();
vector<int> res;
int i = 0;
int j = 0;
for(; i < len1; ++i) {
while(j < len2) {
if (nums2[j] != nums1[i]) {
j++;
} else {
break;
}
}
j++;
while(j < len2 && nums2[j] <= nums1[i]) {
j++;
}
if (j == len2) {
res.push_back(-1);
} else {
res.push_back(nums2[j]);
}
j = 0;
}
return res;
}
};
法二 单调栈
class Solution {
public:
vector<int> nextGreaterElement(vector<int>& nums1, vector<int>& nums2) {
/* 创建一个临时栈,一个哈希表,然后遍历 nums2nums2。
若当前栈无数据,则当前数字入栈备用。
若当前栈有数据,则用当前数字与栈顶比较:
3.1 当前数字 > 栈顶,代表栈顶对应下一个更大的数字就是当前数字,则将该组数字对应关系,记录到哈希表。
3.2 当前数字 < 栈顶,当前数字压入栈,供后续数字判断使用。
这样,我们就可以看到哈希表中存在部分 nums2nums2 数字的对应关系了,而栈中留下的数字,代表无下一个更大的数字,我们 全部赋值为 -1 ,然后存入哈希表即可。
遍历 nums1,直接询问哈希表拿对应关系即可。
作者:demigodliu
链接:https://leetcode-cn.com/problems/next-greater-element-i/solution/zhan-xia-yi-ge-geng-da-yuan-su-i-by-demi-cumj/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
*/
int len1 = nums1.size();
int len2 = nums2.size();
unordered_map<int, int> tab;
stack<int> st;
for(int i = 0; i < len2; ++i) {
while(!st.empty() && st.top() < nums2[i]) {
tab[st.top()] = nums2[i];
st.pop();
}
if (st.empty() || nums2[i] < st.top()) {
st.push(nums2[i]);
}
}
while(!st.empty()) {
tab[st.top()] = -1;
st.pop();
}
vector<int> res;
for(int i = 0; i < len1; ++i) {
res.push_back(tab[nums1[i]]);
}
return res;
}
};
(11)503. 下一个更大元素 II 力扣
class Solution {
public:
vector<int> nextGreaterElements(vector<int>& nums) {
int len = nums.size();
vector<int> res(len, -1);
stack<int> sta;
for(int i = 0; i < 2 * len; ++i) {
while(!sta.empty() && nums[sta.top()] < nums[i % len]) {
res[sta.top()] = nums[i % len];
sta.pop();
}
sta.push(i % len);
}
return res;
/* int n = nums.size();
stack<int> st;
vector<int> res(n, -1); // 用数组实现哈希表可以s设置默认value
for (int i = 0; i < 2 * n; i++) { // 下标取模实现循环遍历数组
while (!st.empty() && nums[i % n] > nums[st.top()]) {
res[st.top()] = nums[i % n]; // 循环找到真正的下一个更大元素, 更新结果数组
st.pop();
}
st.push(i % n);
}
return res; */
}
};
(12) 556. 下一个更大元素 III 力扣
class Solution {
public:
int nextGreaterElement(int n) {
/* 如果n是保持递减的,比如321,这种情况是无法找到的,那么就是-1
从右往左去找是否有更小的数字,找到比右边小的数字 x 就是需要和其他数字交换的
和谁交换呢? 依然是从右往左去找一个正好比 x 大的数字 y,那么交换它们
此时数字其实不是最小整数,因为后面是递减的,翻转后改为递增肯定是最小的,所以从x右边到结束来做一次翻转
例子如下: 247531
从右往左找到小的数字,是4
从右往左找到比4的数字5,交换后是 257431 (不是最小整数!)
然后翻转 7431 -> 251347
*/
string str = to_string(n);
int len = str.size();
if (len == 1) {
return -1;
}
int curLeft;
int curright;
int i = len - 2;
for (; i >= 0; --i) {
if (str[i] < str[i + 1]) {
curLeft = i;
break;
}
}
if (i < 0) {
return -1;
}
/* 再从右向左找刚好比curleft大的数位置记做curright */
for(int i = len - 1; i > curLeft; --i) {
if (str[i] > str[curLeft]) {
curright = i;
break;
}
}
swap(str[curLeft], str[curright]);
sort(str.begin() + curLeft + 1, str.end());
long res = stol(str); //看下stol stoi等函数
return res > INT_MAX ? -1 : res; //看下INT_MAX
}
};
四 二叉树
1. 二叉树中和为某一值的路径 力扣
/**
* 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<int> tmp;
vector<vector<int>> res;
void dfs(TreeNode* root, int target) {
if (!root) {
return;
}
target -= root -> val;
tmp.push_back(root -> val);
if (root -> left == nullptr && root -> right == nullptr && target == 0) {
res.push_back(tmp);
}
dfs(root -> left, target);
dfs(root -> right, target);
tmp.pop_back();
target += root -> val; //这句留不留都没影响
}
vector<vector<int>> pathSum(TreeNode* root, int target) {
if(!root) {
return res;
}
dfs(root, target);
return res; //res是全局变量
}
};
2. 求根节点到某节点的路径 ,求两个节点的最近公共祖先节点,和上面的题是一个类型 力扣
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
vector<TreeNode*> path_p;
vector<TreeNode*> path_q;
vector<TreeNode*> path_tmp; //遍历时的临时路径
vector<TreeNode*> path_vec_p;
vector<TreeNode*> path_vec_q;
TreeNode* ret;
int finish = 0;
void orderpre(TreeNode* root, TreeNode* search, vector<TreeNode*> &path_tmp, vector<TreeNode*>& path_vec, int& finish)
{
if (!root || finish) {
return;
}
path_tmp.push_back(root);
if (root == search) {
path_vec = path_tmp;
finish = true;
return;
}
orderpre(root -> left, search, path_tmp, path_vec, finish);
orderpre(root -> right, search, path_tmp, path_vec, finish);
path_tmp.pop_back();
}
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
orderpre(root, p, path_tmp, path_vec_p, finish);
path_tmp.clear();
finish = 0;
orderpre(root, q, path_tmp, path_vec_q, finish);
int len_p = path_vec_p.size();
int len_q = path_vec_q.size();
int min = len_p;
if (len_p > len_q) {
min = len_q;
}
for (int i = 0; i < min; ++i) {
if (path_vec_p[i] == path_vec_q[i]) {
ret = path_vec_p[i];
}
}
return ret;
}
};
五 回溯算法
(1)全排列 力扣
class Solution {
public:
bool visit[10];
void dfs(vector<vector<int>>& result, vector<int> tmp, vector<int> nums) {
if (tmp.size() == nums.size()) {
result.push_back(tmp);
return;
}
for (int i = 0; i < nums.size(); i++) {
if (!visit[i]) {
visit[i] = 1;
tmp.push_back(nums[i]);
dfs(result, tmp, nums);
visit[i] = 0;
tmp.pop_back();
}
}
}
vector<vector<int>> permute(vector<int>& nums) {
vector<int> tmp;
vector<vector<int>> result;
dfs(result, tmp, nums);
return result;
}
};
(2)上体基础上,求没有重复的所有全排列
思路一,用set去重
class Solution {
public:
bool visit[10];
vector<int> tmp;
vector<vector<int>> result;
set<vector<int>> res_set;
void dfs(vector<vector<int>>& result, vector<int> tmp, vector<int> nums) {
if (tmp.size() == nums.size()) {
res_set.insert(tmp);
return;
}
for (int i = 0; i < nums.size(); i++) {
if (!visit[i]) {
visit[i] = 1;
tmp.push_back(nums[i]);
dfs(result, tmp, nums);
visit[i] = 0;
tmp.pop_back();
}
}
}
vector<vector<int>> permuteUnique(vector<int>& nums) {
dfs(result, tmp, nums);
set<vector<int>>::iterator pos;
for(pos = res_set.begin(); pos != res_set.end(); ++pos) {
result.push_back(*pos);
}
return result;
}
};
思路二 剪枝
/* 剪枝,如果nums[i-1] == nums[i] && visit[i - 1] == 0则for循环中continue*/
bool visit[10];
void dfs(vector<vector<int>>& result, vector<int> tmp, vector<int> nums) {
if (tmp.size() == nums.size()) {
result.push_back(tmp);
return;
}
for (int i = 0; i < nums.size(); i++) {
if (i > 0 && nums[i - 1] == nums[i] && visit[i-1] == 0) {
continue;
}
if (!visit[i]) {
visit[i] = 1;
tmp.push_back(nums[i]);
dfs(result, tmp, nums);
visit[i] = 0;
tmp.pop_back();
}
}
}
vector<vector<int>> permuteUnique(vector<int>& nums) {
sort(nums.begin(), nums.end());
vector<int> tmp;
vector<vector<int>> result;
dfs(result, tmp, nums);
return result;
}
(3)没有重复元素序列的所有子集 力扣
class Solution {
public:
vector<vector<int>> result;
void dfs(int t, vector<int> nums, vector<int> tmp) {
result.push_back(tmp);
if (tmp.size() == nums.size()) {
return;
}
for(int i = t; i < nums.size(); ++i) {
tmp.push_back(nums[i]);
dfs(i + 1, nums, tmp);
tmp.pop_back();
}
}
vector<vector<int>> subsets(vector<int>& nums) {
vector<int> tmp;
//result.push_back(tmp);
dfs(0, nums, tmp);
return result;
}
};
(4)集合中有重复元素,返回所有可能的子集,要求去掉重复子集 力扣
这道题可以用set去重,可以用剪枝,剪枝时候注意看下代码里记录的是不是保证i>0&&nums[i-1]!=nums[i]就可以?
class Solution {
public:
/* vector<vector<int>> result;
set<vector<int>> set_res;
void dfs(int t, vector<int> nums, vector<int> tmp) {
if (tmp.size() == nums.size()) {
return;
}
for(int i = t; i < nums.size(); ++i) { //若i从0 开始 后面还会压入重复元素
tmp.push_back(nums[i]);
set_res.insert(tmp);
dfs(i + 1, nums, tmp);
tmp.pop_back();
}
}
vector<vector<int>> subsetsWithDup(vector<int>& nums) {
vector<int> tmp;
sort(nums.begin(), nums.end()); //帮你去掉[2 2 1] [2 1 2]的重复
result.push_back(tmp); //加入空集
dfs(0, nums, tmp);
set<vector<int>>::iterator pos = set_res.begin();
for (;pos != set_res.end(); ++pos) {
result.push_back(*pos);
}
return result;
} */
/*剪枝去重,仅nums[i] != nums[i-1]对{1 2 2}能行吗? 不行,以{1 2 2}为例,continue的条件是i > 0 && nums[i] != nums[i-1] && nums[i-1]不在tmp里*/
vector<vector<int>> res;
int visit[100] = {0};
void helper(vector<int>& nums, vector<int>& temp, int start) {
res.push_back(temp);
for (int i = start; i < nums.size(); i++) {
if (i > 0 && nums[i] == nums[i - 1] && visit[i -1] == 0) {
continue;
}
if (i == start || nums[i] != nums[i - 1]) {
temp.push_back(nums[i]);
visit[i] = 1;
helper(nums, temp, i + 1);
temp.pop_back();
visit[i] = 0;
}
}
}
vector<vector<int>> subsetsWithDup(vector<int>& nums) {
sort(nums.begin(), nums.end());
vector<int> temp = {};
helper(nums, temp, 0);
return res;
}
};
(5)组合总和,找出集合中所有的满足和是target的子集 ,集合中的某个数可以多次用。力扣
class Solution {
public:
vector<vector<int>> res;
vector<int> tmp;
void dfs(int start, vector<vector<int>>& res, vector<int> nums, vector<int> tmp, int& sum, int target) {
if (sum == target) {
res.push_back(tmp);
return;
}
if (sum > target) {
return;
}
for (int i = start; i < nums.size(); ++i) {
tmp.push_back(nums[i]);
sum += nums[i];
dfs(i, res, nums, tmp, sum, target);
tmp.pop_back();
sum -= nums[i];
}
}
vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
sort(candidates.begin(), candidates.end());
int sum = 0;
dfs(0, res, candidates, tmp, sum, target);
return res;
}
};
(6)上面的题改成集中中的每个数在子集只能用一次 力扣
class Solution {
public:
vector<vector<int>> res;
vector<int> tmp;
// int visit[100] = {0};
void dfs(int start, vector<vector<int>>& res, vector<int> nums, vector<int> tmp, int& sum, int target) {
if (sum == target) {
res.push_back(tmp);
return;
}
if (sum > target) {
return;
}
for (int i = start; i < nums.size(); ++i) {
if (i > start && nums[i] == nums[i - 1]) {
continue;
}
tmp.push_back(nums[i]);
sum += nums[i];
dfs(i + 1, res, nums, tmp, sum, target);
tmp.pop_back();
sum -= nums[i];
}
}
vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
sort(candidates.begin(), candidates.end());
int sum = 0;
dfs(0, res, candidates, tmp, sum, target);
/* set<vector<int>> res_set;
vector<vector<int>> res2;
for(int i = 0; i < res.size(); ++i) {
res_set.insert(res[i]);
}
//res.clear();
set<vector<int>>::iterator pos;
for (pos = res_set.begin(); pos != res_set.end(); ++pos) {
res2.push_back(*pos);
}
return res2; */
return res;
}
};
(7) 力扣 给定两个整数 n 和 k,返回 1 ... n 中所有可能的 k 个数的组合。
class Solution {
public:
vector<vector<int>> res;
vector<int> tmp;
void dfs(int start, vector<int> tmp, int k, vector<vector<int>>& res, int n) {
if (tmp.size() >= k) {
res.push_back(tmp);
return;
}
for (int i = start; i <=n; ++i) {
tmp.push_back(i);
dfs(i + 1, tmp, k, res, n);
tmp.pop_back();
}
}
vector<vector<int>> combine(int n, int k) {
dfs(1, tmp, k, res, n);
return res;
}
};
(8) 括号生成 力扣
class Solution {
public:
/* n对括号,则左括号是n个,右括号是n个时候结束递归,且在递归过程中,只有当左括号数比右括号多时候才能继续递归 */
vector<string> res;
string tmp;
int left = 0;
int right = 0;
void dfs(vector<string>& res, string tmp, int left, int right, int n) {
if (left == n && right == n) {
res.push_back(tmp);
return;
}
if (left < n) {
dfs(res, tmp + '(', left + 1, right, n);
}
if (right < left){
dfs(res, tmp + ')', left, right + 1, n);
}
}
vector<string> generateParenthesis(int n) {
dfs(res, tmp, left, right, n);
return res;
}
};
class Solution {
public:
vector<string> res;
string tmp;
void dfs(string s, int t, string tmp, vector<string>& res) {
if (tmp.size() == s.size()) {
res.push_back(tmp);
return;
} else {
if (isalpha(s[t])) {
s[t] = tolower(s[t]);
dfs(s, t+1, tmp + s[t], res);
s[t] = toupper(s[t]);
dfs(s, t+1, tmp + s[t], res);
} else {
dfs(s, t + 1, tmp + s[t], res);
}
}
}
vector<string> letterCasePermutation(string S) {
dfs(S, 0, tmp, res);
return res;
}
};
(10) LCS 01. 下载插件 力扣
class Solution {
public:
int res =INT_MAX;
int leastMinutes(int n) {
dfs(0,n,1,0);
return res;
}
void dfs(int num, int n, int speed, int minute) {
if(num>=n || minute>=res){
res = min(res,minute);
return;
}
if(num + speed >= n) {
res = min(res,minute+1);
return;
}
//将带宽加倍
dfs(num,n,speed<<1,minute+1);
//使用当前带宽下载
dfs(num+speed,n,speed,minute+1);
}
};
/**
* 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:
void dfs(TreeNode* root, vector<int>& res) {
if (!root) {
return;
}
res.push_back(root -> val);
dfs(root -> left, res);
dfs(root -> right, res);
}
vector<int> preorderTraversal(TreeNode* root) {
vector<int> res;
dfs(root, res);
return res;
}
};
(2) 二叉树中序遍历 力扣
void dfs(TreeNode* root, vector<int>& res) {
if (!root) {
return;
}
dfs(root -> left, res);
res.push_back(root -> val);
dfs(root -> right, res);
}
vector<int> inorderTraversal(TreeNode* root) {
vector<int> res;
dfs(root, res);
return res;
}
(3)后续遍历二叉树 力扣
class Solution {
public:
void dfs(TreeNode* root, vector<int>& res) {
if (!root) {
return;
}
dfs(root -> left, res);
dfs(root -> right, res);
res.push_back(root -> val);
}
vector<int> postorderTraversal(TreeNode* root) {
vector<int> res;
dfs(root, res);
return res;
}
};
(4) 两两交换链表中的节点 力扣
思路:终止条件:递归到最后只剩一个节点(链表总节点数是奇数个),或者空节点(链表总节点数是偶数个)
递归完成后,返回头节点给之前去指
/**
* 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* swapPairs(ListNode* head) {
if (!head || head -> next == nullptr) {
return head;
}
ListNode* releax = head -> next -> next;
ListNode* exict = head -> next;
exict -> next = head;
head -> next = swapPairs(releax);
return exict; //返回的还是一开始的head -> next
}
};
(5)用递归方法原地反转字符串 力扣
class Solution {
public:
void dfs(vector<char>& s, int start, int end) {
if (start >= end) {
return;
}
char tmp;
tmp = s[start];
s[start] = s[end];
s[end] = tmp;
dfs(s, start + 1, end - 1);
}
void reverseString(vector<char>& s) {
dfs(s, 0, s.size() - 1);
}
};
(6) 606. 根据二叉树创建字符串 力扣
思路:如果左右子树都存在,则root +(左)+(右); 只有左子树,root + (左) ; 只有右子树,root + ()+(右); 左右都空,root
/**
* 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:
string tree2str(TreeNode* root) {
if (!root) {
return "";
}
if (root -> left == nullptr && root -> right == nullptr) {
return to_string(root -> val);
}
if (root -> right == nullptr) {
return to_string(root -> val) + "(" + tree2str(root -> left) + ")";
}
if (root -> left == nullptr) {
return to_string(root -> val) + "()" + +"(" + tree2str(root -> right) + ")";
}
else {
return to_string(root -> val) + "(" + tree2str(root -> left) + ")" + "(" + tree2str(root -> right) + ")";
}
return "";
}
};
七 深度优先搜索
class Solution {
public:
map<char,string> mymap={{'2',"abc"}, {'3',"def"}, {'4',"ghi"}, {'5',"jkl"}, {'6',"mno"}, {'7',"pqrs"}, {'8',"tuv"}, {'9',"wxyz"}};
/* map<char,string> mymap;
mymap['2'] = "abc";
mymap['3'] = "def";
mymap['4'] = "ghi";
mymap['5'] = "jkl";
mymap['6'] = "mno";
mymap['7'] = "pqrs";
mymap['8'] = "tuv";
mymap['9'] = "wxyz"; */
vector<string> res;
string tmp;
void dfs(string tmp, string digits, vector<string>& res, int len) {
if (tmp.size() == len) {
res.push_back(tmp);
return;
} else {
char x = digits[0];
//string letter = mp[x];
for(int i = 0; i < mymap[x].size(); ++i) {
tmp.push_back(mymap[x][i]);
dfs(tmp, digits.substr(1), res, len);
tmp.pop_back();
}
}
}
vector<string> letterCombinations(string digits) {
if (digits == "") {
return res;
}
int len = digits.size();
dfs(tmp, digits, res, len);
return res;
}
};
(2) 98. 验证二叉搜索树 https://leetcode-cn.com/problems/validate-binary-search-tree/
/**
* 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 LeftIsBST(TreeNode* root, int value) {
if (!root) {
return true;
}
if (root -> val < value && LeftIsBST(root -> left, value) && LeftIsBST(root -> right,value)) {
return true;
}
return false;
}
bool RightIsBST(TreeNode* root, int value) {
if (!root) {
return true;
}
if (root -> val > value && RightIsBST(root -> right, value) && RightIsBST(root -> left, value)) {
return true;
}
return false;
}
bool isValidBST(TreeNode* root) {
if (!root) {
return true;
}
if (LeftIsBST(root -> left, root -> val) && RightIsBST(root -> right, root -> val) && isValidBST(root -> left) && isValidBST(root -> right)) {
return true;
}
return false;
}
};
//学会to_string的用法,把数转成string,比如23转成"23"
/**
* 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<string> res;
string tmp;
void dfs(TreeNode* root, string tmp, vector<string>& res) {
if (!root) {
return;
}
if (root -> left == nullptr && root -> right == nullptr) {
tmp += to_string(root -> val);
res.push_back(tmp);
return;
}
else {
tmp += to_string(root -> val);
tmp += "->";
if (root -> left != nullptr) {
dfs(root -> left, tmp, res);
}
if (root -> right != nullptr) {
dfs(root -> right, tmp, res);
}
}
}
vector<string> binaryTreePaths(TreeNode* root) {
dfs(root, tmp, res);
return res;
}
};
(4)平衡二叉树 力扣、
class Solution {
public:
bool isSameTree(TreeNode* p, TreeNode* q) {
if (!p && !q) {
return true;
}
if (!p || !q ) {
return false;
}
return (p -> val == q -> val) && isSameTree(p -> left, q -> left) && isSameTree(p -> right, q -> right);
}
};
class Solution {
public:
int minDepth(TreeNode* root) {
if (!root) {
return 0;
}
int lchild = minDepth(root -> left);
int rchild = minDepth(root -> right);
if (lchild == 0) {
return rchild + 1;
}
if (rchild == 0) {
return lchild + 1;
}
return lchild >= rchild ? (rchild + 1) : (lchild + 1);
}
};
(6) 单词搜索 力扣
class Solution {
public:
void dfs(vector<vector<char>>& board, int row, int col, int rows, int cols, int pos, string word, vector<vector<bool>>& visit, bool &find) {
if (row < 0 || row >= rows || col <0 || col >= cols || visit[row][col] == 1 || word[pos] != board[row][col] || find) {
return;
}
if (pos == word.size() - 1) {
find = true;
return;
}
visit[row][col] = true;
dfs(board, row + 1, col, rows, cols, pos + 1, word, visit, find);
dfs(board, row, col + 1, rows, cols, pos + 1, word, visit, find);
dfs(board, row - 1, col, rows, cols, pos + 1, word, visit, find);
dfs(board, row, col - 1, rows, cols, pos + 1, word, visit, find);
visit[row][col] = false;
}
bool exist(vector<vector<char>>& board, string word) {
if (board.size() == 0) {
return false;
}
int pos = 0;
bool find = false;
int rows = board.size();
int cols = board[0].size();
vector<vector<bool>> visit(rows, vector<bool>(cols, false));
for (int i = 0; i < rows; i++) {
for(int j = 0; j < cols; j++) {
dfs(board, i, j, rows, cols, pos, word, visit, find);
}
}
return find;
}
};
class Solution {
public:
void dfs(vector<vector<char>>& grid, int row, int col) {
if (grid.size() == 0 || grid[0].size() == 0) {
return;
}
if (row < 0 || col < 0 ||row>=grid.size()||col>=grid[0].size() || grid[row][col] == '0'){
return;
}
grid[row][col] = '0';
dfs(grid, row + 1, col);
dfs(grid, row , col + 1);
dfs(grid, row -1, col);
dfs(grid, row, col - 1);
}
/* void dfs(vector<vector<char>>& grid,int i,int j){
if(i < 0 || j < 0 || i >= grid.size() || j >= grid[0].size())return;
if(grid[i][j] == '0')return;
grid[i][j] = '0';
dfs(grid,i+1,j);
dfs(grid,i,j+1);
dfs(grid,i-1,j);
dfs(grid,i,j-1);
} */
int numIslands(vector<vector<char>>& grid) {
int ans = 0;
for(int i = 0;i < grid.size(); i++){
for(int j = 0;j < grid[0].size();j++){
if(grid[i][j] == '0')continue;
ans ++;
dfs(grid,i,j);
}
}
return ans;
}
};
(8) 面试题 16.19. 水域大小 力扣
class Solution {
public:
int dfs(vector<vector<int>>& land, int row, int col) {
if (row < 0|| col < 0 || row >= land.size() || col >= land[0].size() || land[row][col] != 0) {
return 0;
}
land[row][col] = 1;
return 1 + dfs(land, row+1, col)+ dfs(land, row-1, col) + dfs(land, row, col+1) +dfs(land, row, col-1) + dfs(land, row+1, col+1) + dfs(land, row-1, col+1) + dfs(land, row-1, col-1)+ dfs(land, row+1, col-1);
}
vector<int> pondSizes(vector<vector<int>>& land) {
int rows = land.size();
int cols = land[0].size();
vector<int> res;
//vector<vector<bool>> visit(rows, vector<bool>(cols, false));
for(int i = 0; i < rows; ++i) {
for(int j = 0; j < cols; ++j) {
if (land[i][j] == 0) {
int tmp = dfs(land, i, j);
res.push_back(tmp);
}
}
}
sort(res.begin(), res.end());
return res;
}
};
(9) 130. 被围绕的区域 力扣
class Solution {
public:
//在边界上找到"O",再从边界上的这个"O",往里深度搜索,遇到相邻的"O",就标记为"F",最后再遍历整个矩阵。将所有"O",改为X
void dfs(vector<vector<char>>& board, int row, int col) {
if (row < 0 || col < 0 || row >= board.size() || col >= board[0].size() || board[row][col]!='O') {
return;
}
board[row][col] = 'F';
dfs(board, row, col + 1);
dfs(board, row, col +-1);
dfs(board, row - 1, col);
dfs(board, row + 1, col);
}
void solve(vector<vector<char>>& board) {
if (board.size() == 0 || board[0].size() == 0) {
return;
}
for (int i = 0; i < board[0].size(); ++i) {
dfs(board, 0, i);
dfs(board, board.size() - 1, i);
}
for (int i = 0; i < board.size(); ++i) {
dfs(board, i, 0);
dfs(board, i, board[0].size() - 1);
}
for(int i = 0; i < board.size(); i++) {
for(int j = 0; j < board[0].size(); ++j) {
if(board[i][j] == 'O')
board[i][j] = 'X';
if(board[i][j] == 'F')
board[i][j] = 'O';
}
}
return;
}
};
(10) 二叉树中所有距离为 K 的结点 力扣
八 滑动窗口
(1)无重复字符的最长子串 力扣
思路:如果游标cur也就是滑动窗口的end对应的字符在窗口出现过,就需要更新窗口,start更新到重复字符后一个位置,同时更新窗口大小与tmpMaxlen比较。怎么知道在窗口里有重复字符?必然是end对应字符位置>=start。用哈希表存字符位置。
class Solution {
public:
int lengthOfLongestSubstring(string s) {
if (s.size() == 0) {
return 0;
}
vector<int> mymap(128, -1);
int maxLen = 0, start = 0;
for(int i = 0; i != s.length(); i++) {
if (mymap[s[i]] >= start) {
start = mymap[s[i]] + 1;
}
mymap[s[i]] = i;
maxLen = max(maxLen, i - start + 1);
}
return maxLen;
}
};
(3) 209. 长度最小的子数组 力扣
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int left = 0;
int right = 0;
int len = nums.size();
int sum = 0;
int optim = len;
bool flag = 0;
while(right <= len - 1) {
sum += nums[right];
while (left <= right && sum >= target) {
flag = 1;
if (right - left + 1 < optim) {
optim = right - left + 1;
}
sum -= nums[left];
left++;
}
right++;
}
if (flag == 1) {
return optim;
}
return 0;
}
};
class Solution {
public://用sort排序p和窗口,超时
vector<int> findAnagrams(string s, string p) {
int lenS = s.size();
int lenP = p.size();
vector<int> res;
if (lenP > lenS) {
return res;
}
int left = 0;
int right = left + lenP - 1;
vector<int> mymap1(26, 0);
for(int i = 0; i < lenP; ++i) {
mymap1[p[i] - 'a']++;
}
vector<int> mymap2(26, 0);
vector<int> mymap3(26, 0);
while(right < lenS) {
for(int i = left; i <= right; ++i) {
mymap2[s[i] - 'a']++;
}
if (mymap2 == mymap1) {
res.push_back(left);
}
mymap2 = mymap3;
left++;
right++;
}
return res;
}
};
(5) 子数组最大平均数 I 力扣
class Solution {
public: /* double计算比int要慢,所以中间记录的值要设成int型,最后返回的时候再转换成double */
/* 计算窗口内sum时候,不要每次都遍历,会超时。减去nums[left],加新的nums[right],*/
double findMaxAverage(vector<int>& nums, int k) {
//int MIN = -9999;
double optimum = -999999;
int left = 0;
int right = left + k - 1;
int len = nums.size();
int sum = 0;
for (int i = left; i <= right; ++i) {
sum += nums[i];
}
while(right <= len - 1) {
if (sum > optimum) {
optimum = sum;
}
sum -= nums[left];
if ((left+1 > len - 1) && (right+1 > len - 1)) {
break;
}
left++;
right++;
sum += nums[right];
}
return ((double)optimum)/k;
}
};
九 (1)102. 二叉树的层序遍历 力扣
/**
* 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) {
return res;
}
queue<TreeNode*> qu;
vector<int> tmp;
qu.push(root);
while(!qu.empty()) {
int len = qu.size();
for(int i = 0; i < len; ++i) { //想下这里能否些换成qu.size()
TreeNode* head = qu.front();
tmp.push_back(head -> val);
qu.pop();
if (head -> left) {
qu.push(head -> left);
}
if (head -> right) {
qu.push(head -> right);
}
}
res.push_back(tmp);
tmp.clear();
}
return res;
}
};
十 二分法
(1)剑指 Offer 53 - I. 在排序数组中查找数字 I
class Solution {
public:
int search(vector<int>& nums, int target) {
int len = nums.size();
if (len == 0) {
return 0;
}
int start = 0;
int end = len - 1;
int count = 0;
while (start <= end) {
int mid = (start + end) / 2;
if (nums[mid] == target) {
++count;
int tmpmid = mid;
while(tmpmid > start && nums[--tmpmid] == target) {
count++;
}
while(mid < end && nums[++mid] == target) {
count++;
}
return count;
}
if (nums[mid] < target) {
start = mid + 1;
}
if (nums[mid] > target) {
end = mid - 1;
}
}
return 0;
}
};
class Solution {
public:
//二分查找找每行最后一个1的位置,这个位置就是军人数量,军人数量乘以1000加行号当作能量值,取能量值最//小的k个
int binarySearch(vector<int> vec) {
int len = vec.size();
int start = 0;
int end = vec.size() - 1;
int mid;
while(start <= end) {
mid = (start + end) / 2;
if (vec[mid] == 1) {
if (mid == len -1 || vec[mid + 1] == 0) {
return mid + 1;
}
start = mid + 1;
} else {
if (mid == 0 || vec[mid - 1] == 1) {
return mid;
}
end = mid - 1;
}
}
return -1;
}
vector<int> kWeakestRows(vector<vector<int>>& mat, int k) {
vector<int> res;
vector<int> ret;
map<int, int> mymap;
int size = mat.size();
for (int i = 0; i < size; ++i) {
int tmp = 1000 * binarySearch(mat[i]) + i;
ret.push_back(tmp);
mymap[tmp] = i;
}
//sort(res.begin(), res.end());
//set<int>::iterator pos = res.begin();
sort(ret.begin(), ret.end());
for(int j = 0; j < k; ++j) {
res.push_back(mymap[ret[j]]);
}
return res;
}
};
(3) 剑指 Offer 53 - II. 0~n-1中缺失的数字 力扣
class Solution {
public:
/* 从左到右第一个位置i不等于a[i]的i就是要找的 */
int missingNumber(vector<int>& nums) {
int len = nums.size();
int start = 0;
int end = len - 1;
while(start <= end) {
int mid = (start + end) / 2;
if (nums[mid] != mid) {
end = mid -1;
} else {
start = mid + 1;
}
}
if (start != 0) {
return start;
}
return 0;
}
};
十一 位运算
·1. 四种GCC内置位运算函数
int __builtin_ffs (unsigned int x)
返回x的最后一位1的是从后向前第几位,比如7368(1110011001000)返回4。
·int __builtin_clz (unsigned int x)
返回前导的0的个数。
·int __builtin_ctz (unsigned int x)
返回后面的0个个数,和__builtin_clz相对。比如7368(1110011001000)返回3。
·int __builtin_popcount (unsigned int x)
返回二进制表示中1的个数。
·int __builtin_parity (unsigned int x)
返回x的奇偶校验位,也就是x的1的个数模2的结果。
此外,这些函数都有相应的usigned long和usigned long long版本,只需要在函数名后面加上l或ll就可以了,比如int __builtin_clzll。
2. 位运算理论
CS-Notes/Leetcode 题解 - 位运算.md at master · CyC2018/CS-Notes · GitHub
https://www.cnblogs.com/nobita/p/14320239.html
(1) 461. 汉明距离
class Solution {
public:
int hammingDistance(int x, int y) {
return __builtin_popcount(x^y);
}
};
(2) 剑指 Offer 56 - I. 数组中数字出现的次数 力扣
class Solution {
public:
vector<int> singleNumbers(vector<int>& nums) {
int two = 2;
int size = nums.size();
vector<int> part1;
vector<int> part2;
vector<int> res;
int x = 0;
for (int i = 0; i < size; ++i) {
x = x ^ nums[i];
}
//从右向左找第一个1,记录这个1的位置,说明两个单数该位不同,再依据这位不同将数组分成两组,则两个单数一定分别在两组,两组各自抑或,找到各自的单数
// 获取一个数二进制最低位的1
int y = x & (-x);
for (int i = 0; i < size; ++i) {
int w = nums[i] & y;
if (w == y) {
part1.push_back(nums[i]);
} else {
part2.push_back(nums[i]);
}
}
int z = 0;
for (int i = 0; i < part1.size(); ++i) {
z= z^ part1[i];
}
res.push_back(z);
int m = 0;
for (int i = 0; i < part2.size(); ++i) {
m= m^ part2[i];
}
res.push_back(m);
return res;
}
};
十二 双指针
(1)11. 盛最多水的容器 力扣
class Solution {
public:
int maxArea(vector<int>& height) {
int start = 0;
int end = height.size() - 1;
int max = -1;
while(start < end) {
if (height[start] <= height[end]) {
int sum = height[start] * (end - start);
if (max < sum) {
max = sum;
}
start++;
}
if (height[start] > height[end]) {
int sum = height[end] * (end - start);
if (max < sum) {
max = sum;
}
end--;
}
}
return max;
}
};
#include <unordered_set>
class Solution {
public:
/*
vector<vector<int>> threeSum(vector<int>& nums) {
int size = nums.size();
vector<vector<int>> res;
std::unordered_set<vector<int>> setVec;
vector<int> tmp;
if (size < 3) {
return res;
}
sort(nums.begin(), nums.end());
for (int i = 0; i < size - 2; ++i) {
int left = i + 1;
int right = size - 1;
if (nums[i] >0) {
break;
}
while(left < right) {
if (nums[i] + nums[left] + nums[right] == 0) {
tmp.push_back(nums[i]);
tmp.push_back(nums[left]);
tmp.push_back(nums[right]);
setVec.insert(tmp);
tmp.clear();
} else if (nums[i] + nums[left] + nums[right] > 0) {
right--;
} else if (nums[i] + nums[left] + nums[right] < 0) {
left++;
}
}
}
std::unordered_set<vector<int>>::iterator iter = setVec.begin();
for(; iter != setVec.end(); ++iter) {
res.push_back(*iter);
}
return res;
} */
vector<vector<int>> threeSum(vector<int>& nums) {
int target;
vector<vector<int>> ans;
sort(nums.begin(), nums.end());
for (int i = 0; i < nums.size(); i++) {
if (i > 0 && nums[i] == nums[i - 1]) continue;
if ((target = nums[i]) > 0) break;
int l = i + 1, r = nums.size() - 1;
while (l < r) {
if (nums[l] + nums[r] + target < 0) ++l;
else if (nums[l] + nums[r] + target > 0) --r;
else {
ans.push_back({target, nums[l], nums[r]});
++l, --r;
while (l < r && nums[l] == nums[l - 1]) ++l;
while (l < r && nums[r] == nums[r + 1]) --r;
}
}
}
return ans;
}
};
(3) 16. 最接近的三数之和 力扣
class Solution {
public:
int threeSumClosest(vector<int>& nums, int target) {
/* 找三数之和和target差的绝对值最小
求三个数之和最接近目标,可以简化为在一个数确定之后,两个数的和是否更接近目标。
那么我怎么去确定这两个数,从而花费更小的时间呢? 我们设数组nums=[-4,2,1,-3,-1,4],target=2,
我们可以先将数组排序,此时花费了O(NlogN)的时间复杂度nums=[-4,-3,-1,1,2,4]。
我们先确定第一个数为x=nums[0]=-4,题目就变成了从nums[1:]中求两个数的和最接近target-nums[1]。
我们通过设置两个指针,一头一尾。此时判两个数的和是否更接近于target-nums[1].
如果大于target,我们将尾巴向前移一位,两个数的和会因此变小,也会更接近target-nums[1]。
如果小于target,我们将头部向后移一位,两个数的和会变大,也会更接近target-nums[1]
通过头尾不断的前后移动,我们最终可能在较为中间的位置找到一个最接近目标的和nums[0]+nums[3]+nums[5]=1。
当然这只是一个确定的一个数,我们最后想遍历所有可能的结果,此时我们需要遍历第一个数x,让其改变的同时,头尾指针也不断的 前后移动,直到找到这个最终的结果。*/
int size = nums.size();
sort(nums.begin(), nums.end());
int retAbs = 99999;
int ret = nums[0] + nums[1] + nums[2];
int left;
int right;
int i;
int sum;
for (i = 0; i < size - 2; ++i) {
left = i + 1;
right = size - 1;
while(left < right) {
sum = nums[i] + nums[left] + nums[right];
if (sum == target) {
return sum;
} else if (sum > target) {
right--;
} else if (sum < target) {
left++;
}
if (abs(sum - target) < abs(ret - target)) {
ret = sum;
}
}
}
return ret;
}
};
class Solution {
public:
void nextPermutation(vector<int>& nums) {
int size = nums.size();
if (size <= 1) {
return;
}
int i = size - 1;
int index1;
int index2;
for (int i = size - 2; i >= 0; --i) {
if (nums[i] < nums[i + 1]) {
index1 = i;
index2 = i + 1;
break;
}
}
if (index1 < 0) {
sort(nums.begin(), nums.end());
return;
}
int min = index1 + 1;
for (int j = size - 1; j > index1; --j) {
if (nums[j] > nums[index1]) {
min = j;
break;
}
}
swap(nums[index1], nums[min]);
sort(nums.begin() + index1 + 1, nums.end());
}
};
(5) 633. 平方数之和 力扣
class Solution {
public:
bool judgeSquareSum(int c) {
//怎么向上合向下取整:https://blog.csdn.net/weixin_30075185/article/details/117044576
long index1 = 0;
long index2 = sqrt(c);
while (index1 <= index2) {
long sum = index1 * index1 + index2 * index2;
if (sum == c) {
return true;
}
if (sum > c) {
index2--;
}
if (sum < c) {
index1++;
}
}
return false;
}
};
(6) 680. 验证回文字符串 Ⅱ 力扣
class Solution {
public:
bool validPalindrome(string s) {
int len = s.size();
int left = 0;
int right = len - 1;
int cur1;
int cur2;
while(left < right) {
if (s[left] == s[right]) {
left++;
right--;
}
if (s[left] != s[right]) {
cur1 = left;
cur2 = right;
break;
}
}
if (left >= right) {
return true;
}
int cur3 = cur1;
int cur4 = cur2;
bool flag1 = true;
bool flag2 = true;
cur3++;
while(cur3 < cur4) {
if (s[cur3] == s[cur4]) {
cur3++;
cur4--;
} else {
flag1 = false;
break;
}
}
if (flag1 == true) {
return true;
}
cur2--;
while(cur1 < cur2) {
if (s[cur1] == s[cur2]) {
cur1++;
cur2--;
} else {
flag2 = false;
break;
}
}
if (flag2 == true) {
return true;
}
return false;
}
};
十三 874. 模拟行走机器人 力扣
class Solution {
public:
int robotSim(vector<int>& commands, vector<vector<int>>& obstacles) {
int dx[4] = {0, 1, 0, -1};
int dy[4] = {1, 0, -1, 0};
int x = 0, y = 0, di = 0;
/*
set<pair<int, int>>obstaclesSet;
for (vector<int>ob : obstacles)
{
obstaclesSet.insert(make_pair(ob[0], ob[1]));
} */
unordered_set<string> obstacleSet;
for(int i = 0; i < obstacles.size(); ++i) {
string tmpStr = to_string(obstacles[i][0]) + "," + to_string(obstacles[i][1]);
obstacleSet.insert(tmpStr); //此处如果不加","会有用例过不了,没想出原因。to_string(-1)///结果确实是"-1"
}
/* set<pair<int, int>>obstaclesSet;
for (int i = 0; i < obstacles.size(); ++i) {
obstaclesSet.insert(make_pair(obstacles[i][0], obstacles[i][1]));
} */
int ans = 0;
for (int i = 0; i < commands.size(); ++i) {
if (commands[i] == -2) {
di = (di + 3) % 4;
}
if (commands[i] == -1) {
di = (di + 1) % 4;
}
else {
for (int k = 0; k < commands[i]; ++k) {
int nx = x + dx[di];
int ny = y + dy[di];
string tmp = to_string(nx);
tmp += ",";
tmp += to_string(ny);
/* if (obstaclesSet.find(make_pair(nx, ny)) == obstaclesSet.end()) { */
if (obstacleSet.find(tmp) == obstacleSet.end()) {
x = nx;
y = ny;
ans = max(ans, x*x + y*y);
} else {
break;
}
}
}
}
return ans;
}
};
十四、 广度优先搜索
(1)226. 翻转二叉树 力扣
/**
* 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:
TreeNode* invertTree(TreeNode* root) {
//层次遍历,遍历到左右节点时候,交换左右节点
queue<TreeNode*> qu;
if(!root) {
return root;
}
qu.push(root);
while(!qu.empty()) {
TreeNode* tmp = qu.front();
qu.pop();
TreeNode* leftTmp = tmp -> left;
if (leftTmp) {
qu.push(leftTmp);
}
TreeNode* rightTmp = tmp -> right;
if (rightTmp) {
qu.push(rightTmp);
}
TreeNode* sw = tmp -> left;
tmp -> left = rightTmp;
tmp -> right = sw;
}
return root;
}
};
(2)404. 左叶子之和 力扣
/**
* 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:
int sumOfLeftLeaves(TreeNode* root) {
/* BFS
int sum = 0;
queue<TreeNode*> que;
if (!root) {
return 0;
}
que.push(root);
while(!que.empty()) {
TreeNode* tmp = que.front();
que.pop();
if (tmp -> left) {
TreeNode* tmpLeft = tmp -> left;
if ((!(tmpLeft -> left)) && (!(tmpLeft -> right))) {
sum += tmpLeft -> val;
} else {
que.push(tmpLeft);
}
}
if (tmp -> right) {
TreeNode* tmpRight = tmp -> right;
que.push(tmpRight);
}
}
return sum; */
/* DFS */
if (!root) {
return 0;
}
int sum = 0;
if ((root -> left) && (!(root -> left -> left)) && (!(root -> left -> right))) {
sum += root -> left -> val;
}
return sum + sumOfLeftLeaves(root -> left) + sumOfLeftLeaves(root -> right);
}
};
(3) 637. 二叉树的层平均值 力扣
/**
* 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<double> averageOfLevels(TreeNode* root) {
vector<double> res;
queue<TreeNode*> qu;
qu.push(root);
while(!qu.empty()) {
int size = qu.size();
double sum = 0;
for(int i = 0; i < size; ++i) {
TreeNode* tmp = qu.front();
sum += tmp -> val;
qu.pop();
if (tmp -> left) {
qu.push(tmp -> left);
}
if (tmp -> right) {
qu.push(tmp -> right);
}
}
double aver = sum / size;
res.push_back(aver);
}
return res;
}
};
(4) 965. 单值二叉树 力扣
/**
* 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 isUnivalTree(TreeNode* root) {
if (!root) {
return true;
}
if ((!(root -> left)) && (!(root -> right))) {
return true;
}
if (root -> left) {
if (root -> val != root -> left -> val) {
return false;
}
}
if (root -> right) {
if (root -> val != root -> right -> val) {
return false;
}
}
return isUnivalTree(root -> left) && isUnivalTree(root -> right);
}
};
十五 动态规划
(1)121. 买卖股票的最佳时机 力扣
class Solution {
public:
int maxProfit(vector<int>& prices) {
/* 一次遍历
int size = prices.size();
int minCost = 999999;
int maxEarn = 0;
for(int i = 0; i < size; ++i) {
if (prices[i] < minCost) {
minCost = prices[i];
} else {
if (prices[i] - minCost > maxEarn) {
maxEarn = prices[i] - minCost;
}
}
}
return maxEarn;
*/
/* 单调栈 */
/* stack<int> sta;
int optimum = 0;
int size = prices.size();
for(int i = 0; i < size; ++i) {
if (sta.empty() || sta.top() >= prices[i]) {
sta.push(prices[i]);
}
else {
if (prices[i] - sta.top() > optimum) {
optimum = prices[i] - sta.top();
}
}
}
return optimum;
*/
int size = prices.size();
if (size < 2) {
return 0;
}
vector<vector<int>> vec(size, vector<int>(2, 0));
vec[0][0] = 0;
vec[0][1] = -prices[0];
for(int i = 1; i < size; ++i) {
vec[i][0] = max(vec[i - 1][0], vec[i - 1][1] + prices[i]);
vec[i][1] = max(-prices[i], vec[i-1][1]);
}
return vec[size -1][0];
}
};
class Solution {
public:
vector<vector<int>> generate(int numRows) {
vector<vector<int>> ans;
for (int i = 0; i < numRows; ++i) {
vector<int> tmp4(i + 1);
tmp4[0] = 1;
tmp4[i] = 1;
for(int j = 1; j < i; ++j) {
tmp4[j] = ans[i - 1][j - 1] + ans[i -1][j];
}
ans.push_back(tmp4);
}
return ans;
}
};
(3) 122. 买卖股票的最佳时机 II 力扣
class Solution {
public:
int maxProfit(vector<int>& prices) {
int size = prices.size();
vector<vector<int>> vec(size, vector<int>(2, 0));
vec[0][0] = 0;
vec[0][1] = -prices[0];
int dp0 = 0;
int dp1 = -prices[0];
for(int i = 1; i < size; ++i) {
vec[i][0] += max(vec[i - 1][0], vec[i - 1][1] + prices[i]);
vec[i][1] += max(vec[i - 1][1], vec[i - 1][0] - prices[i]);
}
return vec[size -1][0];
}
};
(4) 面试题 17.16. 按摩师 力扣
class Solution {
public:
int massage(vector<int>& nums) {
int size = nums.size();
if (size == 0) {
return 0;
}
if (size == 1) {
return nums[0];
}
vector<int> vec(1000, -1);
vec[0] = 0;
vec[1] = nums[0];
for(int i = 2; i <= size; ++i) {
vec[i] = max(vec[i - 1], vec[i - 2] + nums[i -1]);
}
return vec[size];
}
};
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int size = nums.size();
vector<int> vec(size + 1, 0);
vec[0] = nums[0];
for(int i = 1; i < size; ++i) {
if (vec[i - 1] > 0) {
vec[i] = vec[i -1] + nums[i];
} else {
vec[i] = nums[i];
}
}
int max = -99999;
for(int i = 0; i < size; ++i) {
if (max < vec[i]) {
max = vec[i];
}
}
return max;
}
};
(6) 337. 打家劫舍 III 力扣
/**
* 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<int> dfs(TreeNode* root) {
vector<int> res(2, 0);
if (root) {
vector<int> lt(2, 0);
vector<int> rt(2, 0);
lt = dfs(root -> left);
rt = dfs(root -> right);
res[0] = max(lt[0], lt[1]) + max(rt[0], rt[1]);
res[1] = lt[0] + rt[0] + root -> val;
}
return res;
}
int rob(TreeNode* root) {
vector<int> ret(2, 0);
ret = dfs(root);
return max(ret[0], ret[1]);
}
};
class Solution {
public:
int rob(vector<int>& nums) {
int size = nums.size();
vector<int> vec(size + 1, 0);
vec[0] = 0;
vec[1] = nums[0];
for(int i = 2; i <= size; ++i) {
vec[i] = max(vec[i - 1], vec[i - 2] + nums[i - 1]);
}
return vec[size];
}
};
(8) 213. 打家劫舍 II 力扣
class Solution {
public:
int rob(vector<int>& nums) {
int size = nums.size();
if (size == 0) {
return 0;
}
if (size == 1) {
return nums[0];
}
vector<vector<int>> dp(size + 1, vector<int>(2, 0));
//选第一家
dp[0][0] = 0;
dp[1][0] = nums[0];
dp[2][0] = nums[0];
//不选第一家
dp[0][1] = 0;
dp[1][1] = 0;
dp[2][1] = nums[1];
if (size < 3) {
return max(dp[size][1], dp[size][0]);
}
for(int i = 3; i <= size - 1; ++i) {
dp[i][0] = max(dp[i - 1][0], dp[i - 2][0] + nums[i - 1]);
}
for(int i = 3; i <= size; ++i) {
dp[i][1] = max(dp[i -1][1], dp[i - 2][1] + nums[i - 1]);
}
return max(dp[size - 1][0], dp[size][1]);
}
};
(9)