题目300:最长递增子序列(NO)
- 解题思路:动态规划,就是dp[i]的运用,这里dp[i]表示第i个元素为结尾的最长子序列。
给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。
子序列 是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的
子序列。
class Solution
{
public:int lengthOfLIS(vector<int>& nums) {int n = nums.size();if (n == 0) {return 0;}vector<int> dp(n, 0);int max_count=0;for (int i = 0; i < n; ++i) {dp[i] = 1;//如果前面没有比他小的了,那自己本身就是一个最长子序列for (int j = 0; j < i; ++j) {if (nums[j] < nums[i]) {//这里是每次扫描前面就记录最大的dp[i]dp[i] = max(dp[i], dp[j] + 1);}}if(dp[i]>max_count){max_count=dp[i];} }return max_count;}
};
题目215:数组中的第k个最大元素(NO)
- 解题思路:使用快速排序算法
给定整数数组 nums 和整数 k,请返回数组中第 k 个最大的元素。
请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。
你必须设计并实现时间复杂度为 O(n) 的算法解决此问题。
class Solution {
public:void quickSort(std::vector<int>& arr, int left, int right) {if (left >= right) {return;}int pivot = arr[(left + right) / 2];int i = left, j = right;//这次一扫描,就会将整个数组划分为两个区域,以pivot为分界线while (i <= j) {while (arr[i] < pivot) {//找到比中间结点大的i++;}while (arr[j] > pivot) {//找到比中间结点小的j--;}if (i <= j) {//交换两个元素swap(arr[i], arr[j]);i++;j--;}}//检查左边if (left < j) {quickSort(arr, left, j);}//检查右边if (i < right) {quickSort(arr, i, right);}}int findKthLargest(vector<int>& nums, int k) {int len=nums.size();quickSort(nums,0,len-1);return nums[len-k];}
};
题目1:两数之和(YES)
- 解题思路:使用哈希表
给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。
class Solution {
public:vector<int> twoSum(vector<int>& nums, int target) {//使用哈希表unordered_map<int,int>map;for(int i=0;i<nums.size();i++){if(map.find(target-nums[i])!=map.end()){return {i,map[target-nums[i]]};}map[nums[i]]=i;}return {};}
};
题目3:无重复字符的最长子串(NO)
- 解题思路:使用滑动窗口,就是和unordered_set搭配使用,用set来检查是否重复,没有重复在继续添加,如果重复了就删除掉第一个,因为是for一次遍历,所以每个i都可以成为第一个子串。
给定一个字符串 s ,请你找出其中不含有重复字符的 最长
子串的长度。
class Solution {
public:int lengthOfLongestSubstring(string s) {//使用滑动窗口的方法,就是配合unordered_set来实现//用set来判断是否出现了重复的字符,如果重复了就删除第一个,否则没重复的话//就继续在set中添加字符unordered_set<char>set;int ans=0;int temp=-1;int len=s.size();for(int i=0;i<s.size();i++){//第一个字符是不用删除的if(i!=0){//删除第一个元素set.erase(s[i-1]);}//以i为起点一直添加元素//确保下一个位置合法才能够加入while(temp+1<len&&!set.count(s[temp+1])){set.insert(s[temp+1]);temp++;}//说明遇到了重复的字符,保存这次的子串长度ans=max(ans,temp-i+1);}return ans;}
};
题目11:盛最多水的容器(YES)
-
解题思路:最刚开始第一想到的是使用双重for遍历一遍,让每个i都作为第一条边,每个的最大的面积,但是显然这样时间复杂度太高了。
-
错误示例
class Solution {
public:int maxArea(vector<int>& height) {//我现在突然想到的是使用双重for遍历,每个i都可以当容器的第一个位置//然后找到其中最大的int max_ans=0;for(int i=0;i<height.size();i++){for(int j=i+1;j<height.size();j++){int area=(j-i)*min(height[i],height[j]);max_ans=max(area,max_ans);}}return max_ans;}
};
-
后面我又想到了一个思路,既然是要计算面积,底乘以高,当然是保证底部越长越好,所以在大的情况从两边开始扫描一定不会漏掉。且在靠齐的时候,当然是向边长高的靠齐最好。
-
正确写法
class Solution {
public:int maxArea(vector<int>& height) {//此时我又想到了面积的算法是底乘以高,所以底应该尽可能的长,所以直接从两边开始扫描//就行了int left=0;int right=height.size()-1;int max_area=0;while(left<right){//从两边开始记录最大面积int temp=(right-left)*min(height[right],height[left]);if(temp>max_area){max_area=temp;}if(height[left]<height[right]){//想要面积最大,应该向高的一边靠齐left++;}else{right--;}}return max_area;}
};
题目70:爬楼梯(YES)
- 典型的动态规划问题,考察队dp[i]数组的使用,这里dp[i]表示的是到达第i阶楼梯的方法数。这里需要关注的点是第3阶的方法数是第1阶和第2阶方法数的和。
假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
class Solution {
public:int climbStairs(int n) {//这题使用的是动态规划问题//dp[i]的含义是到第i阶有多少不同的方法vector<int>dp(n+1);dp[0]=1;//单纯为了做题而设置的,没意义dp[1]=1;if(n<2){return dp[n];}for(int i=2;i<=n;i++){dp[i]=dp[i-1]+dp[i-2];}return dp[n];}
};
题目146:LRU缓存(NO)
- 解题思路:使用了双链表和哈希表的结合,这题值得关注。
请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。
实现 LRUCache 类:
LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化 LRU 缓存
int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1 。
void put(int key, int value) 如果关键字 key 已经存在,则变更其数据值 value ;如果不存在,则向缓存中插入该组 key-value 。如果插入操作导致关键字数量超过 capacity ,则应该 逐出 最久未使用的关键字。
函数 get 和 put 必须以 O(1) 的平均时间复杂度运行。
//双向链表
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): capacity(_capacity), size(0) {// 使用伪头部和伪尾部节点head = new DLinkedNode();tail = new DLinkedNode();head->next = tail;tail->prev = head;}int get(int key) {if (!cache.count(key)) {return -1;}// 如果 key 存在,先通过哈希表定位,再移到头部DLinkedNode* node = cache[key];moveToHead(node);return node->value;}void put(int key, int value) {if (!cache.count(key)) {// 如果 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 {// 如果 key 存在,先通过哈希表定位,再修改 value,并移到头部DLinkedNode* node = cache[key];node->value = value;moveToHead(node);}}void addToHead(DLinkedNode* node) {node->prev = head;node->next = head->next;head->next->prev = node;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;}
};