【Leetcode题解】--【算法】--【双指针】--by java

No.1 【TwoSum Ⅱ】

【难度】:Easy

【题目描述】:

给定一个已按照升序排列 的有序数组,找到两个数使得它们相加之和等于目标数。
函数应该返回这两个下标值 index1 和 index2,其中 index1 必须小于 index2。

说明:
返回的下标值(index1 和 index2)不是从零开始的。
你可以假设每个输入只对应唯一的答案,而且你不可以重复使用相同的元素。

示例:
输入: numbers = [2, 7, 11, 15], target = 9
输出: [1,2]

解释: 2 与 7 之和等于目标数 9 。因此 index1 = 1, index2 = 2 。

【思路分析与实现】:

暴力解法:

关键比较target - x 与 y 是否相等,所以定义一个双循环遍历,用双循环来比较,外层循环,控制遍历第一个元素,内层循环控制第二个元素且从第二个元素开始,带入公式比较,如果满足公式,则用一个数组储存这两个下标,所以定义一个数组类型的方法,返回一个数组
时间复杂度:O(n²)

代码:

public static int[] m1(int[] a,int num) {
	for(int i = 0;i<a.length;i++) {
		for(int j =a.length-1;j>i;j--) {
			if(num == a[i] + a[j]) {
				return new int[]{i,j};
			}
		}
	}
	throw new IllegalArgumentException("No two sum solution");
}

哈希码表法:

用哈希表简化,用空间换取时间,比暴力拆解会更耗内存
一个简单的实现使用了两次迭代。在第一次迭代中,我们将每个元素的值和它的索引添加到表中。然后,在第二次迭代中,我们将检查每个元素所对应的目标元素(target - nums[i])是否存在于表中。注意,该目标元素不能是 nums[i]本身!
时间复杂度:O(n)

代码:

public int[] twoSum(int[] nums, int target) {
	Map<Integer, Integer> map = new HashMap<>();
	for (int i = 0; i < nums.length; i++) {
	  map.put(nums[i], i);
	}
	for (int i = 0; i < nums.length; i++) {
		int complement = target - nums[i];
		if (map.containsKey(complement) && map.get(complement) != i) {
		  return new int[] { i, map.get(complement) };
		}
	}
	throw new IllegalArgumentException("No two sum solution");
}

No.2 【Sum of Square Numbers】

【难度】:Easy

【题目描述】:

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

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

【思路分析与实现】:

一个数是否为两个整数的平方和,其中一个数a必定<=这个数target(等号成立a²+0²),所以定义一个整数a从0开始遍历,以平方的形式递增到target,再定义一个double类型的数b,因为b可能是有理数,所以判断当b是整数时,代表这个数时两个整数的平方和。

代码:

public static boolean m1(int target) {
	if(target < 0) {
		return false;
	}
	for(int a = 0;a*a <= target;a++) {
		double b = Math.sqrt(target-a*a);
		if(b == (int)b) {
			return true;
		}
	}
	return false;
}

No.3【Reverse Vowels of a String】

【难度】:Easy

【题目描述】:

编写一个函数,以字符串作为输入,反转该字符串中的元音字母。

示例 1:

输入: "hello"
输出: "holle"
示例 2:

输入: "leetcode"
输出: "leotcede"

【思路分析与实现】:

用一个HashSet储存所有的元音字母,大小写都包括进去,定义两个变量,i和j
一个从字符串头向尾开始遍历,一个从字符串尾向头开始遍历,当两个变量指向元音时,交换两个标量所代表的值。

代码:

public static Arrays.asList('a', 'e', 'i', 'o', 'u', 'A', 'E', 'I', 'O', 'U'));

public String reverseVowels(String s) {
    if (s == null) return null;
    int i = 0, j = s.length() - 1;
    char[] result = new char[s.length()];
    while (i <= j) {
        char ci = s.charAt(i);
        char cj = s.charAt(j);
        if (!vowels.contains(ci)) {
            result[i++] = ci;
        } else if (!vowels.contains(cj)) {
            result[j--] = cj;
        } else {
            result[i++] = cj;
            result[j--] = ci;
        }
    }
    return new String(result);
}

