经典算法题准备

搜索旋转排序数组

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

合唱团

  1. 计算每个同学作为合唱队形的中心时,左侧和右侧分别满足严格递增和严格递减的最长子序列长度。
#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;
    }
};
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

饼干饼干圆又圆

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值