语言:C++
目录
172. 阶乘后的零
给定一个整数 n
,返回 n!
结果中尾随零的数量。
提示 n! = n * (n - 1) * (n - 2) * ... * 3 * 2 * 1
示例 1:
输入:n = 3
输出:0
解释:3! = 6 ,不含尾随 0
个人认为这个题最难的点在于大数的处理
拿到这个题的第一想法就是拿sum保存n!
但是0<=n<=10000,显然long long类型的sum都行不通
看了题解
找5的倍数真的是绝,只有n是5的倍数才会有末尾0的出现,5*任何偶数都会出现末尾0
将所有5的倍数x拆分为5*y(即y个5,会有y个0出现)
同时y也有可能是5的倍数,所以return的是n / 5 + trailingZeroes(n / 5)
不断递归,直至n<5
class Solution
{
public:
int trailingZeroes(int n)
{
if (n < 5)
return 0;
return n / 5 + trailingZeroes(n / 5);
}
};
照着递归,写了迭代
class Solution
{
public:
int trailingZeroes(int n)
{
int tmp = 0;
while (n)
{
if (n < 5)
break;
tmp += n / 5;
n /= 5;
}
return tmp;
}
};
1342. 将数字变成 0 的操作次数
给你一个非负整数 num
,请你返回将它变成 0 所需要的步数。 如果当前数字是偶数,你需要把它除以 2 ;否则,减去 1 。
示例 1:
输入:num = 14
输出:6
解释:
步骤 1) 14 是偶数,除以 2 得到 7 。
步骤 2) 7 是奇数,减 1 得到 6 。
步骤 3) 6 是偶数,除以 2 得到 3 。
步骤 4) 3 是奇数,减 1 得到 2 。
步骤 5) 2 是偶数,除以 2 得到 1 。
步骤 6) 1 是奇数,减 1 得到 0 。
class Solution
{
public:
int numberOfSteps(int num)
{
int tmp = 0;
while (num)
{
if (num & 1)
{
num -= 1;
}
else
{
num /= 2;
}
++tmp;
}
return tmp;
}
};
222. 完全二叉树的节点个数
给你一棵 完全二叉树 的根节点 root
,求出该树的节点个数。
完全二叉树 的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h
层,则该层包含 1~ 2h
个节点。
示例 1:
输入:root = [1,2,3,4,5,6]
输出:6
递归
class Solution
{
public:
int countNodes(TreeNode* root)
{
if (root == NULL)
return 0;
return 1 + countNodes(root->left) + countNodes(root->right);
}
};
迭代:层序遍历
class Solution
{
public:
int countNodes(TreeNode* root)
{
int tmp = 0;
queue<TreeNode*> que;
if (root != NULL)
{
que.push(root);
tmp++;
}
while (!que.empty())
{
int size = que.size();
for (int i = 0; i < size; i++)
{
TreeNode* node = que.front();
que.pop();
if (node->left)
{
que.push(node->left);
tmp++;
}
if (node->right)
{
que.push(node->right);
tmp++;
}
}
}
return tmp;
}
};
LCP 44. 开幕式焰火
可dfs
「力扣挑战赛」开幕式开始了,空中绽放了一颗二叉树形的巨型焰火。
给定一棵二叉树 root
代表焰火,节点值表示巨型焰火这一位置的颜色种类。请帮小扣计算巨型焰火有多少种不同的颜色。
示例 1:
输入:root = [1,3,2,1,null,2]
输出:3
解释:焰火中有 3 个不同的颜色,值分别为 1、2、3
层序遍历
不得不说,还是喜欢在二叉树类的题目中使用层序遍历
class Solution
{
public:
int numColor(TreeNode* root)
{
unordered_set<int>set;
queue<TreeNode*>que;
if (root != NULL)
{
que.push(root);
}
while (!que.empty())
{
int size = que.size();
for (int i = 0; i < size; ++i)
{
TreeNode* node = que.front();
set.insert(que.front()->val);
que.pop();
if (node->left)
{
que.push(node->left);
}
if (node->right)
{
que.push(node->right);
}
}
}
return set.size();
}
};
评论区看到的dfs
目前不懂这个算法
class Solution
{
public:
unordered_set<int>set;
void dfs(TreeNode* root)
{
if (root)
set.insert(root->val);
if (root->left)
dfs(root->left);
if (root->right)
dfs(root->right);
}
int numColor(TreeNode* root)
{
dfs(root);
return set.size();
}
};
397. 整数替换
给定一个正整数 n
,你可以做如下操作:
- 如果
n
是偶数,则用n / 2
替换n
。 - 如果
n
是奇数,则可以用n + 1
或n - 1
替换n
。
n
变为 1
所需的最小替换次数是多少?
示例 1:
输入:n = 8
输出:3
解释:8 -> 4 -> 2 -> 1
看了很多题解,只有这个理解了
首先如果一个数是偶数的时候,不断除以二就是最优方案。
如果是奇数,此时只有两种操作:+1 或 -1。
正确的做法不是判断该数是否是 2 的幂次方(悲伤呀,我自己的写法就是判断n+1和n-1哪个会是2的幂次方)。而是应该看这个数最低位是否有 至少 2 个连续的 1。因为在最低位有多个连续 1 的情况下,+1,能够同时消去多个 1,然后在前面补一位 1,在最低位到补的这一个 1 之间都是 0,可以直接通过不断右移得到。
而如果在这种情况下 -1,之后每右移 1 位后都会遇到这些连续的 1,这样每右移一位后都会比之前多一步减 1 的操作。
如果最后只有 2 个连续的 1,那么 +1 和 -1 的最终操作数是一样的。大于 2 个的时候,一定是 +1 操作数少。
唯一特例:3。只有 3 的时候,是直接 -1 最优。 3 → 2 → 1 优于 3 → 4 → 2 → 1。另外注意当 n == INT_MAX 时,+1 会爆 int。
class Solution
{
public:
int integerReplacement(int n)
{
int tmp = 0;
long num = n;
while (num > 1)
{
if (num&1)
{
if (num != 3 && (num >> 1) & 1)
{
num += 1;
}
else
{
num -= 1;
}
}
else
{
num /= 2;
}
tmp++;
}
return tmp;
}
};
938. 二叉搜索树的范围和
给定二叉搜索树的根结点 root
,返回值位于范围 [low, high]
之间的所有结点的值的和。
示例 1:
输入:root = [10,5,15,3,7,null,18], low = 7, high = 15
输出:32
层序遍历
class Solution
{
public:
int rangeSumBST(TreeNode* root, int low, int high)
{
queue<TreeNode*>que;
if (root)
{
que.push(root);
}
int tmp=0;
while (!que.empty())
{
int size = que.size();
for (int i = 0; i < size; i++)
{
TreeNode* node = que.front();
que.pop();
if (node->val >= low && node->val <= high)
{
tmp += node->val;
}
if (node->left)
que.push(node->left);
if (node->right)
que.push(node->right);
}
}
return tmp;
}
};
剑指 Offer 55 - I. 二叉树的深度
输入一棵二叉树的根节点,求该树的深度。从根节点到叶节点依次经过的节点(含根、叶节点)形成树的一条路径,最长路径的长度为树的深度。
例如:
给定二叉树 [3,9,20,null,null,15,7]
,
3
/
9 20
/
15 7
返回它的最大深度 3 。
层序遍历
class Solution
{
public:
int maxDepth(TreeNode* root)
{
queue<TreeNode*>que;
if (root)
que.push(root);
int tmp = 0;
while (!que.empty())
{
tmp++;
int size = que.size();
for (int i = 0; i < size; i++)
{
TreeNode* node = que.front();
que.pop();
if (node->left)
que.push(node->left);
if (node->right)
{
que.push(node->right);
}
}
}
return tmp;
}
};
104. 二叉树的最大深度
给定一个二叉树,找出其最大深度。
二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。
说明: 叶子节点是指没有子节点的节点。
示例:
给定二叉树 [3,9,20,null,null,15,7]
,
3
/ \
9 20
/ \
15 7
返回它的最大深度 3 。
层序遍历
class Solution
{
public:
int maxDepth(TreeNode* root)
{
if (root == NULL)
return 0;
queue< TreeNode*>que;
que.push(root);
int k = 0;
while (!que.empty())
{
int len = que.size();
for (int i = 0; i < len; i++)
{
TreeNode* node = que.front();
que.pop();
if (node->left)
que.push(node->left);
if (node->right)
que.push(node->right);
}
k++;
}
return k;
}
};
226. 翻转二叉树
翻转一棵二叉树。
示例:
输入:
4
/ \
2 7
/ \ / \
1 3 6 9
输出:
4
/ \
7 2
/ \ / \
9 6 3 1
修改递归顺序
class Solution
{
public:
TreeNode* invertTree(TreeNode* root)
{
if (root == NULL) return root;
swap(root->left, root->right); // 中
invertTree(root->left); // 左
invertTree(root->right); // 右
return root;
}
};