LeetCode刷题笔记(2)

LeetCode刷题笔记(2)

背景

今天刷题刷了大概4道半,双指针的题目结束了,刚刚开始了快速选择的题目。

141、给定一个链表,判断链表中是否有环

//ListNode的数据格式
    class ListNode {
      int val;
      ListNode next;
      ListNode(int x) {
          val = x;
          next = null;
      }
  }
  public class LinkedListCycle141 {
    private Object HashSet;
    public boolean hasCycle(ListNode head){
        Set<ListNode> nodesSeen = new HashSet<>();
        //遍历ListNode哈希表中存储每个节点的内存地址
        while (head != null){
            if(nodesSeen.contains(head)){
                return true;
            }else{
                nodesSeen.add(head);
            }
            head = head.next;
        }
        return false;

    }
  //总结:这个方法利用Hash表中每个节点都有独特的引用(或者内存地址)
/*
方法二:双指针
通过使用具有 不同速度 的快、慢两个指针遍历链表,
空间复杂度可以被降低至 O(1)。
慢指针每次移动一步,而快指针每次移动两步。
如果列表中不存在环,最终快指针将会最先到达尾部,此时我们可以返回 false。
 */
public  boolean hasCycle2(ListNode head){
    if(head == null || head.next == null) return false;
    ListNode slow = head;
    ListNode fast = head.next;
    while(slow != fast){
        if(fast == null || fast.next == null){
            return false;
        }
     	slow = slow.next;
        fast=fast.next.next;
    }
    return true;
}
}
//总结:这个方法利用快指针和慢指针,主要的思想就是如果是环,那么快指针一定能够追上慢指针。困惑的地方在于最后为什么是fast.next.next

88、MergeSortedArra

/**

  • Input:
  • nums1 = [1,2,3,0,0,0], m = 3
  • nums2 = [2,5,6], n = 3
  • Output: [1,2,2,3,5,6]
    */
/*
方法二 : 双指针 / 从前往后
最直接的算法实现是将指针p1 置为 nums1的开头,
nums2的开头,在每一步将最小值放入输出数组中。
*/
public class MergeSortedArray88 {
   public void merge(int[] nums1,int m,int[] nums2,int n){
       int[] nums11_copy = new int[m];
       System.arraycopy(nums1,0,nums11_copy,0,m);

       int p1 = 0;
       int p2 = 0;

       int p= 0;
       while((p1<m)&&(p2<n))//nums11_copy与nums2进行比较
           nums1[p++] = (nums11_copy[p1] < nums2[p2]? nums11_copy[p1++]:nums2[p1++];
       if(p1<m)
           System.arraycopy(nums11_copy,p1,nums1,p1+p2,m+n-p1-p2);
       if(p2<n)
           System.arraycopy(nums2,p2,nums1,p1+p2,m+n-p1-p2);
       }
       //总结:这个方法比较繁琐,另外开辟了一个nums11_copy数组,
       //比较nums1和nums2中的元素,谁小就把谁放到nums11_copy当中。
/*

方法三 从后往前
这里的指针 p 用于追踪添加元素的位置。
*/
public void merge2(int[] nums11,int m, int[] nums22, int n){
   int p1 = m-1;
   int p2 = n-1;
   int p = m+n-1;
   while ((p1 >= 0) && (p2 >= 0))
           nums11[p--] = (nums11[p1]<nums22[p1]) ? nums22[p2--]:nums11[p1--];
   System.arraycopy(nums22,0,nums11,0,p2+1);
   //总结:从后往前比第一个方法方便得多,
   //p用来追踪添加元素的位置,p1和p2分别是针对nums11和nums22
}
}

524、查看是否有匹配的字符

/**

  • Input:
  • s = “abpcplea”, d = [“ale”,“apple”,“monkey”,“plea”]
  • Output:
  • “apple”
    */
import java.util.List;

/*
解题思路:
只要利用两个指针i,j,一个指向s字符串,
一个指向sstr字符串,每一次查找过程中,i依次后移,
若i,j对应的两个字符相等,则j后移,
如果j可以移到sstr.length(),
那么说明sstr中对应的字符s中都有,
即s中删除一些字符后,
可以得到sstr字符串,
最后一步就是比较当前的结果字符与找到的sstr字符,
按照题目的需求来决定是否改变结果字符,是不是还挺简单的呀。

*/
public class StringfindLongestWord524 {
   public String findLongestWord(String s, List<String> d) {
       String str = "";
       for (String sstr : d) {
           for (int i = 0, j = 0; i < s.length() && j < sstr.length(); i++) {
               if (s.charAt(i) == sstr.charAt(j)) j++;
               if (j == sstr.length()) {
                   if (sstr.length() > str.length() || (sstr.length() == str.length() && str.compareTo(sstr) > 0))
                       str = sstr;
               }
           }
       }
       return str;
   }
   // 总结:这一步比较特殊,
   //主要是为了满足题目需求的长度最长而且序号在前
   //if (sstr.length() > str.length() || (sstr.length() == str.length() && str.compareTo(sstr) > 0))
   //如果之后有新的满足条件的sstr且长度比较长,可以覆盖之前的,如果两个sstr相等的话,jiuliyongstr.compareTo(sstr)>0
/*
方法二
*/
public String findLongestWord2(String s, List<String> d) {
   String longeatWord = "";
   for (String target:d){
       int l1 = longeatWord.length(),l2 = target.length();
       if(l1>l2||(l1==l2&&longeatWord.compareTo(target)<0)){
           continue;
       }
       if(isSubstr(s,target)){
           longeatWord = target;
       }
   }
   return longeatWord;
}

