一、


c
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* addTwoNumbers(struct ListNode* l1, struct ListNode* l2) {
int jin=0,sum=0;
struct ListNode* pre=(struct ListNode*)malloc(sizeof(struct ListNode));
sum=l1->val+l2->val+jin;
pre->val=sum%10;
pre->next=NULL;
jin=sum/10;
struct ListNode* cur=pre;
l1=l1->next;
l2=l2->next;
while(l1!=NULL&&l2!=NULL){
struct ListNode* te=(struct ListNode*)malloc(sizeof(struct ListNode));
sum=l1->val+l2->val+jin;
cur->next=te;
te->val=sum%10;
te->next=NULL;
jin=sum/10;
cur=te;
l1=l1->next;
l2=l2->next;
}
while(l1!=NULL){
struct ListNode* tem=(struct ListNode*)malloc(sizeof(struct ListNode));
cur->next=tem;
tem->val=(l1->val+jin)%10;
tem->next=NULL;
jin=(l1->val+jin)/10;
l1=l1->next;
cur=tem;
}
while(l2!=NULL){
struct ListNode* tem=(struct ListNode*)malloc(sizeof(struct ListNode));
cur->next=tem;
tem->val=(l2->val+jin)%10;
tem->next=NULL;
jin=(l2->val+jin)/10;
l2=l2->next;
cur=tem;
}
if(jin!=0){
struct ListNode* tem=(struct ListNode*)malloc(sizeof(struct ListNode));
cur->next=tem;
tem->val=jin;
tem->next=NULL;}
return pre;
}
思路
面对这道题,第一反应是把链表转成整数,相加完后再转为链表。以下是这种思路的代码
c
class Solution {
public:
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
unsigned long long x=0,y=0,cnt=0;
while(l1!=nullptr){
x+=l1->val*pow(10,cnt);
cnt++;
l1=l1->next;
}
cnt=0;
while(l2!=nullptr){
y+=l2->val*pow(10,cnt);
cnt++;
l2=l2->next;
}
unsigned long long z=x+y;
ListNode* l3=new ListNode(0);
ListNode* cur=l3;
while(z!=0){
ListNode* t=new ListNode(z%10);
cur->next=t;
cur=cur->next;
z/=10;
}
if(l3->next==nullptr)return l3;
return l3->next;
}
};
但这种办法在力扣上过不了,因为当链表足够长的时候,转成整数会超出unsigned long long,运算无法进行,所以我们只能考虑来操作链表,链表是逆序的,那么也就是说,越往后,位数越高,所以我们只需要从头遍历两个链表,将对应的数位相加,再加上进位,并记录新的进位,将得到值作为新链表的结点值,直到一个链表为空,继续遍历另一个不为空的链表,用节点值加上对应进位,待到两个链表都为空,如果此时还有进位,新建一个结点存储此时的进位,并连接新链表的最后,最后返回新链表的头结点即可。
二、

