目录
一、只出现一次的数字
二、只出现一次的数字 II
三、只出现一次的数字 III
四、删除有序数组中的重复项
五、杨辉三角
六、数组中出现次数超过一半的数字
七、电话号码的字母组合
一、只出现一次的数字
class Solution {
public:
int singleNumber(vector<int>& nums) {
int ans = nums[0];
for (size_t i = 1; i < nums.size(); ++i)
{
ans ^= nums[i];
}
return ans;
}
};
二、只出现一次的数字 II
class Solution {
public:
int singleNumber(vector<int>& nums) {
int ans = 0;
// 求只出现一次的数字的二进制表示的每一位
for (size_t i = 0; i < 32; ++i)
{
size_t cnt = 0;
// 遍历整个数组,统计第 i 位为 1 的数字的个数
for (size_t j = 0; j < nums.size(); ++j)
{
if (nums[j] & (1 << i))
++cnt;
}
if (cnt % 3 == 1) // cnt 为 1,或者为 1 + 3 * k
ans |= (1 << i);
}
return ans;
}
};
三、只出现一次的数字 III
class Solution {
public:
vector<int> singleNumber(vector<int>& nums) {
vector<int> v(2);
int res = nums[0];
for (size_t i = 1; i < nums.size(); ++i)
{
res ^= nums[i];
}
// 找到 res 的二进制表示中最低位的 1 的位置
size_t pos = 0;
for (size_t i = 0; i < 32; ++i)
{
if (res & (1 << i))
{
pos = i;
break;
}
}
// 根据第 pos 位是否为 1 将 nums 分为两组
for (size_t i = 0; i < nums.size(); ++i)
{
if (nums[i] & (1 << pos))
v[0] ^= nums[i];
else
v[1] ^= nums[i];
}
return v;
}
};
四、删除有序数组中的重复项
class Solution {
public:
int removeDuplicates(vector<int>& nums) {
size_t slow = 0;
for (size_t fast = 1; fast < nums.size(); ++fast)
{
if (nums[slow] != nums[fast])
nums[++slow] = nums[fast];
}
return slow + 1;
}
};
五、杨辉三角
class Solution {
public:
vector<vector<int>> generate(int numRows) {
vector<vector<int>> vv(numRows);
for (size_t i = 0; i < numRows; ++i)
{
vv[i].resize(i + 1, 0);
vv[i][0] = vv[i][i] = 1;
if (i >= 2)
{
for (size_t j = 1; j < i; ++j)
{
vv[i][j] = vv[i - 1][j - 1] + vv[i - 1][j];
}
}
}
return vv;
}
};
图解:
-
定义一个包含
numRows
个元素的动态二维数组vv
,每个元素的类型都是vector<int>
:vector<vector<int>> vv(numRows);
假设
numRows
等于 5。 -
生成杨辉三角的前
numRows
行。
六、数组中出现次数超过一半的数字
class Solution {
public:
int MoreThanHalfNum_Solution(vector<int>& numbers) {
int candidate = numbers[0];
int chance = 1;
for (size_t i = 1; i < numbers.size(); ++i)
{
if (chance != 0)
{
if (candidate == numbers[i])
++chance;
else
--chance;
}
else
{
candidate = numbers[i];
chance = 1;
}
}
return candidate;
}
};
-
思路:
如果两个数字不相等,就消去这两个数,由于数组中有一个数字出现的次数超过数组长度的一半,即众数,那么即便在最坏情况下,每次消去一个众数和非众数,最后留下来的数也一定是众数。
-
具体操作:
在遍历数组时保存两个值,分别是众数的候选者 candidate 以及其所剩的机会 chance。当我们遍历到下一个元素的时候,如果下一个元素和候选者相等,则机会加 1,如果不相等,则机会减 1,即消去这两个不相同的数字。如果遍历到下一个元素的时候,机会为 0,即意味着需要重新选候选人了。
七、电话号码的字母组合
class Solution {
public:
string map[10] = { "", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz" };
void combine(const string& digits, size_t level, string combination, vector<string>& v)
{
if (level == digits.size())
{
v.push_back(combination);
return;
}
int number = digits[level] - '0';
string s = map[number];
for (size_t i = 0; i < s.size(); ++i)
{
combine(digits, level + 1, combination + s[i], v);
}
}
vector<string> letterCombinations(string digits) {
vector<string> v;
if (digits.empty())
return v;
combine(digits, 0, "", v);
return v;
}
};
解析(示例一):
level | number | s |
---|---|---|
0 | 2 | "abc" |
1 | 3 | "def" |