   private boolean isSubstr(String s, String target) {
       int i = 0,j = 0;
       while (i < s.length() && j <target.length()){
           if(s.charAt(i)==target.charAt(j)){
               j++;
           }
           i++;
       }
       return  j==target.length();
   }
   }
   //总结:isSubstr是否是子串,如果s中有target里面的元素那么j和i都后移,如果没有的话仅仅是i后移,return j==target.length()非常好,值得学习。

680、可以删除一个字符,判断是否能构成回文字符串。

/*
    贪心算法
    在允许最多删除一个字符的情况下,同样可以使用双指针,通过贪心算法实现。
    初始化两个指针 low 和 high 分别指向字符串的第一个字符和最后一个字符。
    每次判断两个指针指向的字符是否相同,如果相同,则更新指针,
    令 low = low + 1 和 high = high - 1,
    然后判断更新后的指针范围内的子串是否是回文字符串。如果两个指针指向的字符不同,
    则两个字符中必须有一个被删除,此时我们就分成两种情况:即删除左指针对应的字符,
    留下子串 s[low + 1], s[low + 1], ..., s[high],或者删除右指针对应的字符,留下子串 s[low], s[low + 1], ..., s[high - 1]。当这两个子串中至少有一个是回文串时,就说明原始字符串删除一个字符之后就以成为回文串。
 */
public class validPalindrome680 {
    int del = 0;
    public boolean validPalindrome(String s ){
        int i = 0,j= s.length()-1;
        while(i < j){
            if(s.charAt(i)==s.charAt(j)){
                i++;
                j--;
            }else{
                if(del == 0){
                    del++;
                    return validPalindrome(s.substring(i,j))||validPalindrome(s.substring(i+1,j+1));
//public String substring(int beginIndex, int endIndex)
//返回一个新字符串,它是此字符串的一个子字符串。该子字符串从指定的 beginIndex 处开始,
// endIndex:到指定的 endIndex-1处结束。
//参数:beginIndex - 开始处的索引(包括)
//      endindex 结尾处索引(不包括)。
                }
            }
            return false;
        }
        return true;
    }
}
//总结:substring() 方法用于提取字符串中介于两个指定下标之间的字符。
//return validPalindrome(s.substring(i,j))||validPalindrome(s.substring(i+1,j+1))

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值