JZ50 第一个只出现一次的字符
简单 通过率:31.77% 时间限制:1秒 空间限制:64M
知识点字符串
描述
在一个长为 字符串中找到第一个只出现一次的字符,并返回它的位置, 如果没有则返回 -1(需要区分大小写).(从0开始计数)
数据范围:0≤n≤10000,且字符串只有字母组成。
要求:空间复杂度 O(n),时间复杂度 O(n)
示例1
输入:
“google”
返回值:
4
示例2
输入:
“aa”
返回值:
-1
class Solution {
public:
int FirstNotRepeatingChar(string str) {
if (str.empty()) {
return 0;
}
unordered_map<char, int> m;
for (auto ch : str) {
m[ch]++;
}
for (int i = 0; i < str.size(); i++) {
if (m[str[i]] == 1) {
return i;
}
}
return -1;
}
};
JZ5 替换空格
简单 通过率:57.96% 时间限制:1秒 空间限制:256M
知识点字符串
描述
请实现一个函数,将一个字符串s中的每个空格替换成“%20”。
例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。
数据范围:0≤len(s)≤1000 。保证字符串中的字符为大写英文字母、小写英文字母和空格中的一种。
示例1
输入:
“We Are Happy”
返回值:
“We%20Are%20Happy”
示例2
输入:
" "
返回值:
“%20”
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param s string字符串
* @return string字符串
*/
string replaceSpace(string s) {
string res;
for (int i = 0; i < s.length(); ++i){
if (s[i] == ' '){
res.push_back('%');
res.push_back('2');
res.push_back('0');
} else {
res.push_back(s[i]);
}
}
return res;
}
};
JZ21 调整数组顺序使奇数位于偶数前面(一)
中等 通过率:53.75% 时间限制:1秒 空间限制:256M
知识点数组
描述
输入一个长度为 n 整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前面部分,所有的偶数位于数组的后面部分,
并保证奇数和奇数,偶数和偶数之间的相对位置不变。
数据范围:0≤n≤5000,数组中每个数的值 0≤val≤10000
要求:时间复杂度 O(n),空间复杂度 O(n)
进阶:时间复杂度 O(n2),空间复杂度 O(1)
示例1
输入:
[1,2,3,4]
返回值:
[1,3,2,4]
示例2
输入:
[2,4,6,5,7]
返回值:
[5,7,2,4,6]
示例3
输入:
[1,3,5,6,7]
返回值:
[1,3,5,7,6]
要求:时间复杂度 O(n),空间复杂度 O(n)
方法:创建一个新的数组
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param array int整型vector
* @return int整型vector
*/
vector<int> reOrderArray(vector<int>& array) {
vector<int> res(array.size());
int odd = 0;
for (int i = 0; i < array.size(); i++){
if(array[i] % 2 == 1) {
odd++;
}
}
int left = 0;
int right = odd;
for(int i = 0; i < array.size(); i++){
if(array[i] % 2 == 1){
res[left] = array[i];
left++;
} else {
res[right] = array[i];
right++;
}
}
return res;
}
};
进阶:时间复杂度 O(n2),空间复杂度 O(1)
方法:冒泡法(每次循环将一个奇数放在最终的位置)
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param array int整型vector
* @return int整型vector
*/
vector<int> reOrderArray(vector<int>& array) {
if (array.empty()) {
return array;
}
for (int i = 0; i < array.size(); ++i) {
for (int j = array.size()-1; j > i; --j) {
if ((array[j-1] % 2 == 0) && (array[j] % 2 == 1)) {
// 如果左边是偶数,右边是奇数,就交换
swap(array[j-1], array[j]);
}
}
}
return array;
}
};
例子:
left = 0
1 2 3 4 5 6
1 2 3 5 4 6
1 3 2 5 4 6
left = 1
1 3 5 2 4 6
left = 2
left = 3
left = 4
left = 5
优化后的冒泡法:
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param array int整型vector
* @return int整型vector
*/
vector<int> reOrderArray(vector<int>& array) {
if (array.empty()) {
return array;
}
for (int i = 0; i < array.size(); ++i) {
bool is = true;
for (int j = array.size()-1; j > left; --j) {
if ((array[j-1] % 2 == 0) && (array[j] % 2 == 1)) {
// 如果左边是偶数,右边是奇数,就交换
swap(array[j-1], array[j]);
is = false;
}
}
if (is == true) {
break;
}
}
return array;
}
};
例子:
left = 0
1 2 3 4 5 6
1 2 3 5 4 6
1 3 2 5 4 6
left = 1
1 3 5 2 4 6
全部满足条件,break跳出循环
JZ81 调整数组顺序使奇数位于偶数前面(二)
简单 通过率:59.49% 时间限制:1秒 空间限制:256M
知识点数组排序
描述
输入一个长度为 n 整数数组,数组里面可能含有相同的元素,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前面部分,所有的偶数位于数组的后面部分,
对奇数和奇数,偶数和偶数之间的相对位置不做要求,但是时间复杂度和空间复杂度必须如下要求。
数据范围:0≤n≤50000,数组中每个数的值 0≤val≤10000
要求:时间复杂度 O(n),空间复杂度 O(1)
示例1
输入:
[1,2,3,4]
返回值:
[1,3,2,4]
说明:
[3,1,2,4]或者[3,1,4,2]也是正确答案
示例2
输入:
[1,3,5,6,7]
返回值:
[1,3,5,7,6]
说明:
[3,1,5,7,6]等也是正确答案
示例3
输入:
[1,4,4,3]
要求:时间复杂度 O(n),空间复杂度 O(1)
方法:左右交换法
class Solution {
public:
vector<int> reOrderArrayTwo(vector<int>& array) {
int i = 0;
int j = array.size() - 1;
//目标:把左边的偶数移动到右边,把右边的奇数移动到左边
while(i < j) {
if (array[i] % 2 == 1 && array[j] % 2 == 1) {
//左右都是奇数,左边指针向右边移动
i++;
} else if (array[i] % 2 == 0 && array[j] % 2 == 0) {
//左右都是偶数,右边指针向左边移动
j--;
} else if (array[i] % 2 == 1 && array[j] % 2 == 0) {
//左边是奇数,右边是偶数,左右指针都向中间移动
i++;
j--;
} else if (array[i] % 2 == 0 && array[j] % 2 == 1) {
//左边是偶数,右边是奇数,交换,左右指针都向中间移动
swap(array[i], array[j]);
i++;
j--;
}
}
return array;
}
};
JZ74 和为S的连续正数序列
中等 通过率:29.88% 时间限制:1秒 空间限制:64M
知识点穷举
描述
小明很喜欢数学,有一天他在做数学作业时,要求计算出9~16的和,他马上就写出了正确答案是100。但是他并不满足于此,他在想究竟有多少种连续的正数序列的和为100(至少包括两个数)。没多久,他就得到另一组连续正数和为100的序列:18,19,20,21,22。现在把问题交给你,你能不能也很快的找出所有和为S的连续正数序列?
数据范围:0
返回值描述:
输出所有和为S的连续正数序列。序列内按照从小至大的顺序,序列间按照开始数字从小到大的顺序
示例1
输入:
9
返回值:
[[2,3,4],[4,5]]
示例2
输入:
0
返回值:
[]
知识点:滑动窗口
滑动窗口是指在数组、字符串、链表等线性结构上的一段,类似一个窗口,而这个窗口可以依次在上述线性结构上从头到尾滑动,且窗口的首尾可以收缩。我们在处理滑动窗口的时候,常用双指针来解决,左指针维护窗口左界,右指针维护窗口右界,二者同方向不同速率移动维持窗口。
思路:
从某一个数字开始的连续序列和等于目标数如果有,只能有一个,于是我们可以用这个性质来使区间滑动。
两个指针l、r指向区间首和区间尾,公式(l+r)∗(r−l+1)/2计算区间内部的序列和,如果这个和刚好等于目标数,说明以该区间首开始的序列找到了,记录下区间内的序列,同时以左边开始的起点就没有序列了,于是左区间收缩;如果区间和大于目标数,说明该区间过长需要收缩,只能收缩左边;如果该区间和小于目标数,说明该区间过短需要扩大,只能向右扩大,移动区间尾。
具体做法:
step 1:从区间[1,2]开始找连续子序列。
step 2:每次用公式计算区间内的和,若是等于目标数,则记录下该区间的所有数字,为一种序列,同时左区间指针向右。
step 3:若是区间内的序列和小于目标数,只能右区间扩展,若是区间内的序列和大于目标数,只能左区间收缩。
class Solution {
public:
vector<vector<int> > FindContinuousSequence(int sum) {
vector<vector<int> > res;
vector<int> temp;
if (sum < 0) {
return res;
}
int left = 1;
int right = 2;
while (left < right) {
int sum_2 = (left + right) * (right - left + 1) / 2;
if (sum_2 == sum) {
temp.clear();
for (int i = left; i <= right; ++i) {
temp.push_back(i);
}
res.push_back(temp);
left++;
} else if (sum_2 < sum) {
right++;
} else {
left++;
}
}
return res;
}
};
JZ57 和为S的两个数字
中等 通过率:31.05% 时间限制:1秒 空间限制:64M
知识点数学数组双指针
描述
输入一个升序数组 array 和一个数字S,在数组中查找两个数,使得他们的和正好是S,如果有多对数字的和等于S,返回任意一组即可,如果无法找出这样的数字,返回一个空数组即可。
数据范围: 0≤len(array)≤105 , 1≤array[i]≤106
示例1
输入:
[1,2,4,7,11,15],15
返回值:
[4,11]
说明:
返回[4,11]或者[11,4]都是可以的
示例2
输入:
[1,5,11],10
返回值:
[]
说明:
不存在,返回空数组
示例3
输入:
[1,2,3,4],5
返回值:
[1,4]
说明:
返回[1,4],[4,1],[2,3],[3,2]都是可以的
示例4
输入:
[1,2,2,4],4
返回值:
[2,2]
class Solution {
public:
vector<int> FindNumbersWithSum(vector<int> array,int sum) {
vector<int> res;
int start = 0;
int end = array.size()-1;
while (start < end) {
if (array[start] + array[end] == sum) {
res.push_back(array[start]);
res.push_back(array[end]);
//1 2 3 4 5 6
// 1 * 6 = 6
// 2 * 5 = 10
// 3 * 4 = 12
//从两边往中间找,第一对和等于S的两个数的乘积最小
break;
} else if (array[start] + array[end] < sum) {
start++;
} else if (array[start] + array[end] > sum) {
end--;
}
}
return res;
}
};
BM91 反转字符串
题目
题解(192)
讨论(305)
排行
面经new
入门 通过率:66.32% 时间限制:1秒 空间限制:256M
知识点
双指针
字符串
描述
写出一个程序,接受一个字符串,然后输出该字符串反转后的字符串。(字符串长度不超过1000)
数据范围: 0 \le n \le 10000≤n≤1000
要求:空间复杂度 O(n)O(n),时间复杂度 O(n)O(n)
示例1
输入:
“abcd”
复制
返回值:
“dcba”
复制
示例2
输入:
“”
复制
返回值:
“”
复制
class Solution {
public:
/**
* 反转字符串
* @param str string字符串
* @return string字符串
*/
string solve(string str) {
int left = 0;
int right = str.length()-1;
while (left < right) {
swap(str[left], str[right]);
left++;
right--;
}
return str;
}
};
BM89 合并区间
题目
题解(146)
讨论(252)
排行
面经new
中等 通过率:30.35% 时间限制:2秒 空间限制:256M
知识点
排序
数组
描述
给出一组区间,请合并所有重叠的区间。
请保证合并后的区间按区间起点升序排列。
数据范围:区间组数 0 \le n \le 2 \times 10^50≤n≤2×10
5
,区间内 的值都满足 0 \le val \le 2 \times 10^50≤val≤2×10
5
要求:空间复杂度 O(n)O(n),时间复杂度 O(nlogn)O(nlogn)
进阶:空间复杂度 O(val)O(val),时间复杂度O(val)O(val)
示例1
输入:
[[10,30],[20,60],[80,100],[150,180]]
复制
返回值:
[[10,60],[80,100],[150,180]]
复制
示例2
输入:
[[0,10],[10,20]]
复制
返回值:
[[0,20]]
复制
/**
* Definition for an interval.
* struct Interval {
* int start;
* int end;
* Interval() : start(0), end(0) {}
* Interval(int s, int e) : start(s), end(e) {}
* };
*/
class Solution {
public:
static bool cmp(Interval &x, Interval &y) {
return x.start < y.start;
}
vector<Interval> merge(vector<Interval> &intervals) {
vector<Interval> res;
if (intervals.empty()) {
return res;
}
sort(intervals.begin(), intervals.end(), cmp);
res.push_back(intervals[0]);
for (int i = 1; i < intervals.size(); ++i) {
if (intervals[i].start <= res.back().end) {
res.back().end = max(intervals[i].end, res.back().end);
} else {
res.push_back(intervals[i]);
}
}
return res;
}
};
BM88 判断是否为回文字符串
题目
题解(157)
讨论(182)
排行
面经new
入门 通过率:61.61% 时间限制:1秒 空间限制:256M
知识点
字符串
描述
给定一个长度为 n 的字符串,请编写一个函数判断该字符串是否回文。如果是回文请返回true,否则返回false。
字符串回文指该字符串正序与其逆序逐字符一致。
数据范围:0 < n \le 10000000
示例1
输入:
“absba”
复制
返回值:
true
复制
示例2
输入:
“ranko”
复制
返回值:
false
复制
示例3
输入:
“yamatomaya”
复制
返回值:
false
复制
示例4
输入:
“a”
复制
返回值:
true
复制
备注:
字符串长度不大于1000000,且仅由小写字母组成
class Solution {
public:
bool judge(string str) {
//首指针
int left = 0;
//尾指针
int right = str.length() - 1;
//首尾往中间靠
while(left < right){
//比较前后是否相同
if(str[left] != str[right]) {
return false;
}
left++;
right--;
}
return true;
}
};
BM87 合并两个有序的数组
题目
题解(264)
讨论(437)
排行
面经new
简单 通过率:36.95% 时间限制:1秒 空间限制:256M
知识点
数组
双指针
描述
给出一个有序的整数数组 A 和有序的整数数组 B ,请将数组 B 合并到数组 A 中,变成一个有序的升序数组
数据范围: 0 \le n,m \le 1000≤n,m≤100,|A_i| <=100∣A
i
∣<=100, |B_i| <= 100∣B
i
∣<=100
注意:
1.保证 A 数组有足够的空间存放 B 数组的元素, A 和 B 中初始的元素数目分别为 m 和 n,A的数组空间大小为 m+n
2.不要返回合并的数组,将数组 B 的数据合并到 A 里面就好了,且后台会自动将合并后的数组 A 的内容打印出来,所以也不需要自己打印
3. A 数组在[0,m-1]的范围也是有序的
示例1
输入:
[4,5,6],[1,2,3]
复制
返回值:
[1,2,3,4,5,6]
复制
说明:
A数组为[4,5,6],B数组为[1,2,3],后台程序会预先将A扩容为[4,5,6,0,0,0],B还是为[1,2,3],m=3,n=3,传入到函数merge里面,然后请同学完成merge函数,将B的数据合并A里面,最后后台程序输出A数组
示例2
输入:
[1,2,3],[2,5,6]
复制
返回值:
[1,2,2,3,5,6]
复制
关联企业
class Solution {
public:
void merge(int A[], int m, int B[], int n) {
int i = m - 1;
int j = n - 1;
int k = m + n - 1;
//从两个数组最大的元素开始,直到某一个数组遍历完
while(i >= 0 && j >= 0){
//将较大的元素放到最后
if(A[i] > B[j]) {
A[k--] = A[i--];
} else {
A[k--] = B[j--];
}
}
//数组A遍历完了,数组B还有,则还需要添加到数组A前面
if(i < 0){
while(j >= 0) {
A[k--] = B[j--];
}
}
//数组B遍历完了,数组A前面正好有,不用再添加
}
};
JZ67 把字符串转换成整数(atoi)
题目
题解(48)
讨论(58)
排行
面经new
中等 通过率:18.15% 时间限制:1秒 空间限制:256M
知识点
字符串
描述
写一个函数 StrToInt,实现把字符串转换成整数这个功能。不能使用 atoi 或者其他类似的库函数。传入的字符串可能有以下部分组成:
1.若干空格
2.(可选)一个符号字符(‘+’ 或 ‘-’)
3. 数字,字母,符号,空格组成的字符串表达式
4. 若干空格
转换算法如下:
1.去掉无用的前导空格
2.第一个非空字符为+或者-号时,作为该整数的正负号,如果没有符号,默认为正数
3.判断整数的有效部分:
3.1 确定符号位之后,与之后面尽可能多的连续数字组合起来成为有效整数数字,如果没有有效的整数部分,那么直接返回0
3.2 将字符串前面的整数部分取出,后面可能会存在存在多余的字符(字母,符号,空格等),这些字符可以被忽略,它们对于函数不应该造成影响
3.3 整数超过 32 位有符号整数范围 [−231, 231 − 1] ,需要截断这个整数,使其保持在这个范围内。具体来说,小于 −231的整数应该被调整为 −231 ,大于 231 − 1 的整数应该被调整为 231 − 1
4.去掉无用的后导空格
数据范围:
1.0 <=字符串长度<= 100
2.字符串由英文字母(大写和小写)、数字(0-9)、’ ‘、’+‘、’-’ 和 ‘.’ 组成
示例1
输入:
“82”
复制
返回值:
82
复制
示例2
输入:
" -12 "
复制
返回值:
-12
复制
说明:
去掉前后的空格,为-12
示例3
输入:
“4396 clearlove”
复制
返回值:
4396
复制
说明:
6后面的字符不属于有效的整数部分,去除,但是返回前面提取的有效部分
示例4
输入:
“clearlove 4396”
复制
返回值:
0
复制
示例5
输入:
“-987654321111”
复制
返回值:
-2147483648
复制
第一阶段:
44/45 组用例通过
运行时间
4ms
占用内存
452KB
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param s string字符串
* @return int整型
*/
int StrToInt(string s) {
int res = 0;
int index = 0;
int len = s.length();
while (index < len) {
if (s[index] == ' ') {
index++;
} else {
break;
}
}
if (index == len) {
return 0;
}
int sign = 1;
if (s[index] == '+') {
index++;
} else if (s[index] == '-') {
index++;
sign = -1;
}
if (index == len) {
return 0;
}
while (index < len) {
if (s[index] < '0' || s[index] > '9') {
break;
}
if (res > INT_MAX / 10) {
return INT_MAX;
}
if (res < INT_MIN / 10) {
return INT_MIN;
}
res = res * 10 + sign * (s[index] - '0');
index++;
}
return res;
}
};
第二阶段:
全部case通过
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param s string字符串
* @return int整型
*/
int StrToInt(string s) {
int res = 0;
int index = 0;
int len = s.length();
while (index < len) {
if (s[index] == ' ') {
index++;
} else {
break;
}
}
if (index == len) {
return 0;
}
int sign = 1;
if (s[index] == '+') {
index++;
} else if (s[index] == '-') {
index++;
sign = -1;
}
if (index == len) {
return 0;
}
while (index < len) {
if (s[index] < '0' || s[index] > '9') {
break;
}
if (res > INT_MAX / 10 || (res == INT_MAX / 10 && (s[index] - '0') > INT_MAX % 10)) {
return INT_MAX;
}
if (res < INT_MIN / 10 || (res == INT_MIN / 10 && (s[index] - '0') > -(INT_MIN % 10))) {
return INT_MIN;
}
res = res * 10 + sign * (s[index] - '0');
index++;
}
return res;
}
};
JZ17 打印从1到最大的n位数
题目
题解(72)
讨论(74)
排行
面经new
简单 通过率:51.33% 时间限制:1秒 空间限制:256M
知识点
数组
描述
输入数字 n,按顺序打印出从 1 到最大的 n 位十进制数。比如输入 3,则打印出 1、2、3 一直到最大的 3 位数 999。
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param n int整型 最大位数
* @return int整型vector
*/
vector<int> printNumbers(int n) {
vector<int> res;
if (n < 0 || n > 5) {
return res;
}
int num = 9;
int sum = 0;
while (n > 0) {
sum = sum * 10 + num;
n--;
}
for (int i = 1; i <= sum; ++i) {
res.push_back(i);
}
return res;
}
};
BM94 接雨水问题
较难 通过率:41.12% 时间限制:1秒 空间限制:256M
知识点双指针单调栈动态规划
描述
给定一个整形数组arr,已知其中所有的值都是非负的,将这个数组看作一个柱子高度图,计算按此排列的柱子,下雨之后能接多少雨水。(数组以外的区域高度视为0)
数据范围:数组长度 0≤n≤2×105,数组中每个值满足 0
示例1
输入:
[3,1,2,5,2,4]
返回值:
5
说明:
数组 [3,1,2,5,2,4] 表示柱子高度图,在这种情况下,可以接 5个单位的雨水,蓝色的为雨水 ,如题面图。
示例2
输入:
[4,5,1,3,2]
返回值:
2
class Solution {
public:
/**
* max water
* @param arr int整型vector the array
* @return long长整型
*/
long long maxWater(vector<int>& arr) {
if (arr.empty()) {
return 0;
}
long long res = 0;
int left = 0;
int right = arr.size()-1;
int left_max = 0;
int right_max = 0;
while (left < right) {
left_max = max(left_max, arr[left]);
right_max = max(right_max, arr[right]);
if (left_max < right_max) {
res += left_max - arr[left];
left++;
} else {
res += right_max - arr[right];
right--;
}
}
return res;
}
};
BM93 盛水最多的容器
中等 通过率:47.36% 时间限制:1秒 空间限制:256M
知识点双指针数组
描述
给定一个数组height,长度为n,每个数代表坐标轴中的一个点的高度,height[i]是在第i点的高度,请问,从中选2个高度与x轴组成的容器最多能容纳多少水
1.你不能倾斜容器
2.当n小于2时,视为不能形成容器,请返回0
3.数据保证能容纳最多的水不会超过整形范围,即不会超过231-1
数据范围:
0<=height.length<=105
0<=height[i]<=104
如输入的height为[1,7,3,2,4,5,8,2,7],那么如下图:
示例1
输入:
[1,7,3,2,4,5,8,2,7]
返回值:
49
示例2
输入:
[2,2]
返回值:
2
示例3
输入:
[5,4,3,2,1,5]
返回值:
25
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param height int整型vector
* @return int整型
*/
int maxArea(vector<int>& height) {
if (height.size() < 2) {
return 0;
}
int res = 0;
int left = 0;
int right = height.size()-1;
while (left < right) {
int capacity = min(height[left], height[right]) * (right - left);
res = max(res, capacity);
if (height[left] < height[right]) {
left++;
} else {
right--;
}
}
return res;
}
};
BM86 大数加法
中等 通过率:41.49% 时间限制:1秒 空间限制:256M
知识点字符串模拟
描述
以字符串的形式读入两个数字,编写一个函数计算它们的和,以字符串形式返回。
数据范围:s.length,t.length≤100000,字符串仅由’0’~‘9’构成
要求:时间复杂度 O(n)
示例1
输入:
“1”,“99”
返回值:
“100”
说明:
1+99=100
示例2
输入:
“114514”,“”
返回值:
“114514”
s字符串
数值:1 2 3 4 5 6
下标:0 1 2 3 4 5
i=3
t字符串
数值: 6 7 8 9
下标: 0 1 2 3
j=1
两个字符串的总长度不同,但是右边的已经相加的元素的长度相同。
i 和 j的关系公式:
s.length() - i = t.length() - j
根据这个公式,可以通过i请出j
j = i - s.length() + t.length()
class Solution {
public:
string solve(string s, string t) {
if(s.empty()) {
return t;
}
if(t.empty()) {
return s;
}
//让s为较长的字符串,t为较短的字符串
if(s.length() < t.length()) {
swap(s, t);
}
//进位标志
int carry = 0;
//从后往前遍历较长的字符串
for(int i = s.length() - 1; i >= 0; i--){
//第一步:加上s字符串中的数字
int temp = s[i] - '0';
//第二步:加上t字符串中的数字
//转较短的字符串相应的从后往前的下标
int j = i - s.length() + t.length();
//如果较短字符串没有结束
if(j >= 0) {
temp += t[j] - '0';
}
//第三步:加上进位
temp += carry;
//取进位
carry = temp / 10;
//取个位
temp = temp % 10;
//修改结果
s[i] = temp + '0';
}
//最后的进位
if(carry == 1) {
s = '1' + s;
}
return s;
}
};
BM85 验证IP地址
中等 通过率:23.09% 时间限制:1秒 空间限制:256M
知识点字符串
描述
编写一个函数来验证输入的字符串是否是有效的 IPv4 或 IPv6 地址
IPv4 地址由十进制数和点来表示,每个地址包含4个十进制数,其范围为 0 - 255, 用(“.”)分割。比如,172.16.254.1;
同时,IPv4 地址内的数不会以 0 开头。比如,地址 172.16.254.01 是不合法的。
IPv6 地址由8组16进制的数字来表示,每组表示 16 比特。这些组数字通过 (“:”)分割。比如, 2001:0db8:85a3:0000:0000:8a2e:0370:7334 是一个有效的地址。而且,我们可以加入一些以 0 开头的数字,字母可以使用大写,也可以是小写。所以, 2001:db8:85a3:0:0:8A2E:0370:7334 也是一个有效的 IPv6 address地址 (即,忽略 0 开头,忽略大小写)。
然而,我们不能因为某个组的值为 0,而使用一个空的组,以至于出现 (: 的情况。 比如, 2001:0db8:85a3::8A2E:0370:7334 是无效的 IPv6 地址。
同时,在 IPv6 地址中,多余的 0 也是不被允许的。比如, 02001:0db8:85a3:0000:0000:8a2e:0370:7334 是无效的。
说明: 你可以认为给定的字符串里没有空格或者其他特殊字符。
数据范围:字符串长度满足 5≤n≤50
进阶:空间复杂度 O(n),时间复杂度 O(n)
示例1
输入:
“172.16.254.1”
返回值:
“IPv4”
说明:
这是一个有效的 IPv4 地址, 所以返回 “IPv4”
示例2
输入:
“2001:0db8:85a3:0:0:8A2E:0370:7334”
返回值:
“IPv6”
说明:
这是一个有效的 IPv6 地址, 所以返回 “IPv6”
示例3
输入:
“256.256.256.256”
返回值:
“Neither”
说明:
这个地址既不是 IPv4 也不是 IPv6 地址
备注:
ip地址的类型,可能为
IPv4, IPv6, Neither
//必须加正则表达式的库
#include
class Solution {
public:
string solve(string IP) {
//正则表达式限制0-255 且没有前缀0 四组齐全
regex ipv4("(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])");
//正则表达式限制出现8组,0-9a-fA-F的数,个数必须是1-4个
regex ipv6("([0-9a-fA-F]{1,4}\\:){7}[0-9a-fA-F]{1,4}");
//调用正则匹配函数
if (regex_match(IP, ipv4)) {
return "IPv4";
} else if (regex_match(IP, ipv6)) {
return "IPv6";
} else {
return "Neither";
}
}
};
BM100 设计LRU缓存结构
题目
题解(50)
讨论(64)
排行
面经new
较难 通过率:48.18% 时间限制:2秒 空间限制:256M
知识点
链表
哈希
模拟
描述
设计LRU(最近最少使用)缓存结构,该结构在构造时确定大小,假设大小为 capacity ,操作次数是 n ,并有如下功能:
提示:
1.某个key的set或get操作一旦发生,则认为这个key的记录成了最常使用的,然后都会刷新缓存。
2.当缓存的大小超过capacity时,移除最不经常使用的记录。
3.返回的value都以字符串形式表达,如果是set,则会输出"null"来表示(不需要用户返回,系统会自动输出),方便观察
4.函数set和get必须以O(1)的方式运行
5.为了方便区分缓存里key与value,下面说明的缓存里key用""号包裹
数据范围:
1\leq capacity<=10^51≤capacity<=10
5
0\leq key,val \leq 2\times 10^9 \0≤key,val≤2×10
9
1\leq n\leq 10^51≤n≤10
5
示例1
输入:
[“set”,“set”,“get”,“set”,“get”,“set”,“get”,“get”,“get”],[[1,1],[2,2],[1],[3,3],[2],[4,4],[1],[3],[4]],2
复制
返回值:
[“null”,“null”,“1”,“null”,“-1”,“null”,“-1”,“3”,“4”]
复制
说明:
我们将缓存看成一个队列,最后一个参数为2代表capacity,所以
Solution s = new Solution(2);
s.set(1,1); //将(1,1)插入缓存,缓存是{“1”=1},set操作返回"null"
s.set(2,2); //将(2,2)插入缓存,缓存是{“2”=2,“1”=1},set操作返回"null"
output=s.get(1);// 因为get(1)操作,缓存更新,缓存是{“1”=1,“2”=2},get操作返回"1"
s.set(3,3); //将(3,3)插入缓存,缓存容量是2,故去掉某尾的key-value,缓存是{“3”=3,“1”=1},set操作返回"null"
output=s.get(2);// 因为get(2)操作,不存在对应的key,故get操作返回"-1"
s.set(4,4); //将(4,4)插入缓存,缓存容量是2,故去掉某尾的key-value,缓存是{“4”=4,“3”=3},set操作返回"null"
output=s.get(1);// 因为get(1)操作,不存在对应的key,故get操作返回"-1"
output=s.get(3);//因为get(3)操作,缓存更新,缓存是{“3”=3,“4”=4},get操作返回"3"
output=s.get(4);//因为get(4)操作,缓存更新,缓存是{“4”=4,“3”=3},get操作返回"4"
struct Node {
int _key;
int _value;
Node(int key, int value) : _key(key), _value(value) {}
};
class Solution {
public:
Solution(int capacity){
_capacity = capacity;
}
int get(int key) {
if (_cache_map.find(key) != _cache_map.end()) {
// hit cache
_cache_list.splice(_cache_list.begin(), _cache_list, _cache_map[key]);
_cache_map[key] = _cache_list.begin();
return _cache_list.front()._value;
} else {
// not hit cache
return -1;
}
}
void set(int key, int value){
if (_cache_map.find(key) != _cache_map.end()) {
// hit cache
_cache_list.splice(_cache_list.begin(), _cache_list, _cache_map[key]);
_cache_list.front()._value = value;
_cache_map[key] = _cache_list.begin();
} else {
// not hit cache
if (_cache_list.size() >= _capacity) {
_cache_map.erase(_cache_list.back()._key);
_cache_list.pop_back();
}
Node n(key, value);
_cache_list.push_front(n);
_cache_map[key] = _cache_list.begin();
}
}
private:
int _capacity;
list<Node> _cache_list;
unordered_map<int, list<Node>::iterator> _cache_map;
};
/**
* Your Solution object will be instantiated and called as such:
* Solution* solution = new Solution(capacity);
* int output = solution->get(key);
* solution->set(key,value);
*/