赞
踩
维护两个栈,一个维护插入,一个维护删除。需要删除的时候可以把插入栈里的元素全部倒进删除栈里,注意只有删除栈为空了,才会倒,否则会破坏元素的顺序。很巧妙。
class CQueue
{
stack<int> st1, st2;
public:
CQueue()
{
while (st1.size())
st1.pop();
while (st2.size())
st2.pop();
}
void appendTail(int value)
{
st1.push(value);
}
int deleteHead()
{
if (!st2.size()) //为空才会倒,才能保证顺序正确
while (st1.size())
{
st2.push(st1.top());
st1.pop();
}
if (!st2.size())
return -1;
int res = st2.top();
st2.pop();
return res;
}
};
为栈新增功能, O ( 1 ) O(1) O(1)得到栈中最小值。
如果当前压入的元素不是最小值,那么它一定不会作为最小值。所以我们只需要开一个辅助单调栈维护好每个“在压入时是最小值”的元素。
class MinStack
{
public:
stack<int> st, st2;
MinStack()
{
while (!st.empty())
st.pop();
while (!st2.empty())
st2.pop();
}
void push(int x)
{
st.push(x);
if (!st2.size() || x <= st2.top())
st2.push(x);
}
void pop()
{
if (st2.size() && st.top() == st2.top())
st2.pop();
st.pop();
}
int top()
{
return st.top();
}
int min()
{
return st2.top();
}
};
简单题,可以遍历一遍reverse,或者递归回溯打印。
class Solution
{
public:
vector<int> reversePrint(ListNode *head)
{
vector<int> ans;
if (head == nullptr)
return ans;
if (head->next != NULL)
{
ans = reversePrint(head->next);
ans.emplace_back(head->val);
}
else
ans.emplace_back(head->val);
return ans;
}
};
遍历并反转即可。
class Solution
{
public:
ListNode *reverseList(ListNode *head)
{
vector<ListNode *> vec;
ListNode *pre = nullptr;
while (head != nullptr)
{
vec.emplace_back(head);
head = head->next;
vec.back()->next = pre;
pre = vec.back();
}
return pre;
}
};
模拟一遍即可。
class Solution
{
public:
const int N = 1e5 + 5;
Node *copyRandomList(Node *head)
{
vector<Node *> vec;
for (int i = 0; i < N; i++)
{
Node *ptr = new Node(1);
vec.emplace_back(ptr);
}
int id = 1, cnt = 1;
map<Node *, int> mp;
map<int, int> to;
Node *tmp = head;
vec[0] = nullptr;
while (head != nullptr)
{
mp[head] = cnt++;
head = head->next;
}
vec[cnt] = nullptr;
head = tmp;
while (head != nullptr)
{
vec[id]->next = vec[id + 1]; //指向后一个元素
vec[id]->val = head->val; //赋值
// to[i]=j表示i号结点random指向j号结点
to[id++] = mp[head->random];
head = head->next;
}
id = 1;
while (vec[id] != nullptr)
{
vec[id]->random = vec[to[id]];
id++;
}
return vec[1];
}
};
无
class Solution
{
public:
string replaceSpace(string s)
{
string ans;
for (auto it : s)
{
if (it == ' ')
ans += "%20";
else
ans += it;
}
return ans;
}
};
无
class Solution
{
public:
string reverseLeftWords(string s, int n)
{
return s.substr(n) + s.substr(0, n);
}
};
无
class Solution
{
public:
int findRepeatNumber(vector<int> &nums)
{
set<int> st;
for (auto it : nums)
{
if (st.count(it))
return it;
st.insert(it);
}
return -1;
}
};
无
class Solution
{
public:
int search(vector<int> &nums, int target)
{
map<int, int> mp;
for (auto it : nums)
mp[it]++;
return mp[target];
}
};
无
class Solution
{
public:
int missingNumber(vector<int> &nums)
{
int ans = 0;
while (ans < nums.size() && nums[ans] == ans)
ans++;
return ans;
}
};
遍历每一列,采用二分,时间复杂度
O
(
n
l
o
g
m
)
O(nlogm)
O(nlogm)
官方题解:从右上角出发,边走边选择,时间复杂度
O
(
n
l
o
g
m
)
O(nlogm)
O(nlogm)
class Solution
{
public:
bool findNumberIn2DArray(vector<vector<int>> &matrix, int target)
{
if (!matrix.size())
return 0;
int n = matrix.size();
int m = matrix[0].size();
for (int i = 0; i < n; i++)
{
int p = lower_bound(matrix[i].begin(), matrix[i].end(), target) - matrix[i].begin();
if (p != m && matrix[i][p] == target)
return 1;
}
return 0;
}
};
判断一下转折位置和corner test
即可。
class Solution
{
public:
int minArray(vector<int> &numbers)
{
int n = numbers.size();
if (n == 1)
return numbers[0];
for (int i = 0; i < n - 1; i++)
if (numbers[i] > numbers[i + 1])
return numbers[i + 1];
return numbers[0];
}
};
无
class Solution
{
public:
char firstUniqChar(string s)
{
map<char, int> mp;
for (auto it : s)
mp[it]++;
for (auto it : s)
if (mp[it] == 1)
return it;
return ' ';
}
};
遍历一遍即可。、
好吧,其实可以直接BFS。
class Solution
{
public:
map<int, vector<int>> mp;
void dfs(TreeNode *u, int dep)
{
mp[dep].emplace_back(u->val);
if (u->left)
dfs(u->left, dep + 1);
if (u->right)
dfs(u->right, dep + 1);
}
vector<int> levelOrder(TreeNode *root)
{
vector<int> ans;
if (root == nullptr)
return ans;
dfs(root, 0);
int dep = 0;
while (mp[dep].size())
{
for (auto it : mp[dep])
ans.emplace_back(it);
dep++;
}
return ans;
}
};
剑指 Offer 32 - II. 从上到下打印二叉树 II
同上一题
class Solution
{
public:
vector<vector<int>> ans;
vector<int> tmp;
void dfs(TreeNode *u, int dep)
{
if (ans.size() <= dep)
ans.emplace_back(tmp);
ans[dep].emplace_back(u->val);
if (u->left)
dfs(u->left, dep + 1);
if (u->right)
dfs(u->right, dep + 1);
}
vector<vector<int>> levelOrder(TreeNode *root)
{
if (root == nullptr)
return ans;
dfs(root, 0);
return ans;
}
};
对奇数深度的reverse一下即可。
也可以使用deque。
class Solution
{
public:
vector<vector<int>> ans;
void bfs(TreeNode *root)
{
queue<pair<TreeNode *, int>> q;
q.push(make_pair(root, 0));
while (q.size())
{
TreeNode *now = q.front().first;
int depth = q.front().second;
q.pop();
if (ans.size() <= depth)
ans.push_back(vector<int>(0));
ans[depth].push_back(now->val);
if (now->left != nullptr)
q.push(make_pair(now->left, depth + 1));
if (now->right != nullptr)
q.push(make_pair(now->right, depth + 1));
}
}
vector<vector<int>> levelOrder(TreeNode *root)
{
if (root == nullptr)
return ans;
bfs(root);
return ans;
}
};
枚举A树上的一个节点作为根,和B数进行递归比较。
class Solution
{
public:
bool check(TreeNode *rt1, TreeNode *rt2)
{
if (rt1 == nullptr || rt2 == nullptr)
return 0;
if (rt1->val != rt2->val)
return 0;
int s1 = 2, s2 = 2;
//如果A树有左儿子,B数没有,return 0
if (rt1->left == nullptr && rt2->left != nullptr)
return 0;
//如果A树有右儿子,B数没有,return 0
if (rt1->right == nullptr && rt2->right != nullptr)
return 0;
//有左儿子,进行递归
if (rt2->left != nullptr && !check(rt1->left, rt2->left))
return 0;
//有右儿子,进行递归
if (rt2->right != nullptr && !check(rt1->right, rt2->right))
return 0;
//剩下的情况都是满足的
return 1;
}
int ans = 0;
//枚举A上的结点 进行比较
void dfs(TreeNode *A, TreeNode *B)
{
if (ans)
return;
if (check(A, B))
ans = 1;
if (A->left != nullptr)
dfs(A->left, B);
if (A->right != nullptr)
dfs(A->right, B);
}
bool isSubStructure(TreeNode *A, TreeNode *B)
{
dfs(A, B);
return ans;
}
};
遍历树并交换所有左右儿子即可。
class Solution
{
public:
void dfs(TreeNode *root)
{
swap(root->left, root->right);
if (root->left != nullptr)
dfs(root->left);
if (root->right != nullptr)
dfs(root->right);
}
TreeNode *mirrorTree(TreeNode *root)
{
if (root == nullptr)
return root;
dfs(root);
return root;
}
};
双指针即可。
class Solution
{
public:
int ans = 1;
void dfs(TreeNode *A, TreeNode *B)
{
if (!ans)
return;
if (A->val != B->val)
{
ans = 0;
return;
}
if (A->left != nullptr && B->right == nullptr)
{
ans = 0;
return;
}
if (A->left == nullptr && B->right != nullptr)
{
ans = 0;
return;
}
if (A->right != nullptr && B->left == nullptr)
{
ans = 0;
return;
}
if (A->right == nullptr && B->left != nullptr)
{
ans = 0;
return;
}
if (A->right)
dfs(A->right, B->left);
if (A->left)
dfs(A->left, B->right);
}
bool isSymmetric(TreeNode *root)
{
if (root == nullptr)
return ans;
dfs(root, root);
return ans;
}
};
略
class Solution
{
public:
const int mod = 1e9 + 7;
int fib(int n)
{
if (n == 0)
return 0;
else if (n == 1)
return 1;
int a, b, c;
a = 0, b = 1;
n--;
while (n--)
{
c = (a + b) % mod;
a = b;
b = c;
}
return c;
}
};
略
class Solution
{
public:
int numWays(int n)
{
const int mod = 1e9 + 7;
vector<int> dp(n + 5);
dp[0] = 1, dp[1] = 1, dp[2] = 2;
for (int i = 3; i <= n; i++)
dp[i] = (dp[i - 1] + dp[i - 2]) % mod;
return dp[n];
}
};
维护前缀最小值。
class Solution
{
public:
int maxProfit(vector<int> &prices)
{
int minn = 1e9 + 7, ans = 0;
for (auto it : prices)
{
ans = max(ans, it - minn);
minn = min(minn, it);
}
return ans;
}
};
当sum为负数时,丢弃肯定是最优的。
class Solution
{
public:
int maxSubArray(vector<int> &nums)
{
int maxx = *max_element(nums.begin(), nums.end());
if (maxx < 0)
return maxx;
int ans = 0, sum = 0;
for (auto it : nums)
{
if (sum + it < 0)
sum = 0;
else
sum += it;
ans = max(ans, sum);
}
return ans;
}
};
动态规划。
class Solution
{
public:
int maxValue(vector<vector<int>> &grid)
{
for (int i = 0; i < grid.size(); i++)
{
for (int j = 0; j < grid[0].size(); j++)
{
if (i - 1 >= 0 && j - 1 >= 0)
grid[i][j] += max(grid[i - 1][j], grid[i][j - 1]);
else if (i - 1 >= 0)
grid[i][j] += grid[i - 1][j];
else if (j - 1 >= 0)
grid[i][j] += grid[i][j - 1];
}
}
return grid[grid.size() - 1][grid[0].size() - 1];
}
};
动态规划。
dp[i] = (val <= 25 && val >= 10 ?
dp[i - 1] + dp[i - 2] : dp[i - 1]);
class Solution
{
public:
int translateNum(int num)
{
if (num == 0)
return 1;
vector<int> vec;
while (num)
{
vec.emplace_back(num % 10);
num /= 10;
}
reverse(vec.begin(), vec.end());
int n = vec.size();
vector<int> dp(20);
dp[0] = 1;
if (n >= 2)
{
int val = vec[0] * 10 + vec[1];
dp[1] = (val <= 25 && val >= 10 ? 2 : 1);
}
for (int i = 2; i < n; i++)
{
int val = vec[i - 1] * 10 + vec[i];
dp[i] = (val <= 25 && val >= 10 ? dp[i - 1] + dp[i - 2] : dp[i - 1]);
}
return dp[n - 1];
}
};
尺取
class Solution
{
public:
int lengthOfLongestSubstring(string s)
{
map<char, int> mp;
int n = s.size();
int l = 0, r = 0, ans = 0;
while (l < n)
{
while (r < n && mp[s[r]] == 0)
{
mp[s[r]]++;
r++;
}
ans = max(ans, r - l);
if (r >= n)
break;
while (mp[s[r]])
{
mp[s[l]]--;
l++;
}
}
return ans;
}
};
略
class Solution
{
public:
ListNode *deleteNode(ListNode *head, int val)
{
if (head->val == val)
return head->next;
ListNode *tmp = head, *pre = head;
head = head->next;
while (1)
{
if (head->val == val)
{
pre->next = head->next;
break;
}
pre = head;
head = head->next;
}
return tmp;
}
};
维护size = k 的队列。
双指针更优。
class Solution
{
public:
ListNode *getKthFromEnd(ListNode *head, int k)
{
queue<ListNode *> q;
while (head != nullptr)
{
q.push(head);
head = head->next;
}
while (q.size() > k)
q.pop();
return q.front();
}
};
双指针。
class Solution
{
public:
ListNode *mergeTwoLists(ListNode *l1, ListNode *l2)
{
ListNode *ans = new ListNode;
ListNode *tail = ans;
while (l1 != nullptr || l2 != nullptr)
{
if (l1 == nullptr)
tail->next = l2, l2 = l2->next;
else if (l2 == nullptr)
tail->next = l1, l1 = l1->next;
else
{
if (l1->val < l2->val)
tail->next = l1, l1 = l1->next;
else
tail->next = l2, l2 = l2->next;
}
tail = tail->next;
}
return ans->next;
}
};
哈希表记录。
class Solution
{
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB)
{
map<ListNode *, int> mp;
while (headA != nullptr)
{
mp[headA] = 1;
headA = headA->next;
}
while (headB != nullptr)
{
if (mp[headB])
return headB;
headB = headB->next;
}
return nullptr;
}
};
略
class Solution
{
public:
vector<int> exchange(vector<int> &nums)
{
vector<int> ans;
for (auto it : nums)
if (it & 1)
ans.emplace_back(it);
for (auto it : nums)
if (!(it & 1))
ans.emplace_back(it);
return ans;
}
};
哈希表。
可以使用双指针。
class Solution
{
public:
vector<int> twoSum(vector<int> &nums, int target)
{
unordered_map<int, int> mp;
vector<int> ans;
for (auto it : nums)
{
if (mp[target - it])
{
ans.emplace_back(it);
ans.emplace_back(target - it);
return ans;
}
mp[it]++;
}
return ans;
}
};
可以双指针。
class Solution
{
public:
string reverseWords(string s)
{
string ans, res;
s += ' ';
vector<string> vec;
for (auto it : s)
{
if (it == ' ')
{
if (res.size())
{
vec.emplace_back(res);
res.clear();
}
}
else
res += it;
}
reverse(vec.begin(), vec.end());
for (auto it : vec)
ans += it, ans += ' ';
return ans.substr(0, ans.size() - 1);
}
};
dfs即可。
class Solution
{
public:
bool flag = 0;
int n, m;
void dfs(vector<vector<char>> &board, string &word, int x, int y, int p)
{
if (board[x][y] != word[p])
return;
if (p == word.size() - 1 || flag)
{
flag = 1;
return;
}
char tmp = board[x][y];
board[x][y] = '#';
if (x - 1 >= 0)
dfs(board, word, x - 1, y, p + 1);
if (y - 1 >= 0)
dfs(board, word, x, y - 1, p + 1);
if (x + 1 < n)
dfs(board, word, x + 1, y, p + 1);
if (y + 1 < m)
dfs(board, word, x, y + 1, p + 1);
board[x][y] = tmp;
}
bool exist(vector<vector<char>> &board, string word)
{
n = board.size();
m = board[0].size();
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++)
dfs(board, word, i, j, 0);
return flag;
}
};
dfs、bfs都可以。
class Solution
{
public:
int ans = 0;
int mp[110][110];
int f(int x, int y)
{
int res = 0;
while (x)
{
res += x % 10;
x /= 10;
}
while (y)
{
res += y % 10;
y /= 10;
}
return res;
}
void dfs(int x, int y, int &n, int &m, int &k)
{
mp[x][y] = 1;
ans++;
if (x + 1 < n && f(x + 1, y) <= k && !mp[x + 1][y])
dfs(x + 1, y, n, m, k);
if (y + 1 < m && f(x, y + 1) <= k && !mp[x][y + 1])
dfs(x, y + 1, n, m, k);
if (x - 1 >= 0 && f(x - 1, y) <= k && !mp[x - 1][y])
dfs(x - 1, y, n, m, k);
if (y - 1 >= 0 && f(x, y - 1) <= k && !mp[x][y - 1])
dfs(x, y - 1, n, m, k);
}
int movingCount(int m, int n, int k)
{
memset(mp, 0, sizeof mp);
dfs(0, 0, n, m, k);
return ans;
}
};
dfs即可。
class Solution
{
public:
vector<vector<int>> ans;
vector<int> vec;
void dfs(TreeNode *now, int sum, int &target)
{
sum += now->val;
vec.emplace_back(now->val);
if (sum == target && now->left == nullptr && now->right == nullptr)
ans.emplace_back(vec);
if (now->left)
dfs(now->left, sum, target);
if (now->right)
dfs(now->right, sum, target);
vec.pop_back();
sum -= now->val;
}
vector<vector<int>> pathSum(TreeNode *root, int &target)
{
if (root == nullptr)
return ans;
dfs(root, 0, target);
return ans;
}
};
中序遍历一遍即可。
class Solution
{
public:
vector<Node *> vec;
Node *head = new Node;
void dfs(Node *now)
{
if (now->left)
dfs(now->left);
vec.emplace_back(now);
if (now->right)
dfs(now->right);
}
Node *treeToDoublyList(Node *root)
{
if (root == nullptr)
return nullptr;
dfs(root);
int n = vec.size();
if (n == 1)
{
vec[0]->left = vec[0];
vec[0]->right = vec[0];
return vec[0];
}
vec[0]->left = vec[n - 1];
vec[0]->right = vec[1];
vec[n - 1]->left = vec[n - 2];
vec[n - 1]->right = vec[0];
for (int i = 1; i < n - 1; i++)
{
vec[i]->left = vec[i - 1];
vec[i]->right = vec[i + 1];
}
return vec[0];
}
};
中序遍历时先遍历右儿子即可。
class Solution
{
public:
int step = 0;
void dfs(TreeNode *now, int &k, TreeNode **root)
{
if (step == k)
return;
if (now->right)
dfs(now->right, k, root);
step++;
if (step == k)
{
(*root)->val = now->val;
return;
}
if (now->left)
dfs(now->left, k, root);
}
int kthLargest(TreeNode *root, int k)
{
dfs(root, k, &root);
return root->val;
}
};
a + b > b + a 则进行交换。
class Solution
{
public:
string f(int x)
{
string a = "";
while (x)
{
a = char('0' + x % 10) + a;
x /= 10;
}
if (!a.size())
a += '0';
return a;
}
string minNumber(vector<int> &nums)
{
vector<string> vec;
for (auto it : nums)
vec.emplace_back(f(it));
string ans;
for (int j = 0; j < vec.size(); j++)
for (int i = 0; i < vec.size() - 1; i++)
{
if (vec[i] + vec[i + 1] > vec[i + 1] + vec[i])
swap(vec[i], vec[i + 1]);
}
for (auto it : vec)
ans += it;
if (!ans.size())
ans += '0';
return ans;
}
};
成立条件:
class Solution
{
public:
bool isStraight(vector<int> &nums)
{
set<int> st;
int mx = -1, mi = 100;
for (auto it : nums)
{
if (it == 0)
continue;
mx = max(mx, it);
mi = min(mi, it);
if (st.count(it))
return 0;
st.insert(it);
}
if (mx - mi < 5)
return 1;
return 0;
}
};
排序即可。
class Solution
{
public:
vector<int> getLeastNumbers(vector<int> &arr, int k)
{
sort(arr.begin(), arr.end());
arr.resize(k);
return arr;
}
};
对顶堆。
class MedianFinder
{
public:
/*
min max
5
-6 4
-7 3
-8 2
-9 1
*/
priority_queue<int> qmax, qmin;
void addNum(int num)
{
/*
保证qmax里的元素都小于qmin里的元素
并且qmax.size()>=qmin.size()
*/
if (qmax.size() == qmin.size())
{
qmin.push(-num);
qmax.push(-qmin.top());
qmin.pop();
}
else
{
qmax.push(num);
qmin.push(-qmax.top());
qmax.pop();
}
}
double findMedian()
{
if ((qmax.size() + qmin.size()) % 2 == 0)
return 1.0 * (qmax.top() - qmin.top()) / 2;
else
return qmax.top();
}
};
递归回溯统计。
class Solution
{
public:
int maxDepth(TreeNode *root)
{
if (!root)
return 0;
if (root->left && root->right)
return max(maxDepth(root->left), maxDepth(root->right)) + 1;
else if (root->left)
return maxDepth(root->left) + 1;
else if (root->right)
return maxDepth(root->right) + 1;
else
return 1;
}
};
递归求深度即可。
class Solution
{
int ans = 1;
int dfs(TreeNode *now)
{
if (!ans)
return -1;
if (!now)
return 0;
if (now->left && now->right)
{
if (abs(dfs(now->left) - dfs(now->right)) > 1)
ans = 0;
return max(dfs(now->left), dfs(now->right)) + 1;
}
else if (now->left)
{
if (dfs(now->left) > 1)
ans = 0;
return dfs(now->left) + 1;
}
else if (now->right)
{
if (dfs(now->right) > 1)
ans = 0;
return dfs(now->right) + 1;
}
else
return 1;
}
public:
bool isBalanced(TreeNode *root)
{
if (!root)
return 1;
dfs(root);
return ans;
}
};
递归。
题解还有快速乘。
class Solution
{
public:
int sumNums(int n)
{
if (n == 1)
return 1;
return n + sumNums(n - 1);
}
};
根据二叉搜索树的性质,
left->val < now->val < right->val
如果p->val == now->val
,now就是LCA,并且和p为同一节点;
如果q->val == now->val
,now就是LCA,并且和q为同一节点;
如果p->val > now->val && q->val < now->val
,now就是LCA;
如果p->val < now->val && q->val > now->val
,now就是LCA;
如果p->val < now->val && q->val < now->val
,向左递归;
如果p->val > now->val && q->val > now->val
,向右递归;
class Solution
{
TreeNode *ans;
void dfs(TreeNode *now, TreeNode **p, TreeNode **q)
{
if ((*p)->val == now->val || (*q)->val == now->val)
{
ans = now;
return;
}
//剩下的情况:一左一右、都左、都右
if (((*p)->val < now->val) + ((*q)->val > now->val) != 1)
{
ans = now;
return;
}
if ((*p)->val < now->val)
dfs(now->left, p, q);
else
dfs(now->right, p, q);
}
public:
TreeNode *lowestCommonAncestor(TreeNode *root, TreeNode *p, TreeNode *q)
{
dfs(root, &p, &q);
return ans;
}
};
先遍历一次,把所有结点的父亲用哈希表存下来。
然后两个结点都向根节点移动,第一个相遇的节点就是LCA。
class Solution
{
unordered_map<TreeNode *, TreeNode *> father;
unordered_map<TreeNode *, int> vis;
TreeNode *ans;
void dfs(TreeNode *now, TreeNode *fa)
{
father[now] = fa;
if (now->left)
dfs(now->left, now);
if (now->right)
dfs(now->right, now);
}
void f(TreeNode *now)
{
if (vis[now])
{
ans = now;
return;
}
vis[now] = 1;
f(father[now]);
}
public:
TreeNode *lowestCommonAncestor(TreeNode *root, TreeNode *p, TreeNode *q)
{
dfs(root, root);
f(p);
f(q);
return ans;
}
};
给出先序遍历和中序遍历,求后序遍历。
先序遍历顺序为[根结点][左子树][右子树]
中序遍历顺序为[左子树][根结点][右子树]
思路:
class Solution
{
public:
map<int, int> index;
TreeNode *build(vector<int> &pre, vector<int> &in, int l1, int r1, int l2, int r2)
{
if (l1 > r1)
return nullptr;
TreeNode *root = new TreeNode(pre[l1]);
int pos = index[pre[l1]];
int num = pos - 1 - l2 + 1;
root->left = build(pre, in, l1 + 1, l1 + 1 + num - 1, l2, pos - 1);
root->right = build(pre, in, l1 + 1 + num - 1 + 1, r1, pos + 1, r2);
return root;
}
TreeNode *buildTree(vector<int> &preorder, vector<int> &inorder)
{
int n = preorder.size();
for (int i = 0; i < n; i++)
index[inorder[i]] = i;
return build(preorder, inorder, 0, n - 1, 0, n - 1);
}
};
快速幂,注意n为负数的情况。
class Solution
{
public:
double myPow(double x, int n)
{
long long nn = n;
if (nn < 0)
{
nn *= -1;
x = 1.0 / x;
}
double res = 1.0;
while (nn)
{
if (nn & 1)
res = res * x;
x *= x;
nn /= 2;
}
return res;
}
};
后序遍历的遍历结构为[左子树][右子树][根结点]
二叉搜索树的特点是根结点大于左子树的所有值,小于右子树的所有值
class Solution
{
public:
bool check(vector<int> &a, int l, int r)
{
// mid
// |
// [左子树][右子树][根结点]
if (l >= r)
return true;
int mid = upper_bound(a.begin() + l, a.begin() + r, a[r]) - a.begin();
for (int i = l; i <= mid - 1; i++) //左子树都小于根结点
if (a[i] > a[r])
return false;
for (int i = mid; i < r; i++) //右子树都大于根结点
if (a[i] < a[r])
return false;
if (!check(a, l, mid - 1) || !check(a, mid, r - 1)) //左右子树都要满足
return false;
return true;
}
bool verifyPostorder(vector<int> &postorder)
{
return check(postorder, 0, postorder.size() - 1);
}
};
位运算。
class Solution
{
public:
int hammingWeight(uint32_t n)
{
int ans = 0;
for (int i = 0; i <= 32; i++)
ans += (1ll << i) & n ? 1 : 0;
return ans;
}
};
用 & 操作找出进位。
用 ^ 操作找出除去非进位的加和结果。
循环相加到无进位即可。
class Solution
{
public:
int add(int a, int b)
{
while (b)
{
int c = ((unsigned int)(a & b) << 1);
a = (a ^ b);
b = c;
}
return a;
}
};
考虑将两个数分成两组,并分别将两组值异或起来,即可得到两个数。
先将所有值进行异或,可以得到这两个数的异或值res。找到res为1的某个位,因为两个数异或值为1,那么必然有一个数这个位上为0,另一个数这个位上为1。按照这一位进行分组即可。
class Solution
{
public:
vector<int> singleNumbers(vector<int> &nums)
{
int res = 0;
for (auto it : nums)
res ^= it;
int id = 0, ans1 = 0, ans2 = 0;
while (((1 << id) & res) == 0)
id++;
for (auto it : nums)
{
if ((1 << id) & it)
ans1 ^= it;
else
ans2 ^= it;
}
return vector<int>{ans1, ans2};
}
};
剑指 Offer 56 - II. 数组中数字出现的次数 II
把每个数每一位拆出来,出现次数不是3的倍数的位就是这个数的位。
tips:其实两个数的异或也是这个原理,把3改成2即可。
class Solution
{
public:
int singleNumber(vector<int> &nums)
{
int a[40];
memset(a, 0, sizeof a);
for (auto it : nums)
for (int i = 0; i <= 31; i++)
if ((1ll << i) & it)
a[i]++;
int ans = 0;
for (int i = 0; i <= 31; i++)
if (a[i] % 3)
ans += (1ll << i);
return ans;
}
};
按位拆分
class Solution
{
public:
int majorityElement(vector<int> &nums)
{
int a[40];
memset(a, 0, sizeof a);
for (auto it : nums)
for (int i = 0; i <= 31; i++)
if ((1ll << i) & it)
a[i]++;
int ans = 0;
for (int i = 0; i <= 31; i++)
if (a[i] * 2 >= (int)nums.size())
ans += (1ll << i);
return ans;
}
};
特判0即可。
class Solution
{
public:
vector<int> constructArr(vector<int> &a)
{
long long sum = 1, zero = 0, sum2 = 1;
vector<int> ans(a.size());
for (auto it : a)
{
sum *= it;
if (it == 0)
++zero;
else
sum2 *= it;
}
if (zero >= 2)
return ans;
for (int i = 0; i < (int)a.size(); i++)
{
if (!a[i])
ans[i] = sum2;
else
ans[i] = sum / a[i];
}
return ans;
}
};
猜想尽可能等分是最优的。
好像经过证明,最多分成三段。
class Solution
{
public:
int cuttingRope(int n)
{
long long ans = -1;
for (int m = 2; m <= n; m++)
{
int len = n / m;
int len2 = len;
if (n % m)
len2 = n / m + 1;
long long sum = 1;
for (int i = 1; i <= n % m; i++)
sum *= len2;
for (int i = 1; i <= m - n % m; i++)
sum *= len;
ans = max(ans, sum);
}
return ans;
}
};
枚举起点。
可以解方程O1,数学不好放弃。
class Solution
{
public:
long long f(int l, int r)
{
return 1ll*r * (r + 1) / 2 - 1ll*l * (l - 1) / 2;
}
vector<vector<int>> ans;
void save(int l, int r)
{
vector<int> tmp;
for (int i = l; i <= r; i++)
tmp.emplace_back(i);
ans.emplace_back(tmp);
};
vector<vector<int>> findContinuousSequence(int target)
{
for (int i = 1; i <= target / 2; i++)
{
int l = 1, r = target;
while (l <= r)
{
int mid = (l + r) >> 1;
if (f(i, i + mid) == target)
{
save(i,i+mid);
break;
}
else if (f(i, i + mid) < target)
l = mid + 1;
else
r = mid - 1;
}
}
return ans;
}
};
模拟
class Solution
{
public:
int mov[4][2] = {0, 1, 1, 0, 0, -1, -1, 0};
vector<int> ans;
void print(vector<vector<int>> &matrix, int x, int y, int dir)
{
ans.emplace_back(matrix[x][y]);
matrix[x][y] = -10086100;
bool f = 1;
int xx, yy;
xx = x + mov[dir % 4][0];
yy = y + mov[dir % 4][1];
if (xx >= matrix.size() || yy >= matrix[0].size() || xx < 0 || yy < 0 || matrix[xx][yy] == -10086100)
{
dir++;
xx = x + mov[dir % 4][0];
yy = y + mov[dir % 4][1];
} //最多转向一次
if (xx >= matrix.size() || yy >= matrix[0].size() || xx < 0 || yy < 0 || matrix[xx][yy] == -10086100)
return;
print(matrix, xx, yy, dir);
}
vector<int> spiralOrder(vector<vector<int>> &matrix)
{
if (!matrix.size())
return ans;
print(matrix, 0, 0, 0);
return ans;
}
};
模拟
class Solution
{
public:
bool validateStackSequences(vector<int> &pushed, vector<int> &popped)
{
stack<int> st;
int n = pushed.size();
int p = 0;
for (int i = 0; i < n; i++)
{
st.push(pushed[i]);
while (st.size() && st.top() == popped[p])
{
++p;
st.pop();
}
}
if (st.size())
return 0;
return 1;
}
};
模拟
class Solution
{
public:
int strToInt(string str)
{
long long ans = 0;
bool flag = 0, f = 0;
for (auto it : str)
{
if (it == '-' && !f)
{
flag = 1;
f = 1;
continue;
}
if (it == '+' && !f)
{
flag = 0;
f = 1;
continue;
}
if (it == ' ')
{
if (f)
{
if (flag && ans >= 2147483648)
return -2147483648;
if (!flag && ans >= 2147483647)
return 2147483647;
return ans * (flag ? -1 : 1);
}
continue;
}
f = 1;
if (it <= '9' && it >= '0')
ans = ans * 10 + it - '0', f = 1;
else
break;
if (flag && ans >= 2147483648)
return -2147483648;
if (!flag && ans >= 2147483647)
return 2147483647;
}
if (flag && ans >= 2147483648)
return -2147483648;
if (!flag && ans >= 2147483647)
return 2147483647;
return ans * (flag ? -1 : 1);
}
};
单调队列。
如果队首的元素的距离和当前元素的距离超过窗口大小,应该弹出队列。
如果当前的元素大于队尾的元素,那么队尾的元素肯定不会作为最大值贡献了,也应该弹出队列。
class Solution
{
public:
void push(deque<int> &q, vector<int> &nums, int p, int k)
{
while (q.size() && q.front() + k - 1 < p)
q.pop_front();
while (q.size() && nums[p] >= nums[q.back()])
q.pop_back();
q.push_back(p);
}
int get(deque<int> &q, vector<int> &nums)
{
return nums[q.front()];
}
vector<int> maxSlidingWindow(vector<int> &nums, int k)
{
vector<int> ans;
if (!nums.size())
return ans;
deque<int> q;
for (int i = 0; i < k; i++)
push(q, nums, i, k);
ans.emplace_back(get(q, nums));
for (int i = k; i < (int)nums.size(); i++)
{
push(q, nums, i, k);
ans.emplace_back(get(q, nums));
}
return ans;
}
};
维护单调队列
class MaxQueue
{
public:
deque<int> q;
int cnt = 0, p = 0;
vector<int> v;
MaxQueue()
{
}
int max_value()
{
if (!q.size())
return -1;
return v[q.front()];
}
void push_back(int value)
{
while (q.size() && v[q.back()] < value)
q.pop_back();
q.push_back(cnt++);
v.emplace_back(value);
}
int pop_front()
{
if (!q.size())
return -1;
if (q.size() && q.front() <= p)
q.pop_front();
return v[p++];
}
};
(原来只要能解密出自己加密的字符串就行… …
把所有叶子结点悬挂两个null即可。
class Codec
{
public:
const int FUCK = -1008612345;
// Encodes a tree to a single string.
string ans;
string atoi(int x)
{
string res = "";
while (x)
{
res += '0' + x % 10;
x /= 10;
}
reverse(res.begin(), res.end());
return res;
}
void dfs(TreeNode *root)
{
ans += atoi(root->val) + ',';
if (root->left)
dfs(root->left);
else
ans += "null,";
if (root->right)
dfs(root->right);
else
ans += "null,";
}
string serialize(TreeNode *root)
{
ans.clear();
if (root == nullptr)
return "null,";
dfs(root);
return ans;
}
vector<int> vec;
// Decodes your encoded data to tree.
int p;
TreeNode *build()
{
TreeNode *root = new TreeNode(vec[p++]);
if (vec[p] != FUCK)
root->left = build();
else
root->left = nullptr, ++p;
if (vec[p] != FUCK)
root->right = build();
else
root->right = nullptr, ++p;
return root;
}
int itoa(string x)
{
if (x == "null")
return FUCK;
int res = 0;
for (auto it : x)
res = res * 10 + it - '0';
return res;
}
TreeNode *deserialize(string data)
{
ans.clear();
for (auto it : data)
{
if (it == ',')
{
vec.emplace_back(itoa(ans));
ans.clear();
}
else
ans += it;
}
if (vec[0] == FUCK)
return nullptr;
p = 0;
return build();
}
};
事实证明,STL的next_permutation才是yyds。
class Solution
{
public:
vector<string> ans;
string tmp;
void dfs(string &s, int sum)
{
if (tmp.size() == s.size())
{
ans.emplace_back(tmp);
return;
}
for (int i = 0; i < (int)s.size(); i++)
if (s[i] != '#')
{
tmp += s[i];
char tmp_char = s[i];
s[i] = '#';
dfs(s, sum + 1);
tmp.pop_back();
s[i] = tmp_char;
}
}
vector<string> permutation(string s)
{
dfs(s, 0);
sort(ans.begin(), ans.end());
ans.erase(unique(ans.begin(), ans.end()), ans.end());
return ans;
}
};
好恶心的题,情况太多了。
wa了七次,勉强算是ac吧。
class Solution
{
public:
void getmax(int &a, int &b) { a = max(a, b); }
bool isMatch(string s, string p)
{
int n = s.size(), m = p.size();
s = '#' + s, p = '#' + p;
int dp[n + 5][m + 5];
memset(dp, 0, sizeof dp);
dp[0][0] = 1;
for (int i = 0; i <= n; i++)
for (int j = 1; j <= m; j++)
{
if (i >= 1 && p[j] == '.' || p[j] == s[i])
{
getmax(dp[i][j], dp[i - 1][j - 1]); //匹配1次
if (j >= 3 && p[j - 1] == '*')
getmax(dp[i][j], dp[i - 1][j - 3]); //
}
else if (p[j] == '*')
{
if (p[j - 1] == '.') //.*组合
{
if (i >= 1)
{
getmax(dp[i][j], dp[i - 1][j - 1]); //
getmax(dp[i][j], dp[i - 1][j]); //
}
if (j >= 2)
getmax(dp[i][j], dp[i][j - 2]); //
getmax(dp[i][j], dp[i][j - 1]); //
}
else
{
if (j >= 2)
getmax(dp[i][j], dp[i][j - 2]); //*匹配0次
if (i >= 1 && s[i] == p[j - 1])
getmax(dp[i][j], dp[i - 1][j]); //*匹配1次 a*匹配a
if (i >= 1 && j >= 2 && p[j - 1] == s[i]) //*匹配至少一次
{
getmax(dp[i][j], dp[i - 1][j - 1]);
}
}
}
}
return dp[n][m];
}
};
简单思路:堆维护
优秀的思路:动态规划,dp[i]表示第i个丑数,一个丑数肯定是由前一个数乘2/3/5得来的,并且dp[i-1]是正确的,那么dp[i]一定要大于dp[i-1]。
class Solution
{
public:
vector<int> ans;
int nthUglyNumber(int n)
{
vector<int> dp(n + 5);
dp[1] = 1;
int p1, p2, p3;
p1 = p2 = p3 = 1;
for (int i = 2; i <= n; i++)
{
if (dp[p1] * 2 <= dp[i - 1])
p1++;
if (dp[p2] * 3 <= dp[i - 1])
p2++;
if (dp[p3] * 5 <= dp[i - 1])
p3++;
dp[i] = min({dp[p1] * 2, dp[p2] * 3, dp[p3] * 5});
}
return dp[n];
}
};
简单的动态规划。可以用滚动数组优化。
class Solution
{
public:
vector<double> dicesProbability(int n)
{
double dp[n + 5][6 * n + 5];
memset(dp, 0, sizeof dp);
int maxx = 6 * n;
const double fuck = 1.0 / 6;
dp[0][0] = 1;
for (int i = 1; i <= n; i++)
for (int k = 1; k <= maxx; k++)
for (int j = 1; j <= 6; j++)
if (k - j >= 0)
dp[i][k] += dp[i - 1][k - j] * fuck;
vector<double> ans;
for (int k = n; k <= maxx; k++)
ans.emplace_back(dp[n][k]);
return ans;
}
};
据说应该考虑大数。
class Solution
{
public:
vector<int> printNumbers(int n)
{
int maxx = pow(10, n);
vector<int> ans;
for (int i = 1; i < maxx; i++)
ans.emplace_back(i);
return ans;
}
};
树状数组求逆序对板子题。
class Solution
{
public:
int c[(int)5e4 + 5];
int maxx;
void insert(int i)
{
while (i <= maxx)
{
c[i]++;
i += (i) & (-i);
}
}
int getsum(int i)
{
int sum = 0;
while (i)
{
sum += c[i];
i -= (i) & (-i);
}
return sum;
}
int reversePairs(vector<int> &nums)
{
vector<int> vec;
for (auto it : nums)
vec.emplace_back(it);
sort(vec.begin(), vec.end());
maxx = unique(vec.begin(), vec.end()) - vec.begin();
for (int i = 0; i < (int)nums.size(); i++)
nums[i] = lower_bound(vec.begin(), vec.begin() + maxx, nums[i]) - vec.begin() + 1;
int ans = 0;
for (auto it : nums)
{
if (it < maxx)
ans += getsum(maxx) - getsum(it);
insert(it);
}
return ans;
}
};
有个结论,将绳子尽可能切成若干个3的长度,如果最后剩余1, 2 × 2 > 1 × 3 2\times2 > 1\times3 2×2>1×3,因此将一个3分成2更优。
(具体证明还没看)
class Solution
{
public:
const long long mod = 1e9 + 7;
long long qpow(long long a, long long b)
{
long long res = 1;
while (b)
{
if (b & 1)
res = res * a % mod;
b /= 2;
a = a * a % mod;
}
return res;
}
int cuttingRope(int n)
{
if (n <= 3)
return n - 1;
if (n % 3 == 0)
return qpow(3, n / 3);
else if (n % 3 == 1)
return 4ll * qpow(3, (n / 3) - 1) % mod;
else
return 2ll * qpow(3, n / 3) % mod;
}
};
数位DP。对!limit
进行记忆化,会更快。
class Solution
{
public:
int vis[20][20];
int dfs(int a[], int pos, int s, bool limit)
// 第pos位、 前面总共出现了多少个1 、是否状态有限制
{
if (!pos)
return s;
if (vis[pos][s] && !limit)
return vis[pos][s];
int sum = 0;
for (int i = 0; i <= (limit ? a[pos] : 9); i++)
sum += dfs(a, pos - 1, s + (i == 1), limit && a[pos] == i);
if (!limit)
return vis[pos][s] = sum;
else
return sum;
}
int countDigitOne(int n)
{
int a[20];
int pos = 0;
while (n)
{
a[++pos] = n % 10;
n /= 10;
}
return dfs(a, pos, 0, 1);
}
};
待完成:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。