力扣OJ(0201-400)

目录

202. 快乐数

203. 移除链表元素

204. 计数质数

206. 反转链表

207. 课程表

209. 长度最小的子数组

210. 课程表 II

214. 最短回文串

215. 数组中的第K个最大元素

216. 组合总和 III

217. 存在重复元素

222. 完全二叉树的节点个数

223. 矩形面积

225. 用队列实现栈

226. 翻转二叉树

231. 2的幂

232. 用栈实现队列

233. 数字 1 的个数

234. 回文链表

235. 二叉搜索树的最近公共祖先

236. 二叉树的最近公共祖先

239. 滑动窗口最大值

240. 搜索二维矩阵 II 

242. 有效的字母异位词

243. 最短单词距离

244. 最短单词距离 II

245. 最短单词距离 III

246. 中心对称数

247. 中心对称数 II

248. 中心对称数 III

249. 移位字符串分组

250. 统计同值子树

252. 会议室

253. 会议室 II

254. 因子的组合

255. 验证前序遍历序列二叉搜索树

256. 粉刷房子

258. 各位相加

259. 较小的三数之和

260. 只出现一次的数字 III

261. 以图判树

263. 丑数

264. 丑数 II

265. 粉刷房子 II

266. 回文排列

267. 回文排列 II

268. 缺失数字

269. 火星词典

270. 最接近的二叉搜索树值

271. 字符串的编码与解码

273. 整数转换英文表示

274. H 指数

275. H 指数 II

276. 栅栏涂色

279. 完全平方数

280. 摆动排序

285. 二叉搜索树中的中序后继

287. 寻找重复数

290. 单词规律

291. 单词规律 II

292. Nim 游戏

293. 翻转游戏

294. 翻转游戏 II

295. 数据流的中位数

296. 最佳的碰头地点

297. 二叉树的序列化与反序列化

298. 二叉树最长连续序列

299. 猜数字游戏

300. 最长上升子序列

302. 包含全部黑色像素的最小矩形

303. 区域和检索 - 数组不可变

304. 二维区域和检索 - 矩阵不可变

305. 岛屿数量 II

307. 区域和检索 - 数组可修改

309. 买卖股票的最佳时机含冷冻期

310. 最小高度树

311. 稀疏矩阵的乘法

313. 超级丑数

314. 二叉树的垂直遍历

317. 离建筑物最近的距离

318. 最大单词长度乘积

319. 灯泡开关

321. 拼接最大数

322. 零钱兑换

323. 无向图中连通分量的数目

325. 和等于 k 的最长子数组长度

326. 3的幂

328. 奇偶链表

329. 矩阵中的最长递增路径

331. 验证二叉树的前序序列化

332. 重新安排行程

333. 最大 BST 子树

338. 比特位计数

340. 至多包含 K 个不同字符的最长子串

342. 4的幂

343. 整数拆分(快速幂)

344. 反转字符串

346. 数据流中的移动平均值

347. 前 K 个高频元素

348. 设计井字棋

349. 两个数组的交集

350. 两个数组的交集 II

351. 安卓系统手势解锁

356. 直线镜像

357. 统计各位数字都不同的数字个数

358. K 距离间隔重排字符串

359. 日志速率限制器

360. 有序转化数组

362. 敲击计数器

365. 水壶问题

366. 寻找二叉树的叶子节点

367. 有效的完全平方数

368. 最大整除子集

369. 给单链表加一

370. 区间加法

371. 两整数之和

372. 超级次方

373. 查找和最小的K对数字

374. 猜数字大小

375. 猜数字大小 II

376. 摆动序列

377. 组合总和 Ⅳ

378. 有序矩阵中第K小的元素

380. O(1) 时间插入、删除和获取随机元素

382. 链表随机节点

383. 赎金信

384. 打乱数组

389. 找不同

390. 消除游戏

398. 随机数索引


202. 快乐数

 数论数

203. 移除链表元素

rust

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

DP

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. 矩形面积

rust

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. 翻转二叉树

 剑指 Offer 27. 二叉树的镜像

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. 用栈实现队列

请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(pushpoppeekempty):

实现 MyQueue 类:

  • void push(int x) 将元素 x 推到队列的末尾
  • int pop() 从队列的开头移除并返回元素
  • int peek() 返回队列开头的元素
  • boolean empty() 如果队列为空,返回 true ;否则,返回 false

说明:

  • 你 只能 使用标准的栈操作 —— 也就是只有 push to toppeek/pop from topsize, 和 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 次 pushpoppeek 和 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 的个数

数位DP

234. 回文链表

单链表

235. 二叉搜索树的最近公共祖先

lca

236. 二叉树的最近公共祖先

lca

239. 滑动窗口最大值

 剑指 Offer 59 - I. 滑动窗口的最大值

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 and high 不包含任何前导零,除了零本身。

思路:

直接用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. 粉刷房子

剑指 Offer II 091. 粉刷房子

258. 各位相加

rust

259. 较小的三数之和

三指针

260. 只出现一次的数字 III

 数组和集合的搜索

261. 以图判树

环路检测

263. 丑数

水题

264. 丑数 II

  剑指 Offer 49. 丑数

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. 火星词典

LCR 114. 火星词典

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

rust

276. 栅栏涂色

数列DP

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. 二叉树最长连续序列

树形DP

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. 最长上升子序列

DP 数列DP_nameofcsdn的博客-CSDN博客

302. 包含全部黑色像素的最小矩形

DFS

303. 区域和检索 - 数组不可变

给定一个整数数组  nums,处理以下类型的多个查询:

  1. 计算索引 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. 二维区域和检索 - 矩阵不可变

 剑指 Offer II 013. 二维子矩阵的和

305. 岛屿数量 II

并查集

307. 区域和检索 - 数组可修改

树状数组

309. 买卖股票的最佳时机含冷冻期

状态转换DP

310. 最小高度树

反向BFS

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. 超级丑数

rust

314. 二叉树的垂直遍历

二叉树DFS

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] 是 01 或 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. 最大单词长度乘积

 剑指 Offer II 005. 单词长度的最大乘积

319. 灯泡开关

水题

321. 拼接最大数

rust

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. 矩阵中的最长递增路径

图DP

331. 验证二叉树的前序序列化

二叉树DFS

332. 重新安排行程

欧拉链路

333. 最大 BST 子树

树形DP

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. 两个数组的交集

rust

350. 两个数组的交集 II

rust

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. 有效的完全平方数

js

368. 最大整除子集

数列DP

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. 摆动序列

 贪心(4)选取问题

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;
};

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值