LeetCode 66. Plus One
给定一个由整数组成的非空数组所表示的非负整数,在该数的基础上加一。
最高位数字存放在数组的首位, 数组中每个元素只存储一个数字。
你可以假设除了整数 0 之外,这个整数不会以零开头。
示例 1:
输入: [1,2,3]
输出: [1,2,4]
解释: 输入数组表示数字 123。
示例 2:
输入: [4,3,2,1]
输出: [4,3,2,2]
解释: 输入数组表示数字 4321。
class Solution {
public:
//高精度加法
vector<int> plusOne(vector<int>& digits) {
int t = 1;//进位
for(int i = digits.size() - 1; i >= 0; i--)
{
int &x = digits[i];
t += x;
x = t % 10;
t /= 10;
}
//最后还有进位,给最高位补上一
if(t)
{
digits.push_back(0);//在最后补上一位,下面数组往后移一位
for(int i = digits.size() - 1; i > 0; i--) digits[i] = digits[i - 1];
digits[0] = 1;
}
return digits;
}
};
LeetCode 326. Power of Three
给定一个整数,写一个函数来判断它是否是 3 的幂次方。
示例 1:
输入: 27
输出: true
示例 2:
输入: 0
输出: false
示例 3:
输入: 9
输出: true
示例 4:
输入: 45
输出: false
进阶:
你能不使用循环或者递归来完成本题吗?
class Solution {
public:
/*
int范围内 3^19 = 1162261467 以内最大3的整数幂 能整除 n 就是3的整数幂
*/
bool isPowerOfThree(int n) {
return n > 0 && 1162261467 % n == 0;
}
};
LeetCode 883. Projection Area of 3D Shapes
在 N * N 的网格中,我们放置了一些与 x,y,z 三轴对齐的 1 * 1 * 1 立方体。
每个值 v = grid[i][j] 表示 v 个正方体叠放在单元格 (i, j) 上。
现在,我们查看这些立方体在 xy、yz 和 zx 平面上的投影。
投影就像影子,将三维形体映射到一个二维平面上。
在这里,从顶部、前面和侧面看立方体时,我们会看到“影子”。
返回所有三个投影的总面积。
示例 1:
输入:[[2]]
输出:5
示例 2:
输入:[[1,2],[3,4]]
输出:17
解释:
这里有该形体在三个轴对齐平面上的三个投影(“阴影部分”)。
示例 3:
输入:[[1,0],[0,2]]
输出:8
示例 4:
输入:[[1,1,1],[1,0,1],[1,1,1]]
输出:14
示例 5:
输入:[[2,2,2],[2,1,2],[2,2,2]]
输出:21
提示:
1 <= grid.length = grid[0].length <= 50
0 <= grid[i][j] <= 50
class Solution {
public:
int projectionArea(vector<vector<int>>& grid) {
int n = grid.size(), m = grid[0].size();
if(!n || !m) return 0;
int res = 0;
for(int i = 0; i < n; i++)
for(int j = 0; j < m; j++)
//统计非0个数 从顶部看
res += !!grid[i][j]; //第一次非 把0->1 非0->0 第二次非 1->0 0->1
//从前看 累积求每一列的最大高度
for(int i = 0; i < n; i ++)
{
int h = 0;
for(int j = 0; j < m; j++) h = max(h, grid[i][j]);
res += h;
}
//从侧面看 与上面对称
for(int j = 0; j < m; j ++)
{
int h = 0;
for(int i = 0; i < n; i++) h = max(h, grid[i][j]);
res += h;
}
return res;
}
};
LeetCode 230. Kth Smallest Element in a BST
给定一个二叉搜索树,编写一个函数 kthSmallest 来查找其中第 k 个最小的元素。
说明:
你可以假设 k 总是有效的,1 ≤ k ≤ 二叉搜索树元素个数。
示例 1:
输入: root = [3,1,4,null,2], k = 1
3
/ \
1 4
\
2
输出: 1
示例 2:
输入: root = [5,3,6,2,4,null,null,1], k = 3
5
/ \
3 6
/ \
2 4
/
1
输出: 3
进阶:
如果二叉搜索树经常被修改(插入/删除操作)并且你需要频繁地查找第 k 小的值,你将如何优化 kthSmallest 函数?
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
/*
left = 左子树节点个数
1.if(k <= left) dfs(root->left, k); 递归遍历左子树求第k大元素
2.if k == left + 1 return root
3.if k > left + 1 dfs(root_right, k - left - 1); k减去左子树 减去根节点
*/
class Solution {
public:
//二叉搜索树 中序遍历从小到大排好序 即返回中序遍历的第k小元素
int kthSmallest(TreeNode* root, int k) {
return dfs(root, k);
}
int dfs(TreeNode* root, int &k) //加上&引用符号 没遍历一次减少k
{
if(!root) return 0;
int left = dfs(root->left, k);
if(k <= 0) return left; //k<0说明第k个点在左子树里面
if(--k == 0) return root->val;//k = 1 答案根节点
return dfs(root->right, k);
}
};
LeetCode 139. Word Break
给定一个非空字符串 s 和一个包含非空单词列表的字典 wordDict,判定 s 是否可以被空格拆分为一个或多个在字典中出现的单词。
说明:
拆分时可以重复使用字典中的单词。
你可以假设字典中没有重复的单词。
示例 1:
输入: s = “leetcode”, wordDict = [“leet”, “code”]
输出: true
解释: 返回 true 因为 “leetcode” 可以被拆分成 “leet code”。
示例 2:
输入: s = “applepenapple”, wordDict = [“apple”, “pen”]
输出: true
解释: 返回 true 因为 “applepenapple” 可以被拆分成 “apple pen apple”。
注意你可以重复使用字典中的单词。
示例 3:
输入: s = “catsandog”, wordDict = [“cats”, “dog”, “sand”, “and”, “cat”]
输出: false
/*
初始化: f[0] = true
状态表示:f[i] 表示前i个字母,是否存在一种合法的划分方案
状态转移:f[i] = true 当且仅当,存在某个j,使得s[j ... i] in wordDict,且f[j - 1] = true
*/
class Solution {
public:
bool wordBreak(string s, vector<string>& wordDict) {
unordered_set<string> S;
for(auto word : wordDict) S.insert(word);
int n = s.size();
vector<bool> f(n + 1, false);
f[0] = true;
for(int i = 1; i <= n; i++)
for(int j = 0; j < i; j++)
if(S.count(s.substr(j, i - j)) && f[j])
{
f[i] = true;
break;
}
return f[n];
}
};
LeetCode 930. Binary Subarrays With Sum
在由若干 0 和 1 组成的数组 A 中,有多少个和为 S 的非空子数组。
示例:
输入:A = [1,0,1,0,1], S = 2
输出:4
解释:
如下面黑体所示,有 4 个满足题目要求的子数组:
[1,0,1,0,1]
[1,0,1,0,1]
[1,0,1,0,1]
[1,0,1,0,1]
提示:
A.length <= 30000
0 <= S <= A.length
A[i] 为 0 或 1
/*
1.求前缀和 s[i] = A[0] + A[1] +...+ A[i - 1]
f[i] 表示当前有多少个j 满足s[j] = i 即表示s[]里面有多少个数的值是i
2.枚举 s[i] - s[j] = s a[j + 1... i]里面1的个数
s[i] - s = s[j] => f[s[i] - s]
*/
class Solution {
public:
int numSubarraysWithSum(vector<int>& A, int S) {
int n = A.size();
vector<int> sum(n + 1, 0), f(n + 1, 0);
for(int i = 0; i < n; i++) sum[i + 1] = sum[i] + A[i];
f[0] = 1;
int res = 0;
for(int i = 1; i <= n; i++)
{
if(sum[i] >= S) res += f[sum[i] - S];
f[sum[i]] ++;
}
return res;
}
};
LeetCode 228. Summary Ranges
给定一个无重复元素的有序整数数组,返回数组区间范围的汇总。
示例 1:
输入: [0,1,2,4,5,7]
输出: [“0->2”,“4->5”,“7”]
解释: 0,1,2 可组成一个连续的区间; 4,5 可组成一个连续的区间。
示例 2:
输入: [0,2,3,4,6,8,9]
输出: [“0”,“2->4”,“6”,“8->9”]
解释: 2,3,4 可组成一个连续的区间; 8,9 可组成一个连续的区间。
class Solution {
public:
string rangeToString(int st, int ed)
{
if(st == ed) return to_string(st);
return to_string(st) + "->" + to_string(ed);
}
vector<string> summaryRanges(vector<int>& nums) {
vector<string> res;
if(nums.empty()) return res;
int st = nums[0], ed = nums[0];
for(int i = 1; i < nums.size(); i ++)
{
int x = nums[i];
if(x > ed + 1)//断裂的区间
{
res.push_back(rangeToString(st, ed));
st = ed = x;
}
else ed++;
}
res.push_back(rangeToString(st, ed));
return res;
}
};
LeetCode 57. Insert Interval
给出一个无重叠的 ,按照区间起始端点排序的区间列表。
在列表中插入一个新的区间,你需要确保列表中的区间仍然有序且不重叠(如果有必要的话,可以合并区间)。
示例 1:
输入: intervals = [[1,3],[6,9]], newInterval = [2,5]
输出: [[1,5],[6,9]]
示例 2:
输入: intervals = [[1,2],[3,5],[6,7],[8,10],[12,16]], newInterval = [4,8]
输出: [[1,2],[3,10],[12,16]]
解释: 这是因为新的区间 [4,8] 与 [3,5],[6,7],[8,10] 重叠。
class Solution {
public:
vector<vector<int>> insert(vector<vector<int>>& intervals, vector<int>& newInterval) {
vector<vector<int>> res;
bool has_in = false;
for(auto interval : intervals)
{
if(interval[0] > newInterval[1]) //当前区间大于新区间右端点
{
if(!has_in)//如果新区间没有被插入 就插入
{
res.push_back(newInterval);
has_in = true;
}
res.push_back(interval);
}
else if(interval[1] < newInterval[0])//当前区间小于新区间左端点
{
res.push_back(interval);
}
else //中间求并集
{
newInterval[0] = min(newInterval[0], interval[0]);
newInterval[1] = max(newInterval[1], interval[1]);
}
}
if(!has_in) //新区间在所有区间的后面
res.push_back(newInterval);
return res;
}
};
LeetCode 224. Basic Calculator
实现一个基本的计算器来计算一个简单的字符串表达式的值。
字符串表达式可以包含左括号 ( ,右括号 ),加号 + ,减号 -,非负整数和空格 。
示例 1:
输入: “1 + 1”
输出: 2
示例 2:
输入: " 2-1 + 2 "
输出: 3
示例 3:
输入: “(1+(4+5+2)-3)+(6+8)”
输出: 23
说明:
你可以假设所给定的表达式都是有效的。
请不要使用内置的库函数 eval。
class Solution {
public:
//两个栈 一个操作符栈 一个数字栈
void calc(stack<char> &op, stack<int> &num) //把栈顶两个元素拿出来操作
{
int y = num.top();
num.pop();
int x = num.top();
num.pop();
if(op.top() == '+') num.push(x + y);
else num.push(x - y);
op.pop();
}
int calculate(string s) {
stack<char> op;
stack<int> num;
for(int i = 0; i < s.size(); i++)
{
char c = s[i];
if(c == ' ') continue;
if(c == '(' || c == '+' || c == '-') op.push(c);
else if(c == ')')
{
op.pop();
if(op.size() && op.top() != '(')
{
calc(op, num);
}
}
else
{
int j = i;
while(j < s.size() && isdigit(s[j])) j++;
num.push(atoi(s.substr(i, j - i).c_str()));
i = j - 1;
if(op.size() && op.top() != '(')
calc(op, num);
}
}
return num.top();
}
};
LeetCode 857. Minimum Cost to Hire K Workers
有 N 名工人。 第 i 名工人的工作质量为 quality[i] ,其最低期望工资为 wage[i] 。
现在我们想雇佣 K 名工人组成一个工资组。在雇佣 一组 K 名工人时,我们必须按照下述规则向他们支付工资:
1.对工资组中的每名工人,应当按其工作质量与同组其他工人的工作质量的比例来支付工资。
2.工资组中的每名工人至少应当得到他们的最低期望工资。
返回组成一个满足上述条件的工资组至少需要多少钱。
示例 1:
输入: quality = [10,20,5], wage = [70,50,30], K = 2
输出: 105.00000
解释: 我们向 0 号工人支付 70,向 2 号工人支付 35。
示例 2:
输入: quality = [3,1,10,10,1], wage = [4,8,2,2,7], K = 3
输出: 30.66667
解释: 我们向 0 号工人支付 4,向 2 号和 3 号分别支付 13.33333。
提示:
1.1 <= K <= N <= 10000,其中 N = quality.length = wage.length
2.1 <= quality[i] <= 10000
3.1 <= wage[i] <= 10000
4.与正确答案误差在 10^-5 之内的答案将被视为正确的。
/*
招的人
q'[0], q'[1], ... q'[k - 1]
给的薪资
q'[0] * x, q'[1] * x, ..., q'[k - 1] * x
总工资
(q'[0] + q'[1] +...+ q'[k - 1]) * x
x满足的条件
q[0] * x[0] >= w[0] => x[0] >= w[0] / q[0]
x[i] >= w[i] / q[i]
最优解
把所有工人按x[i]从小到大排序
枚举每一个薪资 x = x[i] 此时可以满足所有0...i x[j] <= x
要总工资最小 从q[i]里面选择最小的k个工人 用大根堆
*/
class Solution {
public:
double mincostToHireWorkers(vector<int>& quality, vector<int>& wage, int K) {
int n = quality.size();
vector<pair<double, int>> workers;//第一元素记录比值 第二元素记录q
for(int i = 0; i < n; i ++)
workers.push_back({wage[i] * 1.0 / quality[i], quality[i]});
sort(workers.begin(), workers.end());
//priority_queue<int, vector<int>, greater<int>> heap;小根堆
priority_queue<int> heap;// 大根堆
double res = 1e9;
int sum = 0;// q的和
for(auto worker : workers) //把worker 插入堆里面
{
heap.push(worker.second);
sum += worker.second;
if(heap.size() > K)
{
sum -= heap.top();
heap.pop();
}
if(heap.size() == K) res = min(res, sum * worker.first);
}
return res;
}
};