2017/3/1html
215. Kth Largest Element in an Arrayjava
Find the kth largest element in an unsorted array. Note that it is the kth largest element in the sorted order, not the kth distinct element. For example, Given [3,2,1,5,6,4] and k = 2, return 5. Note: You may assume k is always valid, 1 ≤ k ≤ array's length.
本身的代碼:node
/** * 先利用Arrays的sort()函數對給定的數組進行排序, * 獲得的數組是升序排列的,而後得到數組的長度,從新申請一個新的數組, * 將以前的數組從最後一個開始,一次存入新數組的第一個位置開始, * 這樣新的數組就成了降序排列,這是返回數組當中的第k個位置的數值便可 * @param nums * @param k * @return */ public class Solution { public int findKthLargest(int[] nums, int k) { Arrays.sort(nums); int n=nums.length; int[] res=new int[n]; for(int i=nums.length-1,j=0;i>=0;i--,j++) { res[j]=nums[i]; } return res[k-1]; } }
另外一種解法是利用PriorityQueue,關於priorityQueue的使用詳情,博客以下http://www.cnblogs.com/CarpenterLee/p/5488070.html,具體代碼以下:git
class Solution { /** * @return */ public int findKthLargest(int[] nums, int k) { PriorityQueue<Integer> largek = new PriorityQueue<Integer>(); for (int i : nums) { largek.add(i); if (largek.size() > k) { largek.poll(); } } return largek.poll(); } };
最優解:O(N lg N) running time + O(1) memory算法
public int findKthLargest(int[] nums, int k) { final int N = nums.length; Arrays.sort(nums); return nums[N - k]; }
---------------------------------------------------------------------------------------------------------------------------------express
2017/3/2數組
150. Evaluate Reverse Polish Notation數據結構
Evaluate the value of an arithmetic expression in Reverse Polish Notation. Valid operators are +, -, *, /. Each operand may be an integer or another expression. Some examples: ["2", "1", "+", "3", "*"] -> ((2 + 1) * 3) -> 9 ["4", "13", "5", "/", "+"] -> (4 + (13 / 5)) -> 6
關於Stack的具體介紹見博客:http://www.cnblogs.com/skywang12345/p/3308852.htmlapp
本身的代碼:less
public class Solution { /** * Author: wanghaibo * Complexity Time: O(n); Space: O(n) * Explaination: 利用Stack實現,首先遍歷tokens數組, * 若是字符串不是操做符是數字,則進棧,若是是操做符,則將兩個 * 數字出棧,根據操做符獲得結果後從新壓入棧 * @param tokens * @return */ public int evalRPN(String[] tokens) { if (tokens.length == 1) { return Integer.parseInt(tokens[0]); } Stack<String> stack = new Stack<String>(); for (String i : tokens) { if (isoperator(i) != 0) { int a = Integer.parseInt(stack.pop()); int b = Integer.parseInt(stack.pop()); String c = ""; if (i.equals("+")) { c = String.valueOf(b + a); } else if (i.equals("-")) { c = String.valueOf(b - a); } else if (i.equals("*")) { c = String.valueOf(a * b); } else if (i.equals("/")) { c = String.valueOf(b / a); } stack.push(c); } else { stack.push(i); } } return Integer.parseInt(stack.pop()); } public int isoperator(String s) { if (s.equals("+")) { return 1; } else if (s.equals("-")) { return 2; } else if (s.equals("*")) { return 3; } else if (s.equals("/")) { return 4; }else { return 0; } } }
最優解:
import java.util.Stack; public class Solution { public int evalRPN(String[] tokens) { int a,b; Stack<Integer> S = new Stack<Integer>(); for (String s : tokens) { if(s.equals("+")) { S.add(S.pop()+S.pop()); } else if(s.equals("/")) { b = S.pop(); a = S.pop(); S.add(a / b); } else if(s.equals("*")) { S.add(S.pop() * S.pop()); } else if(s.equals("-")) { b = S.pop(); a = S.pop(); S.add(a - b); } else { S.add(Integer.parseInt(s)); } } return S.pop(); } }
----------------------------------------------------------------------------------------------------------------------------------------
2017/3/5
373. Find K Pairs with Smallest Sums
You are given two integer arrays nums1 and nums2 sorted in ascending order and an integer k. Define a pair (u,v) which consists of one element from the first array and one element from the second array. Find the k pairs (u1,v1),(u2,v2) ...(uk,vk) with the smallest sums. Example 1: Given nums1 = [1,7,11], nums2 = [2,4,6], k = 3 Return: [1,2],[1,4],[1,6] The first 3 pairs are returned from the sequence: [1,2],[1,4],[1,6],[7,2],[7,4],[11,2],[7,6],[11,4],[11,6] Example 2: Given nums1 = [1,1,2], nums2 = [1,2,3], k = 2 Return: [1,1],[1,1] The first 2 pairs are returned from the sequence: [1,1],[1,1],[1,2],[2,1],[1,2],[2,2],[1,3],[1,3],[2,3] Example 3: Given nums1 = [1,2], nums2 = [3], k = 3 Return: [1,3],[2,3] All possible pairs are returned from the sequence: [1,3],[2,3]
先聲明一個優先隊列,重寫compare()函數,實現大頂堆,而後依次入堆,構造一個大頂堆。而後聲明一個LinkedListed,將大頂堆根插入雙向鏈表中,注意k,只須要插入k個就行,若是小於k個,直接返回,代碼以下:
public List<int[]> kSmallestPairs(int[] nums1, int[] nums2, int k) { List<int[]> res = new LinkedList<>(); Queue<int[]> queue = new PriorityQueue<>(k,new Comparator<int[]>(){ public int compare(int[] o1,int[] o2){ int tmp1 = o1[0]+o1[1]; int tmp2 = o2[0]+o2[1]; return tmp1 - tmp2; } }); for(int i = 0;i<nums1.length;i++){ for(int j = 0;j<nums2.length;j++){ queue.add(new int[]{nums1[i],nums2[j]}); } } while(k-->0){ int[] tmp = queue.poll(); if(tmp == null) break; res.add(tmp); } return res; }
須要瞭解LinkedList,具體連接http://www.cnblogs.com/chenssy/p/3514524.html,作不出來主要是由於不瞭解LinekedList和PriorityQueue,須要多看!!!
最優解:
Basic idea: Use min_heap to keep track on next minimum pair sum, and we only need to maintain K possible candidates in the data structure. Some observations: For every numbers in nums1, its best partner(yields min sum) always strats from nums2[0] since arrays are all sorted; And for a specific number in nums1, its next candidate sould be [this specific number] + nums2[current_associated_index + 1], unless out of boundary;) Here is a simple example demonstrate how this algorithm works. image The run time complexity is O(kLogk) since que.size <= k and we do at most k loop. public class Solution { public List<int[]> kSmallestPairs(int[] nums1, int[] nums2, int k) { PriorityQueue<int[]> que = new PriorityQueue<>((a,b)->a[0]+a[1]-b[0]-b[1]); List<int[]> res = new ArrayList<>(); if(nums1.length==0 || nums2.length==0 || k==0) return res; for(int i=0; i<nums1.length && i<k; i++) que.offer(new int[]{nums1[i], nums2[0], 0}); while(k-- > 0 && !que.isEmpty()){ int[] cur = que.poll(); res.add(new int[]{cur[0], cur[1]}); if(cur[2] == nums2.length-1) continue; que.offer(new int[]{cur[0],nums2[cur[2]+1], cur[2]+1}); } return res; } }
------------------------------------------------------------------------------------------------------------------------------------------------
2017/3/6
202. Happy Number
Write an algorithm to determine if a number is "happy". A happy number is a number defined by the following process: Starting with any positive integer, replace the number by the sum of the squares of its digits, and repeat the process until the number equals 1 (where it will stay), or it loops endlessly in a cycle which does not include 1. Those numbers for which this process ends in 1 are happy numbers. Example: 19 is a happy number 12 + 92 = 82 82 + 22 = 68 62 + 82 = 100 12 + 02 + 02 = 1
代碼以下:
/** * 或得一個數每一位的平方相加之和 * @param n * @return */ public int squaresum(int n) { int sum = 0, tmp; while (n != 0) { tmp = n % 10; sum +=tmp * tmp; n /= 10; } return sum; } /** * 將中間結果存入HashSet,若是發現結果爲1,則返回true,若是結果中出現了n,則表明 * 出現環,返回false,不然就將中間結果存入set中 * @param n * @return */ public boolean isHappy(int n) { if (n <= 0) return false; Set<Integer> set = new HashSet<Integer>(); set.add(n); while(true) { n = squaresum(n); if (n == 1) return true; else if (set.contains(n)) return false; else set.add(n); } }
另外一種解法是用快慢指針,代碼以下:
/** * 或得一個數每一位的平方相加之和 * @param n * @return */ public int squaresum(int n) { int sum = 0, tmp; while (n != 0) { tmp = n % 10; sum +=tmp * tmp; n /= 10; } return sum; } /** * 新建一個快指針和一個慢指針 * 慢指針只求一次,下一個數;塊指針每次求兩次,下一個數 * 若是快指針的值和慢指針的值相等,則返回false * 快指針的值等於1,則返回true * @param n * @return */ public boolean isHappy(int n) { int slow = n; int fast = n; while(true) { slow = squaresum(slow); fast = squaresum(squaresum(fast)); if (fast == 1) return true; if (slow == fast) return false; } }
---------------------------------------------------------------------------------------------------------------------------------------
2017/3/7
263. Ugly Number
Write a program to check whether a given number is an ugly number. Ugly numbers are positive numbers whose prime factors only include 2, 3, 5. For example, 6, 8 are ugly while 14 is not ugly since it includes another prime factor 7. Note that 1 is typically treated as an ugly number.
代碼以下:
/** * 首先判斷輸入的數據是否小於等於0,若是是,則確定不是ugly數,返回false * 判斷是否是1,是的話確定是ugly數 * 不然 * 若是能對2,3,5進行整除,則用num除以2,3,5,只要num>1時,循環進行 * 不然返回false * @param num * @return */ public boolean isUgly(int num) { if (num <= 0) { return false; } if (num == 1) { return true; } while (num > 1) { if (num % 2 == 0) { num /= 2; } else if (num % 3 == 0) { num /= 3; } else if (num % 5 == 0) { num /= 5; } else { return false; } } return true; }
最優解與以上相似,代碼以下:
public boolean isUgly(int num) { if (num <= 0) {return false;} if (num == 1) {return true;} if (num % 2 == 0) { return isUgly(num/2); } if (num % 3 == 0) { return isUgly(num/3); } if (num % 5 == 0) { return isUgly(num/5); } return false; }
-------------------------------------------------------------------------------------------------------------------------------------------------
2017/3/8
264. Ugly Number II
Write a program to find the n-th ugly number. Ugly numbers are positive numbers whose prime factors only include 2, 3, 5. For example, 1, 2, 3, 4, 5, 6, 8, 9, 10, 12 is the sequence of the first 10 ugly numbers. Note that 1 is typically treated as an ugly number, and n does not exceed 1690.
代碼以下:
public class Solution { /** * 首先將1加入到集合當中,設置三個指針,分別取出三個指針對應的list * 中的值,分別向相關的數,挑選最小的一個數做爲下一個Ugly數,加入 * list中,只有最小的數對應的那個指針才進行+1操做 * 最後返回第n個數 * @param n * @return */ public int nthUglyNumber(int n) { ArrayList<Integer> list = new ArrayList<Integer>(); list.add(1); int p2 = 0; int p3 = 0; int p5 = 0; while (list.size() < n) { int ugly2 = list.get(p2) * 2; int ugly3 = list.get(p3) * 3; int ugly5 = list.get(p5) * 5; int min = Math.min(ugly2, Math.min(ugly3, ugly5)); list.add(min); if (min == ugly2) p2++; if (min == ugly3) p3++; if (min == ugly5) p5++; } return list.get(n-1); } }
最優解和解析以下:
The idea of this solution is from this page:http://www.geeksforgeeks.org/ugly-numbers/ The ugly-number sequence is 1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, … because every number can only be divided by 2, 3, 5, one way to look at the sequence is to split the sequence to three groups as below: (1) 1×2, 2×2, 3×2, 4×2, 5×2, … (2) 1×3, 2×3, 3×3, 4×3, 5×3, … (3) 1×5, 2×5, 3×5, 4×5, 5×5, … We can find that every subsequence is the ugly-sequence itself (1, 2, 3, 4, 5, …) multiply 2, 3, 5. Then we use similar merge method as merge sort, to get every ugly number from the three subsequence. Every step we choose the smallest one, and move one step after,including nums with same value. Thanks for this author about this brilliant idea. Here is my java solution public class Solution { public int nthUglyNumber(int n) { int[] ugly = new int[n]; ugly[0] = 1; int index2 = 0, index3 = 0, index5 = 0; int factor2 = 2, factor3 = 3, factor5 = 5; for(int i=1;i<n;i++){ int min = Math.min(Math.min(factor2,factor3),factor5); ugly[i] = min; if(factor2 == min) factor2 = 2*ugly[++index2]; if(factor3 == min) factor3 = 3*ugly[++index3]; if(factor5 == min) factor5 = 5*ugly[++index5]; } return ugly[n-1]; } }
----------------------------------------------------------------------------------------------------------------------------------------------
2017/3/14
278. First Bad Version
You are a product manager and currently leading a team to develop a new product. Unfortunately, the latest version of your product fails the quality check. Since each version is developed based on the previous version, all the versions after a bad version are also bad. Suppose you have n versions [1, 2, ..., n] and you want to find out the first bad one, which causes all the following ones to be bad. You are given an API bool isBadVersion(version) which will return whether version is bad. Implement a function to find the first bad version. You should minimize the number of calls to the API.
利用二分查找,最優代碼以下:
public class Solution extends VersionControl { public int firstBadVersion(int n) { int lo = 1, hi = n; while (lo <= hi) { int mid = lo + (hi - lo) / 2; if (isBadVersion(mid)) { hi = mid - 1; } else { lo = mid + 1; } } return lo; } }
-----------------------------------------------------------------------------------------------------------------------------------------------
2017/3/16
74. Search a 2D Matrix
Write an efficient algorithm that searches for a value in an m x n matrix. This matrix has the following properties: Integers in each row are sorted from left to right. The first integer of each row is greater than the last integer of the previous row. For example, Consider the following matrix: [ [1, 3, 5, 7], [10, 11, 16, 20], [23, 30, 34, 50] ] Given target = 3, return true.
解法一以下:
/** * 遍歷每一行,對每一行進行二分查找,假設有m行n列,則算法的時間複雜度爲mlog(n) * @param matrix * @param target * @return */ public boolean searchMatrix(int[][] matrix, int target) { boolean flag = false; if (matrix.length == 0 || matrix == null || matrix[0] == null || matrix[0].length ==0) { return false; } for (int i = 0; i < matrix.length; i++) { int lo = 0; int n = matrix[i].length; int hi = n - 1; while (lo <= hi) { int mid = lo + (hi - lo) / 2; if (matrix[i][mid] == target) { flag = true; break; } if (matrix[i][mid] > target) { hi = mid - 1; } if (matrix[i][mid] < target) { lo = mid + 1; } } } return flag; }
解法二以下:
/** * 從左下角開始查找,若是target小於這個數,則行數減一,若是大於這個數,則列數加一 * 時間複雜度爲O(m)+O(n),m爲行數,n爲列數 * @param matrix * @param target * @return */ public boolean searchMatrix(int[][] matrix, int target) { boolean flag = false; if (matrix.length == 0 || matrix == null || matrix[0] == null || matrix[0].length == 0) { return false; } int m = matrix.length; int n = matrix[0].length; int i = m - 1; int j = 0; while (i >= 0 && j < n) { if (matrix[i][j] < target) { j++; } else if (matrix[i][j] > target) { i--; } else { flag = true; break; } } return flag; }
解法三以下:
/** * 因爲數組是有序遞增的,那麼能夠把二維數組轉換爲一位數組進行操做 * 假設二維數組每一行有n列,那麼一位數組中下標爲x的數對應的二維數組中 * 的數的爲matrix[x/n][x%n],利用二分法對一維數組進行查找便可 * 時間複雜度爲O(log(m*n)) * @param matrix * @param target * @return */ public boolean searchMatrix(int[][] matrix, int target) { boolean flag = false; if (matrix.length == 0 || matrix == null || matrix[0] == null || matrix[0].length == 0) { return false; } int m = matrix.length; int n = matrix[0].length; int left = 0; int right = m * n - 1; while (left <= right) { int mid = left + (right - left) / 2; int num = matrix[mid / n][mid % n]; if (num == target) { flag = true; break; } else if (num > target) { right = mid - 1; } else if (num < target) { left = mid + 1; } } return flag; }
解法四還能夠將target的值於每一行的第一個元素進行比較,找到第一個不大於target的數,並得到這一行,在這一行進行二分查找,這種解法的時間複雜度是O(logm)+O(logn),算是時間複雜度最好的解法。具體的代碼以下:
public class Solution { public boolean searchMatrix(int[][] matrix, int target) { if (matrix == null || matrix.length == 0 || matrix[0] == null || matrix[0].length == 0) { return false; } int low = 0; int high = matrix.length - 1; int mid = 0; while (low + 1 < high) { mid = low + ((high - low) >> 1); if (matrix[mid][0] == target) { return true; } else if (matrix[mid][0] > target) { high = mid; } else { low = mid; } } int index = matrix[high][0] <= target ? high : low; low = 0; high = matrix[0].length - 1; while (low + 1 < high) { mid = low + ((high - low) >> 1); if (matrix[index][mid] == target) { return true; } else if (matrix[index][mid] > target) { high = mid; } else { low = mid; } } if (matrix[index][low] == target || matrix[index][high] == target) { return true; } return false; } }
-------------------------------------------------
240. Search a 2D Matrix II
Write an efficient algorithm that searches for a value in an m x n matrix. This matrix has the following properties: Integers in each row are sorted in ascending from left to right. Integers in each column are sorted in ascending from top to bottom. For example, Consider the following matrix: [ [1, 4, 7, 11, 15], [2, 5, 8, 12, 19], [3, 6, 9, 16, 22], [10, 13, 14, 17, 24], [18, 21, 23, 26, 30] ] Given target = 5, return true. Given target = 20, return false.
和上一題差很少,解法一以下
/** * 遍歷每一行,對每一行進行二分查找,假設有m行n列,則算法的時間複雜度爲mlog(n) * @param matrix * @param target * @return */ public boolean searchMatrix(int[][] matrix, int target) { boolean flag = false; if (matrix.length == 0 || matrix == null || matrix[0] == null || matrix[0].length ==0) { return false; } for (int i = 0; i < matrix.length; i++) { int lo = 0; int n = matrix[i].length; int hi = n - 1; while (lo <= hi) { int mid = lo + (hi - lo) / 2; if (matrix[i][mid] == target) { flag = true; break; } if (matrix[i][mid] > target) { hi = mid - 1; } if (matrix[i][mid] < target) { lo = mid + 1; } } } return flag; }
解法二以下:
/** * 從左下角開始查找,若是target小於這個數,則行數減一,若是大於這個數,則列數加一 * 時間複雜度爲O(m)+O(n),m爲行數,n爲列數 * @param matrix * @param target * @return */ public boolean searchMatrix(int[][] matrix, int target) { boolean flag = false; if (matrix.length == 0 || matrix == null || matrix[0] == null || matrix[0].length == 0) { return false; } int m = matrix.length; int n = matrix[0].length; int i = m - 1; int j = 0; while (i >= 0 && j < n) { if (matrix[i][j] < target) { j++; } else if (matrix[i][j] > target) { i--; } else { flag = true; break; } } return flag; }
---------------------------------------------------------------------------------------------------------------------------------
2017/3/17
153. Find Minimum in Rotated Sorted Array
Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand. (i.e., 0 1 2 4 5 6 7 might become 4 5 6 7 0 1 2). Find the minimum element. You may assume no duplicate exists in the array.
兩種解法,第一種:
/** * 利用position記錄最小值的位置,若是從開始到結尾遞增,則position確定等於0, * 即第一個數。不然比較相鄰的兩個元素,若是左邊的大於右邊的,那麼右邊的確定是最小的元素, * 記錄下右邊元素的位置,時間複雜度爲O(n) * @param nums * @return */ public int findMin(int[] nums) { int position = 0; for (int i = 0; i < nums.length - 1; i++) { if(nums[i] > nums[i+1]) { position = i + 1; break; } } return nums[position]; }
第二種解法是利用二分查找:
public class Solution { public int findMin(int[] nums) { if (nums.length == 0 || nums == null) { return -1; } int low = 0; int high = nums.length - 1; if (nums[low] < nums[high]) { return nums[low]; } int mid; while (low < high) { mid = low + ((high - low) >> 1); if (nums[mid] > nums[high]) { low = mid + 1; } else { high = mid; } } return nums[low]; } }
154. Find Minimum in Rotated Sorted Array II
Follow up for "Find Minimum in Rotated Sorted Array": What if duplicates are allowed? Would this affect the run-time complexity? How and why? Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand. (i.e., 0 1 2 4 5 6 7 might become 4 5 6 7 0 1 2). Find the minimum element. The array may contain duplicates.
解法跟上一題相似,必定要注意,當區間是開區間low<high時,要注意nums[mid]必定是要與nums[right]比較的,最後的值下標是low,有重複值的時候,只須要high--就好了,具體代碼以下:
public class Solution { public int findMin(int[] nums) { int low = 0; int high = nums.length - 1; if (nums[low] < nums[high]) { return nums[low]; } int mid; while (low < high) { mid = low + ((high - low) >> 1); if (nums[mid] > nums[high]) { low = mid + 1; } else if (nums[mid] < nums[high]) { high = mid; } else { high--; } } return nums[low]; } }
-------------------------------------------------------------------------------------------------------------------------------------
2017/3/30
406. Queue Reconstruction by Height
Suppose you have a random list of people standing in a queue. Each person is described by a pair of integers (h, k), where h is the height of the person and k is the number of people in front of this person who have a height greater than or equal to h. Write an algorithm to reconstruct the queue. Note: The number of people is less than 1,100. Example Input: [[7,0], [4,4], [7,1], [5,0], [6,1], [5,2]] Output: [[5,0], [7,0], [5,2], [6,1], [4,4], [7,1]]
這是第一次作,沒作出來,主要是Arrays.sort()方法的排序不熟悉,也不知道LinkedList插入相同下邊元素時候,元素直接後移,就是對插入時候的機制不太瞭解,這個得回頭看一下,具體的解法和詳細的解釋以下:
public class Solution { /** * 複雜度O(nlogn) * 首先按照身高進行降序排序,身高相同的按照k升序排序 * [[7,0], [4,4], [7,1], [5,0], [6,1], [5,2]] 排序後變爲[[7,0], [7,1], [6,1], [5,0], [5,2], [4,4]] * 而後將元素插入到一個LinkedList中,LinkedList每一個元素都保存了先後元素的應用,插入和刪除快。 * 插入的位置就是離res開始位置偏移了元素第二個元素的位置 * people: [7,0],插入到離開始位置偏移了0個距離的位置。 res: [[7,0]] * people: [7,1],插入到離開始位置偏移了1個距離的位置,即插入到[7,0]的後面。 res: [[7,0], [7,1]] * people: [6,1],插入到離開始位置偏移了1個距離的位置,即插入到[7,0]的後面。 res: [[7,0], [6,1], [7,1]] * people: [5,0],插入到離開始位置偏移了0個距離的位置,即插入到[7,0]的前面。 res: [[5,0], [7,0], [6,1], [7,1]] * people: [5,2],插入到離開始位置偏移了2個距離的位置,即插入到[7,0]的後面。 res: [[5,0], [7,0], [5,2], [6,1], [7,1]] * people: [4,4],插入到離開始位置偏移了4個距離的位置,即插入到[6,1]的後面。 res: [[5,0], [7,0], [5,2], [6,1], [4,4], [7,1]] * @param people * @return res */ public int[][] reconstructQueue(int[][] people) { if (people.length == 0 || people == null || people[0].length == 0) { return new int[0][0]; } Arrays.sort(people, new Comparator<int[]>() { public int compare(int[] o1, int[] o2) { return o1[0] != o2[0] ? -o1[0] + o2[0] : o1[1] - o2[1]; } }); List<int[]> res = new LinkedList<>(); for (int[] ans : people) { res.add(ans[1], ans); } return res.toArray(new int[people.length][]); } }
---------------------------------------------------------------------------------------------------------------------------------
2017/4/2
33. Search in Rotated Sorted Array
Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand. (i.e., 0 1 2 4 5 6 7 might become 4 5 6 7 0 1 2). You are given a target value to search. If found in the array return its index, otherwise return -1. You may assume no duplicate exists in the array.
這個題目解得時候,首先查找mid下標元素的值,判斷nums[mid]是否等於target,若是是,返回1;若是不是的話就與low位置的值相比較,判斷nums[low]<nums[mid],若是是,那麼這個範圍內的數字是單調遞增的,若是不是,那麼這個範圍內的數字不是單調的。若是是單調遞增的,那麼判斷這個nums[low]<=target<=nums[mid],是的話那麼讓high=mid,不然的話low=mid+1,;若是不是單調遞增的話,那麼判斷nums[mid]=<target<=nums[high],若是是的話,令low=mid,不然的話讓high=mid-1。因爲區間是low+1<high,因此最後要對結果進行驗證,判斷low和high哪個符合要求,具體代碼以下:
public class Solution { public int search(int[] nums, int target) { if (nums.length == 0 || nums == null) { return -1; } int low = 0; int high = nums.length - 1; while(low + 1 < high) { int mid = low + ((high - low) >> 1); if (nums[mid] == target) { return mid; } if (nums[mid] > nums[low]) {//前半部分是升序 if (target >= nums[low] && target <= nums[mid]) {//待查找的元素再升序子序列中 high = mid; } else { low = mid + 1; } } else if (nums[mid] < nums[low]){//前半部分不是升序 if (target >= nums[mid] && target <= nums[high]) { low = mid; } else { high = mid - 1; } } } if (nums[low] == target) { return low; } if (nums[high] == target) { return high; } return -1; } }
---------------------------
81. Search in Rotated Sorted Array II
Follow up for "Search in Rotated Sorted Array": What if duplicates are allowed? Would this affect the run-time complexity? How and why? Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand. (i.e., 0 1 2 4 5 6 7 might become 4 5 6 7 0 1 2). Write a function to determine if a given target is in the array. The array may contain duplicates.
旋轉數組中存在重複元素的時候,這個時候與上面基本類似,就是加一個判斷若是nums[mid]=nums[low]的話,就是讓low++,具體代碼以下:
public class Solution { public boolean search(int[] nums, int target) { if (nums.length == 0 || nums == null) { return false; } int low = 0; int high = nums.length - 1; int mid; while (low + 1 < high) { mid = low + ((high - low) >> 1); if (nums[mid] == target) { return true; } if (nums[mid] > nums[low]) { if (nums[low] <= target && target <= nums[mid]) { high = mid; } else { low = mid + 1; } } else if (nums[mid] < nums[low]) { if (nums[mid] <= target && target <= nums[high]) { low = mid; } else { high = mid - 1; } } else { low++; } } if (nums[low] == target || nums[high] == target) { return true; } return false; } }
----------------------------
34. Search for a Range
Given an array of integers sorted in ascending order, find the starting and ending position of a given target value. Your algorithm's runtime complexity must be in the order of O(log n). If the target is not found in the array, return [-1, -1]. For example, Given [5, 7, 7, 8, 8, 10] and target value 8, return [3, 4].
先判斷該元素是否在數組中,若是不在返回[-1,-1],不然,先查找下限位置,在查找上限位置,查找下限時直接判斷nums[mid]<target是否成立,是的話low=mid+1,查找上限時判斷nums[mid]>target是否成立,若是成立high=mid-1,代碼以下:
public class Solution { public int[] searchRange(int[] nums, int target) { int[] res = {-1, -1}; if (nums == null || nums.length == 0) { return res; } int mid = binarySearch(nums, target); if (mid < 0) { return res; } int start = mid; while (start >= 0 && nums[start] == target) { start--; } start++; res[0] = start; int end = mid; while (end < nums.length && nums[end] == target) { end++; } end--; res[1] = end; return res; } public int binarySearch(int[] nums, int target) { int idx = -1; int low = 0; int high =nums.length - 1; int mid; while (low <= high) { mid = low + ((high - low) >> 1); if (nums[mid] == target) { idx = mid; break; } else if (nums[mid] > target) { high = mid - 1; } else { low = mid + 1; } } return idx; } }
------------------------------
35. Search Insert Position
Given a sorted array and a target value, return the index if the target is found. If not, return the index where it would be if it were inserted in order. You may assume no duplicates in the array. Here are few examples. [1,3,5,6], 5 → 2 [1,3,5,6], 2 → 1 [1,3,5,6], 7 → 4 [1,3,5,6], 0 → 0
題目很是簡單,能夠採用閉區間,那麼查找到直接返回查找到的mid,不然,返回low便可
public class Solution { public int searchInsert(int[] nums, int target) { if (nums.length == 0 || nums == null) { return 0; } int low = 0; int high = nums.length - 1; int mid; while (low <= high) { mid = low + ((high - low) >> 1); if (nums[mid] == target) { return mid; } else if (nums[mid] > target) { high = mid - 1; } else { low = mid + 1; } } return low; } }
-----------------------------
162. Find Peak Element
A peak element is an element that is greater than its neighbors. Given an input array where num[i] ≠ num[i+1], find a peak element and return its index. The array may contain multiple peaks, in that case return the index to any one of the peaks is fine. You may imagine that num[-1] = num[n] = -∞. For example, in array [1, 2, 3, 1], 3 is a peak element and your function should return the index number 2.
首先若是是單調遞減,即nums[i]>nums[i+1],那麼就往左邊尋找峯值或者i自身就是峯值;若是是單調遞增,即nums[i]<nums[i+1],那麼就去i右邊尋找峯值咱們很容易在紙上畫出來某個點的四種狀況(以下圖所示):
第一種狀況:當前點就是峯值,直接返回當前值。
第二種狀況:當前點是谷點,不論往那邊走均可以找到峯值。
第三種狀況:當前點處於降低的中間,往左邊走能夠到達峯值。
第四種狀況:當前點處於上升的中間,往右邊走能夠達到峯值。
代碼以下,因爲採用的是開區間low<high,因此在對low和high進行操做的時候要使low=low+1,high=high,即支隊low進行加一操做:
public class Solution { public int findPeakElement(int[] nums) { int n = nums.length; if (n == 1) { return 0; } int low = 0; int high = n - 1; int mid; while (low < high) { mid = low + ((high - low) >> 1); if (nums[mid] > nums[mid + 1]) { high = mid; } else { low = mid + 1; } } return low; } }
-------------------------------------------------------------------------------------------------------------------------------
2017/4/6
69. Sqrt(x)
Implement int sqrt(int x). Compute and return the square root of x.
具體的分析能夠看一下二分查找總結的博客,代碼以下:
public class Solution { public int mySqrt(int x) { if (x == 0 || x == 1) { return x; } else { int start = 0; int end = x; int mid; while (true) { mid = (start + end) / 2; if (mid == x / mid || end - start <= 1) { return mid; } else if (mid < x / mid) { start = mid; } else { end = mid; } } } } }
---------------------------------
50. Pow(x, n)
Implement pow(x, n).
具體代碼以下,分析能夠看一下總結:
public class Solution { public double myPow(double x, int n) { if (n == 0) { return 1; } else if (n == 1) { return x; } else { if (n > 0) { return pow(x, n); } else { return 1 / pow(x, -n); } } } public double pow(double x, int n) { if (n == 1) { return x; } else { double half = pow(x, n>>>1); if (n % 2 == 0) { return half * half; } else { return half * half * x; } } } }
-------------------------------------------------------------------------------------------------------------------------------------
2017/04/24
70. Climbing Stairs
You are climbing a stair case. It takes n steps to reach to the top. Each time you can either climb 1 or 2 steps. In how many distinct ways can you climb to the top? Note: Given n will be a positive integer.
解析和代碼以下:
public class Solution { /** * 當n=1時,方法數爲1; * 當n=2時,方法數爲2; * 當n=3時,(因爲咱們只能選擇上1層或者2層)咱們先選擇開始走1層這個方案,剩下兩層, * 那麼方法數就是n=2的方法數,而後再選擇開始走2層這個方案,剩下一層,那麼方法數就是n=1的方法數, * 所以n=3時的總方法數就是n=1時的方法數加上n=2時的方法數; * n=4時,先走1層的話,剩下3層,方法數爲n=3,先走2層的話,剩下2層,方法數爲n=2, * 所以n=4時的總方法數爲n=2時的方法數加n=3時的方法數。 * 由此,可發現規律,便是斐波那契數列。 * 設 f (n) 表示爬 n 階樓梯的不一樣方法數,爲了爬到第 n 階樓梯,有兩個選擇:從第 n - 1 階前進 1 步; * 從第 n - 2 階前進 2 步;所以,有 f (n) = f (n - 1) + f (n - 2)。 **/ public int climbStairs(int n) { if (n <= 0) { return 0; } int[] dp = new int[n + 1]; dp[0] = 1; dp[1] = 1; for (int i = 2; i<= n; i++) { dp[i] = dp[i - 1] + dp[i - 2]; } return dp[n]; } }
上面的解決方案空間複雜度是O(N),其中大部分空間都是浪費的,由於n的值只與n-1和n-2相關,其中1到n-3的值不須要一直保存着,
能夠經過滾動數組的技巧將空間複雜度減小到O(1),代碼以下:
public class Solution { public int climbStairs(int n) { if (n <= 2) { return n; } int num0 = 1; int num1 = 1; int res = 0; for (int i = 2; i <= n; i++) { res = num0 + num1; num0 = num1; num1 = res; } return res; } }
-------------------------------------------------------------------------------------------------------------------------------------
523. Continuous Subarray Sum
Given a list of non-negative numbers and a target integer k, write a function to check if the array has a continuous subarray of size at least 2 that sums up to the multiple of k, that is, sums up to n*k where n is also an integer. Example 1: Input: [23, 2, 4, 6, 7], k=6 Output: True Explanation: Because [2, 4] is a continuous subarray of size 2 and sums up to 6. Example 2: Input: [23, 2, 6, 4, 7], k=6 Output: True Explanation: Because [23, 2, 6, 4, 7] is an continuous subarray of size 5 and sums up to 42.
解析和代碼以下:
public class Solution { /** * 題目的邊界狀況比較多,須要注意如下幾點: * 子數組長度至少爲2; * k可能爲0; * n可能爲0; * 遍歷整個數組,依次加當前數組元素並將相加和與k取餘 * 求餘結果只有0~k-1這k中狀況,將求餘結果存入HashTable中 * 若是遍歷到當前位置求餘結果已經在HashTable中 * 代表從上一求餘結果相同的位置到當前位置的子數組相加和是k的倍數 * 不然將求餘結果存入HashTable。這裏一樣須要注意上面提到的邊界狀況 * 代碼中hash[0] = -1這行即爲了便於邊界狀況的處理 **/ public boolean checkSubarraySum(int[] nums, int k) { if (nums == null || nums.length < 2) { return false; } Map<Integer, Integer> map = new HashMap<>(); map.put(0, -1); int sum = 0; for (int i = 0; i < nums.length; i++) { sum += nums[i]; Integer pre = map.get(k == 0 ? sum : sum % k); if (pre != null) { if (i - pre > 1) { return true; } } else { map.put(k == 0 ? sum : sum % k, i); } } return false; } }
-----------------------------------------------------------------------------------------------------------------------------------------
2017/06/29
Given a string containing just the characters '(', ')', '{', '}', '[' and ']', determine if the input string is valid. The brackets must close in the correct order, "()" and "()[]{}" are all valid but "(]" and "([)]" are not.
思路:
用一個Stack來存儲括號, 主要考察對棧數據結構的操做。算法的時間複雜度是O(n),空間複雜度也是O(n)。
遍歷傳入的String s,若是遇到左括號就入棧;若是遇到右括號,檢查棧若是爲空,證實不能匹配,若是棧不空,pop出棧頂的元素,看是否與當前的右括號匹配。
若是匹配,繼續向下進行新一輪的循環,若是不匹配,返回false.
注意:
所有字符都檢查完了之後,判斷棧是否爲空,空則正確都匹配,不空則證實有沒匹配的。
檢查字符是用==,檢查String是用.isEqual(),由於String是引用類型,值相等可是地址可能不等。
具體代碼以下:
public class Solution { public boolean isValid(String s) { if (s.length() == 0 || s.length() == 1) { return false; } Stack<Character> stack = new Stack<Character>(); for (int i = 0; i < s.length(); i++) { char cur = s.charAt(i); if (cur == '(' || cur == '[' || cur == '{') { stack.push(cur); } else { switch (cur) { case ')' : if (stack.isEmpty() || stack.pop() != '(') { return false; } break; case ']' : if (stack.isEmpty() || stack.pop() != '[') { return false; } break; case '}' : if (stack.isEmpty() || stack.pop() != '{') { return false; } break; default : break; } } } return stack.isEmpty(); } }
還有一種比較簡潔的作法是,先將字符串轉化爲字符數組,而後遍歷數組,當字符是'(','{','[' 時,將 ')','}',']'入棧,不然先判斷棧是否爲空,若是爲空的話,返回false,不爲空的話
比較這個字符與stack.pop()的字符是否相等,不是的話返回false,最後要記的判斷一下棧是否爲空,空的話則正確匹配,不然的話證實有沒匹配的。
具體代碼以下:
public class Solution { public boolean isValid(String s) { Stack<Character> stack = new Stack<Character>(); for (char cur : s.toCharArray()) { if (cur == '(') { stack.push(')'); } else if (cur == '[') { stack.push(']'); } else if (cur == '{') { stack.push('}'); } else if (stack.isEmpty() || stack.pop() != cur) { return false; } } return stack.isEmpty(); } }
-------------------------------------------------------------------------------------------------------------------------------------------
2017/08/17
2. Add Two Numbers
You are given two non-empty linked lists representing two non-negative integers. The digits are stored in reverse order and each of their nodes contain a single digit. Add the two numbers and return it as a linked list. You may assume the two numbers do not contain any leading zero, except the number 0 itself. Input: (2 -> 4 -> 3) + (5 -> 6 -> 4) Output: 7 -> 0 -> 8
具體思路是建立一個新的鏈表來存儲新的值,每個節點存儲相應節點值的和取餘10,注意點是最後可能須要進位,
因此循環的時候要判斷carry是否等於0,若是不等於表時有進位,還須要建立新的節點,具體代碼以下:
/** * Definition for singly-linked list. * public class ListNode { * int val; * ListNode next; * ListNode(int x) { val = x; } * } */ public class Solution { public ListNode addTwoNumbers(ListNode l1, ListNode l2) { if (l1 == null) { return l2; } if (l2 == null) { return l1; } //建立新的鏈表 ListNode head = new ListNode(0); ListNode p = head; //存儲相加的結果 int carry = 0; //任何一個鏈表不爲空,或者carry != 0,這表示最後有進位 //例如最後爲5+5=10,最後carry=1,兩個鏈表都爲空了,這是須要 //進位,建立新的節點 while (l1 != null || l2 != null || carry != 0) { //若是爲空的話不須要將carry+0,直接不操做 if (l1 != null) { carry += l1.val; l1 = l1.next; } if (l2 != null) { carry += l2.val; l2 = l2.next; } //建立新節點 p.next = new ListNode(carry % 10); p = p.next; carry /= 10; } return head.next; } }
--------------------------------------------------------------------------------------------------------------------------------------------
2017/08/18
445. Add Two Numbers II
You are given two non-empty linked lists representing two non-negative integers. The most significant digit comes first and each of their nodes contain a single digit. Add the two numbers and return it as a linked list. You may assume the two numbers do not contain any leading zero, except the number 0 itself. Follow up: What if you cannot modify the input lists? In other words, reversing the lists is not allowed. Example: Input: (7 -> 2 -> 4 -> 3) + (5 -> 6 -> 4) Output: 7 -> 8 -> 0 -> 7
有兩種解法,首先第一種是跟上一題相似,因此要先將鏈表反轉,而後在利用上一道題的思路進行相加,
最後將結果進行反轉後返回,具體代碼以下:
/** * Definition for singly-linked list. * public class ListNode { * int val; * ListNode next; * ListNode(int x) { val = x; } * } */ public class Solution { public ListNode addTwoNumbers(ListNode l1, ListNode l2) { if (l1 == null) { return l2; } if (l2 == null) { return l1; } l1 = recursive(l1); l2 = recursive(l2); ListNode head = new ListNode(0); ListNode phead = head; int tmp = 0; while (l1 != null || l2 != null || tmp != 0) { if (l1 != null) { tmp += l1.val; l1 = l1.next; } if (l2 != null) { tmp += l2.val; l2 = l2.next; } phead.next = new ListNode(tmp % 10); phead = phead.next; tmp /= 10; } return recursive(head.next); } public ListNode recursive(ListNode head) { if (head == null || head.next == null) { return head; } ListNode pre = head; ListNode p = head.next; ListNode next = null; while (p != null) { next = p.next; p.next = pre; pre = p; p = next; } head.next = null; return pre; } }
還有一種是不須要反轉鏈表,利用棧進行計算,首先將兩個鏈表中的元素都入棧,而後出棧進行相加。因此要聲明一個節點head,
而後進行循環,每次將head節點的值從新賦爲carry%10,而後從新聲明一個節點p,指向head,而後head = p,這樣下一次循環
的時候就能夠再指向head節點了,p節點的值是carry/10,由於假如最後須要進位的話,p就是進位的節點,不須要進位的話p節點的
值就是0,最後返回的時候判斷一下就好了,不能將0也返回。具體代碼以下:
/** * Definition for singly-linked list. * public class ListNode { * int val; * ListNode next; * ListNode(int x) { val = x; } * } */ class Solution { public ListNode addTwoNumbers(ListNode l1, ListNode l2) { if (l1 == null) { return l2; } if (l2 == null) { return l1; } Stack<Integer> s1 = new Stack<Integer>(); Stack<Integer> s2 = new Stack<Integer>(); while (l1 != null) { s1.push(l1.val); l1 = l1.next; } while (l2 != null) { s2.push(l2.val); l2 = l2.next; } ListNode head = new ListNode(0); int carry = 0; while (!s1.isEmpty() || !s2.isEmpty()) { if (!s1.isEmpty()) { carry += s1.pop(); } if (!s2.isEmpty()) { carry += s2.pop(); } head.val = carry % 10; ListNode p = new ListNode(carry / 10); p.next = head; head = p; carry /= 10; } return head.val == 0 ? head.next : head; } }
----------------------
328. Odd Even Linked List
Given a singly linked list, group all odd nodes together followed by the even nodes. Please note here we are talking about the node number and not the value in the nodes. You should try to do it in place. The program should run in O(1) space complexity and O(nodes) time complexity. Example: Given 1->2->3->4->5->NULL, return 1->3->5->2->4->NULL. Note: The relative order inside both the even and odd groups should remain as it was in the input. The first node is considered odd, the second node even and so on ...
保存偶節點的第一個節點,而後將奇數節點的next指向奇數節點next.next節點,也就是下一個奇數節點,偶數節點同理
最後將奇數節點的next指向偶數節點的第一個節點,注意循環的條件,even!=null&&even.next!=null,也就是當前的偶數節點
和奇數節點不爲空,若是爲空的話.next就沒有意義了,具體代碼以下:
/** * Definition for singly-linked list. * public class ListNode { * int val; * ListNode next; * ListNode(int x) { val = x; } * } */ class Solution { public ListNode oddEvenList(ListNode head) { if (head == null || head.next == null) { return head; } ListNode odd = head; ListNode even = head.next; ListNode peven = even; while (even != null && even.next != null) { odd.next = odd.next.next; even.next = even.next.next; odd = odd.next; even = even.next; } odd.next = peven; return head; } }
-------------------------------------------------------------------------------------------------------------
2017/08/19
給定一個單鏈表中的一個等待被刪除的節點(非表頭或表尾)。請在在O(1)時間複雜度刪除該鏈表節點。
樣例
Linked list is 1->2->3->4, and given node 3, delete the node in place 1->2->4
通常狀況下刪除鏈表節點須要知道該節點的前一個節點,可是這樣的話時間複雜度就變爲O(n)了,因此看題目知道該節點非表頭或者表尾,
因此直接獲取該節點的下一個節點,將該節點的值賦爲下一個節點的值,該節點的next指針賦爲下一個節點的next,這樣就能在O(1)的
時間內實現刪除節點,當刪除的節點是前n-1個節點時均可以這樣作,當是最後一個時,必須獲取前一個節點,這是時間複雜度是O(n),
可是總的時間複雜度是(O(1)*(n-1) + O(n)*1)/n = O(1),具體代碼以下:
/** * Definition for ListNode. * public class ListNode { * int val; * ListNode next; * ListNode(int val) { * this.val = val; * this.next = null; * } * } */ public class Solution { /** * @param node: the node in the list should be deleted * @return: nothing */ public void deleteNode(ListNode node) { // write your code here //若是刪除節點爲前面的n-1個節點, //則時間複雜度爲O(1), //只有刪除節點爲最後一個時, //時間複雜度才爲O(n), //因此平均的時間複雜度爲:(O(1) * (n-1) + O(n))/n = O(1); //仍然爲O(1) ListNode next = node.next; node.val = next.val; node.next = next.next; } }
---------------------------------
138. Copy List with Random Pointer
A linked list is given such that each node contains an additional random pointer which could point to any node in the list or null. Return a deep copy of the list.
題目對時間複雜度沒有要求,第一種解法,就是建立一個map,key是舊的節點,value是新的節點,首先遍歷舊節點,
同時利用舊節點的label建立新的節點,而後給新節點的random和next賦值,因此要再遍歷一遍舊節點,獲得新的節點,而後新節點
的next的值爲map當中當前舊的節點cur的cur.next在map中所對應的值,也就是map.get(cur).next = map.get(cur.next),同理新節點
的random也是這樣作,map.get(cur).random = map.get(cur.random),這樣時間複雜度和空間複雜度都是O(n),代碼以下:
/** * Definition for singly-linked list with a random pointer. * class RandomListNode { * int label; * RandomListNode next, random; * RandomListNode(int x) { this.label = x; } * }; */ public class Solution { public RandomListNode copyRandomList(RandomListNode head) { if (head == null) { return head; } HashMap<RandomListNode, RandomListNode> map = new HashMap<RandomListNode, RandomListNode>(); RandomListNode p = head; while (p != null) { map.put(p, new RandomListNode(p.label)); p = p.next; } p = head; while (p != null) { map.get(p).next = map.get(p.next); map.get(p).random = map.get(p.random); p = p.next; } return map.get(head); } }
另外一種解法是建立一個新的鏈表,將新節點插入到舊結點後面,這樣的話next的值就不用特地去賦值了,須要賦random的值,
這是直接遍歷一遍舊的鏈表將舊節點的random值賦值給新節點就行,最後將舊節點和新節點拆開,這樣的話時間複雜度是O(n),
空間複雜度變成了O(1),具體代碼以下:
/** * Definition for singly-linked list with a random pointer. * class RandomListNode { * int label; * RandomListNode next, random; * RandomListNode(int x) { this.label = x; } * }; */ public class Solution { public RandomListNode copyRandomList(RandomListNode head) { if (head == null) { return head; } //首先建立一個新的鏈表,將複製的節點插入到舊節點的後面 RandomListNode cur = head; RandomListNode next = null; while (cur != null) { next = cur.next; RandomListNode copy = new RandomListNode(cur.label); cur.next = copy; copy.next = next; cur = next; } //將random指針賦值給新的節點 cur = head; while (cur != null) { if (cur.random != null) { //新的節點的random指向舊節點random所指向節點的下一個節點 cur.next.random = cur.random.next; } cur = cur.next.next; } //將鏈表拆開,將新的鏈表拆出來 cur = head; RandomListNode phead = new RandomListNode(0); RandomListNode p = phead; RandomListNode oldnext = null; RandomListNode newnext = null; while (cur != null) { //拆開新的節點 newnext = cur.next; p.next = newnext; p = newnext; //拆開舊的節點 oldnext = cur.next.next; cur.next = oldnext; cur = oldnext; } return phead.next; } }
--------------------------------
給你一個鏈表以及兩個權值v1和v2,交換鏈表中權值爲v1和v2的這兩個節點。保證鏈表中節點權值各不相同,若是沒有找到對應節點,那麼什麼也不用作。 注意事項 你須要交換兩個節點而不是改變節點的權值 樣例 給出鏈表 1->2->3->4->null ,以及 v1 = 2 , v2 = 4 返回結果 1->4->3->2->null。
首先找到這兩個節點,以及這兩個節點的前面的節點,而後進行交換就行,須要注意的是當兩個節點相鄰時,須要特殊處理,
還有v1和v2的節點先後順序不必定,有可能v2所對應節點在v1前面,這個須要判斷,代碼以下:
public class Solution { /* * @param head: a ListNode * @param v1: An integer * @param v2: An integer * @return: a new head of singly-linked list */ public ListNode swapNodes(ListNode head, int v1, int v2) { // write your code here if (head == null || head.next == null || v1 == v2) { return head; } ListNode node1 = search(head, v1); ListNode node2 = search(head, v2); if (node1 == null || node2 == null) { return head; } ListNode phead = new ListNode(0); phead.next = head; ListNode pre = phead; ListNode pre1 = null; ListNode pre2 = null; while (pre != null) { if (pre.next == node1) { pre1 = pre; } if (pre.next == node2) { pre2 = pre; } pre = pre.next; } //v1在v2的前面 if (pre2 == node1) { node1.next = node2.next; pre1.next = node2; node2.next = node1; } else if (pre1 == node2) {//v2在v1的前面 node2.next = node1.next; pre2.next = node1; node1.next = node2; } else { ListNode next2 = node2.next; node2.next = node1.next; node1.next = next2; pre1.next = node2; pre2.next = node1; } return phead.next; } public ListNode search(ListNode head, int v) { ListNode p = head; ListNode cur = null; while (p != null) { if (p.val == v) { cur = p; break; } p = p.next; } return cur; } };
----------------------------------------------------------------------------------------------------------------
2017/08/21
155. Min Stack
Design a stack that supports push, pop, top, and retrieving the minimum element in constant time. push(x) -- Push element x onto stack. pop() -- Removes the element on top of the stack. top() -- Get the top element. getMin() -- Retrieve the minimum element in the stack. Example: MinStack minStack = new MinStack(); minStack.push(-2); minStack.push(0); minStack.push(-3); minStack.getMin(); --> Returns -3. minStack.pop(); minStack.top(); --> Returns 0. minStack.getMin(); --> Returns -2.
這道題的關鍵就是得到當前棧的最小值,若是是單純的在每次入棧的時候比較一下,而後記錄下當前最小值的話,那麼當出棧
的是當前的最小值的話,就沒法獲取剩餘數據裏面的最小值了,因此在入棧的時候,若是入棧的元素比當前最小值小,那麼
首先將當前最小值入棧,而後改變最小值的值,而後再將新的最小值入棧,這樣最小值下面就是第二小的值,當最小值出棧時,
剩餘元素的最小值就是出棧元素的下一個元素,具體代碼以下:
class MinStack { //min用於保存當前的最小值 int min = Integer.MAX_VALUE; Stack<Integer> stack; /** initialize your data structure here. */ public MinStack() { stack = new Stack<Integer>(); } public void push(int x) { //若是當前入棧的值小於當前的最小值, //那麼首先將當前的最小值,也就是第二小的值入棧,而後令min=當前最小值 //而後再將當前最小的值入棧 //若是沒有min的話,在出棧的時候若是彈出的是當前的最小值,那麼就無法獲得 //剩餘的數據裏面哪個是最小的,因此若是是最小,先將第二小的入棧,再將最小入棧 //那麼當最小的出棧時,就能得到剩餘的數據中最小的數了 if (x <= min) { stack.push(min); min = x; } stack.push(x); } public void pop() { //首先是執行stack.pop(),因此不管怎麼樣,都執行了一次pop操做, //若是當前pop的值是最小值,那麼它的下一個值必定是第二小的, //當最小值出棧後,剩餘數據中的最小值必定是它的下一個,直接令min=stack.pop() if (stack.pop() == min) { min = stack.pop(); } //若是min改變過,那麼在棧爲空的時候要將min改變回來 if (stack.isEmpty()) { min = Integer.MAX_VALUE; } } public int top() { return stack.peek(); } public int getMin() { return min; } } /** * Your MinStack object will be instantiated and called as such: * MinStack obj = new MinStack(); * obj.push(x); * obj.pop(); * int param_3 = obj.top(); * int param_4 = obj.getMin(); */
--------------------------------
225. Implement Stack using Queues
Implement the following operations of a stack using queues. push(x) -- Push element x onto stack. pop() -- Removes the element on top of the stack. top() -- Get the top element. empty() -- Return whether the stack is empty. Notes: You must use only standard operations of a queue -- which means only push to back, peek/pop from front, size, and is empty operations are valid. Depending on your language, queue may not be supported natively. You may simulate a queue by using a list or deque (double-ended queue), as long as you use only standard operations of a queue. You may assume that all operations are valid (for example, no pop or top operations will be called on an empty stack).
建立一個隊列,每次插入新值以後,都將新值前面的全部數據反轉,這樣新插入的值就位於頭部了,具體的作法是每次都push進
pop的元素,直到最後一個元素,其他的操做就好作了,具體代碼以下:
class MyStack { Queue<Integer> queue; /** Initialize your data structure here. */ public MyStack() { queue = new LinkedList<Integer>(); } /** Push element x onto stack. */ public void push(int x) { queue.offer(x); //反轉已經加入的元素,這樣最新加入的元素就跑到隊列頭上去了,這樣就能模擬棧了 for (int i = 0; i < queue.size() - 1; i++) { queue.offer(queue.poll()); } } /** Removes the element on top of the stack and returns that element. */ public int pop() { return queue.poll(); } /** Get the top element. */ public int top() { return queue.peek(); } /** Returns whether the stack is empty. */ public boolean empty() { return queue.isEmpty(); } } /** * Your MyStack object will be instantiated and called as such: * MyStack obj = new MyStack(); * obj.push(x); * int param_2 = obj.pop(); * int param_3 = obj.top(); * boolean param_4 = obj.empty(); */
----------------------------------
232. Implement Queue using Stacks
Implement the following operations of a queue using stacks. push(x) -- Push element x to the back of queue. pop() -- Removes the element from in front of queue. peek() -- Get the front element. empty() -- Return whether the queue is empty. Notes: You must use only standard operations of a stack -- which means only push to top, peek/pop from top, size, and is empty operations are valid. Depending on your language, stack may not be supported natively. You may simulate a stack by using a list or deque (double-ended queue), as long as you use only standard operations of a stack. You may assume that all operations are valid (for example, no pop or peek operations will be called on an empty queue).
建立兩個棧,每次執行push操做時,先將stack1中的元素pop並push到stack2中,而後再將新的元素push到stack2中,
而後再將stack2中全部的元素都pop並push到stack1中,這樣的話最新的元素老是在最底下,
最開始插入的元素老是在棧頂,這樣就能模擬隊列了,具體代碼以下:
class MyQueue { Stack<Integer> stack1; /** Initialize your data structure here. */ public MyQueue() { stack1 = new Stack<Integer>(); } /** Push element x to the back of queue. */ public void push(int x) { Stack<Integer> stack2 = new Stack<Integer>(); while (!stack1.isEmpty()) { stack2.push(stack1.pop()); } stack2.push(x); while (!stack2.isEmpty()) { stack1.push(stack2.pop()); } } /** Removes the element from in front of queue and returns that element. */ public int pop() { return stack1.pop(); } /** Get the front element. */ public int peek() { return stack1.peek(); } /** Returns whether the queue is empty. */ public boolean empty() { return stack1.isEmpty(); } } /** * Your MyQueue object will be instantiated and called as such: * MyQueue obj = new MyQueue(); * obj.push(x); * int param_2 = obj.pop(); * int param_3 = obj.peek(); * boolean param_4 = obj.empty(); */
-------------------------------------------------------------------------------------------------------------
2017/09/05
71. Simplify Path
Given an absolute path for a file (Unix-style), simplify it. For example, path = "/home/", => "/home" path = "/a/./b/../../c/", => "/c" click to show corner cases. Corner Cases: Did you consider the case where path = "/../"? In this case, you should return "/". Another corner case is the path might contain multiple slashes '/' together, such as "/home//foo/". In this case, you should ignore redundant slashes and return "/home/foo".
具體思路和代碼以下:
class Solution { /** *首先對字符串根據'/'進行分割 *這樣分割的結果是:. .. 正常字符串 空字符 *若是遇到的是空字符或者是.,那麼什麼也不作 *若是遇到的是..,那麼須要返回上一級目錄,若是棧不爲空,那麼棧中的元素出棧,不然的話直接不操做,由於沒有上級目錄了 *若是遇到的是正常字符,那麼直接入棧 *最後判斷棧是否爲空,若是爲空,說明在根目錄下,返回/ *不然拼接字符串,注意最早出棧的元素位於後面,中間加上/分隔開,返回結果 */ public String simplifyPath(String path) { if (path.length() == 0 || path == null) { return path; } Stack<String> stack = new Stack<String>(); String[] array = path.split("/"); String res = ""; for (int i = 0; i < array.length; i++) { if (array[i].equals("") || array[i].equals(".")) { } else if (array[i].equals("..")) { if (!stack.isEmpty()) { stack.pop(); } } else { stack.push(array[i]); } } if (stack.isEmpty()) { return "/"; } while (!stack.isEmpty()) { res = "/" + stack.pop() + res; } return res; } }
------------------------------------
42. Trapping Rain Water
Given n non-negative integers representing an elevation map where the width of each bar is 1, compute how much water it is able to trap after raining.
For example,
Given [0,1,0,2,1,0,1,3,2,1,2,1]
, return 6
.
The above elevation map is represented by array [0,1,0,2,1,0,1,3,2,1,2,1]. In this case, 6 units of rain water (blue section) are being trapped. Thanks Marcosfor contributing this image!
解題思路:
思路一:開闢兩個數組空間,逐個遍歷數組,找出該位置左邊的最大值與右邊的最大值,分別放到兩個數組中。而後對整個數組進行遍歷,位置裝水後的值不能超過該位置左右最高值中的最小數。該算法需三次遍歷數組,可是時間複雜度爲O(n);空間需開闢兩個數組空間,空間複雜度爲O(n)。具體代碼以下:
class Solution { public int trap(int[] height) { if (height == null || height.length == 0) { return 0; } int res = 0; int length = height.length; int[] leftMax = new int[length]; int[] rightMax = new int[length]; int tmp = 0; //找到當前位置左邊的最大值 for (int i = 0; i < length; i++) { leftMax[i] = tmp; tmp = Math.max(tmp, height[i]); } tmp = 0; //找到當前位置右邊的最大值 for (int i = length - 1; i >= 0; i--) { rightMax[i] = tmp; tmp = Math.max(tmp, height[i]); } //遍歷數組,找到當前位置左右最大的值中的最小值,而後計算與當前位置的差值,即爲當前位置所能裝的水的高度 for (int i = 0; i < length; i++) { tmp = Math.min(leftMax[i], rightMax[i]); if (tmp >= height[i]) { res += tmp - height[i]; } } return res; } }
思路二:
設置兩個指示變量,分別存放當前指向的兩個位置。找出左位置的左邊的最高值和右位置的右邊的最高值。對於二者中的最小值,代表當前位置加上水事後的值不超出該值,那麼相減便可,反之,對另外一個相減。該算法只須要一次遍歷數組,因此效率更高,時間複雜度爲O(n);空間方面不須要開闢數組空間,因此爲常數空間。具體代碼以下:
class Solution { public int trap(int[] height) { if (height == null || height.length == 0) { return 0; } int length = height.length; int left = 0; int right = length - 1; int leftMax = 0; int rightMax = 0; int res = 0; //建立雙指針,初始時分別指向兩頭 //找出左位置左邊的最高值和右位置右邊的最高值 //對於兩個中的最小值,當前位置加上水以後不超過這個最小值 //因此利用這個最小值減去當前高度便可 //若是是左邊的小,則left++,若是右邊的小,則right++ //只需遍歷一遍數組,時間複雜度O(n),空間複雜度爲O(1) while (left < right) { leftMax = Math.max(leftMax, height[left]); rightMax = Math.max(rightMax, height[right]); if (leftMax < rightMax) { res += leftMax - height[left]; left++; } else { res += rightMax - height[right]; right--; } } return res; } }
---------------------------------------------------------------------------------------
2017/09/11
84. Largest Rectangle in Histogram
Given n non-negative integers representing the histogram's bar height where the width of each bar is 1, find the area of largest rectangle in the histogram.
Above is a histogram where width of each bar is 1, given height = [2,1,5,6,2,3]
.
The largest rectangle is shown in the shaded area, which has area = 10
unit.
For example,
Given heights = [2,1,5,6,2,3]
,
return 10
.
解題思路:
假設當前位置值爲cur,其左邊第一個比cur小得下標爲l, 右邊第一個比cur小的元素下標爲r, 那麼這中間的最大值就是(r-l+1)*heights[cur] 如今假設數組是升序的,那麼r=cur,只需尋找左邊 元素的下標l就好了,具體的思路以下: 1、若是已知height數組是升序的,應該怎麼作? 好比1,2,5,7,8 那麼就是(1*5) vs. (2*4) vs. (5*3) vs. (7*2) vs. (8*1) 也就是max(height[i]*(size-i)) 2、使用棧的目的就是構造這樣的升序序列,按照以上方法求解。 可是height自己不必定是升序的,應該怎樣構建棧? 好比2,1,5,6,2,3 (1)2進棧。s={2}, result = 0 (2)1比2小,不知足升序條件,所以將2彈出,並記錄當前結果爲2*1=2。 將2替換爲1從新進棧。s={1,1}, result = 2 (3)5比1大,知足升序條件,進棧。s={1,1,5},result = 2 (4)6比5大,知足升序條件,進棧。s={1,1,5,6},result = 2 (5)2比6小,不知足升序條件,所以將6彈出,並記錄當前結果爲6*1=6。s={1,1,5},result = 6 2比5小,不知足升序條件,所以將5彈出,並記錄當前結果爲5*2=10(由於已經彈出的5,6是升序的)。s={1,1},result = 10 2比1大,將彈出的5,6替換爲2從新進棧。s={1,1,2,2,2},result = 10 (6)3比2大,知足升序條件,進棧。s={1,1,2,2,2,3},result = 10 棧構建完成,知足升序條件,所以按照升序處理辦法獲得上述的max(height[i]*(size-i))=max{3*1, 2*2, 2*3, 2*4, 1*5, 1*6}=8<10 綜上所述,result=10
代碼以下:
class Solution { public int largestRectangleArea(int[] heights) { if (heights == null || heights.length == 0) { return 0; } Stack<Integer> stack = new Stack<Integer>(); int res = 0; for (int i = 0; i < heights.length; i++) { if (stack.isEmpty() || stack.peek() < heights[i]) { stack.push(heights[i]); } else { int count = 0; while (!stack.isEmpty() && heights[i] < stack.peek()) { count++; res = Math.max(res, stack.pop() * count); } while (count-- >= 0) { stack.push(heights[i]); } } } int count = 1; while (!stack.isEmpty()) { res = Math.max(res, stack.pop() * count); count++; } return res; } }
-------------------------------------------------------------------------
2017/09/12
85. Maximal Rectangle
Given a 2D binary matrix filled with 0's and 1's, find the largest rectangle containing only 1's and return its area. For example, given the following matrix: 1 0 1 0 0 1 0 1 1 1 1 1 1 1 1 1 0 0 1 0 Return 6.
假設把矩陣沿着某一行分開,而後把分開的行做爲底面,將自底面往上的矩陣當作一個直方圖(histogram)。直方圖的中每一個項的高度就是從底面行開始往上1的數量。根據Largest Rectangle in Histogram就能夠求出當前行做爲矩陣下邊緣的一個最大矩陣。接下來若是對每一行都作一次Largest Rectangle in Histogram,從其中選出最大的矩陣,那麼它就是整個矩陣中面積最大的子矩陣。
如何計算某一行爲底面時直方圖的高度呢?若是從新計算,那麼每次須要的計算數量就是當前行數乘以列數。然而會發現一些動態規劃的蹤影,若是知道上一行直方圖的高度,就只須要看新加進來的行(底面)上對應的列元素是否是0,若是是,則高度是0,不然則是上一行直方圖的高度加1。利用歷史信息,就能夠在線行時間內完成對高度的更新。因爲Largest Rectangle in Histogram的算法複雜度是O(n)。因此完成對一行爲底邊的矩陣求解複雜度是O(n+n)=O(n)。接下來對每一行都作一次,那麼算法總時間複雜度是O(m*n)。
上面的矩陣就成這樣了:
時間複雜度:O(mn)
空間複雜度:O(n)
具體代碼以下:
class Solution { public int maximalRectangle(char[][] matrix) { if (matrix.length == 0 || matrix[0].length == 0) { return 0; } int res = 0; int row = matrix.length; int col = matrix[0].length; //tmp數組存儲以該行爲底,上面每列有多少個1 int[] tmp = new int[col]; for (int i = 0; i < row; i++) { for (int j = 0; j < col; j++) { tmp[j] = matrix[i][j] == '0' ? 0 : tmp[j] + 1; } res = Math.max(res, largestRectangleArea(tmp)); } return res; } public int largestRectangleArea(int[] heights) { if (heights == null || heights.length == 0) { return 0; } Stack<Integer> stack = new Stack<Integer>(); int res = 0; for (int i = 0; i < heights.length; i++) { if (stack.isEmpty() || stack.peek() < heights[i]) { stack.push(heights[i]); } else { int count = 0; while (!stack.isEmpty() && heights[i] < stack.peek()) { count++; res = Math.max(res, stack.pop() * count); } while (count-- >= 0) { stack.push(heights[i]); } } } int count = 1; while (!stack.isEmpty()) { res = Math.max(res, stack.pop() * count); count++; } return res; } }
-------------------------------------------------