本系列笔记主要记录笔者刷《程序员面试金典》算法的一些想法与经验总结,按专题分类,主要由两部分构成:经验值点和经典题目。其中重点放在经典题目上;
public ListNode removeDuplicateNodes(ListNode head) {
if(head == null || head.next == null){
return head;
}
ListNode cur = head;
ListNode index = head;
Set<Integer> set = new HashSet<>();
set.add(head.val);
while( cur.next != null){
cur = cur.next;
if( !set.contains(cur.val) ){
index.next = cur;
index = cur;
set.add(cur.val);
} else {
index.next = null;
}
}
return head;
}
public ListNode removeDuplicateNodes(ListNode head) {
ListNode ob = head;
while (ob != null) {
ListNode oc = ob;
while (oc.next != null) {
if (oc.next.val == ob.val) {
oc.next = oc.next.next;
} else {
oc = oc.next;
}
}
ob = ob.next;
}
return head;
}
public int kthToLast(ListNode head, int k) {
if(head == null || head.next == null){
return head.val;
}
ListNode cur = head;
ListNode index = head;
//cur先走k-1个步长
for(int i = 0; i < k - 1; i++ ){
cur = cur.next;
}
//index上链表,跟cur同步运动,当cur到达链表尾时,cur为倒数第k个
while(cur.next != null){
cur = cur.next;
index = index.next;
}
return index.val;
}
public int kthToLast(ListNode head, int k) {
Stack<ListNode> stack = new Stack<>();
//链表节点压栈
while (head != null) {
stack.push(head);
head = head.next;
}
//在出栈串成新的链表
ListNode firstNode = stack.pop();
while (--k > 0) {
ListNode temp = stack.pop();
temp.next = firstNode;
firstNode = temp;
}
return firstNode.val;
}
int size;
public int kthToLast(ListNode head, int k) {
if (head == null){
return 0;
}
int value = kthToLast(head.next, k);
if (++size == k){
return head.val;
}
return value;
}
public void deleteNode(ListNode node) {
if(node == null || node.next == null){
return;
}
ListNode nextNode = node.next;
node.val = nextNode.val;
node.next = nextNode.next;
}
public ListNode partition(ListNode head, int x) {
if(head == null || head.next == null ){
return head;
}
//找到比x小的节点,该节点离x节点最近
ListNode index = head;
while(index.val < x && index.next != null){
index = index.next;
}
//用2个指针完成移位操作
//index为首个大于等于x的节点
//cur为index2的next
ListNode cur = index.next;
while(index.next != null){
if(cur.val >= x){
//继续
index = index.next;
cur = cur.next;
} else {
//移位
index.next = cur.next;
if( head.val < x){
cur.next = head.next;
head.next = cur;
} else {
cur.next = head;
head = cur;
}
cur = index.next;
}
}
return head;
}
public ListNode partition(ListNode head, int x) {
return sortList(head, null);
}
private ListNode sortList(ListNode head, ListNode tail) {
//无法继续拆分的情况
if (head == null) {
return null;
}
//无法继续拆分的情况
if (head.next == tail) {
head.next = null;
return head;
}
//快慢指针找到中间节点
ListNode slow = head, fast = head;
while (fast != tail && fast.next != tail) {
slow = slow.next;
fast = fast.next.next;
}
ListNode mid = slow;
//左边继续拆分
ListNode left = sortList(head, mid);
//右边继续拆分
ListNode right = sortList(mid, tail);
//有序链表合并
return merge(left, right);
}
private ListNode merge(ListNode left, ListNode right) {
ListNode mergeNode = new ListNode();
ListNode help = mergeNode;
//比较两个链表当前的值,值小的链表就把引用赋给mergeNode,并向后移动一位重新赋值给自己,同时help指向值小的那个节点
while (left != null && right != null) {
if (left.val < right.val) {
help.next = left;
left = left.next;
} else {
help.next = right;
right = right.next;
}
help = help.next;
}
//最后如果有剩余的节点,就一次性链上去
help.next = left == null ? right : left;
return mergeNode.next;
}
public ListNode partition(ListNode head, int x) {
ListNode dummy = new ListNode();
dummy.next = head;
while (head != null && head.next != null) {
int nextVal = head.next.val;
if (nextVal < x) {
ListNode next = head.next;
head.next = head.next.next;
next.next = dummy.next;
dummy.next = next;
} else {
head = head.next;
}
}
return dummy.next;
}
public ListNode partition(ListNode head, int x) {
ListNode dummy = new ListNode();
dummy.next = head;
ListNode smallDummy = new ListNode();
ListNode small = smallDummy;
//和删除节点的套路一样,先处理头节点满足条件的情况
while (head != null) {
if (head.val >= x) {
break;
}
small.next = new ListNode(head.val);
small = small.next;
head = head.next;
}
//删除
ListNode cur = head;
ListNode pre = null;
while (cur != null) {
if (cur.val < x) {
pre.next = cur.next;
small.next = new ListNode(cur.val);
small = small.next;
} else {
pre = cur;
}
cur = cur.next;
}
small.next = head;
return smallDummy.next;
}
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
if( l1 == null && l2 == null){
return null;
}
ListNode cur1 = l1;
ListNode cur2 = l2;
int cache = 0;
boolean isFirst = true;
ListNode head = null;
ListNode index = null;
while( cur1 != null || cur2 != null){
//加法
int value = 0;
if( cur1 == null){
value = cur2.val + cache;
cur2 = cur2.next;
} else if ( cur2 == null){
value = cur1.val + cache;
cur1 = cur1.next;
} else {
value = cur1.val + cur2.val + cache;
cur1 = cur1.next;
cur2 = cur2.next;
}
//进位在cache储存
cache = value / 10;
//构造新节点,新节点指向新节点
ListNode node = new ListNode(value%10);
if(isFirst){
head = node;
index = node;
isFirst = false;
} else {
index.next = node;
index = node;
}
}
//判断cache
if(cache != 0){
ListNode node = new ListNode(cache);
index.next = node;
}
return head;
}
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
ListNode head = new ListNode(0);
helper(head, l1, l2, 0);
return head.next;
}
private void helper(ListNode result, ListNode l1, ListNode l2, int carry) {
if (l1 == null && l2 == null && carry == 0){
return;
}
int sum = (l1 != null ? l1.val : 0) + (l2 != null ? l2.val : 0) + carry;
result.next = new ListNode(0);
result.next.val = sum % 10;
carry = sum / 10;
helper(result.next, l1 != null ? l1.next : null, l2 != null ? l2.next : null, carry);
}
public boolean isPalindrome(ListNode head) {
if(head == null){
return true;
}
//统计链表长度
ListNode cur = head;
int count = 0;
while( cur != null ){
count++;
cur = cur.next;
}
if( count < 2){
return true;
}
//改变前 count/2-1 个节点指向,分奇偶讨论
ListNode right = head;
//定位right指针
if( count % 2 == 1 ){
//奇数情况
for( int i = 0; i < count/2+1; i++){
right = right.next;
}
} else {
//偶数情况
for( int i = 0; i < count/2; i++){
right = right.next;
}
}
//改变前count/2-1个节点方向
ListNode left = head;
cur = head.next;
ListNode mid = cur.next;
//判断对只有2~3个节点单独判断
if(count < 4){
return left.val == right.val;
}
for( int i = 0; i < count/2-1; i++){
cur.next = left;
left = cur;
cur = mid;
mid = mid.next;
}
//遍历比较left和right
while(right != null){
if(left.val != right.val){
return false;
}
right = right.next;
left = left.next;
}
return true;
}
public boolean isPalindrome(ListNode head) {
List<Integer> vals = new ArrayList<Integer>();
// 将链表的值复制到数组中
ListNode currentNode = head;
while (currentNode != null) {
vals.add(currentNode.val);
currentNode = currentNode.next;
}
// 使用双指针判断是否回文
int front = 0;
int back = vals.size() - 1;
while (front < back) {
if (!vals.get(front).equals(vals.get(back))) {
return false;
}
front++;
back--;
}
return true;
}
private ListNode frontPointer;
private boolean recursivelyCheck(ListNode currentNode) {
if (currentNode != null) {
if (!recursivelyCheck(currentNode.next)) {
return false;
}
if (currentNode.val != frontPointer.val) {
return false;
}
frontPointer = frontPointer.next;
}
return true;
}
public boolean isPalindrome(ListNode head) {
frontPointer = head;
return recursivelyCheck(head);
}
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
if( headA == null || headB == null ){
return null;
}
ListNode cur = headA;
int countA = 0;
while( cur != null ){
countA++;
cur = cur.next;
}
cur = headB;
int countB = 0;
while( cur != null){
countB++;
cur = cur.next;
}
//保证headA长于headB
if( countA < countB){
return getIntersectionNode(headB,headA);
}
ListNode curA = headA;
ListNode curB = headB;
for( int i = 0; i < countA-countB; i++){
curA = curA.next;
}
while( curA != null ){
if( curA.equals(curB) ){
return curA;
}
curA = curA.next;
curB = curB.next;
}
return null;
}
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode h1 = headA;
ListNode h2 = headB;
while(h1 != h2){
h1 = (h1 == null ? headB : h1.next);
h2 = (h2 == null ? headA : h2.next);
}
return h1;
}
public ListNode detectCycle(ListNode head) {
if( head == null ){
return null;
}
if(head.next == null){
return null;
}
if(head.next.next == null){
return null;
}
//使用快慢指针找到有count个环成圈;
ListNode fast = head.next.next;
ListNode slow = head.next;
int count = 1; //count变量不是必要的
while( fast != slow ){
if(fast == null || slow == null){
return null;
}
slow = slow.next;
if(fast.next != null){
fast = fast.next.next;
} else {
return null;
}
count++;
}
// cur 和 slow 一起走,走n步到环路开头节点
ListNode cur = head;
while( cur != slow ){
cur = cur.next;
slow = slow.next;
}
return cur;
}
public ListNode detectCycle(ListNode head) {
ListNode pos = head;
Set<ListNode> visited = new HashSet<ListNode>();
while (pos != null) {
if (visited.contains(pos)) {
return pos;
} else {
visited.add(pos);
}
pos = pos.next;
}
return null;
}