1. I. 数组中数字出现的次数(位运算)
题目描述:
一个整型数组 nums 里除两个数字之外,其他数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。
难度:中等
示例:
输入:nums = [1,2,10,4,1,4,3,3]
输出:[2,10] 或 [10,2]
题目地址
题解:
class Solution {
public:
vector<int> singleNumbers(vector<int>& nums) {
int xOr=0;
for(auto num:nums)
xOr^=num;
int div=1;
while((xOr&div)==0)
div<<=1;
int a=xOr,b=xOr;
for(auto num:nums){
if((num&div)==0)
a^=num;
else
b^=num;
}
return {a,b};
}
};
异或的性质:两个相同的数异或的结果为0,任何一个数跟0异或的结果都是它本身。
通过性质,我们可以很快知道,如果在数组中,如果只有一个数出现一次,其余数均出现两次,那么对数组中的数做一遍异或,就可以得到这个数。
如果有两个数都出现了一次,考虑将数组分组,把这两个数分到不同的组,并且组中其余数仍然成对出现,对这两个新的数组做异或,就可以得到这两个数。
回到本题,首先,对原数组做一遍异或,就可以得到这两个单独出现的数异或的结果。因为两个数不相同,所以他们异或的二进制数的结果中,至少有一位为1,这意味着,这两个数其中一个该位为1,另一个为0。我们就可以按该数位是否为1,将原来的数组分成两组。再对这两组数分别做异或,就可以得到单独的两个数。
<题解参考力扣官方题解>
2.地图分析(多源dfs)
题目描述:
你现在手里有一份大小为 n x n 的 网格 grid,上面的每个 单元格 都用 0 和 1 标记好了。其中 0 代表海洋,1 代表陆地。
请你找出一个海洋单元格,这个海洋单元格到离它最近的陆地单元格的距离是最大的,并返回该距离。如果网格上只有陆地或者海洋,请返回 -1。
我们这里说的距离是「曼哈顿距离」( Manhattan Distance):(x0, y0) 和 (x1, y1) 这两个单元格之间的距离是 |x0 - x1| + |y0 - y1| 。
题目难度:中等
示例:
题目地址
题解:
class Solution {
int dirs[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
public:
int maxDistance(vector<vector<int>>& grid) {
queue<pair<int,int>> q;
int n=grid.size();
vector<vector<bool>> _grid(n,vector<bool>(n,false));
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
if(grid[i][j]==1){
q.push(make_pair(i,j));
_grid[i][j]=true;
}
int m=q.size();
if(m==n*n||m==0)
return -1;
while(!q.empty()){
int size=q.size();
for(int k=0;k<size;k++){
int x=q.front().first,y=q.front().second;
q.pop();
int i,j;
for(auto dir:dirs){
i=x+dir[0],j=y+dir[1];
if(i>=0&&i<n&&j>=0&&j<n&&_grid[i][j]==false){
grid[i][j]=grid[x][y]+1;
q.push(make_pair(i,j));
_grid[i][j]=true;
}
}
}
}
int ans=0;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
ans=max(ans,grid[i][j]);
return ans-1;
}
};
3.另一个树的子树(bfs,kmp)
题目描述:
给你两棵二叉树 root 和 subRoot 。检验 root 中是否包含和 subRoot 具有相同结构和节点值的子树。如果存在,返回 true ;否则,返回 false 。
二叉树 tree 的一棵子树包括 tree 的某个节点和这个节点的所有后代节点。tree 也可以看做它自身的一棵子树。
难度:简单??
示例:
题目地址
题解:
1.bfs
/**
* 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 isSubtree(TreeNode* root, TreeNode* subRoot) {
if(root==NULL)
return false;
if(dfs(root,subRoot))
return true;
else
return isSubtree(root->left,subRoot)||isSubtree(root->right,subRoot);
}
bool dfs(TreeNode* tree1,TreeNode* tree2){
if(tree1==NULL&&tree2==NULL)
return true;
else if(tree1==NULL||tree2==NULL)
return false;
else if(tree1->val!=tree2->val)
return false;
return dfs(tree1->left,tree2->left)&&dfs(tree1->right,tree2->right);
}
};
2.kmp
class Solution {
public:
vector <int> sOrder, tOrder;
int maxElement, lNull, rNull;
void getMaxElement(TreeNode *o) {
if (!o) {
return;
}
maxElement = max(maxElement, o->val);
getMaxElement(o->left);
getMaxElement(o->right);
}
void getDfsOrder(TreeNode *o, vector <int> &tar) {
if (!o) {
return;
}
tar.push_back(o->val);
if (o->left) {
getDfsOrder(o->left, tar);
} else {
tar.push_back(lNull);
}
if (o->right) {
getDfsOrder(o->right, tar);
} else {
tar.push_back(rNull);
}
}
bool kmp() {
int sLen = sOrder.size(), tLen = tOrder.size();
vector <int> fail(tOrder.size(), -1);
for (int i = 1, j = -1; i < tLen; ++i) {
while (j != -1 && tOrder[i] != tOrder[j + 1]) {
j = fail[j];
}
if (tOrder[i] == tOrder[j + 1]) {
++j;
}
fail[i] = j;
}
for (int i = 0, j = -1; i < sLen; ++i) {
while (j != -1 && sOrder[i] != tOrder[j + 1]) {
j = fail[j];
}
if (sOrder[i] == tOrder[j + 1]) {
++j;
}
if (j == tLen - 1) {
return true;
}
}
return false;
}
bool isSubtree(TreeNode* s, TreeNode* t) {
maxElement = INT_MIN;
getMaxElement(s);
getMaxElement(t);
lNull = maxElement + 1;
rNull = maxElement + 2;
getDfsOrder(s, sOrder);
getDfsOrder(t, tOrder);
return kmp();
}
};
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/subtree-of-another-tree/solution/ling-yi-ge-shu-de-zi-shu-by-leetcode-solution/
来源:力扣(LeetCode)
kmp题解来自官方,将两个树的先序遍历转化为字符串,再比较第二个是否为第一个的子串。暴力比较时间复杂度为O(m*n),kmp算法优化到O(m+n)。
计算next数组:
void getNext(string s, int* next, int length) {
int j = 0, k = -1;
next[0] = -1;
while (j < length - 1) {
if (k == -1 || s[j] == s[k]) {
k++;
j++;
next[j] = k;
}
else
k = next[k];
}
}
匹配:
int pos = -1;
for (int i = 0; i < length; i++) {
while (pos != -1 && s[pos + 1] != s0[i]) {
pos = next[pos];
}
if (s[pos + 1] == s0[i])
pos++;
}
代码来自数据结构课程作业。