Leetcode 680
题目描述:给定一个非空字符串 s,最多删除一个字符。判断是否能成为回文字符串。
示例一:
输入: "aba"
输出: True
示例二:
输入: "abca"
输出: True
解释: 你可以删除c字符。
思路:
双指针思想,分别从字符串头和尾进行依次遍历和比较。
增设删除标记判断是否使用过删除机会,遇到不等情况,则先判断删除标记,后选择删除后继续遍历或者返回不能成为回文字符串的结论。
踩坑点:
有一种情况:两个元素不相等时,且无论删除左边元素或是删除右边元素,都满足可以继续遍历的要求。例如"…cu…cu…"情况。
这时需要判断一下删除左边的或者右边的元素。故使用左右两个删除标记,始终规定先删除左边元素,后删除右边元素。
实现代码如下:
public class Lc680 {
public static void main(String[] args) {
String s = "aguokepatgbnvfqmgmlcupuufxoohdfpgjdmysgvhmvffcnqxjjxqncffvmhvgsymdjgpfdhooxfuupuculmgmqfvnbgtapekouga";
System.out.println(validPalindrome(s));
}
public static boolean validPalindrome(String s) {
char[] character = s.toCharArray();
int i = 0;
int j = character.length - 1;
boolean isRFirst = false,isLFirst=false;
while (i < j) {
if (character[i] == character[j]) {
i++;
j--;
} else if (!isLFirst) {
i++;
isLFirst = true;
}else if(!isRFirst){
i--;
j--;
isRFirst = true;
}
else return false;
}
return true;
}
}
查看题解后,发现递归解法很妙,简洁的同时不会遇到上述坑点。
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;
}
private boolean isPalindrome(String s, int i, int j) {
while (i < j) {
if (s.charAt(i++) != s.charAt(j--)) {
return false;
}
}
return true;
}
Leetcode 88
题目描述:给你两个有序整数数组 nums1 和 nums2,请你将 nums2 合并到 nums1 中*,*使 nums1 成为一个有序数组。m,n分别是两个数组的元素数量。
输入:
nums1 = [1,2,3,0,0,0], m = 3
nums2 = [2,5,6], n = 3
输出:
[1,2,2,3,5,6]
思路:
典型的归并排序。同时应用双指针的思想,与前者不同的是,前者双指针分别从头尾开始进行遍历。但此问题双指针分别从两个数组的头到尾进行遍历。
实现代码如下:
public class Lc88 {
public static void main(String[] args) {
int[] nums1 = new int[]{1, 2, 3, 0, 0, 0};
int[] nums2 = new int[]{2, 5, 6};
merge(nums1, 3, nums2, nums2.length);
System.out.println(Arrays.toString(nums1));
}
public static void merge(int[] nums1, int m, int[] nums2, int n) {
int[] temp = new int[m + n];
int i = 0;
int j = 0;
int k = 0;
while (i < m && j < n) {
if (nums1[i] < nums2[j]) {
temp[k++] = nums1[i++];
} else if (nums1[i] > nums2[j]) {
temp[k++] = nums2[j++];
} else {
temp[k] = nums1[i++];
temp[k + 1] = nums2[j++];
k += 2;
}
}
if (i < m) {
while (i < m) {
temp[k++] = nums1[i++];
}
}
if (j < n) {
while (j < n) {
temp[k++] = nums2[j++];
}
}
for (int d = 0; d < (m + n); d++) {
nums1[d] = temp[d];
}
}
}
提交后看题解,发现可以调库。/(ㄒoㄒ)/~~
Leetcode 141
题目描述:为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。
输入:head = [3,2,0,-4], pos = 1
输出:true
解释:链表中有一个环,其尾部连接到第二个节点。
思路:
双指针思想。但与之前不同的是,此问题需要用快慢双指针,即一个快指针和一个慢指针来求解。一个指针移动慢,一个指针移动快,如果存在环,那么这两个指针一定会相遇。
public class Lc141 {
public static void main(String[] args) {
ListNode node1 = new ListNode(3);
ListNode node2 = new ListNode(2);
ListNode node3 = new ListNode(0);
ListNode node4 = new ListNode(-4);
node1.next = node2;
node2.next = node3;
node3.next = node4;
node4.next = node2;
System.out.println(hasCycle(node1));
}
public static boolean hasCycle(ListNode head) {
if (head == null) return false;
ListNode p = head;
ListNode q = head.next;
while (q != null && (q.next) != null) {
if (p == q) return true;
p = p.next;
q = q.next.next;
}
return false;
}
}
class ListNode {
int val;
ListNode next;
ListNode(int x) {
val = x;
next = null;
}
}
题解中还有哈希表的解法,设置一个记录是否访问过该节点的标记数组,遍历整个链表,如果存在哈希冲突,则说明形成了环。
解法如下:
public boolean hasCycle(ListNode head) {
Set nodesSeen = new HashSet<>();
while (head != null) {
if (nodesSeen.contains(head)) {
return true;
} else {
nodesSeen.add(head);
}
head = head.next;
}
return false;
}作者:LeetCode
链接:https://leetcode-cn.com/problems/linked-list-cycle/solution/huan-xing-lian-biao-by-leetcode/
来源:力扣(LeetCode)
总结:双指针的用法层出不穷,头尾指针、快慢指针等等,在不同的问题求解时灵活使用。