链表

链表问题算法难度不高,考察实现代码能力
线性结构,分为单链表和双链表。

1.不创建新节点的情况下进行链表排序,时间复杂度 nlogn.

解析:归并排序,每次找寻链表中间节点,并断开链表

class ListNode {
     int val;
     ListNode next;
     ListNode(int x) {
     val = x;
     next = null;
     }
}
public class sortList {
    public ListNode sortList(ListNode head) {
        if(head == null || head.next ==null) return head;
        ListNode mid = getMiddle(head);
        //断开
        ListNode midnext = mid.next;
        mid.next=null;
        //排序,合并
        return merge(sortList(head),sortList(midnext));
    }

    /**
     * 合并两个有序链表 递归实现
     * @param head
     * @return
     */
    private ListNode merge(ListNode sortList, ListNode sortList2) {
        // TODO Auto-generated method stub
        if(sortList == null)
            return sortList2;
        if(sortList2 == null)
            return sortList;
        ListNode head = null;
        if(sortList.val>=sortList2.val) {
            head = sortList2;
            head.next = merge(sortList,sortList2.next);
        }
        if(sortList.val<sortList2.val) {
            head = sortList;
            head.next = merge(sortList.next,sortList2);
        }
        return head;
    }

    /**
     * 合并两个有序链表 非递归实现
     * @param head
     * @return
     */
    private ListNode merge2(ListNode sortList,ListNode sortList2) {
        //处理有一链表为空的情况
        if(sortList==null)
            return sortList2;
        if(sortList2==null) {
            return sortList;
        }
        //确定链表的头节点,并单独用一个变量记录
        ListNode newhead = null;
        ListNode res = null;
        if(sortList.val<=sortList2.val) {
            res = newhead = sortList;
            sortList=sortList.next;
        }else{
            res = newhead = sortList2;
            sortList2 = sortList2.next;
        }
        while(sortList!=null || sortList2!=null) {
            if(sortList==null){
                newhead.next = sortList2;
                return res;}
            else if(sortList2==null){
                newhead.next=sortList;
                return res;}
            else if(sortList.val<=sortList2.val) {
                newhead.next = sortList;
                sortList=sortList.next;
                newhead = newhead.next;
            }else{
                newhead.next = sortList2;
                sortList2 = sortList2.next;
                newhead = newhead.next;
            }
        }
        return res;

    }

    /**
     * 获取链表的中间结点,偶数时取中间第一个
     * @param head
     * @return
     */
    public ListNode getMiddle(ListNode head) {
        if(head==null || head.next==null)
            return head;
        ListNode fast,slow;
        fast = slow =head;
        while(fast.next!=null && fast.next.next!=null) {
            fast = fast.next.next;
            slow = slow.next;

        }
        return slow;
    }
}
2. 采用创建新链表情况下进行链表排序
public class sortByInsertion {
    public ListNode insertionSortList(ListNode head) {
        ListNode dumy = new ListNode(Integer.MIN_VALUE); 
        ListNode cur = head;
        ListNode pre = dumy;
        while(cur!=null) {
            ListNode next = cur.next;
            pre = dumy;
            while(pre.next!=null && pre.next.val<cur.val) {
                pre =pre.next;
            }
            cur.next = pre.next;
            pre.next = cur;
            cur = next;
        }
        return dumy.next;
    }
}
3. 深拷贝一个带有随机指针的双指针链表

思路:
1.在每个结点后面连接当前结点的拷贝结点
2. 让新结点直接联系起来
3. 在新结点中的随机指针联系起来

class RandomListNode {
     int label;
     RandomListNode next, random;
     RandomListNode(int x) { this.label = x; }
}
public class copyListwithRandomPointer {
    public RandomListNode copyRandomList(RandomListNode head) {
        if(head==null || (head.next==null && head.random==null))
            return head;
        RandomListNode nod = head;
        while(nod!=null) {
            RandomListNode nod2 = copyNode(nod);
            nod.next = nod2;
            nod = nod.next.next;
        }
        nod = head.next;
        while(nod!=null) {
            //只有 非空值时候才能进行。next  null.next 会运行时候报错。
            //所以大都数情况下  nod.next!=null ,避免上述情况 ,但是本文有两个指针,所以分开讨论更合适
            if(nod.next!=null)
                nod.next = nod.next.next;
            if(nod.random!=null)
                nod.random = nod.random.next;
            nod = nod.next;
        }
        return head.next;
    }

