web组第一次考核题解

一、


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),我们只能用二分查找,虽然旋转后的数组不是有序的,但它却是两个有序的部分拼起来的,那么二分产生的两部分一定有一部分是有序的,我们先看目标值是否在有序序列的范围内,如果在,对有序序列继续二分查找即可,如果他不在有序的那部分,那麽我们就二分无序的那部分,对二分得到的两部分继续上面的判断,有序则判断目标值在不在,不在则二分无序的那部分,直到判断完整个数组。

相关推荐
wayz112 小时前
Day 16:PCA主成分分析与降维
人工智能·算法·机器学习
熬夜敲代码的猫2 小时前
C++继承:让你从入门到深入
c++·算法·继承
人道领域2 小时前
【LeetCode刷题日记】239.滑动窗口最大值:单调队列解法(困难)
java·开发语言·算法
Irissgwe2 小时前
优选算法精讲(专题一)
数据结构·算法
睡觉就不困鸭2 小时前
第十五天 反转字符串
数据结构·算法
生物信息与育种2 小时前
JIPB | 一个表观多组学整合分析与可视化工具OmicsCanvas
运维·人工智能·算法·自动化·transformer
AI人工智能+电脑小能手2 小时前
【大白话说Java面试题】【Java基础篇】第17题:HashMap的加载因子为什么是0.75而不是1或0.5
java·开发语言·算法·哈希算法·散列表
谭欣辰3 小时前
C++ 哈希表详解
c++·算法·哈希算法·散列表
shehuiyuelaiyuehao3 小时前
算法11,滑动窗口,最大连续1的个数|||
算法·leetcode·职场和发展