结果两个都是 1 2 3
局部
可以理解为, 内存是个大数组, ref和pointer都是数组的下标, 是index
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.
Only constant memory is allowed.
复杂的, 不能一眼看到结果的, 要拆分.
拆分就是要步骤化, 先框架, 再细节.
复杂的问题通过一个for循环, 一个while循环, 或者一个123步怎么做, 变成一个更小的问题.
每个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