    private RandomListNode copyNode(RandomListNode nod) {
        // TODO Auto-generated method stub
        RandomListNode node = new RandomListNode(nod.label);
        node.next = nod.next;
        node.random = nod.random;
        return node;
    }
}
4. 链表是否有环判断
public class hasCycle {
    public boolean hasCycle(ListNode head) {
        if(head==null )
            return false;
        ListNode slow =head;
        ListNode fast = head;
        //下面的判断不能只判断后面的。
        while(fast.next!=null && fast.next.next!=null) {
            fast = fast.next.next;
            slow = slow.next;
            if(slow == fast)
                return true;
        }
        return false;
    }
}
5.

环形链表插入:有一个整数val,如何在一个有序的环形链表插入一个节点值为val 的节点,并且保证这个环形单链表依然有序。
思路:设置两个指针即可。

struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) : val(x), next(NULL) {}
};
class InsertValue {
public:
    ListNode * insert(vector<int> A, vector<int> nxt,int val){
        if(A.empty())
            ListNode *head = new ListNode(val);
            return head;
        ListNode *head = new ListNode(A[0]),*p=head;
        for(vector<int>::iterator iter=nxt.begin();iter!=nxt.end();iter++)
        {
            if(*iter==0)
            {
                (*p).next=Head;
                break;
            }
            (*p).next=new ListNode(A[*iter]);
            p=(*p).next;
        }
        ListNode *pre = head,*now =(*Head).next;
        while(now!=head){
            if((*pre).val<=val && (*now).val>=val){
                ListNode *p = new ListNode(val);
                (*p).next =now;
                (Ipre).next = p;
                break;
            }
            esle{
                pre = now;
                now = (*now).next;
            }
        }
        if(now == head){
            ListNode *p = new ListNode(val);
            (*p).next = now;
            (*pre).next  p;
            if(val<(*head).val)
                head = p;
            }
        pre = head,p=(*head).next;
        while(p!=head){
            pre = p;
            p = (*p).next;
        }
        (*pre).next = Null;
        retrun head;
    }
};

访问单个节点的删除:实现一个算法,删除单向链表中间的某个节点,你只能访问该节点。
思路:该节点复制后面节点,进一步删除后面节点,但如果是最后一个节点呢?

struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) : val(x), next(NULL) {}
};
class Remove {
public:
    bool removeNode(ListNode* pNode) 
    {
        if((*pnode).next==null)
            return false;
        ListNode *p = (*pNode).next,*pre = pNode;
        While((*p).next!=null){
            (*pre).val = (*p).val;
            pre = p;
            p = (*p).next;
        }
        (*pre).val = (*p).val;
        (*pre).next = Null;
        delete p;
        return true;
    }
};

链表分化 :对于一个链表,需要一个特定阀值对他进行分化,大于右边,小于左边。
思路额外空间:通过数组进行排序。

打印两个链表公共部分:现有两个升序链表,无重复元素,打印公共值部分。

class Common {
public:
    vector<int> findCommonParts(ListNode* headA, ListNode* headB) 
    {
        vector<int> res;
        ListNode *p=headA,*q=headB;
        while(p&&q)
        {
            if((*p).val==(*q).val)
            {
                res.push_back((*p).val);
                p=(*p).next;
                q=(*q).next;
            }
            else if((*p).val<(*q).val)
                p=(*p).next;
            else
                q=(*q).next;
        }
        return res;
    }
};

删除指定值:现在有一个单链表,给定一个值,将所有等于该值的val 节点删掉。尾插法

struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) : val(x), next(NULL) {}
};
class ClearValue {
public:
    ListNode* clear(ListNode* head, int val) 
    {
        if(!head)
            return head;
        ListNode *Head =null,*tail=null,*p = head,*temp = null
        while(p){
            temp = *p.next;
            if((*p).val == val)
                delete p;
            else{
                if(!=Head)
                    Head=p;
                    tail=head;
                else
                    *tail.next = p;
                tail=p;
                *tail.next=null
            }
            p=temp;
        }
        return Head;
    }
};

链表回文结构判断:给定一个链表,判断该链表是否是回文。
思路:元素进栈,然后出栈与原始链表对比

链表判环:判断一个单链表是否有环,有的话返回入环第一个节点。
思路:普通方法 通过hash 表实现,第一个重复出现的点
空间复杂度O(1) ,快慢两个指针实现

struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) : val(x), next(NULL) {}
};
class ChkLoop {
public:
    int chkLoop(ListNode *head,int adjust){
        if(!head)
            return -1;
        ListNode *slow=head,*fast = head;
        while(((*fast).next&&(*(*fast).next).next)){
        slow = (*slow).next;
        fast =(*(*fast).next).next;
        if(slow == fast)
            break;
        }
        if(!(*fast).next||!(*(*fast).next).next)
            return -1;
        slow =head;
        while(slow!=fast){
            slow =(*slow).next;
            fast=(*fast).next;
        }
        return (*fast).val;
    }
};

无环单链表相交判断:现在有两个无环单链表,长度为n,M,请设计出一个时间复杂度O(n+M)的算法,判断两个是否相交。
思路:常用方法:使用一个哈希表添加第一个链表元素,并判断是否包含第二个链表中元素。

struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) : val(x), next(NULL) {}
};
class CheckIntersect {
public:
    bool chkIntersect(ListNode* headA, ListNode* headB) {
        if(!headA ||!headB)
            return false;
         int NumberA=0,NumberB=0,count=0;
         ListNode *p = headA;
         while(p){
             NumberofA++;
             p=(*p).next;
        }
        while(p)
        {
            NumofB++;
            p=(*p).next;
        }
        ListNode *L=Null,*S=Null;
        if(NumofA>NumofB)
            L=headA,S=headB;
        else
            L=headB,S=headA;
        count=(NumofA>NumofB)?(NumofA-NumofB):(NumofB-NumofA);
        while(count--)
            L=(*L).next;
        while(L&&S)
        {
            if(L==S)
                return true;
            L=(*L).next;
            S=(*S).next;
        }
        return false;
      }
  };


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
图像识别技术在病虫害检测的应用是一个快速发展的领域,它结合了计算机视觉和机器学习算法来自动识别和分类植物上的病虫害。以下是这一技术的一些关键步骤和组成部分: 1. **数据收集**:首先需要收集大量的植物图像数据,这些数据包括健康植物的图像以及受不同病虫害影响的植物图像。 2. **图像预处理**:对收集到的图像进行处理,以提高后续分析的准确性。这可能包括调整亮度、对比度、去噪、裁剪、缩放等。 3. **特征提取**:从图像提取有助于识别病虫害的特征。这些特征可能包括颜色、纹理、形状、边缘等。 4. **模型训练**:使用机器学习算法(如支持向量机、随机森林、卷积神经网络等)来训练模型。训练过程,算法会学习如何根据提取的特征来识别不同的病虫害。 5. **模型验证和测试**:在独立的测试集上验证模型的性能,以确保其准确性和泛化能力。 6. **部署和应用**:将训练好的模型部署到实际的病虫害检测系统,可以是移动应用、网页服务或集成到智能农业设备。 7. **实时监测**:在实际应用,系统可以实时接收植物图像,并快速给出病虫害的检测结果。 8. **持续学习**:随着时间的推移,系统可以不断学习新的病虫害样本,以提高其识别能力。 9. **用户界面**:为了方便用户使用,通常会有一个用户友好的界面,显示检测结果,并提供进一步的指导或建议。 这项技术的优势在于它可以快速、准确地识别出病虫害,甚至在早期阶段就能发现问题,从而及时采取措施。此外,它还可以减少对化学农药的依赖,支持可持续农业发展。随着技术的不断进步,图像识别在病虫害检测的应用将越来越广泛。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值