No.4 【Valid Palindrome II】

【难度】:Easy

【题目描述】:

给定一个非空字符串 s,最多删除一个字符。判断是否能成为回文字符串。

示例 1:

输入: "aba"
输出: True
示例 2:

输入: "abca"
输出: True
解释: 你可以删除c字符。

注意:
字符串只包含从 a-z 的小写字母。字符串的最大长度是50000。

【思路分析与实现】:

定义两个指针,一个从左到右遍历,一个从右到左遍历,如果一样就继续遍历,每次移动一个位置,就判断一次。如果不一样,就删除左边或者右边指针所对应的值,然后继续遍历。

代码:

public boolean validPalindrome(String s) {
  for (int i = 0, j = s.length() - 1; i < j; i++, j--) {
      if (s.charAt(i) != s.charAt(j)) {
          return isPalindrome(s, i, j - 1) || isPalindrome(s, i + 1, j);
      }
  }
  return true;
}
boolean isPalindrome(String s, int i, int j) {
    while (i < j) {
        if (s.charAt(i++) != s.charAt(j--)) {
            return false;
        }
    }
    return true;
}

No.5 【Merge Sorted Array】

【难度】:Easy

【题目描述】:

给定两个有序整数数组 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]

【思路分析与实现】:

因为假设第一个数组有足够的空间,所以不会发生要扩展数组内存的情况,且从后往前开始比较整合,因为整合后的数组是有序的,从后往前开始比较整合就不用移动元素来腾出空间放新的元素。

代码:

public void merge(int[] nums1, int m, int[] nums2, int n) {
    int index1 = m - 1, index2 = n - 1;
    int indexMerge = m + n - 1;
    while (index1 >= 0 || index2 >= 0) {
        if (index1 < 0) {
            nums1[indexMerge--] = nums2[index2--];
        } else if (index2 < 0) {
            nums1[indexMerge--] = nums1[index1--];
        } else if (nums1[index1] > nums2[index2]) {
            nums1[indexMerge--] = nums1[index1--];
        } else {
            nums1[indexMerge--] = nums2[index2--];
        }
    }
}

No.6 【Linked List Cycle】

【难度】:Easy

【题目描述】:

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

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

示例 1:

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

在这里插入图片描述

【思路分析与实现】:

定义两个指针,一个每次移动一个节点,一个每次移动两个节点,如果有环,
那么一定会相遇两个指针

public boolean hasCycle(ListNode head) {
    if (head == null) {
        return false;
    }
    ListNode l1 = head, l2 = head.next;
    while (l1 != null && l2 != null && l2.next != null) {
        if (l1 == l2) {
            return true;
        }
        l1 = l1.next;
        l2 = l2.next.next;
    }
    return false;
}

No.7 【 Longest Word in Dictionary through Deleting】

【难度】:Medium

【题目描述】:

给定一个字符串和一个字符串字典,找到字典里面最长的字符串,该字符串可以通过删
除给定字符串的某些字符来得到。如果答案不止一个,返回长度最长且字典顺序最小的
字符串。如果答案不存在,则返回空字符串。

示例 1:

输入:
s = "abpcplea", d = ["ale","apple","monkey","plea"]

输出: 
"apple"
示例 2:

输入:
s = "abpcplea", d = ["a","b","c"]

输出: 
"a"
说明:

所有输入的字符串只包含小写字母。
字典的大小不会超过 1000。
所有输入的字符串长度不会超过 1000。

【思路分析与实现】:

通过删除字符串 s 中的一个字符能得到字符串 t,可以认为 t 是 s 的子序列,我们可以使用双指针来判断一个字符串是否为另一个字符串的子序列

代码:

public String findLongestWord(String s, List<String> d) {
   String longestWord = "";
   for (String target : d) {
       int l1 = longestWord.length(), l2 = target.length();
       if (l1 > l2 || (l1 == l2 && longestWord.compareTo(target) < 0)) {
           continue;
       }
       if (isSubstr(s, target)) {
           longestWord = target;
       }
   }
   return longestWord;
}

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();
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值