기본 개념: 배열이나 문자열을 처리할 때, 두 개의 포인터를 사용하여 양 끝에서 또는 같은 방향으로 이동하면서 문제를 해결합니다.
1-1. 정렬된 배열에서 두 수의 합 구하기 (Two Sum)
문제: 정렬된 배열에서 두 수의 합이 주어진 값이 되는 두 수의 인덱스를 구합니다.
int[] twoSum(int[] nums,int target) {int left =0;int right =nums.length-1;while (left < right) {int sum = nums[left] + nums[right];if (sum == target) {returnnewint[]{left, right}; } elseif (sum < target) { left++; // 합이 작으면 왼쪽 포인터를 오른쪽으로 이동 } else { right--; // 합이 크면 오른쪽 포인터를 왼쪽으로 이동 } }returnnewint[]{-1,-1}; // 두 수를 찾지 못한 경우}
1-2. 회문(팰린드롬) 확인
문제: 주어진 문자열이 회문인지 확인합니다.
booleanisPalindrome(String s) {int left =0;int right =s.length() -1;while (left < right) {while (left < right &&!Character.isLetterOrDigit(s.charAt(left))) { left++; // 문자가 아닌 경우 건너뜀 }while (left < right &&!Character.isLetterOrDigit(s.charAt(right))) { right--; }if (Character.toLowerCase(s.charAt(left)) !=Character.toLowerCase(s.charAt(right))) {returnfalse; // 대소문자 무시하고 비교 } left++; right--; }returntrue;}
2. Sliding Window (슬라이딩 윈도우)
기본 개념: 고정된 크기 또는 가변 크기의 창을 배열 또는 문자열 위에 슬라이딩 시키며 문제를 해결합니다.
2-1. 최대 길이의 부분 문자열 찾기 (Sliding Window)
문제: 주어진 문자열에서 중복 문자가 없는 가장 긴 부분 문자열의 길이를 구합니다.
intlengthOfLongestSubstring(String s) {Set<Character> set =newHashSet<>();int maxLength =0;int left =0;for (int right =0; right <s.length(); right++) {while (set.contains(s.charAt(right))) {set.remove(s.charAt(left)); // 중복 문자를 제거하며 윈도우 축소 left++; }set.add(s.charAt(right)); maxLength =Math.max(maxLength, right - left +1); }return maxLength;}
2-2. 고정 크기의 슬라이딩 윈도우에서 최대합 찾기
문제: 주어진 배열에서 고정된 크기의 슬라이딩 윈도우 내에서 최대합을 구합니다.
intmaxSlidingWindowSum(int[] arr,int k) {int windowSum =0;int maxSum =Integer.MIN_VALUE;// 첫 번째 윈도우의 합 계산for (int i =0; i < k; i++) { windowSum += arr[i]; } maxSum = windowSum;// 윈도우를 한 칸씩 오른쪽으로 슬라이드for (int i = k; i <arr.length; i++) { windowSum += arr[i] - arr[i - k]; // 새로 추가되는 값은 더하고, 앞쪽 값은 뺌 maxSum =Math.max(maxSum, windowSum); }return maxSum;}
3. Two Pointer와 Sliding Window를 함께 사용하는 문제
3-1. 주어진 합을 가지는 부분 배열 찾기 (Subarray with Given Sum)
문제: 비음수가 포함된 배열에서, 주어진 합을 가지는 가장 짧은 부분 배열의 길이를 구합니다.
intminSubArrayLen(int target,int[] nums) {int left =0;int sum =0;int minLength =Integer.MAX_VALUE;for (int right =0; right <nums.length; right++) { sum += nums[right];while (sum >= target) { minLength =Math.min(minLength, right - left +1); sum -= nums[left++]; } }return minLength ==Integer.MAX_VALUE?0: minLength;}
3-2. 문자열 내의 아나그램 찾기 (Find All Anagrams in a String)
문제: 문자열 s에서 p의 아나그램이 되는 부분 문자열을 모두 찾습니다.
List<Integer>findAnagrams(String s,String p) {List<Integer> result =newArrayList<>();if (s.length() <p.length()) return result;int[] pCount =newint[26];int[] sCount =newint[26];// p와 s의 첫 번째 윈도우 초기화for (int i =0; i <p.length(); i++) { pCount[p.charAt(i) -'a']++; sCount[s.charAt(i) -'a']++; }if (Arrays.equals(pCount, sCount)) {result.add(0); }// 윈도우 슬라이딩for (int i =p.length(); i <s.length(); i++) { sCount[s.charAt(i) -'a']++; sCount[s.charAt(i -p.length()) -'a']--;if (Arrays.equals(pCount, sCount)) {result.add(i -p.length() +1); } }return result;}