Leetcode训练算法入门——双指针全刷

Posted 胡毛毛_三月

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Leetcode训练算法入门——双指针全刷相关的知识,希望对你有一定的参考价值。

目录

977. 有序数组的平方——简单

题目描述

题解

方法一:直接排序

class Solution 
    public int[] sortedSquares(int[] nums) 
        for (int i = 0; i < nums.length; i++) 
			nums[i] = nums[i]*nums[i];
		
		Arrays.sort(nums);
        return nums;
    

复杂度分析

  • 时间复杂度:O(nlogn),其中 nn 是数组 nums 的长度。
  • 空间复杂度:O(logn)。除了存储答案的数组以外,我们需要 O(logn) 的栈空间进行排序。

方法二:双指针

class Solution 
    public int[] sortedSquares(int[] nums) 
        int arr[] = new int [nums.length];
		for (int i = 0,j=nums.length-1,k=nums.length-1;i<=j;) 
			if (nums[i]*nums[i]>nums[j]*nums[j]) 
				arr[k]=nums[i]*nums[i];
				i++;
			
			else 
				arr[k]=nums[j]*nums[j];
				j--;
			
			k--;
		
        return arr;
    

复杂度分析

  • 时间复杂度:O(n),其中 n 是数组nums 的长度。
  • 空间复杂度:O(1)。除了存储答案的数组以外,我们只需要维护常量空间。

189. 轮转数组——中等

题目描述

题解

方法一:使用额外的数组

我们可以使用额外的数组来将每个元素放至正确的位置。用 nn 表示数组的长度,我们遍历原数组,将原数组下标为 i 的元素放至新数组下标为 (i+k)mod n 的位置,最后将新数组拷贝至原数组即可。

class Solution 
    public void rotate(int[] nums, int k) 
        int n = nums.length;
        int[] newArr = new int[n];
        for (int i = 0; i < n; ++i) 
            newArr[(i + k) % n] = nums[i];
        
        System.arraycopy(newArr, 0, nums, 0, n);
    

复杂度分析

  • 时间复杂度: O(n),其中 nn 为数组的长度。
  • 空间复杂度: O(n)。

方法二:

将原数组从后往前的k个数取出,放入新数组,再将原数组的剩余前面的数取出放入新数组后面

class Solution 
    public void rotate(int[] nums, int k) 
        int arr[]=new int[nums.length];
		if(k>nums.length) 
			k=k%nums.length;
		
		for (int i = nums.length-k,j=0; i < nums.length; i++) 
			arr[j]=nums[i];
			j++;
		
		for (int i = 0,j=k; i <nums.length-k;) 
			arr[j]= nums[i];
			++i;
			j++;
		
//		for (int i : arr) 
//			System.out.println(i);
//		
		
		System.arraycopy(arr, 0, nums, 0, nums.length);
    


283. 移动零——简单

题目描述

题解

方法一:

//思路:设置一个index,表示非0数的个数,循环遍历数组,
// 如果不是0,将非0值移动到第index位置,然后index + 1
//遍历结束之后,index值表示为非0的个数,再次遍历,从index位置后的位置此时都应该为0
class Solution 
    public void moveZeroes(int[] nums) 
        		int index=0;
		for (int i = 0; i < nums.length; i++) 
			if (nums[i]!=0) 
				nums[index]=nums[i];
				index++;
			
		
		for (int i = index; i < nums.length; i++) 
			nums[index] = 0;
			index++;
		
    

方法二:双指针

class Solution 
    public void moveZeroes(int[] nums) 
        int left = 0;
    	int right =0;
    	while (right<nums.length) 
			if (nums[right]!=0) 
				swap(nums, left, right);
				left++;
			
			right++;
		
    
    public void swap(int nums[],int left,int right) 
    	int temp = nums[left];
    	nums[left] = nums[right];
    	nums[right] = temp;
    
    

复杂度分析


167. 两数之和 II - 输入有序数组——简单

题目描述

题解

方法一:双指针

class Solution 
    public int[] twoSum(int[] numbers, int target) 
//    	int arr [] = new int [2];
    	int left = 0;
    	int right = numbers.length-1;
    	while (left<right) 
    		if (numbers[left]+numbers[right]==target) 
    			return new int[] left+1,right+1;
			else if (numbers[left]+numbers[right]<target) 
				left++;
			else 
				right--;
			
		   	
    	return new int[0];
    

复杂度分析

方法二:二分查找

class Solution 
    public int[] twoSum(int[] numbers, int target) 
//    	int arr[] = new int [2];
    	for (int i = 0; i < numbers.length; i++) 
			int low = i+1;
			int high = numbers.length-1;
			while (low<=high) 
				int middle = low +(high-low)/2;
				if (numbers[middle]==target-numbers[i]) 
					 return new int[]i + 1, middle + 1;
				else if (numbers[middle]>target-numbers[i]) 
					high=middle-1;
				else 
					low=middle+1;
				
			
		
    	return new int[0];
    

