- 字符串相乘
给定两个以字符串形式表示的非负整数 num1 和 num2,返回 num1 和 num2 的乘积,它们的乘积也表示为字符串形式。
本题其实就是竖式计算,但是有个地方可以优化:m位乘以n位最多只有m + n位,而单独位相乘则最多两位,因此可以拆分为多个两位相乘并累加上一位
class Solution {
public:
string multiply(string num1, string num2) {
int n1=num1.size();
int n2=num2.size();
string res(n1 + n2, '0');
for(int i = n2 - 1; i >= 0; i--)
{
for(int j = n1 - 1; j >= 0; j--)
{
int temp = (res[i + j + 1] - '0') + (num1[j] - '0') * (num2[i] - '0');
res[i + j + 1] = temp % 10 + '0';//当前位
res[i + j ] += temp / 10; //前一位加上进位,res[i+j]已经初始化为'0',加上int类型自动转化为char,所以此处不加'0'
}
}
//去除首位'0'
for(int i = 0; i < n1 + n2; i++)
{
if(res[i] != '0')
return res.substr(i);
}
return "0";
}
};
- 通配符匹配
给定一个字符串 (s) 和一个字符模式 § ,实现一个支持 ‘?’ 和 ‘*
’ 的通配符匹配。
‘?’ 可以匹配任何单个字符。
‘*
’ 可以匹配任意字符串(包括空字符串)。
两个字符串完全匹配才算匹配成功。
本题中?其实不用在意,s和p指针自增略过即可,但是*
需要着重考虑,因为可以代替任意长度。这里有一个容易出现的误区,如果匹配让*
后一个字符等于s中判断位置之后第一个值则会出现错误。所以这里需要记录星号所在位置,然后继续自增s匹配下一处相同的值
class Solution {
public:
bool isMatch(string s, string p) {
int i = 0, j = 0, iStar = -1, jStar = -1, m = s.size(), n = p.size();
while (i < m) {
if (j < n && (s[i] == p[j] || p[j] == '?')) {
++i, ++j;
} else if (j < n && p[j] == '*') {
iStar = i;
jStar = j++;
} else if (iStar >= 0) {
i = ++iStar;
j = jStar + 1;
} else return false;
}
while (j < n && p[j] == '*') ++j;//去除多余星号
return j == n;
}
};
- 跳跃游戏
给定一个非负整数数组,你最初位于数组的第一个位置。
数组中的每个元素代表你在该位置可以跳跃的最大长度。
你的目标是使用最少的跳跃次数到达数组的最后一个位置。
本题的解法大致可以算作动态规划:dp[0] = 1 + dp[1]或dp[2], … dp[dp[0]],倒推至可以一步到达n,则完成,计数在dp之中,然后取最小值返回即可
int jump(vector<int>& nums) {
int size = nums.size();
int dp[100] = { 0 };
if (size == 1)
return 0;
for (int i = size - 2; i >= 0; i--)
{
if (nums[i] + i >= size - 1)
dp[i] = 1;
else
{
int min = size + 1;
for (int j = 1; j <= nums[i]; j++)
{
if (dp[i + j] >= 0 && dp[i + j] < min)
{
min = dp[i + j] + 1;
}
}
dp[i] = min;
}
}
return dp[0];
}
第二种方法是从头往后贪心算法求解
class Solution {
public:
int jump(vector<int>& nums) {
int farthest=0;
if (size(nums) <= 1) return 0;
int *p = new int[size(nums)];
for (int i = 0; i < size(nums); i++)
p[i]=INT_MAX;
p[0]=0;
for (int i=0;i<size(nums);i++){
if ((i+nums[i]+1)>=size(nums)) return p[i]+1;
else if ((i+nums[i])>farthest) {
for (int j=farthest-i;j<=nums[i];j++){
if (p[i]+1<p[i+j]) p[i+j]=p[i]+1;
}
farthest=i+nums[i];
}
}
return -1;
}
};
- 全排列
给定一个没有重复数字的序列,返回其所有可能的全排列。
这种问题显然采用回溯法求解,如果到最后一位则push并返回,否则求下一位
class Solution {
public:
vector<vector<int>> permute(vector<int>& nums) {
vector<vector<int>> res;
backtrack(res,nums,0);
return res;
}
void backtrack(vector<vector<int>> &res,vector<int> nums,int level){
if(level==nums.size()){
res.push_back(nums);
return;
}
for(int j=level;j<nums.size();j++){
if(j!=level) swap(nums[level],nums[j]);
backtrack(res,nums,level+1);
if(j!=level) swap(nums[level],nums[j]);
}
}
};
- 全排列 II
给定一个可包含重复数字的序列,返回所有不重复的全排列。
本题解法和上题类似,但是需要增加一个剪枝的过程。
class Solution {
public:
public:
vector<vector<int>> m_vecs;
int N;
bool isValid(vector<int> & vec, int x)
{
for (auto v:vec) if(v==x) return false;
return true;
}
void recur_per(vector<int>& nums, vector<int> & vec, int row)
{
if (row == N)
{
vector<int> vec2;
for (auto v: vec) vec2.push_back(nums[v]);
m_vecs.push_back(vec2);
return;
}
for (int i = 0; i< N; i++)
{
if (!isValid(vec, i)) continue;
if (i>0 && nums[i]==nums[i-1] && isValid(vec, i-1)) continue;
vec.push_back(i);
recur_per(nums, vec, row+1);
vec.pop_back();
}
}
vector<vector<int>> permuteUnique(vector<int>& nums) {
int n = nums.size();
if (!n) return m_vecs;
this->N = n;
sort(nums.begin(),nums.end());
vector<int> vec;
recur_per(nums, vec, 0);
return m_vecs;
}
};
- 旋转图像
给定一个 n × n 的二维矩阵表示一个图像。将图像顺时针旋转 90 度。
说明:
你必须在原地旋转图像,这意味着你需要直接修改输入的二维矩阵。请不要使用另一个矩阵来旋转图像。
直接转置矩阵然后镜像调换即可,也可以采用一个规律:
对于尺寸为n*n的矩阵,其任意(i, j)点,旋转后的坐标为(j, n - 1 - i)
class Solution {
public:
void rotate(vector<vector<int>>& matrix) {
for (int i=0; i<matrix.size(); i++)
for (int j=0; j<i; j++) swap(matrix[i][j], matrix[j][i]);
for (auto& row: matrix) reverse(row.begin(), row.end());
}
};
- 字母异位词分组
给定一个字符串数组,将字母异位词组合在一起。字母异位词指字母相同,但排列不同的字符串。
这种一看就知道是用哈希表进行分类处理:key为字母,value为出现次数,然后每一个和前面的进行比较,一样则放在一类,不一样则放在下一类,依次处理
class Solution {
public:
map<map<char,int>,vector<string> >mp;
vector<vector<string>> groupAnagrams(vector<string>& strs) {
for(int i=0,len=strs.size();i<len;++i){
map<char,int>m; //
for(int j=0,l=strs[i].size();j<l;++j)
m[strs[i][j]]++; // 该字符串字母出现次数
mp[m].push_back(strs[i]); // 该字母出现次数相同的map插入该字符串
}
vector<vector<string> >ans;
map<map<char,int>,vector<string> >::iterator it = mp.begin();
for(;it!=mp.end();++it)
ans.push_back(it->second);
return ans;
}
};
但是这种做法最大的问题在于时间和空间效率均极低,因此如果想要优化则应采用别的方法,比如对字母进行排序然后比较,如果相同则是字母异位词。也可以对数字进行统计计数(比特位),计数相同为同一个词