leetCode每日十题---排序(三)

题目描述1

在这里插入图片描述

笔者解答1.1

class Solution {
    
    
    public String findLongestWord(String s, List<String> d) {
    
    
     PriorityQueue<String> queue=new PriorityQueue<>((o1,o2)->{
    
    
         if(o1.length()==o2.length()){
    
    
             return o1.compareTo(o2);
         }else{
    
    
             return o2.length()-o1.length();
         }
     });
     if(s.length()==0)return "";
     int n=d.size();
     int i;
     for(i=0;i<n;i++){
    
    
         queue.offer(d.get(i));
     }
     String str="";
     n=s.length();
     while(!queue.isEmpty()){
    
    
         String temp_str=queue.poll();
         int k=0;
         int j=0;
         for(;j<temp_str.length();j++){
    
    
             for(;k<n;k++){
    
    
                if(temp_str.charAt(j)==s.charAt(k))break; 
             }
             if(k==n&&j!=temp_str.length()-1)break;
         }
         if(j==temp_str.length())return temp_str;
     }
     return str;
    }
}

笔者分析1.2

这次代码还有最后几个用例没有通过,不太明白为什么,而且感觉自己的算法虽然在每个字符串比较前排了序,可以较快的找到合适的字符串,但是在单一字符串每个字符验证的时候,算法过于笨拙,时间复杂度太高,哎,求助评论区。等下,下面这个AC的算法好像和我思路是一样的。。。。而且看最后执行数据的话,好像也还不错。!

class Solution {
    
    
    public String findLongestWord(String s, List<String> d) {
    
    
        Collections.sort(d);
        String res = "";
        for(String word:d){
    
    
            if(check(s,word)&&word.length()>res.length()){
    
    
                res = word;
            }
        }
        
        return res;
    }
    
    /*利用双指针法判断子串*/
    public boolean check(String s,String p){
    
    
        char[] ss = s.toCharArray();
        char[] pp = p.toCharArray();
        int i=0,j=0;
        while(i<ss.length&&j<pp.length){
    
    
            if(pp[j]==ss[i])
                j++;
            i++;
        }
        return j==pp.length;
    }
}

题目描述2

在这里插入图片描述

笔者分析2.1

可能开始看到这道题时,会觉得特别简单,我也是这么认为的,不就是用个优先遍历序列,再新建一个链表头结点,把堆中的结点弹出来就行么。但当我看到这道题,评论和题解数量都快破千的时候,才意识到这题里大有学问,有意思的 不是如何把这题写出来,而是如何更巧妙的写出来。
归并排序(递归法)

  • 题目要求空间复杂度分别为O(nlogn)和O(1),根据事件复杂度我们自然想到二分法,从而联想到归并排序;
  • 对数组做归并排序的空间复杂度为O(nlogn),分别由新开辟数组O(n)和递归递归函数调用O(logn)组成,而根据链表特性:数组额外空间:链表可以通过修改应用来更改节点顺序,无需像数组一样开辟额外空间;递归额外空间:递归函数将带来O(logn)的空间复杂度,因此若希望达到O(1)空间复杂度,则不能使用递归。
  • 通过递归实现链表归并排序,有以下两个环节:
  • 分割cut环节:当找到当前链表中点,并从中点将链表断开(以便在下次递归cut时,链表片段拥有正确边界);我们使用fast,slow快慢双指针法,奇数个结点找到中点,偶数个结点找到中心左边的结点;找到中点slow后,执行slow.next=None将链表切断;递归分割时,输入当前链表左端点head和中心结点slow的下一个结点tmp(因为链表是从slow切断的);cut递归终止条件:当head.next==None时,说明只有一个结点了,直接返回此结点。
  • 合并merge环节:将两个排序链表合并,转化为一个排序链表。双指针法合并,建立辅助ListNode h作为头部;设置两指针left,right分别指向两链表头部,比较两指针处结点值大小,由小到大加入合并链表头部,指针交替前进,直至添加完两个链表;返回辅助ListNode h作为头部的下一个结点h.next;时间复杂度O(l+r),l,r分别代表两个链表长度。
  • 当题目输入的head==None时,直接返回None.
public ListNode sortList(ListNode head){
    
    
  //1.递归结束条件
  if(head==null||head.next==null)
     return head;
  //2.找到链表中间结点并断开链表&递归下探
  ListNode midNode=middleNode(head);
  ListNode rightHead=midNode.next;
  midNode.next=null;
  ListNode left=sortList(head);
  ListNode right=sortList(rightHead);
  //3.当前层业务操作(合并有序链表)
   return mergeTwoLists(left,right);   
}
//找到链表中间结点
private ListNode middleNode(ListNode head){
    
    
  if(head==null||head.next==null){
    
    
     return head;
  }
  ListNode slow=head;
  ListNode fast=head.next.next;
  while(fast!=null&&fast.next!=null){
    
    
    slow=slow.next;
    fast=fast.next.next;
  }
  return slow;
}
//合并两个有序链表
private ListNode mergeTwoLists(ListNode l1,ListNode l2)
{
    
    
 ListNode sentry=new ListNode(-1);
 ListNode curr=sentry;
 while(L1!=null&&l2!=null){
    
    
  if(l1.val<l2.val){
    
    
   curr.next=l1;
   l1=l1.next;
  }else{
    
    
    curr.next=l2;
    l2=l2.next;
  }
  curr=curr.next;
 }
 curr.next=l1!=null?l1:l2;
 return sentry.next;
}

总结

感觉自己变懒了,虽然打卡不会停止,但热情没有刚开始的高了。可是,如果你想体会到真正的快乐,那就请给它多点时间,每日打卡第十一天,以下图为证
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/Achenming1314/article/details/108452452