复杂度分析


344. 反转字符串——简单

题目描述

题解

方法一:倒叙输出

class Solution 
    public void reverseString(char[] s) 
        StringBuffer sb = new StringBuffer();
    	for (int i = s.length-1; i >=0; i--) 
			 sb.append(s[i]);
		
    	for(int i=0;i<sb.length();i++) 
    		s[i] = sb.charAt(i);
    	
    

复杂度分析

方法二:reserve()反转

class Solution 
    public void reverseString(char[] s) 
    	StringBuffer sb = new StringBuffer();
    	for(int i=0;i<s.length;i++) 
    		sb.append(s[i]);
    	
    	sb=sb.reverse();
    	
    	for(int i=0;i<sb.length();i++) 
    		s[i] = sb.charAt(i);
    	
    

复杂度分析

方法三:双指针

class Solution 
    public void reverseString(char[] s) 
    	int p1 = 0;
    	int p2 = s.length-1;
    	char a;
    	while (p1<p2) 
    		a = s[p1];
    		s[p1++] = s[p2];
    		s[p2--] = a;
		
    

复杂度分析


557. 反转字符串中的单词 III——简单

题目描述

题解

方法一:字符串分割反转

class Solution 
    public String reverseWords(String s) 
    	StringBuffer sb = new StringBuffer();
    	String a[] = s.split(" ");
    	
    	for (int i = 0; i < a.length; i++) 
			StringBuffer sb2 = new StringBuffer(a[i]);
			sb2 = sb2.reverse();
			if (i!=a.length-1) 
				sb.append(sb2+" ");
			else 
				sb.append(sb2);
			
    	
    	s = sb.toString();
    	return s;
    	

复杂度分析


876. 链表的中间结点——简单

题目描述

题解

思路:

方法一:快慢指针法

快指针q每次走2步,慢指针p每次走1步,当q走到末尾时p正好走到中间。

/**
 * Definition for singly-linked list.
 * public class ListNode 
 *     int val;
 *     ListNode next;
 *     ListNode() 
 *     ListNode(int val)  this.val = val; 
 *     ListNode(int val, ListNode next)  this.val = val; this.next = next; 
 * 
 */
class Solution 
    public ListNode middleNode(ListNode head) 
    	ListNode p1 = head;
    	ListNode p2 = head;
    	while (p2!=null&&p2.next!=null) 
			p1 = p1.next;
			p2 = p2.next.next;
		
    	return p1;
    

复杂度分析

方法二:List数组

/**
 * Definition for singly-linked list.
 * public class ListNode 
 *     int val;
 *     ListNode next;
 *     ListNode() 
 *     ListNode(int val)  this.val = val; 
 *     ListNode(int val, ListNode next)  this.val = val; this.next = next; 
 * 
 */
class Solution 
    public ListNode middleNode(ListNode head) 
    	List<ListNode> list = new ArrayList<>();
    	while (head!=null) 
    		list.add(head);
    		head = head.next;
		
    	int middle = list.size();
		middle = middle/2;
    	return list.get(middle);
    


19. 删除链表的倒数第 N 个结点——中等

题目描述

给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。

示例 1:

示例 2:

示例 3:

题解

方法一:双指针

/**
 * Definition for singly-linked list.
 * public class ListNode 
 *     int val;
 *     ListNode next;
 *     ListNode() 
 *     ListNode(int val)  this.val = val; 
 *     ListNode(int val, ListNode next)  this.val = val; this.next = next; 
 * 
 */
class Solution 
    public ListNode removeNthFromEnd(ListNode head, int n) 
    	ListNode p1 = head;
    	ListNode p2 = head;
    	if (head==null||head.next==null) 
			return null;
		
        // 先让快指针走n步
    	for(int i=0;i<n;i++) 
			p1 = p1.next;
    	
        // 如果快指针走到了最后说明删除的是第一个节点,就返回head.next就好
    	if(p1 == null) 
    		return head.next;
    	
    	while (p1.next!=null) 
			p1 = p1.next;
			p2 = p2.next;
		
    	p2.next = p2.next.next;
    	return head;
    	
    

复杂度分析


以上是关于Leetcode训练算法入门——双指针全刷的主要内容,如果未能解决你的问题,请参考以下文章

Leetcode训练剑指 Offer(专项突击)——双指针全刷

Leetcode训练数据结构入门——数组全刷

算法入门双指针(中等 - 第二题)LeetCode 567

算法入门双指针(中等 - 第一题)LeetCode 3

算法入门 03双指针(简单 - 第二题)LeetCode 283

⭐算法入门⭐《双指针》困难01 —— LeetCode 76. 最小覆盖子串