LeetCode刷题-- 双指针

被刻印的时光 ゝ 提交于 2020-02-19 04:27:09

26. 删除数组中的新元素

给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。

不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。

示例 1:
给定数组 nums = [1,1,2],
函数应该返回新的长度 2, 并且原数组 nums 的前两个元素被修改为 1, 2。

示例 2:
给定 nums = [0,0,1,1,1,2,2,3,3,4],
函数应该返回新的长度 5, 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4。

class Solution {
    public int removeDuplicates(int[] nums) {
   //i指向要保留的数;
   //j遍历整个数组
   int i = 0;
   for(int j = 1; j < nums.length; j++){
       if(nums[i] != nums[j]){
           i++;//找到了需要保留的数字,让i后移,腾出位置
           nums[i] = nums[j];
       }
   }
   return i+1;
    }
}

633. 平方数之和

给定一个非负整数 c ,你要判断是否存在两个整数 a 和 b,使得 a2 + b2 = c。

示例1:
输入: 5
输出: True
解释: 1 * 1 + 2 * 2 = 5

示例2:
输入: 3
输出: False

class Solution {
    public boolean judgeSquareSum(int c) {
     int i = 0;
     int j = (int) Math.sqrt(c);//取平方根
     int target = 0;
     //当两数平方和等于2时,i和j都等于1,说明i可以等于j
     while(i<=j){
         target = i*i+j*j;
         if(target == c){
             return true;
         }else if(target < c){
             i++;
         }else{
             j--;
         }
     }
     return false;
    }
}

88. 合并两个有序数组

给定两个有序整数数组 nums1 和 nums2,将 nums2 合并到 nums1 中,使得 num1 成为一个有序数组。

说明:
初始化 nums1 和 nums2 的元素数量分别为 m 和 n。
你可以假设 nums1 有足够的空间(空间大小大于或等于 m + n)来保存 nums2 中的元素。

示例:
输入:
nums1 = [1,2,3,0,0,0], m = 3
nums2 = [2,5,6], n = 3

输出: [1,2,2,3,5,6]

class Solution {
    public void merge(int[] nums1, int m, int[] nums2, int n) {
       //归并排序
       //因为填充数字在nums1后面,所以从后往前开始遍历
       int i1 = m-1;//指向nums1的末尾
       int i2 = n-1; //指向nums2的末尾
       int index = m+n-1;//指向合并完的数组的末尾

       while(i1>=0 && i2>= 0){
           //如果nums1大,就填充nums1
           if(nums1[i1] > nums2[i2]){
            nums1[index--] = nums1[i1--];
           }else{
               nums1[index--] = nums2[i2--];
           }
        
       }
       //如果还有数组没有被填充完;
       //如果是nums1,就不用管,因为本来就是要填充给nums1的;
       //如果是nums2,就全部赋值进去
       while(i2>=0){
           nums1[index--] = nums2[i2--];
       }
    }
}

141. 环形链表

给定一个链表,判断链表中是否有环。
为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。

示例 1:
输入:head = [3,2,0,-4], pos = 1
输出:true
解释:链表中有一个环,其尾部连接到第二个节点。

在这里插入图片描述
思路:遍历,如果遇到null,则一定不是环形;
遍历,如果遇到之前重复的node,则一定是环形。
两种方法解决:快慢指针; HashMap
对应情景:快慢指针,想象是两个运动员在操场上进行长跑,最终肯定会相遇。
HashMap想想运动员每跑几分钟,就拍一下照片,最终肯定有重复场景的两张照片

/**
 * Definition for singly-linked list.
 * class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public boolean hasCycle(ListNode head) {
        //头部处理
        //没有节点,不能构成环;
        //只有一个结点,也不能构成环
        if(head == null || head.next == null)  return false;

        //快慢指针
        //想想自己在运动场进行长跑的场景,
        //如果有环,快指针跑两圈,慢指针跑一圈,他们就会相遇
        ListNode slow = head;
        ListNode fast = head.next;
        while(fast != null && fast.next != null){
           //此时让快指针走两步
           //慢指针走一步
           slow = slow.next;
           fast = fast.next.next;
           //如果相遇,有环
           if(slow == fast){
               return true;
           }
       }
       return false;      
    }
}
/**
 * Definition for singly-linked list.
 * class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
 //思路:判断链表有无环;
 //找出环的入口
public class Solution {
    public ListNode detectCycle(ListNode head) {
      //先对链表进行一个自检
      if(head == null || head.next == null){
          return null;
      }

      //定义一个快指针,慢指针,判断有无环
      //快指针每次走两步,慢指针每次走一步
      //设在环状列表入口前有a个节点,环形里面有b个节点,链表总共有a+b个节点
      //那么在相遇时,fast指针走了s+nb步
      //fast是slow的步数两倍,所以f = s+nb = 2s
      //f = 2nb, s= nb,这是第一次相遇时两个指针走的步数
      //此时我们想知道环形的入口,s已经走了nb步,我们只要再让s走a步数停下来,
      //把这个链表走完,他(s)就从链表口,也就是环形入口那里出来了
      //就可以知道链表环状入口在哪里了
      //依旧使用双指针的方法,我们定义一个指针,从头开始走,陪着s走a步,在环状入口他们就会第二次相遇
      //因为他们一起把链表走完了
      ListNode fast = head;
      ListNode slow =head;
      boolean hascycle = false;
      while(fast!=null && fast.next != null){
          fast = fast.next.next;
          slow = slow.next;
          if(fast == slow){
              hascycle = true;
              break;
              //break是跳出本层循环,在本题中,是跳出if语句;
              //continue是跳出本次循环,但是下次循环仍继续
          }
      }
      //定义第三个指针,第三个指针和慢指针相遇的地方就是环的入口 
      if(hascycle){
       ListNode third = head;
       while(slow != third){
           slow = slow.next;
           third = third.next;
       }
       return third;
      }
      return null;
}
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!