备战复试,每日三题
题目一:买卖股票的最佳时间
给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。
你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。
返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0 。
示例 1:
输入:[7,1,5,3,6,4]
输出:5
解释:在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。
注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格;同时,你不能在买入前卖出股票。
示例 2:
输入:prices = [7,6,4,3,1]
输出:0
解释:在这种情况下, 没有交易完成, 所以最大利润为 0。
提示:
1 <= prices.length <= 105
0 <= prices[i] <= 104
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock
class Solution {
public:
/*
动态规划问题:
dp[i][j]:表示在第i天持有的现金,i表示天数,j表示状态(0代表未持有股票,1代表持有股票)
basecase:第一天,若未持有股票,则手中现金为0,若持有则花了当天股票的价钱买入了股票(所以为负值)
状态转移方程:当天手中持有的现金与是否持有股票以及前一天是否持有股票有关:
即若今天未持有股票,则可能是昨天也未持有股票,或是昨天持有但今天卖了,那今天的最大收益就是比较这两种情况的最大值。
若今天持有股票,则可能昨天未持有今天刚买入,也可能昨天持有,今天未卖出,那今天的最大收益就是比较这两种情况的最大值。
最后一天一定是未持有的状态收益大。
*/
int maxProfit(vector<int>& prices) {
int len=prices.size();
int dp[len][2];//dp数组
if(len<2){
return 0;
}
// basecase
dp[0][0]=0;
dp[0][1]=-prices[0];
for(int i=1;i<len;i++){
//状态转移方程
// 即若今天未持有股票,则可能是昨天也未持有股票,或是昨天持有但今天卖了,那今天的最大收益就是比较这两种情况的最大值。
dp[i][0]=fmax(dp[i-1][1]+prices[i],dp[i-1][0]); //C++中用fmax,fmin求两个数之间的最大最小值
// 若今天持有股票,则可能昨天未持有今天刚买入,也可能昨天持有,今天未卖出,那今天的最大收益就是比较这两种情况的最大值。
dp[i][1]=fmax(-prices[i],dp[i-1][1]);
}
// 最后一天一定是未持有的状态收益大
return dp[len-1][0];
}
};
这是一道动态规划的题目,动态规划的步骤一般是确定dp数组,起始状态以及状态转移方程。
题目二: 无重复元素的最长子串
给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。
示例 1:
输入: s = “abcabcbb”
输出: 3
解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。
示例 2:
输入: s = “bbbbb”
输出: 1
解释: 因为无重复字符的最长子串是 “b”,所以其长度为 1。
示例 3:
输入: s = “pwwkew”
输出: 3
解释: 因为无重复字符的最长子串是 “wke”,所以其长度为 3。
请注意,你的答案必须是 子串 的长度,“pwke” 是一个子序列,不是子串。
示例 4:
输入: s = “”
输出: 0
提示:
0 <= s.length <= 5 * 104
s 由英文字母、数字、符号和空格组成
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/longest-substring-without-repeating-characters
class Solution {
public:
int lengthOfLongestSubstring(string s) {
int num[128]={};//num数组用来记录字符出现的次数
int i=0,j=0,res=0,k=0,h=0;
while(j<s.length()){
//从字符串s的第一个元素开始,以该字符与空字符的ASCII差值作为num数组的下标
k=s[j++]-' ';
//num数组中存储的元素表示该字符已出现的次数
num[k]++;
//当次数大于1时,表明出现当前子串中出现重复元素
while(num[k]>1){
//缩短该子串
h=s[i++]-' ';
//对应字符出现次数-1
num[h]--;
}
//记录不含重复元素子串的最大长度
res=fmax(res,j-i);
}
return res;
}
};
题目三: 两两交换链表中的节点
给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。
示例 1:
输入:head = [1,2,3,4]
输出:[2,1,4,3]
示例 2:
输入:head = []
输出:[]
示例 3:
输入:head = [1]
输出:[1]
提示:
链表中节点的数目在范围 [0, 100] 内
0 <= Node.val <= 100
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/swap-nodes-in-pairs
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
if(head==nullptr||head->next==nullptr){
return head;
}
//以下讨论至少有两个节点的情况
ListNode *p=head,*q=head->next,*r=q->next;
//因为至少有两个节点,所以前两个节点一定发生了互换,则交换后链表头节点为q所指向的节点
head=q;
//当r不为空时,交换p,q所指向的节点
while(r!=nullptr){
q->next=p;
p->next=r;
//因为是两两交换,所以还剩一个节点时就不用再交换,退出循环
if(r->next==nullptr){
break;
}
//若剩余节点大于1,则必发生两两交换,所以将p的next指向交换后的下一个节点
p->next=r->next;
// 将p,q指向将要互换的两个节点,为下一轮交换作准备
p=r;
q=r->next;
r=q->next;
}
//此时退出循环有两种情况,①剩余一个节点②剩余两个节点,可用以下过程统一处理
p->next=r;
q->next=p;
return head;
}
};