博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java数据结构与算法——双指针(滑动窗口)
阅读量:3944 次
发布时间:2019-05-24

本文共 7337 字,大约阅读时间需要 24 分钟。

双指针

双指针也是所谓滑动窗口算法。

一般用于求解具有某种特质的子数组、子字符串、链表查询的分隔问题,通过两个指针来标识窗口的边界(子数组、子字符串、链表标记)。

顾名思义,有2个指针,头指针和尾指针(窗口边界),结合while使用。二分也是利用双指针的思想。

import java.util.HashMap;import java.util.HashSet;import java.util.Map;import java.util.Set;/** * Title:NC41-最长无重复, 数组中最长连续无重复长度 * Description:双指针、Set、Map * @author WZQ * @version 1.0.0 * @date 2021/2/24 */public class NC41 {
/** * @param arr int整型一维数组 the array * @return int整型 */ public int maxLength (int[] arr) {
int length = arr.length; if (length < 2){
return length; } // 双指针 // j纪录尾部,遍历到尾部 // i纪录头部,遇到重复的向后遍历删除 int max = 0, i = 0, j = 0;// Map
map = new HashMap<>();// while (j < length){
// //包含// if (map.containsKey(arr[j])){
// //存在相同的元素// // 123412 1234 i=0 j=4,// i = map.get(arr[j])// }else {
// //不包含// map.put(arr[j], j);// }// max = Math.max(max, j - i + 1);// j++;// } Set
set = new HashSet<>(); while (j < length){
//包含 if (set.contains(arr[j])){
//头指针, 删除到重复元素的下一个位置 set.remove(arr[i]); i ++; }else {
//不包含 set.add(arr[j]); j ++; } max = Math.max(max, set.size()); } return max; }}
/** * Title:NC22-合并2个有序数组, 不能开辟额外的空间,结果存放在A数组中 * Description:双指针 * @author WZQ * @version 1.0.0 * @date 2021/3/3 */public class NC22 {
public static void merge(int A[], int m, int B[], int n) {
//双指针,纪录2个集合确定合并的位置 int a = 0, b = 0, temp = 0; while (a < (m+n) && b < n){
//小于,A[a]位置不变 while (a < (m+b) && A[a] < B[b]){
a ++; } //等于,大于,A[a]后未判断的全体后退 if (m + b - a >= 0) System.arraycopy(A, a, A, a + 1, m + b - a);// for (int i = m+b-1; i>=a; i--) {
// A[i+1] = A[i];// } //B[b]放到A[a]位置 A[a] = B[b]; a ++; b ++; } } /** * 1 3 7 * 1 5 6 * 1 1 3 5 6 7 * * @param args */ public static void main(String[] args) {
int[] arr1 = {
1, 3, 7, 0, 0, 0}; int[] arr2 = {
1, 5, 6}; merge(arr1, arr1.length/2, arr2, arr2.length); }}
import java.util.HashMap;import java.util.Map;/** * Title:leetcode-76. 最小覆盖子串 * Description:滑动窗口+Hash * * 给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。 * 如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 "" 。 *  * @author WZQ * @version 1.0.0 * @date 2021/3/26 */public class Main76 {
public String minWindow(String s, String t) {
String res = ""; // 窗口,统计字符的方式 Map
window = new HashMap<>(); // 子串t字符统计 Map
chars = new HashMap<>(); int tLen = t.length(); int sLen = s.length(); for (int i = 0; i < tLen; i++) {
chars.put(t.charAt(i), chars.getOrDefault(t.charAt(i), 0) + 1); } // 双指针, left到right窗口长度 > tLen开始check int left = 0, right = 0, min = Integer.MAX_VALUE; while (right < sLen) {
char ch = s.charAt(right); // 纪录到窗口 window.put(ch, window.getOrDefault(ch, 0) + 1); // check成功,则left向后,压缩窗口,直到check失败,纪录min,right接着向后,依次类推 while (check(window, chars)) {
if ((right - left + 1) < min) {
min = right - left + 1; res = s.substring(left, right + 1); } // left向后压缩窗口 char ch2 = s.charAt(left); window.put(ch2, window.get(ch2) - 1); if (window.get(ch2) == 0) {
window.remove(ch2); } left++; } // check失败,则right继续向后,直到符合 right++; } return res; } // 当前窗口是否符合题目条件 public boolean check(Map
window, Map
chars) {
for (char ch : chars.keySet()) {
// window存在所有子串字符 if (!window.containsKey(ch) || (window.get(ch) < chars.get(ch))) {
return false; } } return true; }}

