算法刷题
1.判断镜像树
1.1判断二叉树是否对称
题目描述:Symmetric Tree
bool isSymmetric(TreeNode* root1,TreeNode *root2){
if(root1 == NULL && root2 == NULL) return true;
else if(root1 == NULL && root2 != NULL) return false;
else if(root1 != NULL && root2 == NULL) return false;
if(root1->val == root2->val){
return isSymmetric(root1->left,root2->right) && isSymmetric(root1->right,root2->left);
}else{
return false;
}
}
其实与一道经典题型相类似
是谷歌的一道面试题,是翻转二叉树
有兴趣的童鞋可以看我的另一篇博文
面试经典
1.2判断n叉树是否对称(1.1的推广)
请参考面试经典
寻找重复数组中的唯一数字
Input: arr = [7, 3, 5, 5, 4, 3, 4, 8, 8]
Output: 7
例如:
arr中只有7是单身狗,其他数字都有两个
在此提供思路:
使用异或操作
类似题型:Missing Number
类似题型
题目描述:
思路提示:
将nums[i]置换到其对应的位置nums[nums[i]-1]上去,比如对于没有缺失项的正确
顺序应该是[1, 2, 3, 4, 5, 6, 7, 8],而我们现在却是[4,3,2,7,8,2,3,1],我们需要把数>>字移动到正确的位置上去,比如第一个4就应该和7先交换个位置,以此类推,最后>>得到的顺序应该是[1, 2, 3, 4, 3, 2, 7, 8],我们最后在对应位置检验,如果nums[i]和>>i+1不等,那么我们将i+1存入结果res中即可. 即剑指offer面试题3.
将罗马数字转换为10进制阿拉伯数字
Input: IX
Output: 9
Input: VII
Output: 7
Input: MCMIV
Output: 1904
知识补充:
I 1
IV 4
V 5
IX 9
X 10
XL 40
L 50
XC 90
C 100
CD 400
D 500
CM 900
M 1000
在此提供思路:
将输入字符数组从后向前遍历,设置一个per指针和cur指针,cur指针指向当前值,per指针指向当前位置的上一个位置。如果pre<cur。则证明是一个符合数字,需要加上cur所指向的值减去per所指向的值。
举个例子:MCMIV. 首先cur指向V,而per指向I,所以result += 4.
如果是MCMIVI, 那么cur指向I,而per指向V. 因为I < V,所以result += 1.
我当初想的是从前向后遍历,这样处理明显没有上一个思路方便。
逆向思维很重要
二进制手表
题目描述:
Binary Watch
思路描述:
枚举,因为hours最多=11(hours没有12点只有0点),minutes最多=59
源码示例:
class Solution {
public:
string getones(int hours,int minutes,int count1){
int sum = 0;
bitset<4> b(hours);
bitset<6> c(minutes);
sum = b.count() + c.count();
if(sum == count1){
if(minutes / 10 == 0){
return (to_string(hours) + ":0" + to_string(minutes));
}else{
return to_string(hours) + ":" + to_string(minutes);
}
}else{
return "";
}
}
vector<string> readBinaryWatch(int num) {
string str;
vector<string> v1;
for(int hours = 0;hours < 12;hours ++){
for(int minutes = 0;minutes < 60;minutes ++){
str = getones(hours,minutes,num);
if(str != ""){
v1.push_back(str);
}
}
}
return v1;
}
};
重复字母不毗邻的字符串
题目描述:
给定一个字符串,重排使得重排后字符串重复字母不相邻输入:
abbccc
输出:
cbcbca
思路解析(贪心):
1.遍历字符串,记录字符出现次数
2.将元素存储进最大堆中
3.每次根据出现次数取出最大堆的根,然后将该两个字符出现次数减一,重新入堆。如果存在这样一种情况,就是堆,但是当前字符出现次数>1,则证明不存在满足题意的重排序列
请注意:
可能会出现这样的一种情况:比如输入序列为abbdcccc。第一次最大堆输出了c,但是第二次最大堆依旧输出c,但这并不影响结果的正确性。因为一个萝卜一个坑。字符在重排后的字符串的顺序并非按照出堆的顺序来(又不是堆排序)
给出最大整数
题目描述:
给定一组整数,给定该组整数的一个排列,使得总体最大输入:
[17,7,2,45,72]
输出:
77245217思路描述:
比较mn和nm之间的大小,如果mn<nm则n在前,m在后。反之m在前,n在后。
Path Sum III
题目描述:
path sum III
输入示例10
/ \
5 -3
/ \ \
3 2 11
/ \ \
3 -2 1输出示例
3
explanation:
- 5 -> 3
- 5 -> 2 -> 1
- -3 -> 11
思路描述:
1.将每个结点至根结点的和求出来,
2.然后计算A = tempsum - pathsum (tempsum是某节点至最终的根结点的路径上所有结点的值的和。)。
3.如果存在某个结点的值等于A。那么则存在对应的pathSum(pathSum = tempSum - A)上面的输入实例如果计算区间和(从根节点到当前结点的路径和):
10
/ \
15 7
/ \ \
18 17 18
/ \ \
21 16 18
map<int,int> m1;
class Solution {
public:
void getPathSum(TreeNode* root,int tempsum, int sum,int& count){
if(root == NULL) return;
tempsum += root->val;
if(m1.count(tempsum - sum) != 0){
// cout<<root->val<<endl;
//cout<<tempsum<<endl;
count += m1[tempsum - sum];
cout<<count<<endl;
}
if(!m1.count(tempsum)){
m1.insert(pair<int,int>(tempsum,1));
}else{
m1[tempsum] ++;
}
getPathSum(root->left,tempsum,sum,count);
getPathSum(root->right,tempsum,sum,count);
m1[tempsum] --;
if(m1[tempsum] == 0){
m1.erase(tempsum);
}
}
int pathSum(TreeNode* root, int sum) {
int count = 0;
m1.clear();
m1.insert(pair<int,int>(0,1));
getPathSum(root,0, sum,count);
return count;
}
};
注意:
第11行的代码之所以采用count += m1[tempsum - sum]而不是count ++
是为了应对这种情况:
0
/
10
/
3
上面的情况是因为计算13有两种情况:0 + 10 + 3 以及 10 + 3
二叉树两个结点的最低的共同祖先结点
题目描述:
给定一棵二叉树其中的两个结点,求这两个结点的最低的共同祖先结点
数据结构:
struct Node{
struct Node* left;
struct Node* right;
struct Node* parent;
int weight;
}思路描述:
这道题其本质上是找到两个单链表的交集
首先,从A遍历到根,计算路径的长度。
其次,从B遍历到根,计算路径的长度。
最后,将指针设置在A和B处,并将较长路径的指针不断向前移动,直到两个路径的长度相等。
将两个指针同时向上移动,直到它们都在同一结点上,该结点就是最低的共同祖先结点
Minimum Moves to Equal Array Elements
题目描述:
思路描述:
假设数组为a1,a2,a3,a4,a5,…an,不妨假设a1<a2<a3<…<an.
首先将a1移到与a2相等。需要将a1移到与a2相等,需要移动a2 - a1步,序列变成a2,a2,a3 + a2 - a1,…,an + a2 - a1.
继续将a2移到与(a3 + a2 - a1)相等,需要移动(a3 + a2 - a1) - a2步即a3 - a1步。所以此时序列变成a3 + a2 - a1, a3 + a2 - a1, a3 + a2 - a1 , … , an+a2-a1+a3-a1.
所以依此类推,将前n-1个数移动an-a1步。所以总的移动步数时a2 + a3 + … + an - (n-1) * a1(其中an是最大值,a1是最小值)