位1的个数
编写一个函数,输入是一个无符号整数(以二进制串的形式),返回其二进制表达式中数字位数为 ‘1’ 的个数(也被称为汉明重量)。
提示:
- 请注意,在某些语言(如 Java)中,没有无符号整数类型。在这种情况下,输入和输出都将被指定为有符号整数类型,并且不应影响您的实现,因为无论整数是有符号的还是无符号的,其内部的二进制表示形式都是相同的。
- 在 Java 中,编译器使用二进制补码记法来表示有符号整数。因此,在上面的 示例 3 中,输入表示有符号整数 -3。
示例 1:
输入:00000000000000000000000000001011
输出:3
解释:输入的二进制串 00000000000000000000000000001011 中,共有三位为 '1'。
示例 2:
输入:00000000000000000000000010000000
输出:1
解释:输入的二进制串 00000000000000000000000010000000 中,共有一位为 '1'。
示例 3:
输入:11111111111111111111111111111101
输出:31
解释:输入的二进制串 11111111111111111111111111111101 中,共有 31 位为 '1'。
提示:
输入必须是长度为 32 的 二进制串 。
进阶:
如果多次调用这个函数,你将如何优化你的算法?
解题思路:遍历 n,让 n 的每一位和 1 进行与运算,结果为 1 则表面该位是 1。
class Solution {
public:
int hammingWeight(uint32_t n) {
int res = 0;
uint32_t scan = 1;
for(int i = 0; i < 32; ++i) {
if(n & scan) res++;
scan <<= 1;
}
return res;
}
};
打家劫舍
你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。
示例 1:
输入:[1,2,3,1]
输出:4
解释:偷窃 1 号房屋 (金额 = 1) ,然后偷窃 3 号房屋 (金额 = 3)。
偷窃到的最高金额 = 1 + 3 = 4 。
示例 2:
输入:[2,7,9,3,1]
输出:12
解释:偷窃 1 号房屋 (金额 = 2), 偷窃 3 号房屋 (金额 = 9),接着偷窃 5 号房屋 (金额 = 1)。
偷窃到的最高金额 = 2 + 9 + 1 = 12 。
提示:
1 <= nums.length <= 100
0 <= nums[i] <= 400
解题思路:利用动态规划,偷窃当前房屋的时候判断是偷这家和上上家,还是偷上家金额谁高。第一家和第二家需要特殊处理一下。
class Solution {
public:
int rob(vector<int>& nums) {
vector<int> dp(nums.size(), 0);
for(int i = 0; i < nums.size(); ++i) {
if(i == 0 ) dp[i] = nums[i];
else if(i == 1) dp[i] = max(dp[0], nums[i]);
else {
dp[i] = max(dp[i-2] + nums[i], dp[i-1]);
}
}
return dp[nums.size() -1];
}
};
二叉树的右视图
给定一棵二叉树,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。
示例:
输入: [1,2,3,null,5,null,4]
输出: [1, 3, 4]
解释:
1 <---
/ \
2 3 <---
\ \
5 4 <---
解题思路:利用层级遍历把每一层的最右边的数字存下来即可得到答案。
/**
* 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:
vector<int> rightSideView(TreeNode* root) {
queue<TreeNode* > qtn;
vector<int> res;
if(!root) return res;
qtn.push(root);
while(!qtn.empty()) {
for(int n = qtn.size(); n > 0; --n) {
TreeNode* tmp = qtn.front();
qtn.pop();
if(tmp->left) qtn.push(tmp->left);
if(tmp->right) qtn.push(tmp->right);
if(n == 1) res.push_back(tmp->val);
}
}
return res;
}
};
岛屿数量
给你一个由 ‘1’(陆地)和 ‘0’(水)组成的的二维网格,请你计算网格中岛屿的数量。
岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。
此外,你可以假设该网格的四条边均被水包围。
示例 1:
输入:grid = [
["1","1","1","1","0"],
["1","1","0","1","0"],
["1","1","0","0","0"],
["0","0","0","0","0"]
]
输出:1
示例 2:
输入:grid = [
["1","1","0","0","0"],
["1","1","0","0","0"],
["0","0","1","0","0"],
["0","0","0","1","1"]
]
输出:3
提示:
m == grid.length
n == grid[i].length
1 <= m, n <= 300
grid[i][j] 的值为 '0' 或 '1'
解题思路:从 grid[0][0] 开始,给每个岛屿编号,利用广度或者深度将同一个岛屿相同编号。
class Solution {
public:
void doMark(vector<vector<char>>& grid, int res, int x, int y) {
if(x < 0 || y < 0 || x == grid.size() || y == (*grid.begin()).size()) return;
if(grid[x][y] == '1'){
grid[x][y] += res;
doMark(grid, res, x-1, y);
doMark(grid, res, x, y-1);
doMark(grid, res, x+1, y);
doMark(grid, res, x, y+1);
}
}
int numIslands(vector<vector<char>>& grid) {
int res = 1;
int m = grid.size();
int n = (*grid.begin()).size();
for(int i = 0; i < m; ++i) {
for(int j = 0; j < n; ++j) {
if(grid[i][j] == '1') {
doMark(grid, res, i, j);
res++;
}
}
}
// for(auto vc : grid) {
// for(auto c : vc) {
// cout << c << " ";
// }cout << endl;
// }
return res-1;
}
};