快慢指针

快慢指针,一般用于解决链表问题,快指针每次走n步或者提前走n步,而慢指针还是一步一步原地走

/** * Title:NC53-删除链表倒数第n个值,并返回头结点 * Description: 要求O(n) * @author WZQ * @version 1.0.0 * @date 2021/2/27 */public class NC53 {
/** * @param head ListNode类 * @param n int整型 * @return ListNode类 */ public ListNode removeNthFromEnd (ListNode head, int n) {
if(head == null){
return head; } // 双指针,快慢指针 // 采用两个指针,对前指针,使其先走出N步,随后两个指针同时前进, // 当前指针到达链表尾部时,后指针到达倒数第N个节点的位置。 ListNode slow = head; ListNode fast = head; // 先走n步 for(int i = 0; i
import java.util.List;/** * Title:NC4-寻找链表闭环 * Description: * @author WZQ * @version 1.0.0 * @date 2021/1/7 */public class NC4 {
/** * 思路1:hash map/set * 开一个哈希表,标记访问过的节点, * 如果重复访问了某一节点,说明有环。 * 需要额外O(n)的空间复杂度。 */ /** * 思路2:快慢指针 * 用一快一慢指针,开始两个指针都指向链表头部。 * 慢指针每次向前走一步,快指针每次向前走两步。 * 如果有环,则两个指针最终一定会相遇。 * 这种方法无须额外的空间。 * @param head * @return */ public boolean hasCycle(ListNode head) {
if (head == null || head.next == null){
return false; } ListNode s = head; ListNode q = head; while (q != null && q.next != null){
s = s.next; q = q.next.next; if (s == q){
return true; } } return false; } //Definition for singly-linked list. class ListNode {
int val; ListNode next; ListNode(int x) {
val = x; next = null; } }}

链表闭环升级版,寻找环的入口节点

/** * Title:NC-3,链表的入口节点,环的入口节点 * Description:双指针 * * @author WZQ * @version 1.0.0 * @date 2021/3/5 */public class NC3 {
/** * 1)首先判断是否有环,有环时,返回相遇的节点,无环,返回null * 2)有环的情况下, 求链表的入环节点 * fast再次从头出发,每次走一步, * slow从相遇点出发,每次走一步, * 再次相遇即为环入口点。 */ public ListNode detectCycle(ListNode head) {
if (head == null || head.next == null){
return null; } ListNode meetNode = meetingNode(head); //说明无环 if (meetNode == null) {
return null; } //fast再次从头出发,每次走一步, //slow从相遇点出发,每次走一步, ListNode fast = head; ListNode slow = meetNode; //再次相遇即为环入口点 while (slow != fast) {
slow = slow.next; fast = fast.next; } return slow; } //寻找相遇节点,如果无环,返回null public ListNode meetingNode(ListNode head) {
ListNode slow = head; ListNode fast = head; while (fast != null && fast.next != null) {
// 快指针走2步 slow = slow.next; fast = fast.next.next; // 相遇点 if (slow == fast) {
return slow; } } return null; } //节点 class ListNode {
int val; ListNode next; ListNode(int x) {
val = x; next = null; } }}

转载地址:http://pviwi.baihongyu.com/

你可能感兴趣的文章
android studio drawable目录的分辨率
查看>>
j2me MIDP2.0已移植到 MT6225 GEMINI 0812 版本上
查看>>
MIDP2.1规范的新特性
查看>>
J2ME开发
查看>>
Java ME平台
查看>>
Unicode 汉字内码表
查看>>
MT6235
查看>>
mtk camera isp
查看>>
j2me 扑克发牌算法实现
查看>>
J2ME贪吃蛇源代码——200行左右,包含详细注释
查看>>
J2ME游戏源代码免费下载——国外Digiment公司商业化代码
查看>>
手机银行技术应用探讨
查看>>
角色扮演游戏引擎的设计原理
查看>>
j2me开发FAQ整理
查看>>
J2ME程序开发新手入门九大要点
查看>>
双向搜索算法
查看>>
日本GAME製作方式
查看>>
移动行业术语资料
查看>>
3G到来将全面颠覆SP、CP游戏规则
查看>>
射击游戏中跟踪弹及小角度移动的开发
查看>>