搜索旋转排序数组
数组nums升序排列,数组中的值互不相同。
二分查找
对于有序数组,可以使用二分查找的方法查找元素。
我们将数组从中间分开,一定有一部分是有序的,[4,5,6]和[7,0,1,2]。
可以分割出[l, mid],[mid+1, r]哪个部分有序。
class Solution {
public:
int search(vector<int>& nums, int target) {
int n = nums.size();
if(!n){
return -1;
}
if(n == 1){
return nums[0] == target ? 0 : -1;
}
int l = 0, r = n -1;
while(l <= r){
int mid = l + ((r-l) >> 1);
if(nums[mid] == target){
return mid;
}
if(nums[l] <= nums[mid]){
if(nums[l] <= target && target < nums[mid]){
r = mid - 1;
}else{
l = mid + 1;
}
}else{
if(nums[mid+1] <= target && target <= nums[r]){
l = mid + 1;
}else{
r = mid - 1;
}
}
}
return -1;
}
};
在排序数组中查找元素的第一个和最后一个位置
class Solution {
public:
vector<int> searchRange(vector<int>& nums, int target) {
int n = nums.size();
int left = 0, right = n - 1;
while(left <= right){
int mid = left + ((right - left) >> 1);
if(nums[mid] == target){
int leftIndex = mid, rightIndex = mid;
for(int i=mid-1; i>=0 && nums[i] == target; i--){
leftIndex = i;
}
for(int i=mid+1; i<n && nums[i] == target; i++){
rightIndex = i;
}
return {leftIndex, rightIndex};
}else if(nums[mid] < target){
left = mid + 1;
}else{
right = mid - 1;
}
}
return {-1, -1};
}
};
三数之和
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> res;
sort(nums.begin(), nums.end());
int n = nums.size();
for(int i=0; i<n-2; i++){
if(i != 0 && nums[i] == nums[i-1]){
continue;
}
int j = i+1;
int k = n-1;
while(j < k){
if(nums[i] + nums[j] + nums[k] == 0){
res.push_back({nums[i], nums[j], nums[k]});
do{
++j;
k--;
}while(j < k && nums[j] == nums[j-1] && nums[k] == nums[k+1]);
}else if(nums[i] + nums[j] + nums[k] < 0){
j++;
}else{
k--;
}
}
}
return res;
}
};
LRU缓存
请设计并实现一个满足LRU(最近最少使用)缓存约束的数据结构。
实现LRUCache类:
- LRUCache(int capacity)以正整数作为容量capacity初始化LRU缓存
- int get(int key)如果关键字key存在于缓存中,则返回关键字的值,否则返回-1。
- void put(int key, int value)如果关键字key已经存在,则变更其数据值value,如果不存在,则向缓存中插入该组key-value
- get和put必须以O(1)的平均时间复杂度运行。
哈希表+双向链表
LRU缓存机制可以通过哈希表+双向链表实现。
双向链表按照被使用的顺序存储了这些键值对,靠近头部的键值对是最近使用的,靠近尾部的键值对是最久未使用的。
struct DLinkedNode {
int key, value;
DLinkedNode* prev;
DLinkedNode* next;
DLinkedNode() : key(0), value(0), prev(nullptr), next(nullptr) {}
DLinkedNode(int _key, int _value)
: key(_key), value(_value), prev(nullptr), next(nullptr) {}
};
class LRUCache {
private:
unordered_map<int, DLinkedNode*> cache;
DLinkedNode* head;
DLinkedNode* tail;
int size;
int capacity;
public:
LRUCache(int capacity) {
this->capacity = capacity;
this->size = 0;
head = new DLinkedNode();
tail = new DLinkedNode();
head->next = tail;
tail->prev = head;
}
int get(int key) {
if (!cache.count(key)) {
return -1;
}
DLinkedNode* node = cache[key];
moveToHead(node);
return node->value;
}
void put(int key, int value) {
if (!cache.count(key)) {
DLinkedNode* node = new DLinkedNode(key, value);
cache[key] = node;
addToHead(node);
++size;
if (size > capacity) {
DLinkedNode* removed = removeTail();
cache.erase(removed->key);
delete removed; // 防止内存泄漏
--size;
}
} else {
DLinkedNode* node = cache[key];
node->value = value;
moveToHead(node);
}
}
void addToHead(DLinkedNode* node) {
node->next = head->next;
head->next->prev = node;
node->prev = head;
head->next = node;
}
void removeNode(DLinkedNode* node) {
node->prev->next = node->next;
node->next->prev = node->prev;
}
void moveToHead(DLinkedNode* node) {
removeNode(node);
addToHead(node);
}
DLinkedNode* removeTail() {
DLinkedNode* node = tail->prev;
removeNode(node);
return node;
}
};
/**
* Your LRUCache object will be instantiated and called as such:
* LRUCache* obj = new LRUCache(capacity);
* int param_1 = obj->get(key);
* obj->put(key,value);
*/
字符串解码
栈操作
class Solution {
public:
string decodeString(string s) {
stack<int> numStack;
stack<string> strStack;
string res;
int num = 0;
for(char c: s){
if(isdigit(c)){
num = num * 10 + (c - '0');
}else if(c == '['){
numStack.push(num);
strStack.push(res);
num = 0;
res.clear();
}else if(c == ']'){
string temp = res;
res = strStack.top();
strStack.pop();
int repeatTimes = numStack.top();
numStack.pop();
while(repeatTimes--){
res += temp;
}
}else{
res += c;
}
}
return res;
}
};
字符串编码与解码
要设计一个算法,实现字符串的编码与解码。
编码函数需要将一个字符串数组编码成一个字符串,解码函数需要将这个字符串还原成原始的字符串数组。
#include <iostream>
#include <string>
using namespace std;
class Codec{
public:
string encode(vector<string>& strs){
string encoded;
for(const string&s : strs){
encoded += to_string(s.size()) + "@" + s;
}
return encoded;
}
vector<string> decode(string s){
vector<string> decoded;
int i = 0;
while(i < s.size()){
int at_pos = s.find('@', i);
int len = stoi(s.substr(i, at_pos-i));
decoded.push_back(s.substr(at_pos+1, len));
i = at_pos + 1 + len + 1;
}
return decoded;
}
};
合唱团
- 计算每个同学作为合唱队形的中心时,左侧和右侧分别满足严格递增和严格递减的最长子序列长度。
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main(){
int n;
cin >> n;
}
杨辉三角的变形
以上三角形的数阵,第一行只有一个数1,以下每行的个数是它上面的数,左上角数和右上角的数,三个数之和,如果不存在某个数就返回0。
求第n行第一个偶数出现的位置。
找到字符串中所有字母异位词
滑动窗口
根据题目要求,我们需要在字符串s中寻找字符串p的异位词。
因为字符串p的异位词的长度一定与字符串p的长度相同,所以可以在s中构造一个长度与字符串p的长度相同的滑动窗口,并在滑动中维护窗口中每种字母的数量,当数量相同时,说明当前窗口为异位词。
class Solution {
public:
vector<int> findAnagrams(string s, string p) {
int n = s.size(), m = p.size();
if(n < m){
return {};
}
vector<int> res;
vector<int> count(26);
vector<int> tempCount(26);
for(int i=0; i<m; i++){
count[p[i]-'a']++;
tempCount[s[i]-'a']++;
}
if(count == tempCount){
res.push_back(0);
}
for(int i=0; i<n-m ; i++){
tempCount[s[i]-'a']--;
tempCount[s[i+m] - 'a']++;
if(tempCount == count){
res.push_back(i+1);
}
}
return res;
}
};