Prefix Sum
class Solution {
public:
vector<vector<int>> imageSmoother(vector<vector<int>>& img) {
vector<vector<int>> prefix_sum(img.size()+1,vector<int>(img[0].size()+1,0));
for (int i = 1; i <= img.size(); ++i) {
for (int j = 1; j <=img[0].size() ; ++j) {
prefix_sum[i][j]=prefix_sum[i][j-1]+prefix_sum[i-1][j]+img[i-1][j-1]-prefix_sum[i-1][j-1];
}
}
vector<vector<int>> ans(img.size(),vector<int>(img[0].size(),0));
int m=img.size();
int n=img[0].size();
for (int i = 0; i < img.size(); i++) {
for (int j = 0; j < img[0].size(); j++) {
int a = max(0, i - 1), b = max(0, j - 1);
int c = min(m- 1, i + 1), d =min(n - 1, j + 1);
int cnt = (c - a + 1) * (d - b + 1);
int tot = prefix_sum[c + 1][d + 1] - prefix_sum[a][d + 1] - prefix_sum[c + 1][b] + prefix_sum[a][b];
ans[i][j] = tot / cnt;
}
}
return ans;
}
};
662. Maximum Width of Binary Tree
考虑各个节点与其子节点的关系
public int widthOfBinaryTree(TreeNode root) {
if (root==null){
return 0;
}
int max_len=1;
Queue<TreeNode> nodeQueue=new LinkedList<>();
Queue<TreeNode> nextQueue=new LinkedList<>();
nodeQueue.offer(root);
root.val=1;
while (!nodeQueue.isEmpty()){
int start = nodeQueue.peek().val;//获取每层起始节点(即最左端点)的下标
int curr_val=start;
while (!nodeQueue.isEmpty()){
var curr=nodeQueue.poll();
curr_val=curr.val;
if (curr.left!=null){
curr.left.val=2*curr_val;
nextQueue.offer(curr.left);
}
if (curr.right!=null){
curr.right.val=2*curr_val+1;
nextQueue.offer(curr.right);
}
}
max_len=Math.max(max_len,curr_val-start+1);
nodeQueue.addAll(nextQueue);
nextQueue.clear();
}
return max_len;
}
665. Non-decreasing Array
bool checkPossibility(vector<int>& nums) {
if(nums.size()<3){
return true;
}
int availability=1;
int prev=nums[0];
for (int i = 1; i < nums.size(); ++i) {
if (nums[i]<prev){
availability--;
if (availability<0){
return false;
}
if(i>=2&&nums[i]<nums[i-2]){
continue;
}
}
prev=nums[i];
}
return true;
}
*667. Beautiful Arrangement II
不要想得太复杂,其他差距是1就ok
vector<int> constructArray(int n, int k) {
if (k == 1) {
vector<int> v(n);
iota(v.begin(), v.end(), 1);
return v;
}
int arr_group = k + 1;
vector<int> res;
int curr_begin = 1;
int curr_base = curr_begin;
int curr_max = min(curr_begin + k, n);
while (curr_base < curr_max) {
res.push_back(curr_max);
res.push_back(curr_base);
curr_base++;
curr_max--;
}
if (curr_base == curr_max) {
res.push_back(curr_base);
}
curr_begin += arr_group;
for(;curr_begin<=n;curr_begin++){
res.push_back(curr_begin);
}
return res;
}
*669. Trim a Binary Search Tree
public TreeNode trimBST(TreeNode root, int low, int high) {
if (root==null){
return null;
}
if (root.val<low){
return trimBST(root.right,low,high);
}
if (root.val>high){
return trimBST(root.left,low,high);
}
root.left=trimBST(root.left,low,high);
root.right=trimBST(root.right,low,high);
return root;
}
670. Maximum Swap
public int maximumSwap(int num) {
char[] arr=String.valueOf(num).toCharArray();
char num_prev=10+'0';
for (int i=0;i<arr.length;i++){
if (num_prev>=arr[i]){
num_prev=arr[i];
}
else {
int max_right=findSubMax(arr,i);
int j=0;
for (;j<i;j++){
if (arr[j]<arr[max_right]){
break;
}
}
char tmp=arr[j];
arr[j]=arr[max_right];
arr[max_right]=tmp;
return Integer.parseInt(String.valueOf(arr));
}
}
return num;
}
public int findSubMax(char[] arr,int start_idx){
char curr_digit=arr[start_idx];
int max_digit=start_idx;
for (int i=start_idx+1;i<arr.length;i++){
if (arr[i]>=curr_digit){
curr_digit=arr[i];
max_digit=i;
}
}
return max_digit;
}
671. Second Minimum Node In a Binary Tree
DFS
class Solution {
public:
int min_val;
long second_min_val = numeric_limits<long>::max();
int findSecondMinimumValue(TreeNode *root) {
min_val = root->val;
dfs(root);
if (second_min_val == min_val || second_min_val == numeric_limits<long>::max()) {
return -1;
}
return second_min_val;
}
void dfs(TreeNode *root) {
if (!root->left) {
return;
}
if (root->left->val < root->right->val) {
if (root->right->val != min_val) {
second_min_val = min(second_min_val, (long)root->right->val);
dfs(root->left);
}
} else if (root->left->val > root->right->val) {
if (root->left->val != min_val) {
second_min_val = min(second_min_val, (long)root->left->val);
dfs(root->right);
}
}else{
dfs(root->left);
dfs(root->right);
}
}
};
674. Longest Continuous Increasing Subsequence
int findLengthOfLCIS(vector<int>& nums) {
int maxLen=1;
int currLen=1;
if (nums.empty()){
return 0;
}
for (int i = 1; i < nums.size(); ++i) {
if (nums[i]>nums[i-1]){
currLen++;
}
else{
maxLen= max(currLen,maxLen);
currLen=1;
}
}
maxLen= max(currLen,maxLen);
return maxLen;
}
677. Map Sum Pairs
class MapSum {
TrieNode root=new TrieNode();
public static class TrieNode{
boolean end=false;
int val;
HashMap<Character,TrieNode> children=new HashMap<>();
}
public MapSum() {
}
public void insert(String key, int val) {
TrieNode curr=root;
for (char ch:key.toCharArray()){
if (!curr.children.containsKey(ch)){
curr.children.put(ch,new TrieNode());
}
curr=curr.children.get(ch);
}
curr.end=true;
curr.val=val;
}
public int sum(String prefix) {
TrieNode curr=root;
int currSum=0;
for (char ch:prefix.toCharArray()){
if (!curr.children.containsKey(ch)){
return currSum;
}
curr=curr.children.get(ch);
}
currSum=bfsSearch(curr,currSum);
return currSum;
}
public int bfsSearch(TrieNode currNode,int currSum){
if (currNode.end){
currSum+=currNode.val;
}
for (Character key:currNode.children.keySet()){
currSum = bfsSearch(currNode.children.get(key),currSum);
}
return currSum;
}
}
/**
* Your MapSum object will be instantiated and called as such:
* MapSum obj = new MapSum();
* obj.insert(key,val);
* int param_2 = obj.sum(prefix);
*/
680. Valid Palindrome II
class Solution {
public:
bool strictCheck(string s) {
if (s.length() < 2) {
return true;
}
int start = 0;
int end = s.size() - 1;
while (start < end) {
if (s[start] != s[end]) {
return false;
}
start++;
end--;
}
return true;
}
bool validPalindrome(string s) {
if (s.length() < 2) {
return true;
}
int start = 0;
int end = s.size() - 1;
while (start < end) {
if (s[start] != s[end]) {
int length = end - start;
return strictCheck(s.substr(start, length)) || strictCheck(s.substr(start + 1, length));
}
start++;
end--;
}
return true;
}
};
682. Baseball Game
class Solution {
public:
bool findTarget(TreeNode* root, int k) {
unordered_set<int> require;
queue<TreeNode*> queue1;
queue1.push(root);
while (!queue1.empty()){
auto curr=queue1.front();
queue1.pop();
if(require.count(curr->val)){
return true;
}
else{
require.insert(k-curr->val);
}
if (curr->left){
queue1.push(curr->left);
}
if (curr->right){
queue1.push(curr->right);
}
}
return false;
}
};
*684. Redundant Connection
Union Find
vector<int> findRedundantConnection(vector<vector<int>>& edges) {
vector<int> unifind(1001,-1);
int size=edges.size();
for (int i = 0; i <= size; ++i) {
unifind[i]=i;
}
for (auto edge:edges) {
int set1= find(edge[0],unifind);
int set2= find(edge[1],unifind);
if (set1==set2){
return edge;
}
unifind[set1]=set2;
}
return {};
}
int find(int n, vector<int> &rp){
int num = n;
while(rp[num] != num)
num = rp[num];
return num;
}
*685. Redundant Connection II
Graph Theory & Union Find
先重点读懂题目中的这句 该图由一个有着 N 个节点 (节点值不重复 1, 2, …, N) 的树及一条附加的边构成。附加的边的两个顶点包含在 1 到 N 中间,这条附加的边不属于树中已存在的边。
这说明题目中的图原本是是一棵树,只不过在不增加节点的情况下多加了一条边!
还有 若有多个答案,返回最后出现在给定二维数组的答案。这说明在两条边都可以删除的情况下,要删顺序靠后的!
那么有如下三种情况,前两种情况是出现入度为 2 的点,如图:
且只有一个节点入度为 2,为什么不看出度呢,出度没有意义,一颗树中随便一个父节点就有多个出度。
第三种情况是没有入度为 2 的点,那么图中一定出现了有向环(注意这里强调是有向环!)
首先先计算节点的入度,代码如下:
int inDegree[N] = {0}; // 记录节点入度
n = edges.size(); // 边的数量
for (int i = 0; i < n; i++) {
inDegree[edges[i][1]]++; // 统计入度
}
前两种入度为 2 的情况,一定是删除指向入度为 2 的节点的两条边其中的一条,如果删了一条,判断这个图是一个树,那么这条边就是答案,同时注意要从后向前遍历,因为如果两天边删哪一条都可以成为树,就删最后那一条。
代码如下:
vector<int> vec; // 记录入度为2的边(如果有的话就两条边)
// 找入度为2的节点所对应的边,注意要倒叙,因为优先返回最后出现在二维数组中的答案
for (int i = n - 1; i >= 0; i--) {
if (inDegree[edges[i][1]] == 2) {
vec.push_back(i);
}
}
// 处理图中情况1 和 情况2
// 如果有入度为2的节点,那么一定是两条边里删一个,看删哪个可以构成树
if (vec.size() > 0) {
if (isTreeAfterRemoveEdge(edges, vec[0])) {
return edges[vec[0]];
} else {
return edges[vec[1]];
}
}
在来看情况三,明确没有入度为 2 的情况,那么一定有有向环,找到构成环的边就是要删除的边。
可以定义一个函数,代码如下:
// 在有向图里找到删除的那条边,使其变成树,返回值就是要删除的边
vector<int> getRemoveEdge(const vector<vector<int>>& edges)
此时 大家应该知道了,我们要实现两个最为关键的函数:
isTreeAfterRemoveEdge()
判断删一个边之后是不是树了
getRemoveEdge()
确定图中一定有了有向环,那么要找到需要删除的那条边
此时应该是用到 并查集了,并查集为什么可以判断 一个图是不是树呢?
因为如果两个点所在的边在添加图之前如果就可以在并查集里找到了相同的根,那么这条边添加上之后 这个图一定不是树了
实现代码:
class UnionFind {
int parent[1001];
public:
UnionFind(){
for (int i = 0; i < 1001; ++i) {
parent[i]=i;
}
}
int find(int x);
int merge(int a,int b);
};
int UnionFind::find(int x) {
//路径压缩
if (x != parent[x]) {
parent[x]= find(parent[x]);
}
return parent[x];
}
int UnionFind::merge(int a, int b) {
int parent_a= find(a);
int parent_b= find(b);
if (parent_a==parent_b){
return parent_a;
}
parent[parent_a]=parent_b;
return -1;
}
class Solution {
public:
bool isTreeAfterRemoveEdge(const vector<vector<int>>& edges, vector<int> deleteEdge) {
UnionFind unionFind; // 初始化并查集
for(auto edge:edges){
if (edge==deleteEdge){
continue;
}
int res=unionFind.merge(edge[0],edge[1]);
if (res>0){
return false;
}
}
return true;
}
vector<int> findRedundantDirectedConnection(vector<vector<int>>& edges) {
unordered_map<int,vector<int>> inDegrees;
vector<vector<int>> ans;
vector<int> nochange={-1,-1};
for (auto edge:edges) {
if (!inDegrees.count(edge[1])){
inDegrees[edge[1]]={edge[0]};
continue;
}
auto vec=inDegrees[edge[1]];
vec.push_back(edge[0]);
if (vec.size()>=2){
for (int element:vec) {
ans.push_back({element,edge[1]});
}
}
}
if (!ans.empty()){
vector<int> final_ans;
for (auto & an : ans) {
if (isTreeAfterRemoveEdge(edges,an)){
final_ans=an;
}
}
return final_ans;
}
UnionFind unionFind;
for (auto edge:edges) {
int res = unionFind.merge(edge[0],edge[1]);
if (res!=-1){
return edge;
}
}
return {12};
}
};
686. Repeated String Match
class Solution {
public:
int repeatedStringMatch(string a, string b) {
if (b.empty()) {
return 0;
}
if (a.empty()) {
return -1;
}
int curr_min_repeats = numeric_limits<int>::max();
for (int i = 0; i < a.size(); ++i) {
if (a[i] == b[0]) {
if (b.size() == 1) {
return 1;
}
int repeats = confirmSubstr(a, b, i + 1);
if (repeats >= 0) {
curr_min_repeats = min(curr_min_repeats, repeats);
}
}
}
if (curr_min_repeats == numeric_limits<int>::max()) {
return -1;
}
return curr_min_repeats + 1;
}
int confirmSubstr(string a, string b, int a_idx) {
int b_idx = 1;
int repeats = 0;
while (b_idx < b.size()) {
if (a_idx >= a.size()) {
a_idx = 0;
repeats++;
}
if (a[a_idx] != b[b_idx]) {
return -1;
}
a_idx++;
b_idx++;
}
return repeats;
}
};
*687. Longest Univalue Path
class Solution {
int ans = 0;
public int longestUnivaluePath(TreeNode root) {
if (root == null) {
return 0;
}
longestImpl(root);
return ans;
}
public int longestImpl(TreeNode root) {
if (root == null) {
return 0;
}
int lMax = longestImpl(root.left);
int rMax = longestImpl(root.right);
if (root.left != null && root.val == root.left.val) {
lMax++;
} else {
lMax = 0;
}
if (root.right != null && root.val == root.right.val) {
rMax++;
} else {
rMax = 0;
}
ans = Math.max(ans, lMax + rMax);
return Math.max(lMax, rMax);
}
}