結果兩個都是 1 2 3java
局部node
能夠理解爲, 內存是個大數組, ref和pointer都是數組的下標, 是indexc++
Given a linked list, reverse the nodes of a linked list k at a time and return its modified list.面試
If the number of nodes is not a multiple of k then left-out nodes in the end should remain as it is.算法
You may not alter the values in the nodes, only nodes itself may be changed.shell
Only constant memory is allowed.數組
複雜的, 不能一眼看到結果的, 要拆分.框架
拆分就是要步驟化, 先框架, 再細節.dom
複雜的問題經過一個for循環, 一個while循環, 或者一個123步怎麼作, 變成一個更小的問題.wordpress
每一個function須要明確
java要new, c++不要new,c++若是new了要刪除
幾乎
鏈表結構發生變化的時候
不須要
他沒那麼神精病, O(1)的額外空間不算額外空間,O(n)纔算
不是, 可是用了代碼比較簡潔
不重要, 只須要它的next的值
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.
相似clone graph, 其中clone graph的步驟是:
連同老節點和新節點.
public class Solution { public RandomListNode copyRandomList(RandomListNode head) { if (head == null) { return null; } HashMap<RandomListNode, RandomListNode> map = new HashMap<RandomListNode, RandomListNode>(); RandomListNode dummy = new RandomListNode(0); RandomListNode pre = dummy, newNode; while (head != null) { if (map.containsKey(head)) { newNode = map.get(head); } else { newNode = new RandomListNode(head.label); map.put(head, newNode); } pre.next = newNode; if (head.random != null) { if (map.containsKey(head.random)) { newNode.random = map.get(head.random); } else { newNode.random = new RandomListNode(head.random.label); map.put(head.random, newNode.random); } } pre = newNode; head = head.next; } return dummy.next; } }
神馬是extra space?
除了input 和output之外的額外空間叫extra space
1->2->3->4
=>
1->1’->2->2’->3->3’->4->4’->NULL
A.next.random = A.random.next
/*第一遍掃的時候巧妙運用next指針, 開始數組是1->2->3->4 。 而後掃描過程當中 先創建copy節點 1->1`->2->2`->3->3`->4->4`, 而後第二遍copy的時候去創建邊的copy, 拆分節點, 一邊掃描一邊拆成兩個鏈表,這裏用到兩個dummy node。第一個鏈表變回 1->2->3 , 而後第二變成 1`->2`->3` */ //No HashMap version public class Solution { private void copyNext(RandomListNode head) { while (head != null) { RandomListNode newNode = new RandomListNode(head.label); newNode.random = head.random; newNode.next = head.next; head.next = newNode; head = head.next.next; } } private void copyRandom(RandomListNode head) { while (head != null) { if (head.next.random != null) { head.next.random = head.random.next; } head = head.next.next; } } private RandomListNode splitList(RandomListNode head) { RandomListNode newHead = head.next; while (head != null) { RandomListNode temp = head.next; head.next = temp.next; head = head.next; if (temp.next != null) { temp.next = temp.next.next; } } return newHead; } public RandomListNode copyRandomList(RandomListNode head) { if (head == null) { return null; } copyNext(head); copyRandom(head); return splitList(head); } }
public class Solution { public Boolean hasCycle(ListNode head) { if (head == null || head.next == null) { return false; } ListNode fast, slow; fast = head.next; slow = head; while (fast != slow) { if(fast==null || fast.next==null) return false; fast = fast.next.next; slow = slow.next; } return true; } }
個人理解:
網上別人的偏數學的解釋,參考LeetCode Discuss(https://leetcode.com/discuss/16567/concise-solution-usi:
1). 使用快慢指針法,若鏈表中有環,能夠獲得兩指針的交點M
2). 記鏈表的頭節點爲H,環的起點爲E
2.1) L1爲H到E的距離
2.2) L2爲從E出發,首次到達M時的路程
2.3) C爲環的周長
2.4) n爲快慢指針首次相遇時,快指針在環中繞行的次數
根據L1,L2和C的定義,咱們能夠獲得:
慢指針行進的距離爲L1 + L2
快指針行進的距離爲L1 + L2 + n * C
因爲快慢指針行進的距離有2倍關係,所以:
2 * (L1+L2) = L1 + L2 + n * C => L1 + L2 = n * C => L1 = (n – 1)* C + (C – L2)
能夠推出H到E的距離 = 從M出發繞環到達E時的路程
所以,當快慢指針在環中相遇時,咱們再令一個慢指針從頭節點出發
接下來當兩個慢指針相遇時,即爲E所在的位置
實在不明白,就背下來吧。。。
L1走到頭,而後把尾巴接到L2上, 而後liked list cycle II
public class Solution { /** * @param headA: the first list * @param headB: the second list * @return: a ListNode */ public ListNode getIntersectionNode(ListNode headA, ListNode headB) { if (headA == null || headB == null) { return null; } // get the tail of list A. ListNode node = headA; while (node.next != null) { node = node.next; } node.next = headB; ListNode result = listCycleII(headA); node.next = null; return result; } private ListNode listCycleII(ListNode head) { ListNode slow = head, fast = head.next; while (slow != fast) { if (fast == null || fast.next == null) { return null; } slow = slow.next; fast = fast.next.next; } slow = head; fast = fast.next; while (slow != fast) { slow = slow.next; fast = fast.next; } return slow; }
Sort a linked list in O(n log n) time using constant space complexity.
constant space
O(1) memory
no extra space
三者同樣
O(n) bucket sort
O(n * n^(1/2)) shell sort
O(nlogn) quick merge heap
radix sort 和counting sort(數數有幾個1 有幾個2 再用hash??)
這兩個是基於value的排序, 要求key可數, float double啥的就不行了
quick: O(1)
merge: O(n) 必定要倒騰出來,再挪回去,因此須要其餘的n個位置
heap:O(1)/O(n) 取決於用不用priority queue
list:靈活,可打亂,可重組
array:下標連續,整塊內存
ps:quick sort和merge sort都本身實現下
// version 1: Merge Sort public class Solution { private ListNode findMiddle(ListNode head) { ListNode slow = head, fast = head.next; while (fast != null && fast.next != null) { fast = fast.next.next; slow = slow.next; } return slow; } private ListNode merge(ListNode head1, ListNode head2) { ListNode dummy = new ListNode(0); ListNode tail = dummy; while (head1 != null && head2 != null) { if (head1.val < head2.val) { tail.next = head1; head1 = head1.next; } else { tail.next = head2; head2 = head2.next; } tail = tail.next; } if (head1 != null) { tail.next = head1; } else { tail.next = head2; } return dummy.next; } public ListNode sortList(ListNode head) { if (head == null || head.next == null) { return head; } ListNode mid = findMiddle(head); ListNode right = sortList(mid.next); mid.next = null; ListNode left = sortList(head); return merge(left, right); } } // version 2: Quick Sort 1 public class Solution { public ListNode sortList(ListNode head) { if (head == null || head.next == null) { return head; } ListNode mid = findMedian(head); // O(n) ListNode leftDummy = new ListNode(0), leftTail = leftDummy; ListNode rightDummy = new ListNode(0), rightTail = rightDummy; ListNode middleDummy = new ListNode(0), middleTail = middleDummy; while (head != null) { if (head.val < mid.val) { leftTail.next = head; leftTail = head; } else if (head.val > mid.val) { rightTail.next = head; rightTail = head; } else { middleTail.next = head; middleTail = head; } head = head.next; } leftTail.next = null; middleTail.next = null; rightTail.next = null; ListNode left = sortList(leftDummy.next); ListNode right = sortList(rightDummy.next); return concat(left, middleDummy.next, right); } private ListNode findMedian(ListNode head) { ListNode slow = head, fast = head.next; while (fast != null && fast.next != null) { slow = slow.next; fast = fast.next.next; } return slow; } private ListNode concat(ListNode left, ListNode middle, ListNode right) { ListNode dummy = new ListNode(0), tail = dummy; tail.next = left; tail = getTail(tail); tail.next = middle; tail = getTail(tail); tail.next = right; tail = getTail(tail); return dummy.next; } private ListNode getTail(ListNode head) { if (head == null) { return null; } while (head.next != null) { head = head.next; } return head; } } // version 3: Quick Sort 2 /** * Definition for ListNode. * public class ListNode { * int val; * ListNode next; * ListNode(int val) { * this.val = val; * this.next = null; * } * } */ class Pair { public ListNode first, second; public Pair(ListNode first, ListNode second) { this.first = first; this.second = second; } } public class Solution { /** * @param head: The head of linked list. * @return: You should return the head of the sorted linked list, using constant space complexity. */ public ListNode sortList(ListNode head) { if (head == null || head.next == null) { return head; } ListNode mid = findMedian(head); // O(n) Pair pair = partition(head, mid.val); // O(n) ListNode left = sortList(pair.first); ListNode right = sortList(pair.second); getTail(left).next = right; // O(n) return left; } // 1->2->3 return 2 // 1->2 return 1 private ListNode findMedian(ListNode head) { ListNode slow = head, fast = head.next; while (fast != null && fast.next != null) { slow = slow.next; fast = fast.next.next; } return slow; } // < value in the left, > value in the right private Pair partition(ListNode head, int value) { ListNode leftDummy = new ListNode(0), leftTail = leftDummy; ListNode rightDummy = new ListNode(0), rightTail = rightDummy; ListNode equalDummy = new ListNode(0), equalTail = equalDummy; while (head != null) { if (head.val < value) { leftTail.next = head; leftTail = head; } else if (head.val > value) { rightTail.next = head; rightTail = head; } else { equalTail.next = head; equalTail = head; } head = head.next; } leftTail.next = null; rightTail.next = null; equalTail.next = null; if (leftDummy.next == null && rightDummy.next == null) { ListNode mid = findMedian(equalDummy.next); leftDummy.next = equalDummy.next; rightDummy.next = mid.next; mid.next = null; } else if (leftDummy.next == null) { leftTail.next = equalDummy.next; } else { rightTail.next = equalDummy.next; } return new Pair(leftDummy.next, rightDummy.next); } private ListNode getTail(ListNode head) { if (head == null) { return null; } while (head.next != null) { head = head.next; } return head; } }
Given two sorted integer arrays A and B, merge B into A as one sorted array.
從後往前排
class Solution {
/** * @param A: sorted integer array A which has m elements, * but size of A is m+n * @param B: sorted integer array B which has n elements * @return: void */ public void mergeSortedArray(int[] A, int m, int[] B, int n) { int i = m-1, j = n-1, index = m + n - 1; while (i >= 0 && j >= 0) { if (A[i] > B[j]) { A[index--] = A[i--]; } else { A[index--] = B[j--]; } } while (i >= 0) { A[index--] = A[i--]; } while (j >= 0) { A[index--] = B[j--]; } } }
每次比較, 誰小誰出列的反向, 誰大誰出列
class Solution {
/** * @param A and B: sorted integer array A and B. * @return: A new sorted integer array */ public int[] mergeSortedArray(int[] A, int[] B) { if (A == null || B == null) { return null; } int[] result = new int[A.length + B.length]; int i = 0, j = 0, index = 0; while (i < A.length && j < B.length) { if (A[i] < B[j]) { result[index++] = A[i++]; } else { result[index++] = B[j++]; } } while (i < A.length) { result[index++] = A[i++]; } while (j < B.length) { result[index++] = B[j++]; } return result; } }
Given two arrays, write a function to compute their intersection.
1.哈希表 小的塞哈希表
2.小的出去
相同的都出去, 加到新的隊列裏
3.排小的
for打的的每一個數, 二分查n
// version 1: sort & merge public class Solution { /** * @param nums1 an integer array * @param nums2 an integer array * @return an integer array */ public int[] intersection(int[] nums1, int[] nums2) { Arrays.sort(nums1); Arrays.sort(nums2); int i = 0, j = 0; int[] temp = new int[nums1.length]; int index = 0; while (i < nums1.length && j < nums2.length) { if (nums1[i] == nums2[j]) { if (index == 0 || temp[index - 1] != nums1[i]) { temp[index++] = nums1[i]; } i++; j++; } else if (nums1[i] < nums2[j]) { i++; } else { j++; } } int[] result = new int[index]; for (int k = 0; k < index; k++) { result[k] = temp[k]; } return result; } } // version 2: hash map public class Solution { /** * @param nums1 an integer array * @param nums2 an integer array * @return an integer array */ public int[] intersection(int[] nums1, int[] nums2) { if (nums1 == null || nums2 == null) { return null; } HashSet hash = new HashSet<>(); for (int i = 0; i < nums1.length; i++) { hash.add(nums1[i]); } HashSet resultHash = new HashSet<>(); for (int i = 0; i < nums2.length; i++) { if (hash.contains(nums2[i]) && !resultHash.contains(nums2[i])) { resultHash.add(nums2[i]); } } int size = resultHash.size(); int[] result = new int[size]; int index = 0; for (Integer num : resultHash) { result[index++] = num; } return result; } } // version 3: sort & binary search public class Solution { /** * @param nums1 an integer array * @param nums2 an integer array * @return an integer array */ public int[] intersection(int[] nums1, int[] nums2) { if (nums1 == null || nums2 == null) { return null; } HashSet set = new HashSet<>(); Arrays.sort(nums1); for (int i = 0; i < nums2.length; i++) { if (set.contains(nums2[i])) { continue; } if (binarySearch(nums1, nums2[i])) { set.add(nums2[i]); } } int[] result = new int[set.size()]; int index = 0; for (Integer num : set) { result[index++] = num; } return result; } private boolean binarySearch(int[] nums, int target) { if (nums == null || nums.length == 0) { return false; } int start = 0, end = nums.length - 1; while (start + 1 < end) { int mid = (end - start) / 2 + start; if (nums[mid] == target) { return true; } if (nums[mid] < target) { start = mid; } else { end = mid; } } if (nums[start] == target) { return true; } if (nums[end] == target) { return true; } return false; } }
There are two sorted arrays A and B of size m and n respectively. Find the median of the two sorted arrays.
聯想到quick select那道題, 其中k = median
就merge k= (n+m/2)次, 可是不夠快
若是O(k)不夠快,只能往logn方向走
可是兩個數組的二分, 很差分, 因此想到縮小一倍問題的size
因此在一個數組裏刪掉2/k個數
A沒了
B沒了
k= 1
public class Solution { public double findMedianSortedArrays(int A[], int B[]) { int len = A.length + B.length; if (len % 2 == 1) { return findKth(A, 0, B, 0, len / 2 + 1); } return ( findKth(A, 0, B, 0, len / 2) + findKth(A, 0, B, 0, len / 2 + 1) ) / 2.0; } // find kth number of two sorted array public static int findKth(int[] A, int A_start, int[] B, int B_start, int k){ if (A_start >= A.length) { return B[B_start + k - 1]; } if (B_start >= B.length) { return A[A_start + k - 1]; } if (k == 1) { return Math.min(A[A_start], B[B_start]); } int A_key = A_start + k / 2 - 1 < A.length ? A[A_start + k / 2 - 1] : Integer.MAX_VALUE; int B_key = B_start + k / 2 - 1 < B.length ? B[B_start + k / 2 - 1] : Integer.MAX_VALUE; if (A_key < B_key) { return findKth(A, A_start + k / 2, B, B_start, k - k / 2); } else { return findKth(A, A_start, B, B_start + k / 2, k - k / 2); } } }
Given an array of integers, find a contiguous subarray which has the largest sum.
求數組中間的一段, 就長減短
PrefixSum[i] = A[0] + A[1] + … A[i – 1], PrefixSum[0] = 0
易知構造 PrefixSum 耗費 O(n) 時間和 O(n) 空間
如需計算子數組從下標i到下標j之間的全部數之和
則有 Sum(i~j) = PrefixSum[j + 1] – PrefixSum[i]
相似的closest就拍個序
// Version 1: Greedy public class Solution { public int maxSubArray(int[] A) { if (A == null || A.length == 0){ return 0; } int max = Integer.MIN_VALUE, sum = 0; for (int i = 0; i < A.length; i++) { sum += A[i]; max = Math.max(max, sum); sum = Math.max(sum, 0); } return max; } } // Version 2: Prefix Sum public class Solution { public int maxSubArray(int[] A) { if (A == null || A.length == 0){ return 0; } int max = Integer.MIN_VALUE, sum = 0, minSum = 0; for (int i = 0; i < A.length; i++) { sum += A[i]; max = Math.max(max, sum - minSum); minSum = Math.min(minSum, sum); } return max; } } public class Solution { /** * @param nums: a list of integers * @return: A integer indicate the sum of minimum subarray */ public int maxSubArray(ArrayList nums) { // write your code if(nums.size()==0) return 0; int n = nums.size(); int []global = new int[n]; int []local = new int[n]; global[0] = nums.get(0); local[0] = nums.get(0); for(int i=1;i<n;i++) { local[i] = Math.max(nums.get(i),local[i-1]+nums.get(i)); global[i] = Math.max(local[i],global[i-1]); } return global[n-1]; } }
Given an integer array, find a subarray with sum closest to zero. Return the indexes of the first number and last number.
class Solution { public: /** * @param nums: A list of integers * @return: A list of integers includes the index of the first number * and the index of the last number */ struct node { //成員,生成,比較 node(int _value, int _pos):value(_value), pos(_pos) {} int value, pos; //重點有二,一個是&,一個是const bool operator<(const node &o) const{ return (value < o.value || value == o.value && pos < o.pos); } }; vector<int> subarraySumClosest(vector<int> nums){ // write your code here vector<node> s; vector<int> results(2); s.push_back(node(0,-1)); int sum = 0, len = nums.size(); for (int i = 0; i < len ; ++i) { sum += nums[i]; s.push_back(node(sum, i)); } sort(s.begin(), s.end()); len = s.size(); int ans = 0x7fffffff; for (int i = 0; i < len-1; ++i) if (abs(s[i+1].value - s[i].value) < ans) { ans = abs(s[i+1].value - s[i].value); results[0] = min(s[i].pos, s[i+1].pos)+1; results[1] = max(s[i].pos, s