目录
202. 快乐数
203. 移除链表元素
204. 计数质数
206. 反转链表
剑指 Offer 24. 反转链表 力扣OJ 剑指 Offer(1-30)_nameofcsdn的博客-CSDN博客
207. 课程表
209. 长度最小的子数组
给定一个含有 n 个正整数的数组和一个正整数 target 。
找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。
示例 1:
输入:target = 7, nums = [2,3,1,2,4,3]
输出:2
解释:子数组 [4,3] 是该条件下的长度最小的子数组。
示例 2:
输入:target = 4, nums = [1,4,4]
输出:1
示例 3:
输入:target = 11, nums = [1,1,1,1,1,1,1,1]
输出:0
提示:
1 <= target <= 109
1 <= nums.length <= 105
1 <= nums[i] <= 105
class Solution:
def minSubArrayLen(self, target: int, nums: List[int]) -> int:
s = e = 0
sum = nums[0]
ans = len(nums)+1
while s < len(nums) and e < len(nums):
if sum >= target:
ans = min(ans, e-s+1)
s += 1
sum -= nums[s - 1]
else:
e += 1
if e < len(nums):
sum += nums[e]
if ans == len(nums)+1:
return 0
return ans
210. 课程表 II
214. 最短回文串
散列表 散列表(哈希表)_nameofcsdn的博客-CSDN博客
215. 数组中的第K个最大元素
216. 组合总和 III
217. 存在重复元素
给你一个整数数组 nums 。如果任一值在数组中出现 至少两次 ,返回 true ;如果数组中每个元素互不相同,返回 false 。
示例 1:
输入:nums = [1,2,3,1]
输出:true
示例 2:
输入:nums = [1,2,3,4]
输出:false
示例 3:
输入:nums = [1,1,1,3,3,4,3,2,4,2]
输出:true
提示:
1 <= nums.length <= 105
-109 <= nums[i] <= 109
class Solution:
def containsDuplicate(self, nums: List[int]) -> bool:
dict={}
for i in range (0, len(nums)):
if dict.get(nums[i],'-1') == 0:
return True
dict[nums[i]] = 0
return False
222. 完全二叉树的节点个数
完全二叉树 完全二叉树_nameofcsdn的博客-CSDN博客_完全二叉树代码
223. 矩形面积
225. 用队列实现栈
使用队列实现栈的下列操作:
push(x) -- 元素 x 入栈
pop() -- 移除栈顶元素
top() -- 获取栈顶元素
empty() -- 返回栈是否为空
注意:
你只能使用队列的基本操作-- 也就是 push to back, peek/pop from front, size, 和 is empty 这些操作是合法的。
你所使用的语言也许不支持队列。 你可以使用 list 或者 deque(双端队列)来模拟一个队列 , 只要是标准的队列操作即可。
你可以假设所有操作都是有效的(例如, 对一个空的栈不会调用 pop 或者 top 操作)。
class MyStack {
public:
queue<int>q;
int thetop;
void clear()
{
while(q.size())q.pop();
}
MyStack() {
clear();
}
void push(int x) {
q.push(thetop=x);
}
int pop() {
queue<int>q2=q;
clear();
while(q2.size()>1)
{
q.push(thetop=q2.front());
q2.pop();
}
return q2.front();
}
int top() {
return thetop;
}
bool empty() {
return q.empty();
}
};
226. 翻转二叉树
231. 2的幂
题目:
给定一个整数,编写一个函数来判断它是否是 2 的幂次方。
示例 1:
输入: 1
输出: true
解释: 20 = 1
示例 2:
输入: 16
输出: true
解释: 24 = 16
示例 3:
输入: 218
输出: false
代码:
class Solution {
public:
bool isPowerOfTwo(int n) {
return (n>0 && (n&(-n))==n);
}
};
232. 用栈实现队列
请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(push
、pop
、peek
、empty
):
实现 MyQueue
类:
void push(int x)
将元素 x 推到队列的末尾int pop()
从队列的开头移除并返回元素int peek()
返回队列开头的元素boolean empty()
如果队列为空,返回true
;否则,返回false
说明:
- 你 只能 使用标准的栈操作 —— 也就是只有
push to top
,peek/pop from top
,size
, 和is empty
操作是合法的。 - 你所使用的语言也许不支持栈。你可以使用 list 或者 deque(双端队列)来模拟一个栈,只要是标准的栈操作即可。
示例 1:
输入: ["MyQueue", "push", "push", "peek", "pop", "empty"] [[], [1], [2], [], [], []] 输出: [null, null, null, 1, 1, false] 解释: MyQueue myQueue = new MyQueue(); myQueue.push(1); // queue is: [1] myQueue.push(2); // queue is: [1, 2] (leftmost is front of the queue) myQueue.peek(); // return 1 myQueue.pop(); // return 1, queue is [2] myQueue.empty(); // return false
提示:
1 <= x <= 9
- 最多调用
100
次push
、pop
、peek
和empty
- 假设所有操作都是有效的 (例如,一个空的队列不会调用
pop
或者peek
操作)
进阶:
- 你能否实现每个操作均摊时间复杂度为
O(1)
的队列?换句话说,执行n
个操作的总时间复杂度为O(n)
,即使其中一个操作可能花费较长时间。
class MyQueue {
public:
void push(int value) {
s1.push(value);
}
int pop() {
int ans;
if(s2.size())
{
ans=s2.top();
s2.pop();
return ans;
}
if(!s1.size())return -1;
while(s1.size())
{
s2.push(s1.top());
s1.pop();
}
return pop();
}
int peek() {
if(s2.size())
{
return s2.top();
}
if(!s1.size())return -1;
while(s1.size())
{
s2.push(s1.top());
s1.pop();
}
return peek();
}
bool empty() {
return s1.empty() && s2.empty();
}
private:
stack<int>s1,s2;
};
233. 数字 1 的个数
234. 回文链表
235. 二叉搜索树的最近公共祖先
236. 二叉树的最近公共祖先
239. 滑动窗口最大值
240. 搜索二维矩阵 II
剑指 Offer 04. 二维数组中的查找 https://blog.csdn.net/nameofcsdn/article/details/113202911
242. 有效的字母异位词
哈希表 散列表(哈希表)_nameofcsdn的博客-CSDN博客
243. 最短单词距离
给定一个字符串数组 wordDict 和两个已经存在于该数组中的不同的字符串 word1 和 word2 。返回列表中这两个单词之间的最短距离。
示例 1:
输入: wordsDict = ["practice", "makes", "perfect", "coding", "makes"], word1 = "coding", word2 = "practice"
输出: 3
示例 2:
输入: wordsDict = ["practice", "makes", "perfect", "coding", "makes"], word1 = "makes", word2 = "coding"
输出: 1
提示:
1 <= wordsDict.length <= 3 * 104
1 <= wordsDict[i].length <= 10
wordsDict[i] 由小写英文字母组成
word1 和 word2 在 wordsDict 中
word1 != word2
class Solution {
public:
int shortestDistance(vector<string>& wordsDict, string word1, string word2) {
vector<int>v;
for (int i = 0; i < wordsDict.size(); i++)if (wordsDict[i] == word1 || wordsDict[i] == word2) {
v.push_back(i);
}
int ans = wordsDict.size();
for (int i = 1; i < v.size(); i++)if (wordsDict[v[i]] != wordsDict[v[i - 1]]) {
ans = min(ans, v[i] - v[i - 1]);
}
return ans;
}
};
244. 最短单词距离 II
245. 最短单词距离 III
246. 中心对称数
247. 中心对称数 II
给定一个整数 n
,返回所有长度为 n
的 中心对称数 。你可以以 任何顺序 返回答案。
中心对称数 是一个数字在旋转了 180
度之后看起来依旧相同的数字(或者上下颠倒地看)。
示例 1:
输入:n = 2 输出:["11","69","88","96"]
示例 2:
输入:n = 1 输出:["0","1","8"]
提示:
1 <= n <= 14
class Solution {
public:
vector<string> findStrobogrammatic(int n) {
if (n == 1)return vector<string>{"0", "1", "8"};
string s = "1";
map<int, string>m;
m[0] = "689";
for (int i = 1; i < n / 2; i++)s += '0', m[i] = "1689";
if (n % 2)s += '0', m[n / 2] = "18";
auto v = SubMeiJu(s, s.length(), m);
map<char, char>m2;
m2['1'] = '1', m2['0'] = '0', m2['8'] = '8', m2['6'] = '9', m2['9'] = '6';
for (auto& vi : v) {
for (int j = n / 2 - 1; j >= 0; j--)vi += m2[vi[j]];
}
return v;
}
};
248. 中心对称数 III
给定两个字符串 low 和 high 表示两个整数 low
和 high
,其中 low <= high
,返回 范围 [low, high]
内的 「中心对称数」总数 。
中心对称数 是一个数字在旋转了 180
度之后看起来依旧相同的数字(或者上下颠倒地看)。
示例 1:
输入: low = "50", high = "100" 输出: 3
示例 2:
输入: low = "0", high = "0" 输出: 1
提示:
1 <= low.length, high.length <= 15
low
和high
只包含数字low <= high
low
andhigh
不包含任何前导零,除了零本身。
思路:
直接用247. 中心对称数 II的代码生成所有对称数,再二分搜索。
bool cmp(const string& s1, const string& s2) {
if (s1.length() == s2.length())return s1 < s2;
return s1.length() < s2.length();
}
vector<string> findStrobogrammatic(int n) {
if (n == 1)return vector<string>{"0", "1", "8"};
string s = "1";
map<int, string>m;
m[0] = "689";
for (int i = 1; i < n / 2; i++)s += '0', m[i] = "1689";
if (n % 2)s += '0', m[n / 2] = "18";
auto v = SubMeiJu(s, s.length(), m);
map<char, char>m2;
m2['1'] = '1', m2['0'] = '0', m2['8'] = '8', m2['6'] = '9', m2['9'] = '6';
for (auto& vi : v) {
for (int j = n / 2 - 1; j >= 0; j--)vi += m2[vi[j]];
}
return v;
}
vector<string> f15()
{
vector<string> ans(312499);
int id = 0;
for (int i = 1; i <= 15; i++) {
auto v = findStrobogrammatic(i);
sort(v.begin(), v.end(), cmp);
copy(v.begin(), v.end(), ans.begin() + id);
id += v.size();
}
return ans;
}
vector<string> ans = f15();
class Solution {
public:
int strobogrammaticInRange(string low, string high) {
int id1 = lower_bound(ans.begin(), ans.end(), low, cmp) - ans.begin();
int id2 = upper_bound(ans.begin(), ans.end(), high, cmp) - ans.begin();
return id2 - id1;
}
};
249. 移位字符串分组
给定一个字符串,对该字符串可以进行 “移位” 的操作,也就是将字符串中每个字母都变为其在字母表中后续的字母,比如:"abc" -> "bcd"
。这样,我们可以持续进行 “移位” 操作,从而生成如下移位序列:
"abc" -> "bcd" -> ... -> "xyz"
给定一个包含仅小写字母字符串的列表,将该列表中所有满足 “移位” 操作规律的组合进行分组并返回。
示例:
输入:["abc", "bcd", "acef", "xyz", "az", "ba", "a", "z"]
输出:
[
["abc","bcd","xyz"],
["az","ba"],
["acef"],
["a","z"]
]
解释:可以认为字母表首尾相接,所以 'z' 的后续为 'a',所以 ["az","ba"] 也满足 “移位” 操作规律。
class Solution {
public:
vector<vector<string>> groupStrings(vector<string>& v) {
map<vector<int>, vector<string>>m;
for (auto s : v)m[dif(s)].push_back(s);
vector<vector<string>>ans;
for (auto mi : m)ans.push_back(mi.second);
return ans;
}
vector<int>dif(string& s) {
vector<int>v;
for (int i = 1; i < s.length(); i++)v.push_back((s[i] - s[i - 1] + 26) % 26);
return v;
}
};
250. 统计同值子树
252. 会议室
253. 会议室 II
254. 因子的组合
整数可以被看作是其因子的乘积。
例如:
8 = 2 x 2 x 2;
= 2 x 4.
请实现一个函数,该函数接收一个整数 n 并返回该整数所有的因子组合。
注意:
你可以假定 n 为永远为正数。
因子必须大于 1 并且小于 n。
示例 1:
输入: 1
输出: []
示例 2:
输入: 37
输出: []
示例 3:
输入: 12
输出:
[
[2, 6],
[2, 2, 3],
[3, 4]
]
示例 4:
输入: 32
输出:
[
[2, 16],
[2, 2, 8],
[2, 2, 2, 4],
[2, 2, 2, 2, 2],
[2, 4, 4],
[4, 8]
]
class Solution {
public:
vector<vector<int>> dfs(int n, int minfac)
{
vector<vector<int>> ans;
for (int d = minfac; d*d <= n; d++) {
if (n % d == 0) {
vector<vector<int>> ans2 = dfs(n / d, d);
ans2.push_back({ n / d });
for (auto &ai : ans2)ai.insert(ai.begin(), d);
ans = FvecJoin <vector<int>>(ans, ans2);
}
}
return ans;
}
vector<vector<int>> getFactors(int n) {
return dfs(n, 2);
}
};
255. 验证前序遍历序列二叉搜索树
二叉搜索树 二叉搜索树(BST)_nameofcsdn的博客-CSDN博客
256. 粉刷房子
258. 各位相加
259. 较小的三数之和
260. 只出现一次的数字 III
261. 以图判树
263. 丑数
264. 丑数 II
265. 粉刷房子 II
266. 回文排列
给你一个字符串 s
,如果该字符串的某个排列是 回文 ,则返回 true
;否则,返回 false
。
示例 1:
输入:s = "code" 输出:false
示例 2:
输入:s = "aab" 输出:true
示例 3:
输入:s = "carerac" 输出:true
提示:
1 <= s.length <= 5000
s
仅由小写英文字母组成
class Solution {
public:
bool canPermutePalindrome(string s) {
map<char,int>m;
for(auto c:s)m[c]++;
int n=0;
for(auto mi:m)n+=mi.second%2;
return n<2;
}
};
267. 回文排列 II
给定一个字符串 s
,返回 其重新排列组合后可能构成的所有回文字符串,并去除重复的组合 。
你可以按 任意顺序 返回答案。如果 s
不能形成任何回文排列时,则返回一个空列表。
示例 1:
输入: s ="aabb"
输出:["abba", "baab"]
示例 2:
输入: s ="abc"
输出:[]
提示:
1 <= s.length <= 16
s
仅由小写英文字母组成
class Solution {
public:
vector<string> generatePalindromes(string s) {
if(s.length()==1)return vector<string>{s};
map<char, int>m;
for (auto c : s)m[c]++;
char c = 0;
vector<char>v;
for (auto mi : m) {
if (mi.second % 2) {
if (c)return vector<string>{};
c = mi.first;
}
for (int i = 0; i < mi.second / 2; i++)v.push_back(mi.first);
}
vector<vector<char>> v2 = GetAllPermutation(v, v.size(), true);
vector<string>ans;
for (auto& vi : v2) {
string s1, s2;
for (auto c : vi) {
s1 += c, s2 = c + s2;
}
if (c)s1 += c;
ans.push_back(s1 + s2);
}
return ans;
}
};
268. 缺失数字
数组和集合的搜索 数组和集合的搜索_nameofcsdn的博客-CSDN博客
269. 火星词典
270. 最接近的二叉搜索树值
271. 字符串的编码与解码
请你设计一个算法,可以将一个 字符串列表 编码成为一个 字符串。这个编码后的字符串是可以通过网络进行高效传送的,并且可以在接收端被解码回原来的字符串列表。
1 号机(发送方)有如下函数:
string encode(vector<string> strs) { // ... your code return encoded_string; }
2 号机(接收方)有如下函数:
vector<string> decode(string s) { //... your code return strs; }
1 号机(发送方)执行:
string encoded_string = encode(strs);
2 号机(接收方)执行:
vector<string> strs2 = decode(encoded_string);
此时,2 号机(接收方)的 strs2
需要和 1 号机(发送方)的 strs
相同。
请你来实现这个 encode
和 decode
方法。
注意:
- 因为字符串可能会包含 256 个合法 ascii 字符中的任何字符,所以您的算法必须要能够处理任何可能会出现的字符。
- 请勿使用 “类成员”、“全局变量” 或 “静态变量” 来存储这些状态,您的编码和解码算法应该是非状态依赖的。
- 请不要依赖任何方法库,例如
eval
又或者是serialize
之类的方法。本题的宗旨是需要您自己实现 “编码” 和 “解码” 算法。
class Codec {
public:
// Encodes a list of strings to a single string.
string encode(vector<string>& strs) {
string ans=to_string(strs.size())+"#";
for(auto s:strs){
ans+=to_string(s.length())+"#";
}
for(auto s:strs){
ans+=s;
}
return ans;
}
vector<string> decode(string s) {
int slen = getFirstInt(s,'#');
vector<int>lens;
for(int i=0;i<slen;i++){
lens.push_back(getFirstInt(s,'#'));
}
vector<string>ans;
for(int i=0;i<slen;i++){
ans.push_back(s.substr(0,lens[i]));
s=s.substr(lens[i],s.length()-lens[i]);
}
return ans;
}
int getFirstInt(string &s,char c)
{
for(int i=0;i<10;i++){
if(s[i]==c){
int ans=atoi(s.substr(0,i).data());
s=s.substr(i+1,s.length()-i-1);
return ans;
}
}
return 0;
}
};
273. 整数转换英文表示
将非负整数 num
转换为其对应的英文表示。
示例 1:
输入:num = 123 输出:"One Hundred Twenty Three"
示例 2:
输入:num = 12345 输出:"Twelve Thousand Three Hundred Forty Five"
示例 3:
输入:num = 1234567 输出:"One Million Two Hundred Thirty Four Thousand Five Hundred Sixty Seven"
提示:
0 <= num <= 231 - 1
class Solution {
public:
string numberToWords(int num) {
if(!num)return "Zero";
int a = num % 1000;
num /= 1000;
int b = num % 1000;
num /= 1000;
int c = num % 1000, d = num / 1000;
string ans;
if (d)ans = numberToWords2(d) + " Billion ";
if (c)ans += numberToWords2(c) + " Million ";
if (b)ans += numberToWords2(b) + " Thousand ";
if (a)ans += numberToWords2(a) + " ";
return ans.substr(0, ans.length() - 1);
}
string numberToWords2(int n) {
int a = n / 100, b = n % 100;
string ans;
if (a)ans = numberToWords3(a) + " Hundred";
if (!b) return ans;
if (ans != "")ans += " ";
if (b < 20)ans += numberToWords3(b);
else {
int c = b / 10 * 10, d = b % 10;
ans += numberToWords3(c);
if (d)ans += " " + numberToWords3(d);
}
return ans;
}
string numberToWords3(int n) {
switch (n) {
case 1:
return "One";
case 2:
return "Two";
case 3:
return "Three";
case 4:
return "Four";
case 5:
return "Five";
case 6:
return "Six";
case 7:
return "Seven";
case 8:
return "Eight";
case 9:
return "Nine";
case 10:
return "Ten";
case 11:
return "Eleven";
case 12:
return "Twelve";
case 13:
return "Thirteen";
case 14:
return "Fourteen";
case 15:
return "Fifteen";
case 16:
return "Sixteen";
case 17:
return "Seventeen";
case 18:
return "Eighteen";
case 19:
return "Nineteen";
case 20:
return "Twenty";
case 30:
return "Thirty";
case 40:
return "Forty";
case 50:
return "Fifty";
case 60:
return "Sixty";
case 70:
return "Seventy";
case 80:
return "Eighty";
case 90:
return "Ninety";
}
return "";
}
};
274. H 指数
275. H 指数 II
276. 栅栏涂色
279. 完全平方数
拉格朗日四平方和定理 拉格朗日四平方和定理_nameofcsdn的博客-CSDN博客_拉格朗日四平方和定理
280. 摆动排序
给你一个的整数数组 nums, 将该数组重新排序后使 nums[0] <= nums[1] >= nums[2] <= nums[3]...
输入数组总是有一个有效的答案。
示例 1:
输入:nums = [3,5,2,1,6,4]
输出:[3,5,1,6,2,4]
解释:[1,6,2,5,3,4]也是有效的答案
示例 2:
输入:nums = [6,6,5,6,3,8]
输出:[6,6,5,6,3,8]
提示:
1 <= nums.length <= 5 * 104
0 <= nums[i] <= 104
输入的 nums 保证至少有一个答案。
进阶:你能在 O(n) 时间复杂度下解决这个问题吗?
class Solution {
public:
void wiggleSort(vector<int>& nums) {
for (int i = 1; i < nums.size(); i++)
{
if (i % 2 && nums[i - 1] > nums[i])nums[i - 1] ^= nums[i] ^= nums[i - 1] ^= nums[i];
if(i % 2==0 && nums[i - 1] < nums[i])nums[i - 1] ^= nums[i] ^= nums[i - 1] ^= nums[i];
}
}
};
285. 二叉搜索树中的中序后继
二叉搜索树 二叉搜索树(BST)_nameofcsdn的博客-CSDN博客
287. 寻找重复数
290. 单词规律
给定一种规律 pattern 和一个字符串 s ,判断 s 是否遵循相同的规律。
这里的 遵循 指完全匹配,例如, pattern 里的每个字母和字符串 str 中的每个非空单词之间存在着双向连接的对应规律。
示例1:
输入: pattern = "abba", str = "dog cat cat dog"
输出: true
示例 2:
输入:pattern = "abba", str = "dog cat cat fish"
输出: false
示例 3:
输入: pattern = "aaaa", str = "dog cat cat dog"
输出: false
提示:
1 <= pattern.length <= 300
pattern 只包含小写英文字母
1 <= s.length <= 3000
s 只包含小写英文字母和 ' '
s 不包含 任何前导或尾随对空格
s 中每个单词都被 单个空格 分隔
class Solution {
public:
bool wordPattern(string pattern, string s) {
vector<string> vs = StringSplit(s);
if (pattern.length() != vs.size())return false;
map<char, string>m;
for (int i = 0; i < vs.size(); i++) {
if (m[pattern[i]] != "" && m[pattern[i]] != vs[i])return false;
m[pattern[i]] = vs[i];
}
map<string, int>m2;
for (auto &it : m)m2[it.second] = 1;
return m.size() == m2.size();
}
};
291. 单词规律 II
给你一种规律 pattern 和一个字符串 s,请你判断 s 是否和 pattern 的规律相匹配。
如果存在单个字符到字符串的 双射映射 ,那么字符串 s 匹配 pattern ,即:如果pattern 中的每个字符都被它映射到的字符串替换,那么最终的字符串则为 s 。双射 意味着映射双方一一对应,不会存在两个字符映射到同一个字符串,也不会存在一个字符分别映射到两个不同的字符串。
示例 1:
输入:pattern = "abab", s = "redblueredblue"
输出:true
解释:一种可能的映射如下:
'a' -> "red"
'b' -> "blue"
示例 2:
输入:pattern = "aaaa", s = "asdasdasdasd"
输出:true
解释:一种可能的映射如下:
'a' -> "asd"
示例 3:
输入:pattern = "aabb", s = "xyzabcxzyabc"
输出:false
提示:
1 <= pattern.length, s.length <= 20
pattern 和 s 由小写英文字母组成
class Solution {
public:
map<string, int>m2;
bool dfs(string pattern, string s, int deep, int loc, map<char,string>m)
{
if (deep == pattern.length() && loc == s.length())return true;
if (deep == pattern.length() || loc == s.length())return false;
int len = m[pattern[deep]].length();
if (len) {
if (s.length() < loc + len)return false;
string sub = s.substr(loc, len);
if (m[pattern[deep]] != sub)return false;
return dfs(pattern, s, deep + 1, loc + len, m);
}
for (len = 1; len <= s.length() - loc; len++) { //上限还可以优化一些
string sub = s.substr(loc, len);
m[pattern[deep]] = sub;
if (m2[sub])continue;
m2[sub] = 1;
if (dfs(pattern, s, deep + 1, loc + len, m))return true;
m2[sub] = 0;
}
return false;
}
bool wordPatternMatch(string pattern, string s) {
return dfs(pattern, s, 0, 0, map<char, string>());
}
};
292. Nim 游戏
293. 翻转游戏
294. 翻转游戏 II
295. 数据流的中位数
296. 最佳的碰头地点
给你一个 m x n 的二进制网格 grid ,其中 1 表示某个朋友的家所处的位置。返回 最小的 总行走距离 。
总行走距离 是朋友们家到碰头地点的距离之和。
我们将使用 曼哈顿距离 来计算,其中 distance(p1, p2) = |p2.x - p1.x| + |p2.y - p1.y| 。
示例 1:
输入: grid = [[1,0,0,0,1],[0,0,0,0,0],[0,0,1,0,0]]
输出: 6
解释: 给定的三个人分别住在(0,0),(0,4) 和 (2,2):
(0,2) 是一个最佳的碰面点,其总行走距离为 2 + 2 + 2 = 6,最小,因此返回 6。
示例 2:
输入: grid = [[1,1]]
输出: 1
提示:
m == grid.length
n == grid[i].length
1 <= m, n <= 200
grid[i][j] == 0 or 1.
grid 中 至少 有两个朋友
思路:
其实2个维度是独立的,所以直接拆分成2个简单的一维问题。
class Solution {
public:
int minTotalDistance(vector<vector<int>>& grid) {
vector<int>vr, vc;
for (int i = 0; i < grid.size(); i++) {
for (int j = 0; j < grid[i].size(); j++) {
if (grid[i][j])vr.push_back(i), vc.push_back(j);
}
}
return MinSumLen(vr) + MinSumLen(vc);
}
};
297. 二叉树的序列化与反序列化
序列化是将一个数据结构或者对象转换为连续的比特位的操作,进而可以将转换后的数据存储在一个文件或者内存中,同时也可以通过网络传输到另一个计算机环境,采取相反方式重构得到原数据。
请设计一个算法来实现二叉树的序列化与反序列化。这里不限定你的序列 / 反序列化算法执行逻辑,你只需要保证一个二叉树可以被序列化为一个字符串并且将这个字符串反序列化为原始的树结构。
提示: 输入输出格式与 LeetCode 目前使用的方式一致,详情请参阅 LeetCode 序列化二叉树的格式。你并非必须采取这种方式,你也可以采用其他的方法解决这个问题。
示例 1:
输入:root = [1,2,3,null,null,4,5] 输出:[1,2,3,null,null,4,5]
示例 2:
输入:root = [] 输出:[]
示例 3:
输入:root = [1] 输出:[1]
示例 4:
输入:root = [1,2] 输出:[1,2]
提示:
- 树中结点数在范围
[0, 104]
内 -1000 <= Node.val <= 1000
class Codec {
public:
vector<int> serialize(TreeNode* root, int error) {
queue<TreeNode*>q;
q.push(root);
vector<int>ans;
while (!q.empty()) {
auto p = q.front();
q.pop();
if (p == nullptr) {
ans.push_back(error);
continue;
}
ans.push_back(p->val);
q.push(p->left);
q.push(p->right);
}
return ans;
}
TreeNode* deserialize(vector<int>v, int error) {
int id = 0;
TreeNode* root = nullptr;
queue<TreeNode**>q;
q.push(&root);
while (!q.empty()) {
auto p = q.front();
q.pop();
int val = v[id++];
if (val != error) {
*p = new TreeNode(val);
q.push(&((*p)->left));
q.push(&((*p)->right));
}
}
return root;
}
// Encodes a tree to a single string.
string serialize(TreeNode* root) {
auto v = serialize(root, 123456);
string s;
for (auto x : v)s += to_string(x) + " ";
return s;
}
// Decodes your encoded data to tree.
TreeNode* deserialize(string data) {
auto v = stringSplit(data);
vector<int>vals;
for (auto s : v)vals.push_back(atoi(s.data()));
return deserialize(vals, 123456);
}
};
298. 二叉树最长连续序列
299. 猜数字游戏
你在和朋友一起玩 猜数字(Bulls and Cows)游戏,该游戏规则如下:
写出一个秘密数字,并请朋友猜这个数字是多少。朋友每猜测一次,你就会给他一个包含下述信息的提示:
- 猜测数字中有多少位属于数字和确切位置都猜对了(称为 "Bulls",公牛),
- 有多少位属于数字猜对了但是位置不对(称为 "Cows",奶牛)。也就是说,这次猜测中有多少位非公牛数字可以通过重新排列转换成公牛数字。
给你一个秘密数字 secret
和朋友猜测的数字 guess
,请你返回对朋友这次猜测的提示。
提示的格式为 "xAyB"
,x
是公牛个数, y
是奶牛个数,A
表示公牛,B
表示奶牛。
请注意秘密数字和朋友猜测的数字都可能含有重复数字。
示例 1:
输入:secret = "1807", guess = "7810" 输出:"1A3B" 解释:数字和位置都对(公牛)用 '|' 连接,数字猜对位置不对(奶牛)的采用斜体加粗标识。 "1807" | "7810"
示例 2:
输入:secret = "1123", guess = "0111" 输出:"1A1B" 解释:数字和位置都对(公牛)用 '|' 连接,数字猜对位置不对(奶牛)的采用斜体加粗标识。 "1123" "1123" | or | "0111" "0111" 注意,两个不匹配的 1 中,只有一个会算作奶牛(数字猜对位置不对)。通过重新排列非公牛数字,其中仅有一个 1 可以成为公牛数字。
提示:
1 <= secret.length, guess.length <= 1000
secret.length == guess.length
secret
和guess
仅由数字组成
class Solution {
public:
string getHint(string secret, string guess) {
int a=0,b=0;
map<char,int>m,m2;
for(auto c:secret)m[c]++;
for(int i=0;i<guess.length();i++){
if(guess[i]==secret[i])a++;
m2[guess[i]]++;
}
for(auto mi:m2)b+=min(mi.second,m[mi.first]);
return to_string(a)+"A"+to_string(b-a)+"B";
}
};
300. 最长上升子序列
302. 包含全部黑色像素的最小矩形
303. 区域和检索 - 数组不可变
给定一个整数数组 nums
,处理以下类型的多个查询:
- 计算索引
left
和right
(包含left
和right
)之间的nums
元素的 和 ,其中left <= right
实现 NumArray
类:
NumArray(int[] nums)
使用数组nums
初始化对象int sumRange(int i, int j)
返回数组nums
中索引left
和right
之间的元素的 总和 ,包含left
和right
两点(也就是nums[left] + nums[left + 1] + ... + nums[right]
)
示例 1:
输入: ["NumArray", "sumRange", "sumRange", "sumRange"] [[[-2, 0, 3, -5, 2, -1]], [0, 2], [2, 5], [0, 5]] 输出: [null, 1, -1, -3] 解释: NumArray numArray = new NumArray([-2, 0, 3, -5, 2, -1]); numArray.sumRange(0, 2); // return 1 ((-2) + 0 + 3) numArray.sumRange(2, 5); // return -1 (3 + (-5) + 2 + (-1)) numArray.sumRange(0, 5); // return -3 ((-2) + 0 + 3 + (-5) + 2 + (-1))
提示:
1 <= nums.length <= 104
-105 <= nums[i] <= 105
0 <= i <= j < nums.length
- 最多调用
104
次sumRange
方法
class NumArray {
public:
NumArray(vector<int>& nums) {
v.clear();
int s = 0;
v.push_back(s);
for(auto x:nums)s+=x, v.push_back(s);
}
int sumRange(int left, int right) {
return v[right + 1] - v[left];
}
private:
vector<int>v;
};
304. 二维区域和检索 - 矩阵不可变
305. 岛屿数量 II
307. 区域和检索 - 数组可修改
309. 买卖股票的最佳时机含冷冻期
310. 最小高度树
311. 稀疏矩阵的乘法
给定两个 稀疏矩阵 :大小为 m x k
的稀疏矩阵 mat1
和大小为 k x n
的稀疏矩阵 mat2
,返回 mat1 x mat2
的结果。你可以假设乘法总是可能的。
示例 1:
输入:mat1 = [[1,0,0],[-1,0,3]], mat2 = [[7,0,0],[0,0,0],[0,0,1]] 输出:[[7,0,0],[-7,0,3]]
示例 2:
输入:mat1 = [[0]], mat2 = [[0]] 输出:[[0]]
提示:
m == mat1.length
k == mat1[i].length == mat2.length
n == mat2[i].length
1 <= m, n, k <= 100
-100 <= mat1[i][j], mat2[i][j] <= 100
class Solution {
public:
vector<vector<int>> multiply(vector<vector<int>>& mat1, vector<vector<int>>& mat2) {
int m = mat1.size(), k = mat2.size(), n = mat2[0].size();
vector<vector<int>>v(m, vector<int>(n));
for (int i = 0; i < k; i++) {
for (int j = 0; j < n; j++) {
if (mat2[i][j] == 0)continue;
for (int d = 0; d < m; d++)v[d][j] += mat1[d][i] * mat2[i][j];
}
}
return v;
}
};
313. 超级丑数
314. 二叉树的垂直遍历
317. 离建筑物最近的距离
给你一个 m × n
的网格,值为 0
、 1
或 2
,其中:
- 每一个
0
代表一块你可以自由通过的 空地 - 每一个
1
代表一个你不能通过的 建筑 - 每个
2
标记一个你不能通过的 障碍
你想要在一块空地上建造一所房子,在 最短的总旅行距离 内到达所有的建筑。你只能上下左右移动。
返回到该房子的 最短旅行距离 。如果根据上述规则无法建造这样的房子,则返回 -1
。
总旅行距离 是朋友们家到聚会地点的距离之和。
使用 曼哈顿距离 计算距离,其中距离 (p1, p2) = |p2.x - p1.x | + | p2.y - p1.y |
。
示例 1:
输入:grid = [[1,0,2,0,1],[0,0,0,0,0],[0,0,1,0,0]] 输出:7 解析:给定三个建筑物 (0,0)、
(0,4) 和
(2,2) 以及一个
位于(0,2) 的障碍物。 由于总距离之和 3+3+1=7 最优,所以位置
(1,2)
是符合要求的最优地点。 故返回7。
示例 2:
输入: grid = [[1,0]] 输出: 1
示例 3:
输入: grid = [[1]] 输出: -1
提示:
m == grid.length
n == grid[i].length
1 <= m, n <= 50
grid[i][j]
是0
,1
或2
grid
中 至少 有 一幢 建筑
注意!有毒!!
说好的是曼哈顿距离啊,于是我的思路一:
分2个核心功能,一个求出从哪些0出发,可以到达所有的1,另一个是求出任意位置到所有1的曼哈顿距离之和。
class Solution {
public:
void bfs(vector<vector<int>>& grid, int x, int y) {
int r = grid.size(), c = grid[0].size();
GridGraph gg(r, c);
if (ok[gg.gridId(x, y)]|| notok[gg.gridId(x, y)])return;
map<int, int>visit;
queue<int>q;
q.push(gg.gridId(x, y));
visit[gg.gridId(x, y)] = 1;
while (!q.empty()) {
int id = q.front();
q.pop();
for (auto neibor : gg.getNeighbor4(id)) {
if (visit[neibor])continue;
if (grid[neibor / c][neibor % c] <= 1)visit[neibor] = 1;
if (grid[neibor / c][neibor % c] == 0)q.push(neibor);
}
}
bool flag = true;
for (int i = 0; i < vx.size(); i++) {
if (visit[gg.gridId(vx[i], vy[i])] == 0)flag = false;
}
auto& m = flag ? ok : notok;
for (auto p : visit)m[p.first] = 1;
}
int shortestDistance(vector<vector<int>>& grid) {
int r = grid.size(), c = grid[0].size();
vx.clear(), vy.clear();
for (int i = 0; i < r; i++) { //先统计所有的1的位置
for (int j = 0; j < c; j++) {
if (grid[i][j] == 1)vx.push_back(i), vy.push_back(j);
}
}
auto sx = EverSumLen(vx, 0, r - 1), sy = EverSumLen(vy, 0, c - 1); // 再统计每个位置到所有1的距离
int ans = INT_MAX;
for (int i = 0; i < r; i++) {
for (int j = 0; j < c; j++) {
if (grid[i][j] == 0) {
bfs(grid, i, j);
if (ok[i * c + j])ans = min(ans, sx[i] + sy[j]);
}
}
}
return ans == INT_MAX ? -1 : ans;
}
vector<int>vx, vy;
map<int, int>ok;
map<int, int>notok;
};
提交了之后,根据错误用例,我才发现题目的意思是,从0到1的距离是一条除了终点是1之外其他全是0的路径的最短长度。
class Solution {
public:
inline int bfs(vector<vector<int>>& grid, int x, int y, int times) {
vector<int>len(r*c);
q.push(x*c+y);
len[x*c + y] = 1;
int num = 0;
static const vector<int> dx4{ 0,0,1,-1 };
static const vector<int> dy4{ 1,-1,0,0 };
while (!q.empty()) {
int id = q.front();
int x = id / c, y = id % c;
q.pop();
for (int i = 0; i < 4; i++) {
if (x + dx4[i] < 0 || x + dx4[i] >= r)continue;
if (y + dy4[i] < 0 || y + dy4[i] >= c)continue;
auto neibor = (x + dx4[i])*c + y + dy4[i];
if (len[neibor] == 0 && grid[neibor / c][neibor % c] == 0 && visitTimes[neibor]>=times) {
q.push(neibor);
sumLen[neibor] += len[id], len[neibor] = len[id] + 1;
visitTimes[neibor]++, num++;
}
}
}
return num;
}
int shortestDistance(vector<vector<int>>& grid) {
r = grid.size(), c = grid[0].size();
visitTimes.resize(r*c);
sumLen.resize(r*c);
vector<int>vx, vy;
int times = 0;
for (int i = 0; i < r; i++) { //先统计所有的1的位置
for (int j = 0; j < c; j++) {
if (grid[i][j] == 1) {
if (bfs(grid, i, j, times++) == 0)return -1;
}
}
}
int ans = INT_MAX;
for (int i = 0; i < r; i++) {
for (int j = 0; j < c; j++) {
if (grid[i][j])continue;
int id = i * c + j;
if (visitTimes[id]>= times)ans = min(ans, sumLen[id]);
}
}
return ans == INT_MAX ? -1 : ans;
}
vector<int>sumLen;
vector<int>visitTimes;
queue<int>q;
int r, c;
};
318. 最大单词长度乘积
319. 灯泡开关
321. 拼接最大数
322. 零钱兑换
323. 无向图中连通分量的数目
325. 和等于 k 的最长子数组长度
给定一个数组 nums 和一个目标值 k,找到和等于 k 的最长连续子数组长度。如果不存在任意一个符合要求的子数组,则返回 0。
示例 1:
输入: nums = [1,-1,5,-2,3], k = 3
输出: 4
解释: 子数组 [1, -1, 5, -2] 和等于 3,且长度最长。
示例 2:
输入: nums = [-2,-1,2,1], k = 1
输出: 2
解释: 子数组 [-1, 2] 和等于 1,且长度最长。
提示:
1 <= nums.length <= 2 * 105
-104 <= nums[i] <= 104
-109 <= k <= 109
class Solution {
public:
int maxSubArrayLen(vector<int>& nums, int k) {
map<int, int>m;
int s = 0, ans = 0;
for (int i = 0; i < nums.size(); i++)s += nums[i], m[s] = i+1;
s = 0;
nums.insert(nums.begin(), 0);
for (int i = 0; i < nums.size(); i++){
s += nums[i];
if(m[s + k])ans = max(ans, m[s + k] - i);
}
return ans;
}
};
326. 3的幂
题目:
给定一个整数,写一个函数来判断它是否是 3 的幂次方。
示例 1:
输入: 27
输出: true
示例 2:
输入: 0
输出: false
示例 3:
输入: 9
输出: true
示例 4:
输入: 45
输出: false
代码:
class Solution {
public:
bool isPowerOfThree(int n) {
if (n <= 0)return false;
while (n % 3 == 0)n /= 3;
return n == 1;
}
};
328. 奇偶链表
题目:
给定一个单链表,把所有的奇数节点和偶数节点分别排在一起。请注意,这里的奇数节点和偶数节点指的是节点编号的奇偶性,而不是节点的值的奇偶性。
请尝试使用原地算法完成。你的算法的空间复杂度应为 O(1),时间复杂度应为 O(nodes),nodes 为节点总数。
示例 1:
输入: 1->2->3->4->5->NULL
输出: 1->3->5->2->4->NULL
示例 2:
输入: 2->1->3->5->6->4->7->NULL
输出: 2->3->6->7->1->5->4->NULL
说明:
应当保持奇数节点和偶数节点的相对顺序。
链表的第一个节点视为奇数节点,第二个节点视为偶数节点,以此类推。
代码:
class Solution {
public:
ListNode* oddEvenList(ListNode* head) {
if (!head)return head;
ListNode* tail = head, *p1 = head, *p2 = p1->next, *evenHead = p2;
while (tail->next && tail->next->next)tail = tail->next->next;
while (p1!=tail && p2!=tail)
{
p1 = p1->next = p2->next, p2 = p2->next = p1->next;
}
tail->next = evenHead;
return head;
}
};
329. 矩阵中的最长递增路径
331. 验证二叉树的前序序列化
332. 重新安排行程
333. 最大 BST 子树
338. 比特位计数
题目:
给定一个非负整数 num。对于 0 ≤ i ≤ num 范围中的每个数字 i ,计算其二进制数中的 1 的数目并将它们作为数组返回。
示例 1:
输入: 2
输出: [0,1,1]
示例 2:
输入: 5
输出: [0,1,1,2,1,2]
进阶:
给出时间复杂度为O(n*sizeof(integer))的解答非常容易。但你可以在线性时间O(n)内用一趟扫描做到吗?
要求算法的空间复杂度为O(n)。
你能进一步完善解法吗?要求在C++或任何其他语言中不使用任何内置函数(如 C++ 中的 __builtin_popcount)来执行此操作。
代码:
class Solution {
public:
vector<int> countBits(int num) {
vector<int>ans;
ans.insert(ans.end(), 0);
for (int i = 1; i <= num; i++)
{
ans.insert(ans.end(), i % 2 + ans[i / 2]);
}
return ans;
}
};
340. 至多包含 K 个不同字符的最长子串
342. 4的幂
题目:
给定一个整数 (32 位有符号整数),请编写一个函数来判断它是否是 4 的幂次方。
示例 1:
输入: 16
输出: true
示例 2:
输入: 5
输出: false
进阶:
你能不使用循环或者递归来完成本题吗?
代码:
class Solution {
public:
bool isPowerOfFour(int n) {
if (n <= 0)return false;
while (n % 4 == 0)n /= 4;
return n == 1;
}
};
343. 整数拆分(快速幂)
快速乘法、快速幂、矩阵快速幂 快速乘法、快速幂、矩阵快速幂_nameofcsdn的博客-CSDN博客
344. 反转字符串
编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 s
的形式给出。
不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。
示例 1:
输入:s = ["h","e","l","l","o"] 输出:["o","l","l","e","h"]
示例 2:
输入:s = ["H","a","n","n","a","h"] 输出:["h","a","n","n","a","H"]
提示:
1 <= s.length <= 105
s[i]
都是 ASCII 码表中的可打印字符
class Solution {
public:
void reverseString(vector<char>& s) {
for(int i=0;i<s.size()/2;i++)s[i]^=s[s.size()-1-i]^=s[i]^=s[s.size()-1-i];
}
};
346. 数据流中的移动平均值
347. 前 K 个高频元素
题目:
给定一个非空的整数数组,返回其中出现频率前 k 高的元素。
示例 1:
输入: nums = [1,1,1,2,2,3], k = 2
输出: [1,2]
示例 2:
输入: nums = [1], k = 1
输出: [1]
说明:
你可以假设给定的 k 总是合理的,且 1 ≤ k ≤ 数组中不相同的元素的个数。
你的算法的时间复杂度必须优于 O(n log n) , n 是数组的大小。
代码:
struct dist
{
int num;
int fre;
};
struct cmp
{
bool operator()(dist a, dist b)
{
return a.fre < b.fre;
}
};
class Solution {
public:
vector<int> topKFrequent(vector<int>& nums, int k) {
map<int, int> m;
dist d;
priority_queue<dist, vector<dist>, cmp>que;
vector<int> ans;
for (auto it = nums.begin(); it != nums.end(); it++)
{
m[*it]++;
}
for (auto it = m.begin(); it != m.end(); it++)
{
d.num = (*it).first, d.fre = (*it).second, que.push(d);
}
while (k--)
{
ans.insert(ans.end(), que.top().num);
que.pop();
}
return ans;
}
};
348. 设计井字棋
请在 n × n 的棋盘上,实现一个判定井字棋(Tic-Tac-Toe)胜负的神器,判断每一次玩家落子后,是否有胜出的玩家。
在这个井字棋游戏中,会有 2 名玩家,他们将轮流在棋盘上放置自己的棋子。
在实现这个判定器的过程中,你可以假设以下这些规则一定成立:
1. 每一步棋都是在棋盘内的,并且只能被放置在一个空的格子里;
2. 一旦游戏中有一名玩家胜出的话,游戏将不能再继续;
3. 一个玩家如果在同一行、同一列或者同一斜对角线上都放置了自己的棋子,那么他便获得胜利。
示例:
给定棋盘边长 n = 3, 玩家 1 的棋子符号是 "X",玩家 2 的棋子符号是 "O"。
TicTacToe toe = new TicTacToe(3);
toe.move(0, 0, 1); -> 函数返回 0 (此时,暂时没有玩家赢得这场对决)
|X| | |
| | | | // 玩家 1 在 (0, 0) 落子。
| | | |
toe.move(0, 2, 2); -> 函数返回 0 (暂时没有玩家赢得本场比赛)
|X| |O|
| | | | // 玩家 2 在 (0, 2) 落子。
| | | |
toe.move(2, 2, 1); -> 函数返回 0 (暂时没有玩家赢得比赛)
|X| |O|
| | | | // 玩家 1 在 (2, 2) 落子。
| | |X|
toe.move(1, 1, 2); -> 函数返回 0 (暂没有玩家赢得比赛)
|X| |O|
| |O| | // 玩家 2 在 (1, 1) 落子。
| | |X|
toe.move(2, 0, 1); -> 函数返回 0 (暂无玩家赢得比赛)
|X| |O|
| |O| | // 玩家 1 在 (2, 0) 落子。
|X| |X|
toe.move(1, 0, 2); -> 函数返回 0 (没有玩家赢得比赛)
|X| |O|
|O|O| | // 玩家 2 在 (1, 0) 落子.
|X| |X|
toe.move(2, 1, 1); -> 函数返回 1 (此时,玩家 1 赢得了该场比赛)
|X| |O|
|O|O| | // 玩家 1 在 (2, 1) 落子。
|X|X|X|
进阶:
您有没有可能将每一步的 move() 操作优化到比 O(n2) 更快吗?
class TicTacToe {
public:
TicTacToe(int n) {
v.resize(n);
for (int i = 0; i < n; i++)for (int j = 0; j < n; j++)v[i].push_back(0);
}
int move(int row, int col, int player) {
v[row][col] = player;
bool flag = true;
for (int i = 0; i < v.size(); i++)if (v[row][i] != player)flag = false;
if (flag)return player;
flag = true;
for (int i = 0; i < v.size(); i++)if (v[i][col] != player)flag = false;
if (flag)return player;
flag = true;
for (int i = 0; i < v.size(); i++)if (v[i][i] != player)flag = false;
if (flag)return player;
flag = true;
for (int i = 0; i < v.size(); i++)if (v[i][v.size() - i - 1] != player)flag = false;
if (flag)return player;
return 0;
}
vector<vector<int>>v;
};
349. 两个数组的交集
350. 两个数组的交集 II
351. 安卓系统手势解锁
我们都知道安卓有个手势解锁的界面,是一个 3 x 3 的点所绘制出来的网格。用户可以设置一个 “解锁模式” ,通过连接特定序列中的点,形成一系列彼此连接的线段,每个线段的端点都是序列中两个连续的点。如果满足以下两个条件,则 k 点序列是有效的解锁模式:
解锁模式中的所有点 互不相同 。
假如模式中两个连续点的线段需要经过其他点的 中心 ,那么要经过的点 必须提前出现 在序列中(已经经过),不能跨过任何还未被经过的点。
例如,点 5 或 6 没有提前出现的情况下连接点 2 和 9 是有效的,因为从点 2 到点 9 的线没有穿过点 5 或 6 的中心。
然而,点 2 没有提前出现的情况下连接点 1 和 3 是无效的,因为从圆点 1 到圆点 3 的直线穿过圆点 2 的中心。
以下是一些有效和无效解锁模式的示例:
无效手势:[4,1,3,6] ,连接点 1 和点 3 时经过了未被连接过的 2 号点。
无效手势:[4,1,9,2] ,连接点 1 和点 9 时经过了未被连接过的 5 号点。
有效手势:[2,4,1,3,6] ,连接点 1 和点 3 是有效的,因为虽然它经过了点 2 ,但是点 2 在该手势中之前已经被连过了。
有效手势:[6,5,4,1,9,2] ,连接点 1 和点 9 是有效的,因为虽然它经过了按键 5 ,但是点 5 在该手势中之前已经被连过了。
给你两个整数,分别为 m 和 n ,那么请返回有多少种 不同且有效的解锁模式 ,是 至少 需要经过 m 个点,但是 不超过 n 个点的。
两个解锁模式 不同 需满足:经过的点不同或者经过点的顺序不同。
示例 1:
输入:m = 1, n = 1
输出:9
示例 2:
输入:m = 1, n = 2
输出:65
提示:
1 <= m, n <= 9
首先求出答案
bool ok(int num)
{
return num % 2 == 0 && num != 4;
}
bool ok(const vector<int>& num)
{
int n = num.size();
for (int i = 0; i < n - 1; i++)
{
if (num[i] + num[i + 1] == 8 || (ok(num[i]) && ok(num[i + 1]))) {
int k = (num[i] + num[i + 1]) / 2;
bool flag = false;
for (int j = 0; j < i; j++)if (num[j] == k)flag = true;
if (!flag)return false;
}
}
return true;
}
int f(int n)
{
vector<int>v(9);
for (int i = 0; i < 9; i++)v[i] = i;
vector<vector<int>> pers = GetAllPermutation(v, n, false);
int ans = 0;
for (auto& pi : pers) {
if (ok(pi))ans++;
}
return ans;
}
int main()
{
for (int i = 1; i <= 9; i++)cout << f(i) << ",";
return 0;
}
输出:9,56,320,1624,7152,26016,72912,140704,140704,
ps:这一步也可以用力扣的调试功能直接试出来。
再二次编程
class Solution {
public:
int numberOfPatterns(int m, int n) {
int ans[] = {0, 9, 56, 320, 1624, 7152, 26016, 72912, 140704, 140704};
int k=0;
for(int i=m;i<=n;i++)k+=ans[i];
return k;
}
};
356. 直线镜像
357. 统计各位数字都不同的数字个数
给你一个整数 n
,统计并返回各位数字都不同的数字 x
的个数,其中 0 <= x < 10n
。
示例 1:
输入:n = 2
输出:91
解释:答案应为除去 11、22、33、44、55、66、77、88、99
外,在 0 ≤ x < 100 范围内的所有数字。
示例 2:
输入:n = 0 输出:1
提示:
0 <= n <= 8
class Solution {
public:
int countNumbersWithUniqueDigits(int n) {
vector<int>v(9);
v[0]=1,v[1]=9;
for(int i=2;i<9;i++)v[i]=v[i-1]*(11-i);
for(int i=1;i<9;i++)v[i]+=v[i-1];
return v[n];
}
};
358. K 距离间隔重排字符串
给你一个非空的字符串 s 和一个整数 k ,你要将这个字符串 s 中的字母进行重新排列,使得重排后的字符串中相同字母的位置间隔距离 至少 为 k 。如果无法做到,请返回一个空字符串 ""。
示例 1:
输入: s = "aabbcc", k = 3
输出: "abcabc"
解释: 相同的字母在新的字符串中间隔至少 3 个单位距离。
示例 2:
输入: s = "aaabc", k = 3
输出: ""
解释: 没有办法找到可能的重排结果。
示例 3:
输入: s = "aaadbbcc", k = 2
输出: "abacabcd"
解释: 相同的字母在新的字符串中间隔至少 2 个单位距离。
提示:
1 <= s.length <= 3 * 105
s 仅由小写英文字母组成
0 <= k <= s.length
思路:
先把字母排序,然后按顺序去摆,先把出现次数多的字母按照间隔摆,然后再摆出现次数少的。
struct Node
{
char c;
int n;
};
bool cmp(Node a, Node b)
{
if (a.n == b.n)return a.c < b.c;
else return a.n > b.n;
}
class Solution {
public:
string rearrangeString(string s, int k) {
map<int, int>m;
for (int i = 0; i < s.length(); i++)m[s[i] - 'a']++;
int ma = 0;
for (int i = 0; i < 26; i++)ma = max(ma, m[i]);
int mn = 0;
for (int i = 0; i < 26; i++)if (m[i] == ma)mn++;
if (s.length() < (ma - 1)*k + mn)return "";
vector<Node>v;
char a = 'a';
Node nod;
for (int i = 0; i < 26; i++) {
nod.c = a + i, nod.n = m[i];
v.push_back(nod);
}
sort(v.begin(), v.end(), cmp);
string ans = s;
for (int i = 0; i < s.length(); i++)ans[i] = a - 1;
int loc = 0;
for (int i = 0; i < v.size(); i++)
{
for (int j = 0; j < v[i].n; j++) {
while (ans[loc] >= a) {
loc++;
if (loc >= s.length())loc = 0;
}
ans[loc] = v[i].c;
if(j<v[i].n-1)loc += k;
if (loc >= s.length())loc = 0;
}
}
return ans;
}
};
359. 日志速率限制器
请你设计一个日志系统,可以流式接收消息以及它的时间戳。每条 不重复 的消息最多只能每 10 秒打印一次。也就是说,如果在时间戳 t
打印某条消息,那么相同内容的消息直到时间戳变为 t + 10
之前都不会被打印。
所有消息都按时间顺序发送。多条消息可能到达同一时间戳。
实现 Logger
类:
Logger()
初始化logger
对象bool shouldPrintMessage(int timestamp, string message)
如果这条消息message
在给定的时间戳timestamp
应该被打印出来,则返回true
,否则请返回false
。
示例:
输入: ["Logger", "shouldPrintMessage", "shouldPrintMessage", "shouldPrintMessage", "shouldPrintMessage", "shouldPrintMessage", "shouldPrintMessage"] [[], [1, "foo"], [2, "bar"], [3, "foo"], [8, "bar"], [10, "foo"], [11, "foo"]] 输出: [null, true, true, false, false, false, true] 解释: Logger logger = new Logger(); logger.shouldPrintMessage(1, "foo"); // 返回 true ,下一次 "foo" 可以打印的时间戳是 1 + 10 = 11 logger.shouldPrintMessage(2, "bar"); // 返回 true ,下一次 "bar" 可以打印的时间戳是 2 + 10 = 12 logger.shouldPrintMessage(3, "foo"); // 3 < 11 ,返回 false logger.shouldPrintMessage(8, "bar"); // 8 < 12 ,返回 false logger.shouldPrintMessage(10, "foo"); // 10 < 11 ,返回 false logger.shouldPrintMessage(11, "foo"); // 11 >= 11 ,返回 true ,下一次 "foo" 可以打印的时间戳是 11 + 10 = 21
提示:
0 <= timestamp <= 109
- 每个
timestamp
都将按非递减顺序(时间顺序)传递 1 <= message.length <= 30
- 最多调用
104
次shouldPrintMessage
方法
class Logger {
public:
Logger() {
m.clear();
}
bool shouldPrintMessage(int timestamp, string message) {
if(m.find(message)==m.end())m[message]=-10;
bool ans=m[message]+10<=timestamp;
if(ans)m[message]=timestamp;
return ans;
}
map<string,int>m;
};
360. 有序转化数组
给你一个已经 排好序 的整数数组 nums
和整数 a
、 b
、 c
。对于数组中的每一个元素 nums[i]
,计算函数值 f(x) = ax2 + bx + c
,请 按升序返回数组 。
示例 1:
输入: nums = [-4,-2,2,4], a = 1, b = 3, c = 5 输出: [3,9,15,33]
示例 2:
输入: nums = [-4,-2,2,4], a = -1, b = 3, c = 5 输出: [-23,-5,1,7]
提示:
1 <= nums.length <= 200
-100 <= nums[i], a, b, c <= 100
nums
按照 升序排列
进阶:你可以在时间复杂度为 O(n)
的情况下解决这个问题吗?
class Solution {
public:
vector<int> sortTransformedArray(vector<int>& nums, int a, int b, int c) {
if (a == 0) {
for (auto& x : nums)x = x * b + c;
if(b<0)reverse(nums.begin(), nums.end());
return nums;
}
for (auto& x : nums)x = (x * a * 2 + b) * (x * a * 2 + b);
int id = min_element(nums.begin(), nums.end()) - nums.begin();
auto nums2 = VecSplit(nums, id);
reverse(nums.begin(), nums.end());
auto v = MergeSortVector(nums, nums2);
for (auto& x : v)x = (x - b * b) / a / 4 + c;
if(a<0)reverse(v.begin(), v.end());
return v;
}
};
362. 敲击计数器
365. 水壶问题
366. 寻找二叉树的叶子节点
367. 有效的完全平方数
368. 最大整除子集
369. 给单链表加一
370. 区间加法
假设你有一个长度为 n 的数组,初始情况下所有的数字均为 0,你将会被给出 k 个更新的操作。
其中,每个操作会被表示为一个三元组:[startIndex, endIndex, inc],你需要将子数组 A[startIndex ... endIndex](包括 startIndex 和 endIndex)增加 inc。
请你返回 k 次操作后的数组。
示例:
输入: length = 5, updates = [[1,3,2],[2,4,3],[0,2,-2]]
输出: [-2,0,3,5,3]
解释:
初始状态:
[0,0,0,0,0]
进行了操作 [1,3,2] 后的状态:
[0,2,2,2,0]
进行了操作 [2,4,3] 后的状态:
[0,2,5,5,3]
进行了操作 [0,2,-2] 后的状态:
[-2,0,3,5,3]
class Solution {
public:
vector<int> getModifiedArray(int length, vector<vector<int>>& updates) {
vector<int> ans(length);
for (int i = 0; i < length; i++)ans[i] = 0;
for (auto& ui : updates) {
ans[ui[0]] += ui[2];
if(ui[1]+1<length)ans[ui[1]+1] -= ui[2];
}
for (int i = 1; i < length; i++)ans[i] += ans[i - 1];
return ans;
}
};
371. 两整数之和
372. 超级次方
快速幂 快速乘法、快速幂、矩阵快速幂_nameofcsdn的博客-CSDN博客
373. 查找和最小的K对数字
题目:
给定两个以升序排列的整形数组 nums1 和 nums2, 以及一个整数 k。
定义一对值 (u,v),其中第一个元素来自 nums1,第二个元素来自 nums2。
找到和最小的 k 对数字 (u1,v1), (u2,v2) ... (uk,vk)。
示例 1:
输入: nums1 = [1,7,11], nums2 = [2,4,6], k = 3
输出: [1,2],[1,4],[1,6]
解释: 返回序列中的前 3 对数:
[1,2],[1,4],[1,6],[7,2],[7,4],[11,2],[7,6],[11,4],[11,6]
示例 2:
输入: nums1 = [1,1,2], nums2 = [1,2,3], k = 2
输出: [1,1],[1,1]
解释: 返回序列中的前 2 对数:
[1,1],[1,1],[1,2],[2,1],[1,2],[2,2],[1,3],[1,3],[2,3]
示例 3:
输入: nums1 = [1,2], nums2 = [3], k = 3
输出: [1,3],[2,3]
解释: 也可能序列中所有的数对都被返回:[1,3],[2,3]
代码:
struct dist
{
int a;
int b;
};
struct cmp
{
bool operator()(dist d1, dist d2)
{
return d1.a + d1.b > d2.a + d2.b;
}
};
class Solution {
public:
vector<vector<int>> kSmallestPairs(vector<int>& nums1, vector<int>& nums2, int k) {
priority_queue<dist, vector<dist>, cmp>que;
vector<vector<int>>ans;
vector<int>anstmp;
dist tmp;
for (int i = 0; i < k && i < nums1.size(); i++)for (int j = 0; j < k && j < nums2.size(); j++)
{
tmp.a = nums1[i], tmp.b = nums2[j];
que.push(tmp);
}
anstmp.insert(anstmp.end(), 0);
anstmp.insert(anstmp.end(), 0);
while (que.size() && k--)
{
tmp = que.top();
que.pop();
anstmp[0] = tmp.a, anstmp[1] = tmp.b;
ans.insert(ans.end(), anstmp);
}
return ans;
}
};
374. 猜数字大小
375. 猜数字大小 II
376. 摆动序列
377. 组合总和 Ⅳ
378. 有序矩阵中第K小的元素
题目:
给定一个 n x n 矩阵,其中每行和每列元素均按升序排序,找到矩阵中第k小的元素。
请注意,它是排序后的第k小元素,而不是第k个元素。
示例:
matrix = [
[ 1, 5, 9],
[10, 11, 13],
[12, 13, 15]
],
k = 8,
返回 13。
说明:
你可以假设 k 的值永远是有效的, 1 ≤ k ≤ n^2 。
代码:
class Solution {
public:
int kthSmallest(vector<vector<int>>& matrix, int k) {
priority_queue<int, vector<int>>q;
for (int i = 0; i < matrix.size(); i++)for (int j = 0; j < matrix[i].size(); j++)q.push(-matrix[i][j]);
k--;
while (k--)q.pop();
return q.top();
}
};
380. O(1) 时间插入、删除和获取随机元素
剑指 Offer II 030. 插入、删除和随机访问都是 O(1) 的容器
382. 链表随机节点
给你一个单链表,随机选择链表的一个节点,并返回相应的节点值。每个节点 被选中的概率一样 。
实现 Solution
类:
Solution(ListNode head)
使用整数数组初始化对象。int getRandom()
从链表中随机选择一个节点并返回该节点的值。链表中所有节点被选中的概率相等。
示例:
输入 ["Solution", "getRandom", "getRandom", "getRandom", "getRandom", "getRandom"] [[[1, 2, 3]], [], [], [], [], []] 输出 [null, 1, 3, 2, 2, 3] 解释 Solution solution = new Solution([1, 2, 3]); solution.getRandom(); // 返回 1 solution.getRandom(); // 返回 3 solution.getRandom(); // 返回 2 solution.getRandom(); // 返回 2 solution.getRandom(); // 返回 3 // getRandom() 方法应随机返回 1、2、3中的一个,每个元素被返回的概率相等。
提示:
- 链表中的节点数在范围
[1, 104]
内 -104 <= Node.val <= 104
- 至多调用
getRandom
方法104
次
进阶:
- 如果链表非常大且长度未知,该怎么处理?
- 你能否在不使用额外空间的情况下解决此问题?
class Solution {
public:
Solution(ListNode* head) {
v=listToVec(head);
}
int getRandom() {
int id = rand() % v.size();
return v[id]->val;
}
vector<ListNode*> v;
};
383. 赎金信
给你两个字符串:ransomNote
和 magazine
,判断 ransomNote
能不能由 magazine
里面的字符构成。
如果可以,返回 true
;否则返回 false
。
magazine
中的每个字符只能在 ransomNote
中使用一次。
示例 1:
输入:ransomNote = "a", magazine = "b" 输出:false
示例 2:
输入:ransomNote = "aa", magazine = "ab" 输出:false
示例 3:
输入:ransomNote = "aa", magazine = "aab" 输出:true
提示:
1 <= ransomNote.length, magazine.length <= 105
ransomNote
和magazine
由小写英文字母组成
class Solution {
public:
bool canConstruct(string ransomNote, string magazine) {
map<char,int>m;
for(auto x:magazine)m[x]++;
for(auto x:ransomNote)if(--m[x]<0)return false;
return true;
}
};
384. 打乱数组
给你一个整数数组 nums
,设计算法来打乱一个没有重复元素的数组。打乱后,数组的所有排列应该是 等可能 的。
实现 Solution
class:
Solution(int[] nums)
使用整数数组nums
初始化对象int[] reset()
重设数组到它的初始状态并返回int[] shuffle()
返回数组随机打乱后的结果
示例 1:
输入 ["Solution", "shuffle", "reset", "shuffle"] [[[1, 2, 3]], [], [], []] 输出 [null, [3, 1, 2], [1, 2, 3], [1, 3, 2]] 解释 Solution solution = new Solution([1, 2, 3]); solution.shuffle(); // 打乱数组 [1,2,3] 并返回结果。任何 [1,2,3]的排列返回的概率应该相同。例如,返回 [3, 1, 2] solution.reset(); // 重设数组到它的初始状态 [1, 2, 3] 。返回 [1, 2, 3] solution.shuffle(); // 随机返回数组 [1, 2, 3] 打乱后的结果。例如,返回 [1, 3, 2]
提示:
1 <= nums.length <= 50
-106 <= nums[i] <= 106
nums
中的所有元素都是 唯一的- 最多可以调用
104
次reset
和shuffle
class Solution {
public:
Solution(vector<int>& nums) {
num=nums;
for(int i=0;i<num.size();i++)v.push_back(i);
}
vector<int> reset() {
return num;
}
vector<int> shuffle() {
vector<int>ans;
for(int i=0;i<v.size();i++)ans.push_back(num[v[i]]);
next_permutation(v.begin(),v.end());
return ans;
}
vector<int>v,num;
};
389. 找不同
给定两个字符串 s 和 t,它们只包含小写字母。
字符串 t 由字符串 s 随机重排,然后在随机位置添加一个字母。
请找出在 t 中被添加的字母。
示例:
输入:
s = "abcd"
t = "abcde"
输出:
e
解释:
'e' 是那个被添加的字母。
class Solution {
public:
char findTheDifference(string s, string t) {
int ans = 0;
for (int i = 0; i < s.length(); i++)ans ^= s[i];
for (int i = 0; i < t.length(); i++)ans ^= t[i];
return ans;
}
};
390. 消除游戏
列表 arr
由在范围 [1, n]
中的所有整数组成,并按严格递增排序。请你对 arr
应用下述算法:
- 从左到右,删除第一个数字,然后每隔一个数字删除一个,直到到达列表末尾。
- 重复上面的步骤,但这次是从右到左。也就是,删除最右侧的数字,然后剩下的数字每隔一个删除一个。
- 不断重复这两步,从左到右和从右到左交替进行,直到只剩下一个数字。
给你整数 n
,返回 arr
最后剩下的数字。
示例 1:
输入:n = 9 输出:6 解释: arr = [1, 2, 3, 4, 5, 6, 7, 8, 9] arr = [2, 4, 6, 8] arr = [2, 6] arr = [6]
示例 2:
输入:n = 1 输出:1
提示:
1 <= n <= 109
class Solution {
public:
int lastRemaining(int n) {
if (n < 4)return n / 2 + 1;
return lastRemaining(n / 4) * 4 - (n % 4 < 2) * 2;
}
};
398. 随机数索引
给你一个可能含有 重复元素 的整数数组 nums
,请你随机输出给定的目标数字 target
的索引。你可以假设给定的数字一定存在于数组中。
实现 Solution
类:
Solution(int[] nums)
用数组nums
初始化对象。int pick(int target)
从nums
中选出一个满足nums[i] == target
的随机索引i
。如果存在多个有效的索引,则每个索引的返回概率应当相等。
示例:
输入 ["Solution", "pick", "pick", "pick"] [[[1, 2, 3, 3, 3]], [3], [1], [3]] 输出 [null, 4, 0, 2] 解释 Solution solution = new Solution([1, 2, 3, 3, 3]); solution.pick(3); // 随机返回索引 2, 3 或者 4 之一。每个索引的返回概率应该相等。 solution.pick(1); // 返回 0 。因为只有 nums[0] 等于 1 。 solution.pick(3); // 随机返回索引 2, 3 或者 4 之一。每个索引的返回概率应该相等。
提示:
1 <= nums.length <= 2 * 104
-231 <= nums[i] <= 231 - 1
target
是nums
中的一个整数- 最多调用
pick
函数104
次
class Solution {
public:
Solution(vector<int>& nums) {
for(int i=0;i<nums.size();i++)m[nums[i]].push_back(i);
}
int pick(int target) {
int id = rand() % m[target].size();
return m[target][id];
}
map<int,vector<int>>m;
};