Leetcode(easy Double pointer)
Posted BOTAK
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Leetcode(easy Double pointer)相关的知识,希望对你有一定的参考价值。
Leetcode(easy Double pointer)
Leetcode 双指针简单题目
26 删除排序数组中的重复项
class Solution{
public int removeDuplicates(int[] nums){
// step代表慢指针
int step = 0;
// 这里面的i就相当于快指针
for(int i = 1;i<nums.length;i++){
if(nums[i] != nums[step]){
// 满指针后移 存放i指向的不同的元素
step++;
nums[step] = nums[i];
}
}
return step+1;
}
}
27 移除元素
class Solution{
public int removeElement(int[] nums,int val){
int step = 0;
for(int i = 0;i<nums.length;i++){
if(nums[i]!=val){
nums[step] = nums[i];
step++;
}
}
return step;
}
}
28 实现strStr()
实现 strStr() 函数。给定一个 haystack 字符串和一个 needle 字符串,在 haystack 字符串中找出 needle 字符串出现的第一个位置 (从0开始)。如果不存在,则返回 -1。
class Solution {
public int strStr(String haystack, String needle) {
int L = needle.length(), n = haystack.length();
if (L == 0) return 0;
int pn = 0;
while (pn < n - L + 1) {
while (pn < n - L + 1 && haystack.charAt(pn) != needle.charAt(0)) ++pn;
int currLen = 0, pL = 0;
while (pL < L && pn < n && haystack.charAt(pn) == needle.charAt(pL)) {
++pn;
++pL;
++currLen;
}
if (currLen == L) return pn - L;
pn = pn - currLen + 1;
}
return -1;
}
}
88 合并两个有序数组
给你两个有序整数数组 nums1 和 nums2,请你将 nums2 合并到 nums1 中,使 nums1 成为一个有序数组。
class Solution {
public void merge(int[] nums1, int m, int[] nums2, int n) {
int i = m-1;
int j = n-1;
int index = m+n-1;
while(i>-1&&j>-1){
if(nums1[i]<nums2[j]){
nums1[index] = nums2[j];
j--;
index--;
}else{
nums1[index] = nums1[i];
i--;
index--;
}
}
while(i>-1){
nums1[index] = nums1[i];
i--;
index--;
}
while(j>-1){
nums1[index] = nums2[j];
j--;
index--;
}
}
}
125 验证回文串
给定一个字符串,验证它是否是回文串,只考虑字母和数字字符,可以忽略字母的大小写。
class Solution {
public boolean isPalindrome(String s) {
int n = s.length();
int left = 0, right = n - 1;
while (left < right) {
while (left < right && !Character.isLetterOrDigit(s.charAt(left))) {
++left;
}
while (left < right && !Character.isLetterOrDigit(s.charAt(right))) {
--right;
}
if (left < right) {
if (Character.toLowerCase(s.charAt(left)) != Character.toLowerCase(s.charAt(right))) {
return false;
}
++left;
--right;
}
}
return true;
}
}
141 环形链表
给定一个链表,判断链表中是否有环。
/**
* 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 fast = head;
ListNode slow = head;
while(fast!=null && fast.next !=null && slow!=null){
// 一定要把if(fast == slow) return 放在移动过指针的下面,不然的话初始状态肯定是相等的
slow = slow.next;
fast = fast.next.next;
if(fast == slow) return true;
}
return false;
}
}
167. 两数之和 II - 输入有序数组
给定一个已按照升序排列 的有序数组,找到两个数使得它们相加之和等于目标数。函数应该返回这两个下标值 index1 和 index2,其中 index1 必须小于 index2。
class Solution {
public int[] twoSum(int[] numbers, int target) {
// 设置两个指针
int i = 0;
int j = numbers.length - 1;
boolean flag = true;
while(flag){
if(numbers[i] + numbers[j] > target) j--;
else if(numbers[i] + numbers[j] < target) i++;
else return new int[]{i+1,j+1};
}
return new int[2];
}
}
234 回文链表
请判断一个链表是否为回文链表。
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public boolean isPalindrome(ListNode head) {
if(head == null || head.next == null) return true;
ListNode pre = head;
ListNode cur = head;
int len = 0;
while(pre != null){
pre=pre.next;
len++;
}
pre = head;
int mid = (len%2)==1?(len/2+2):(len/2+1);
while(mid-- >1) cur = cur.next;
cur = reverse(cur);
while(cur != null && pre != null){
if(pre.val != cur.val) return false;
pre = pre.next;
cur = cur.next;
}
return true;
}
// 将链表翻转,并返回翻转之后的头结点
public ListNode reverse(ListNode root){
if(root == null || root.next == null) return root;
ListNode dummy = new ListNode(0);
dummy.next = null;
ListNode pre = root;
ListNode cur = root.next;
while(pre != null){
pre.next = dummy.next;
dummy.next = pre;
pre = cur;
if(cur!=null) cur = cur.next;
}
return dummy.next;
}
}
283. 移动零
给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
class Solution {
public void moveZeroes(int[] nums) {
/**
// 这种解法会导致非零元素的相对位置的改变
int i = 0;
int j = nums.length-1;
while(i<j){
// 正向找到0所在的下标
while(i<j && nums[i]!=0) i++;
// 反向找到不为0的数字所在的下标
while(i<j && nums[j]==0) j--;
int tmp = nums[i];
nums[i] = nums[j];
nums[j] = tmp;
i++;
j--;
}
*/
if(nums==null) {
return;
}
//第一次遍历的时候,j指针记录非0的个数,只要是非0的统统都赋给nums[j]
int j = 0;
for(int i=0;i<nums.length;++i) {
if(nums[i]!=0) {
nums[j++] = nums[i];
}
}
//非0元素统计完了,剩下的都是0了
//所以第二次遍历把末尾的元素都赋为0即可
for(int i=j;i<nums.length;++i) {
nums[i] = 0;
}
}
}
344. 反转字符串
编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 char[] 的形式给出。不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。
你可以假设数组中的所有字符都是 ASCII 码表中的可打印字符。
class Solution {
public void reverseString(char[] s) {
// 设置两个指针
int i = 0;
int j = s.length-1;
while(i<j){
char tmp = s[i];
s[i] = s[j];
s[j] = tmp;
i++;
j--;
}
}
}
345. 反转字符串中的元音字母
编写一个函数,以字符串作为输入,反转该字符串中的元音字母
class Solution {
public String reverseVowels(String s) {
Set<Character> yuan = new HashSet<>();
String str = "aeiouAEIOU";
for(Character c:str.toCharArray()) yuan.add(c);
// 设置两个指针,left和right,其中left指针从左向右查找元音字符,right从右向左查找元音字符,
int left = 0;
int right = s.length()-1;
// 因为java无法对字符串进行直接的操作,这里我们将字符串s变为字符数组
char[] s2c = s.toCharArray();
// 遍历s2c
while(left < right){
while(left < right && !yuan.contains(s2c[left])) left++;
while(left < right && !yuan.contains(s2c[right])) right--;
char temp = s2c[left];
s2c[left] = s2c[right];
s2c[right] = temp;
// 交换完毕之后,让指针移动
left++;
right--;
}
return String.valueOf(s2c);
}
}
349 两个数组的交集
题目:给定两个数组,编写一个函数来计算它们的交集。 不允许重复的元素出现在最终结果中。
class Solution {
public int[] intersection(int[] nums1, int[] nums2) {
Set<Integer> union = new HashSet<>();
Arrays.sort(nums1);
Arrays.sort(nums2);
// 设置两个指针 i和j 其中i指向nums1中的元素,j指向nums2中的元素
int i = 0;
int j = 0;
//只要两个nums还没有被遍历完,就继续便利
while(i < nums1.length && j < nums2.length){
// 如果指向的元素相同,则将元素添加到union中
if(nums1[i] == nums2[j]){
union.add(nums1[i]);
i++;
j++;
}
// 如果指向的元素不相同,则移动指针
else{
// 这时候移动指针也分为两种情况,第一种是nums1[i] > nums2[j]
if(nums1[i] > nums2[j]) j++;
else i++;
}
}
int[] res = new int[union.size()];
int index = 0;
for(int k:union) res[index++] = k;
return res;
}
}
350 两个数组的交集2
题目:给定两个数组,编写一个函数来计算它们的交集。 允许重复的元素出现在最终结果中。
class Solution {
public int[] intersect(int[] nums1, int[] nums2) {
List<Integer> union = new ArrayList<>();
Arrays.sort(nums1);
Arrays.sort(nums2);
// 设置两个指针 i和j 其中i指向nums1中的元素,j指向nums2中的元素
int i = 0;
int j = 0;
//只要两个nums还没有被遍历完,就继续便利
while(i < nums1.length && j < nums2.length){
// 如果指向的元素相同,则将元素添加到union中
if(nums1[i] == nums2[j]){
union.add(nums1[i]);
i++;
j++;
}
// 如果指向的元素不相同,则移动指针
else{
// 这时候移动指针也分为两种情况,第一种是nums1[i] > nums2[j]
if(nums1[i] > nums2[j]) j++;
else i++;
}
}
int[] res = new int[union.size()];
for(int k = 0;k<union.size();k++) res[k] = union.get(k);
return res;
}
}
844 比较含退格的字符串
题目:给定 S 和 T 两个字符串,当它们分别被输入到空白的文本编辑器后,判断二者是否相等,并返回结果。 # 代表退格字符。
// 虽然是可以用双指针来写这道题,不过相对而言,使用额外的数据结构更容易理解以及更容易实现。使用stack
class Solution {
public boolean backspaceCompare(String S, String T) {
return toString(S).equals(toString(T));
}
public String toString(String str){
Stack<Character> stack = new Stack<>();
for(Character c:str.toCharArray()){
if(c==‘#‘ && !stack.isEmpty()) stack.pop();
else if(c==‘#‘) continue;
else{
stack.push(c);
}
}
String res = "";
while(!stack.isEmpty()) res+=stack.pop();
return res;
}
}
925 长键按入
题目:你的朋友正在使用键盘输入他的名字 name。偶尔,在键入字符 c 时,按键可能会被长按,而字符可能被输入 1 次或多次。你将会检查键盘输入的字符 typed。如果它对应的可能是你的朋友的名字(其中一些字符可能被长按),那么就返回 True。
class Solution {
public boolean isLongPressedName(String name, String typed) {
// 设置两个指针,i,j 其中i指针指向的是name中的字符,j指针指向的是typed中的字符
int i = 0;
int j = 0;
// 只要typed还有字符,就一直向后遍历
while(j<typed.length()){
// 如果i指针指向的name中的字符与j指针指向的typed中字符相同的话,两个指针均向后移动
if(i<name.length()&&name.charAt(i) == typed.charAt(j)){
i++;
j++;
}else if(j>0 && typed.charAt(j) == typed.charAt(j-1)){
//如果i指针指向的name中的字符与j指针指向的typed中的字符不相等并且typed中的j指向的字符与上一个j-1指向的字符相同,
j++;
}else{
return false;
}
}
return i == name.length();
}
}
977. 有序数组的平方
给定一个按非递减顺序排序的整数数组 A,返回每个数字的平方组成的新数组,要求也按非递减顺序排序。
class Solution {
public int[] sortedSquares(int[] A) {
// 循环便利,将A中的元素替换成为原是数子的平方
for(int i =0;i<A.length;i++) A[i] = A[i]*A[i];
quickSort(A,0,A.length-1);
return A;
}
// 手动实现快速排序
public void quickSort(int[] nums,int l,int r){
if(l<r){
int i = l;
// 选取基准值
int pivot = nums[l];
int j = r;
while(i<j){
// 从右到左找到比pivot小的值
while(i<j && nums[j]>=pivot) j--;
// 找到了比pivot小的值,按照快速排序的思想,该值应该出现在基准值的左边,所以交换位置
if(i<j) nums[i] = nums[j];
// 从左到右找到比pivot大的值
while(i<j && nums[i]<=pivot) i++;
if(i<j) nums[j] = nums[i];
}
//交换完之后,将pivot放到他本来应该在的位置
nums[i] = pivot;
// 然后递归处理基准值左边的以及基准值右边的子数列
quickSort(nums,l,i-1);
quickSort(nums,i+1,r);
}
}
}
剑指 Offer 04. 二维数组中的查找
在一个 n * m 的二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
class Solution {
public boolean findNumberIn2DArray(int[][] matrix, int target) {
// 从数组的右上角开始查找,如果当前元素比target小就向下移动,如果当前元素比target大就向左移动
if(matrix.length == 0 || matrix == null) return false;
// 获取matrix的行数和列数
int m = matrix.length;
int n = matrix[0].length;
// 设计两个指针,i和j 其中i指向当前所在的行数,j指向当前所在的列数,初始化i=0,j=n-1
int i = 0;
int j = n-1;
while(j>-1 && i<m){
if(matrix[i][j] > target) j--;
else if(matrix[i][j] < target) i++;
else return true;
}
return false;
}
}
剑指 Offer 22. 链表中倒数第k个节点
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public int kthToLast(ListNode head, int k) {
// 因为题目中说了k保证是有效的,所以不用先计算整个链表的长度
// 定义两个指针,一个快指针,一个慢指针,快指针在满指针后k个,当快指针为空的时候,满指针就到了目的元素的位置
ListNode slow = head;
ListNode fast = head;
while(k-->0) fast = fast.next;
while(fast!=null){
slow = slow.next;
fast = fast.next;
}
return slow.val;
}
}
面试题 02.02. 返回倒数第 k 个节点
实现一种算法,找出单向链表中倒数第 k 个节点。返回该节点的值。
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public int kthToLast(ListNode head, int k) {
// 因为题目中说了k保证是有效的,所以不用先计算整个链表的长度
// 定义两个指针,一个快指针,一个慢指针,快指针在满指针后k个,当快指针为空的时候,满指针就到了目的元素的位置
ListNode slow = head;
ListNode fast = head;
while(k-->0) fast = fast.next;
while(fast!=null){
slow = slow.next;
fast = fast.next;
}
return slow.val;
}
}
面试题 10.01. 合并排序的数组
给定两个排序后的数组 A 和 B,其中 A 的末端有足够的缓冲空间容纳 B。 编写一个方法,将 B 合并入 A 并排序。初始化 A 和 B 的元素数量分别为 m 和 n。
class Solution {
public void merge(int[] A, int m, int[] B, int n) {
// 一看就是倒着来嘛
int aLen = A.length-1;
// 设置两个指针分别指向A,B中的元素,i指向A,j指向B
int i = m-1;
int j = n-1;
while(i>-1 && j>-1){
if(A[i] > B[j]){
A[aLen] = A[i];
aLen--;
i--;
}else{
A[aLen] = B[j];
aLen--;
j--;
}
}
while(i>-1){
A[aLen] = A[i];
aLen--;
i--;
}
while(j>-1){
A[aLen] = B[j];
aLen--;
j--;
}
}
}
以上是关于Leetcode(easy Double pointer)的主要内容,如果未能解决你的问题,请参考以下文章
算法 Notes|LeetCode 26. 删除排序数组中的重复项 - easy
算法 Notes|LeetCode 26. 删除排序数组中的重复项 - easy
哈工大机试 Easy *枚举,个人感觉dp贪心也可以,但是一定要注意double 1/3得问题