1. 868. 二进制间距
目录
今天继续第一波剑指扫盲,接近尾声了:
1. 868. 二进制间距
难度简单102
给定一个正整数 n
,找到并返回 n
的二进制表示中两个 相邻 1 之间的 最长距离 。如果不存在两个相邻的 1,返回 0
。
如果只有 0
将两个 1
分隔开(可能不存在 0
),则认为这两个 1 彼此 相邻 。两个 1
之间的距离是它们的二进制表示中位置的绝对差。例如,"1001"
中的两个 1
的距离为 3 。
示例 1:
输入:n = 22 输出:2 解释:22 的二进制是 "10110" 。 在 22 的二进制表示中,有三个 1,组成两对相邻的 1 。 第一对相邻的 1 中,两个 1 之间的距离为 2 。 第二对相邻的 1 中,两个 1 之间的距离为 1 。 答案取两个距离之中最大的,也就是 2 。
示例 2:
输入:n = 8 输出:0 解释:8 的二进制是 "1000" 。 在 8 的二进制表示中没有相邻的两个 1,所以返回 0 。
示例 3:
输入:n = 5 输出:2 解释:5 的二进制是 "101" 。
提示:
1 <= n <= 109
简单的位运算题,每次遇到1时记录和上一个1的距离,更新最大距离:
class Solution {
public:
int binaryGap(int n) {
int ret = 0;//最远距离,至少为0
int cnt = 0;//当前处理到第几位
int pre = -1;//上一个1在第几位
while(n){
if(n & 1){//找到一个1
if(pre != -1){
ret = max(ret,cnt - pre);//这不是第一个1,计算距离
}
pre = cnt;//更新上一个1的位置
}
n >>= 1;
cnt++;
}
return ret;
}
};
2. 剑指 Offer 40. 最小的k个数
难度简单423
输入整数数组 arr
,找出其中最小的 k
个数。例如,输入4、5、1、6、2、7、3、8这8个数字,则最小的4个数字是1、2、3、4。
示例 1:
输入:arr = [3,2,1], k = 2 输出:[1,2] 或者 [2,1]
示例 2:
输入:arr = [0,1,2,1], k = 1 输出:[0]
限制:
0 <= k <= arr.length <= 10000
0 <= arr[i] <= 10000
通过次数330,845提交次数577,315
堆排序(这部分还不是很熟练...),用优先队列实现,要求前K个最小数字,先用前K个元素构成一个大小为K的最大堆,剩余元素只要大于堆顶元素就弹出堆顶并取代。
class Solution {
public:
vector<int> getLeastNumbers(vector<int>& arr, int k) {
vector<int> vec(k, 0);
if (k == 0) {
return vec;
}
priority_queue<int> que;//优先队列(堆)
for (int i = 0; i < k; i++) {
que.push(arr[i]);
}//默认降序排列(最大堆)
for (int i = k; i < arr.size(); i++) {
if (que.top() > arr[i]) {
que.pop();
que.push(arr[i]);
}
}
for (int i = 0; i < k; ++i) {
vec[i] = que.top();
que.pop();
}
return vec;
}
};
3. 剑指 Offer 48. 最长不含重复字符的子字符串
难度中等419
请从字符串中找出一个最长的不包含重复字符的子字符串,计算该最长子字符串的长度。
示例 1:
输入: "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其
长度为 3。
示例 2:
输入: "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b"
,所以其长度为 1。
示例 3:
输入: "pwwkew" 输出: 3 解释: 因为无重复字符的最长子串是"wke"
,所以其长度为 3。 请注意,你的答案必须是 子串 的长度,"pwke"
是一个子序列,不是子串。
提示:
s.length <= 40000
这道题做了好几遍了但还是不太顺利TT,双指针+哈希,用right来向右遍历字符串,同时把遍历过的字符加入集合,如果当前字符没有出现过,更新子串长度,如果遇到已经出现过的字符,则向右移动left(子串起点)并删除left所指的字符,直到越过与right指向的字符重复的字符。
class Solution {
public:
int lengthOfLongestSubstring(string s) {
if(s.empty()){
return 0;
}
int ret = 1;
int left = 0,right = 0;
unordered_set<char> occured;
while(right < s.size()){
while(occured.count(s[right])){
occured.erase(s[left]);
left++;
}
occured.insert(s[right]);
ret = max(ret,right - left + 1);
right++;
}
return ret;
}
};
4. 剑指 Offer 46. 把数字翻译成字符串
难度中等423
给定一个数字,我们按照如下规则把它翻译为字符串:0 翻译成 “a” ,1 翻译成 “b”,……,11 翻译成 “l”,……,25 翻译成 “z”。一个数字可能有多个翻译。请编程实现一个函数,用来计算一个数字有多少种不同的翻译方法。
示例 1:
输入: 12258
输出: 5
解释: 12258有5种不同的翻译,分别是"bccfi", "bwfi", "bczi", "mcfi"和"mzi"
提示:
0 <= num < 231
通过次数175,859提交次数336,028
一个动态规划题,青蛙跳台阶的变种。
递推关系:如果新加的字符和上一个字符能组成26以内的数,则说明这两个字符可以单独翻译,也可以合成一个字符串翻译。前者的方法个数=不加新字符的方法数,后者的方法个数=不加新字符和前一个字符的方法数,相当于跳到某台阶的方法数=跳到前一级和前两级台阶的方法数之和。
这题位运算有点麻烦,直接转成字符串顺序处理比较方便,注意char转int要-‘0’。
class Solution {
public:
int translateNum(int num) {
vector<int> dp(10);//最大2147483647
dp[0] = 1;
int cur = 0;//当前位的数字
int pre = 0;//上一位的数字
string temp = to_string(num);
if(temp.size() == 1){
return 1;
}
if((temp[0] - '0') * 10 + temp[1] - '0' < 26 && temp[0] != '0'){
dp[1] = 2;
}
else dp[1] = 1;
pre = temp[1] - '0';
for(int i = 2; i < temp.size(); i++){
cur = temp[i] - '0';
if(cur + pre * 10 < 26 && pre){
dp[i] = dp[i - 1] + dp[i - 2];
}
else{
dp[i] = dp[i - 1];
}
pre = cur;
}
return dp[temp.size() - 1];
}
};
C++基础
重写和重载
重写是子类对父类函数的重写,是子类和父类之间多态性的一种体现。如果在子类中定义了和父类中某函数名称、参数、返回值类型相同的函数,则该函数被重写。
重载是在一个类中定义了多个同名函数方法,是一个类中多态性的体现。
final关键字
final可以用于修饰类,表示这个类不可以再被继承;
也可以用于修饰方法,表示这个方法不可以被重写。
**后面打算三四天一更,以便每次能多积累一点题/知识点。