贪心解法
class Solution {
public:
int maxProfit(vector& prices) {
int sum=0,max=0;
vector a(prices.size());
for(int i=1;i<prices.size();i++){
a[i]=prices[i]-prices[i-1];
}
for(int i=1;i<a.size();i++){
if(sum+a[i]>=0){
sum+=a[i];
if(sum>max)max=sum;
}
else sum=0;
}
return max;
}
};
### 思路
这道题要求的是最大利润,贪心的局部最优是只要有利润就卖,全局最优就是找到赚钱过程中的最大利润。所以我们先获取每隔两天的价格差,sum代表总利润,如果价格差加上总利润为正数,那就代表卖出去是赚的,那麽就拿总利润加上当前的价格差,否则就是亏钱的,此时不操作,sum变为0.用max统计这个过程中的最大值,数组遍历完后得到的最大值,也就是最大利润。
## 动态规划解法
```c
class Solution {
public:
int maxProfit(vector<int>& prices) {
int n=prices.size();
vector<vector<int>> dp(n,vector<int>(2));
dp[0][0]=-prices[0];
dp[0][1]=0;
for(int i=1;i<n;i++){
dp[i][0]=max(dp[i-1][0],-prices[i]);
dp[i][1]=max(dp[i-1][1],dp[i-1][0]+prices[i]);
}
return dp[n-1][1];
}
};
思路
用一个二维数组作为dp数组,用于统计最大利润,状态零代表持有彩票,状态一代表不持有彩票,初始持有需花钱购买,所以利润为负数,初始不持有则无需操作,利润为零,对于持有状态,要么是前一天就持有,今天维持原状,或是今天买入,取两者中的利润较大者,对于不持有状态,要么是前一天就不持有,或者是今天刚卖出,取两者中的较大者。最终最后一天的不持有状态所获得的最大利润就是最终的最大利润。
三、

c
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* removeNthFromEnd(struct ListNode* head, int n) {
if (head==NULL)return head;
struct ListNode* pre=(struct ListNode*)malloc(sizeof(struct ListNode));
pre->next=head;
struct ListNode* fast = head,*slow=pre;
while(n-->0&&fast!=NULL){
fast=fast->next;
}
while(fast!=NULL){
slow=slow->next;
fast=fast->next;
}
slow->next=slow->next->next;
return pre->next;
}
思路
这道题我们可以用双指针的解法,用快慢指针,维持两者之间的距离,保证快指针走到末尾时,慢指针刚好走到要删除结点的前一个结点,然后利用慢指针进行删除即可。快慢指针的距离差是多少呢,我们以图为例,如果要删除节点四,当快指针指向空时,慢指针要刚好指向三,也就是快指针比慢指针快三步,即n+1步。所以我们先让快指针移动n+1步,再将二者同时移动当快指针为空时,慢指针也就刚好走到要删除结点的前一个结点,用慢指针删除,然后返回头结点即可。
四

c
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
if(head==nullptr||head->next==nullptr)return nullptr;
ListNode* fast=head->next->next,*slow=head->next;
while(fast!=nullptr&&fast->next!=nullptr){
fast=fast->next->next;
slow=slow->next;
if(fast==slow){
fast=head;
while(slow!=fast){
slow=slow->next;
fast=fast->next;
}
return slow;
}
}
return nullptr;
}
};
思路
这道题的难点在于判环和寻找入口。我们利用快慢指针来处理,快指针的速度是慢指针的二倍。如果链表成环,那么慢指针一定会被快指针套圈,也就是说快慢指针一定会相遇,如果二者相遇,那么只需要将其中一个指针从头结点重新遍历,再次相遇的地方就是入口,为什么呢?我们假设k为步数,fast=2k; slow=k;快慢指针相遇时,快一定比慢多走了n圈,那么此时有 2k-k=nb(b为圈的节点数),那么slow=k=nb;如果我们只看慢指针在环上走的距离 ,即从入口点开始,得到slow(环)=nb-a;所以说慢指针从入口点开始在环上走的距离为nb-a,那么在加a,就是(n+1)b,入口点了。
所以总结一下,我们利用快慢指针是否相遇判环,利用相遇后将其中一个指针从头结点重新遍历,再次相遇的地方就是入口,来找环的入口。
五、

c
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
int n=nums.size(),maxlen=1;
if(n==0)return 0;
vector<int> dp(n,1);
for(int i=1;i<nums.size();i++){
for(int j=0;j<i;j++){
if(nums[j]<nums[i]){
dp[i]=max(dp[i],dp[j]+1);
}
if(dp[i]>maxlen)maxlen=dp[i];
}
}
return maxlen;
}
};
思路
这是一道动态规划的题目,首先定义dp数组,dp[i]代表以元素i为结尾的最长递增子序列,所以所有元素初始化为一,单个元素可以被看作递增序列。位置i的最长递增子序列等于从0到i-1各个位置的最长升序子序列 + 1 的值(因为nums[j]<nums[i],所以以nums[j]为结尾的子序列里加上nums[i]依旧递增,因为加了nums[i],所以长度加1)和dp[i]的值相比取最大值,然后再遍历过程中,,再统计出dp[i]中的·最大值,即是我们要求的结果。
六

c
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int sum=0,max=nums[0];
for(int i=0;i<nums.size();i++){
if(nums[i]>max)max=nums[i];
}
for(int i=0;i<nums.size();i++){
if(sum+nums[i]>=0){sum+=nums[i];if(sum>max)max=sum;}
else sum=0;
}
return max;
}
};
思路
首先遍历整个数组,找出单个元素最大值,作为初始最大值,然后遍历,找最大连续子数组和,这里依旧用贪心思路,与求最大利润那道题一样,如果总和加上当前元素大于零,那麽他就是有利于下一个元素增长,有可能创出新的最大值的,我们就拿总和加上当前元素,否则的话,他对下一个元素而言是累赘,只会让下一个元素变小,我们就将当前总和变为0,在整个过程中统计出最大值,即是我们要求的最大值。
七

c
class Solution {
public:
int search(vector<int>& nums, int target) {
int n=nums.size();
if(n==0)return -1;
if(n==1)return target==nums[0]? 0: -1;
int l=0,r=n-1;
while(l<=r){
int mid=(l+r)/2;
if(nums[mid]==target)return mid;
if(nums[mid]>=nums[0]){
if(target>=nums[0]&&target<nums[mid]){
r=mid-1;
}
else l=mid+1;
}
else {
if(target>nums[mid]&&target<=nums[n-1]){
l=mid+1;
}
else {
r=mid-1;
}
}
}
return -1;
}
};
思路
这道题是一道查找题,还要求时间复杂度o(logn),我们只能用二分查找,虽然旋转后的数组不是有序的,但它却是两个有序的部分拼起来的,那么二分产生的两部分一定有一部分是有序的,我们先看目标值是否在有序序列的范围内,如果在,对有序序列继续二分查找即可,如果他不在有序的那部分,那麽我们就二分无序的那部分,对二分得到的两部分继续上面的判断,有序则判断目标值在不在,不在则二分无序的那部分,直到判断完整个数组。