目录
一. 剑指 Offer 56 - I. 数组中数字出现的次数
二. 剑指 Offer 56 - II. 数组中数字出现的次数 II
一. 剑指 Offer 39. 数组中出现次数超过一半的数字
二. 剑指 Offer 57 - II. 和为 s 的连续正数序列
题目:
编写一个函数,输入是一个无符号整数(以二进制串的形式),返回其二进制表达式中数字位数为 '1' 的个数。
示例:
输入:n = 11 (控制台输入 00000000000000000000000000001011)
输出:3
解释:输入的二进制串
00000000000000000000000000001011?中,共有三位为 '1'。
解题思路:?
设 n 为二进制数,根据与运算的定义可得:
每判断一次若结果为 1 则对 计数器+1,并且将 n 右移一位。
C++代码:
class Solution {
public:
int hammingWeight(uint32_t n) {
unsigned int res = 0;
while(n)
{
res += n & 1;
n >>= 1;
}
return res;
}
};
题目:
写一个函数,求两个整数之和,要求在函数体内不得使用 “+”、“-”、“*”、“/” 四则运算符号。
示例:
输入:a = 1, b = 1
输出:2
解题思路:?
由于无进位和?与?异或运算?规律相同,进位?和?与运算?规律相同(并需左移一位),可得:
所以a + b = n +c ,循环求 n 和 c ,直到进位c = 0,最终 a+b = n。
C++代码:
class Solution {
public:
int add(int a, int b) {
while(b)
{
int c = (unsigned)(a & b) << 1;
a ^= b;
b = c;
}
return a;
}
};
题目:
一个整型数组?nums
?里除两个数字之外,其他数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。
示例:
输入:nums = [4,1,4,6]
输出:[1,6] 或 [6,1]
解题思路:?
位运算(或者哈希表)
C++代码:
class Solution {
public:
vector<int> singleNumbers(vector<int>& nums) {
int n = 0;
for(int i = 0; i < nums.size(); i++)
n ^= nums[i];
int m = 1;
while((m & n) == 0)
m <<= 1;
int x = 0;
int y = 0;
for(int i = 0; i < nums.size(); i++)
{
if(nums[i] & m) x ^= nums[i];
else y ^= nums[i];
}
return {x, y};
}
};
题目:
在一个数组?nums
?中除一个数字只出现一次之外,其他数字都出现了三次。请找出那个只出现一次的数字。
示例:
输入:nums = [3,4,3,3]
输出:4
解题思路:?
位运算(或者哈希表)
C++代码:
class Solution {
public:
int singleNumber(vector<int>& nums) {
int counts[32] = {0};
for(int i = 0; i < nums.size(); i++)
{
for(int j = 0; j < 32; j++)
{
counts[j] += nums[i] & 1;
nums[i] >>= 1;
}
}
int res = 0;
for(int i = 31; i >= 0; i--)
{
res <<= 1;
res |= counts[i] % 3;
}
return res;
}
};
题目:
数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。
示例:
输入:[1, 2, 3, 2, 2, 2, 5, 4, 2]
输出:2
解题思路一:?
排序
C++代码:
class Solution {
public:
int majorityElement(vector<int>& nums) {
sort(nums.begin(), nums.end());
int k = nums.size();
return nums[(k-1)/2];
}
};
解题思路二:?
摩尔投票法
C++代码:
class Solution {
public:
int majorityElement(vector<int>& nums) {
int vector = 0;
int k = 0;
for(int i = 0; i < nums.size(); i++)
{
if(vector == 0) k = nums[i];
vector += (nums[i] == k ? 1:-1);
}
return k;
}
};
题目:
给定一个数组 A[0,1,…,n-1],请构建一个数组 B[0,1,…,n-1],其中?B[i] 的值是数组 A 中除了下标 i 以外的元素的积, 即?B[i]=A[0] × A[1] × … × A[i-1] × A[i+1] × … × A[n-1]。不能使用除法。
示例:
输入:[1,2,3,4,5]
输出:[120,60,40,30,24]
C++代码:
class Solution {
public:
vector<int> constructArr(vector<int>& a) {
if(a.size() == 0) return {};
vector<int> b(a.size(), 1);
b[0] = 1;
for(int i = 1; i < a.size(); i++)
{
b[i] = b[i-1] * a[i-1];
}
int mul = 1;
for(int i = a.size()-2; i >= 0; i--)
{
mul *= a[i+1];
b[i] *= mul;
}
return b;
}
};
题目:
给你一根长度为 n 的绳子,请把绳子剪成整数长度的 m 段(m、n都是整数,n>1并且m>1),每段绳子的长度记为 k[0],k[1]...k[m-1] 。请问 k[0]*k[1]*...*k[m-1] 可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。
示例:
输入:2
输出:1
解释:2 = 1 + 1, 1 × 1 = 1
解题思路:?
数学知识:
推论一:?将绳子?以相等的长度等分为多段?,得到的乘积最大。
推论二:?尽可能将绳子以长度?3?等分为多段时,乘积最大。
C++代码:
class Solution {
public:
int cuttingRope(int n) {
if(n <= 3) return n-1;
int cnt = n % 3, k = n / 3;
if(cnt == 0) return pow(3, k);
if(cnt == 1) return pow(3, k-1)*4;
return pow(3, k)*2;
}
};
题目:
输入一个正整数 target ,输出所有和为 target 的连续正整数序列(至少含有两个数)。
序列内的数字由小到大排列,不同序列按照首个数字从小到大排列。
示例:
输入:target = 9
输出:[[2,3,4],[4,5]]
解题思路:?
双指针
C++代码:
class Solution {
public:
vector<vector<int>> findContinuousSequence(int target) {
int i = 1, j = 2, sum = 3;
vector<vector<int>> res;
while(i < j)
{
if(sum == target)
{
vector<int> temp;
for(int k = i; k <= j; k++)
{
temp.push_back(k);
}
res.push_back(temp);
}
if(sum < target)
{
j++;
sum += j;
}
else
{
sum -= i;
i++;
}
}
return res;
}
};
题目:
0,1,···,n-1这n个数字排成一个圆圈,从数字0开始,每次从这个圆圈里删除第m个数字(删除后从下一个数字开始计数)。求出这个圆圈里剩下的最后一个数字。
例如,0、1、2、3、4这5个数字组成一个圆圈,从数字0开始每次删除第3个数字,则删除的前4个数字依次是2、0、4、1,因此最后剩下的数字是3。
示例:
输入:n = 5, m = 3
输出:3
解题思路:?
“约瑟夫环” 问题:
F[n] = ( F[n-1] + m ) % n?
C++代码:
class Solution {
public:
int lastRemaining(int n, int m) {
return dfs(n, m);
}
private:
int dfs(int n, int m)
{
if(n == 1)
return 0;
else
return (dfs(n-1, m) + m) % n;
}
};
题目:
输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字。
示例:
输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]
输出:[1,2,3,6,9,8,7,4,5]
C++代码:
class Solution {
public:
vector<int> spiralOrder(vector<vector<int>>& matrix) {
if (matrix.empty()) return {};
vector<int> res;
int l = 0, r = matrix[0].size() - 1;
int t = 0, b = matrix.size() - 1;
while(true)
{
//从左向右
for(int i = l; i <= r; i++) res.push_back(matrix[t][i]);
if(++t > b) break;
//从上向下
for(int i = t; i <= b; i++) res.push_back(matrix[i][r]);
if(--r < l) break;
//从右向左
for(int i = r; i >= l; i--) res.push_back(matrix[b][i]);
if(--b < t) break;
//从下向上
for(int i = b; i >= t; i--) res.push_back(matrix[i][l]);
if(++l > r) break;
}
return res;
}
};
题目:
输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如,序列 {1,2,3,4,5} 是某栈的压栈序列,序列 {4,5,3,2,1} 是该压栈序列对应的一个弹出序列,但 {4,3,5,1,2} 就不可能是该压栈序列的弹出序列。
示例:
输入:pushed = [1,2,3,4,5], popped = [4,5,3,2,1]
输出:true
解题思路:?
利用栈的特性:?每次入栈后,循环判断 “栈顶元素?==?弹出序列的当前元素” 是否成立,将符合弹出序列顺序的栈顶元素全部弹出。
C++代码:
class Solution {
public:
bool validateStackSequences(vector<int>& pushed, vector<int>& popped) {
stack<int> res;
int i = 0;
for(auto num: pushed)
{
res.push(num);
while(!res.empty() && res.top() == popped[i])
{
res.pop();
i++;
}
}
return res.empty();
}
};
题目:
请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。
示例:
输入:s = "0"
输出:true
C++代码:
class Solution {
public:
bool isNumber(string s) {
int i = 0;
while (s[i] == ' ')
i++;
if (s[i] == '+' || s[i] == '-')
i++;
//记录是否存在字符'.'
bool res = false;
if(s[i] == '.')
{
res = true;
i++;
}
if(s[i] < '0' || s[i] > '9')
return false;
while(s[i] >= '0' && s[i] <= '9')
i++;
if(s[i] == '.')
{
if(res)
return false;
else
{
i++;
while(s[i] >= '0' && s[i] <= '9')
i++;
}
}
if(s[i] == 'e' || s[i] == 'E')
{
i++;
if (s[i] == '+' || s[i] == '-')
i++;
if(s[i] < '0' || s[i] > '9')
return false;
while(s[i] >= '0' && s[i] <= '9')
i++;
}
while(s[i] == ' ')
i++;
if(s[i] == '\0')
return true;
else
return false;
}
};
题目:
写一个函数 StrToInt,实现把字符串转换成整数这个功能。不能使用 atoi 或者其他类似的库函数。
示例:
输入:"42"
输出:42
C++代码:
class Solution {
public:
int strToInt(string str) {
int insize = INT_MAX / 10;
int i = 0, len = str.size();
int res = 0;
//标记遇到的第一个数字是'+' 或 '-'
int sign = 1;
//当数组中没有元素时返回0
if(len == 0) return 0;
//当数组中元素全部是空格时返回0
while(str[i] == ' ')
{
if(++i == len) return 0;
}
if(str[i] == '-') sign = -1;
if(str[i] == '+' || str[i] == '-') i++;
for(int j = i; j < len; j++)
{
if(str[j] < '0' || str[j] > '9') break;
if(res > insize || (res == insize && str[j] > '7'))
return sign == 1 ? INT_MAX:INT_MIN;
res = res * 10 + (str[j] - '0');
}
return sign * res;
}
};
?题目源自: