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