My leetcode

链表

链表空间不一定保证连续,为临时分配

返回值为链表节点

画图方法理清逻辑

边界条件要求严格

链表为空或链表长度为1

可以使用额外数据结构来简化调整过程,但最优解往往不需要使用额外数据结构

技巧

  1. 构建新的不参与运算的头节点

    ListNode* dummy = new ListNode(-1)//用-1是因为node没有无参构造
    dummy->next = head;
    ...
    return dummy->next;
    
  2. 画图! 举例!

简单难度

删除排序链表中的重复元素 (重复的保留一个)

leetcode 203

ListNode* deleteDuplicates(ListNode* head) {
    if (head == nullptr || head->next == nullptr) return head;
    head->next = deleteDuplicates(head->next);
    return head->val == head->next->val?head->next:head;                    
}

移除给定值的所有链表元素

leetcode 83

ListNode* removeElements(ListNode* head, int val) {
     if (head == nullptr) return head;
     head->next = removeElements(head->next, val);
     return head->val == val ? head->next : head;
    }

合并两个有序链表

leetcode 21

输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4

ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
    if (l1 == nullptr)
        return l2;
    if (l2 == nullptr)
        return l1;
    //递归,一步步返回两个值较小的数;
    if(l1->val<l2->val){
        l1->next = mergeTwoLists(l1->next,l2);
        return l1; 
    }
    else{
        l2->next = mergeTwoLists(l1,l2->next);
        return l2;            
    }
    
}

反转链表

leetcode 206

ListNode* reverseList(ListNode* head) {
    if(head == nullptr || head->next == nullptr)
        return head;
    ListNode* next = head->next;
    ListNode* newhead = reverseList(next);//遍历至最后一个节点
    next->next = head;
    head->next = nullptr;
    return newhead;
    //递归的方法其实是非常巧的,它利用递归走到链表的末端,然后再更新每一个node的next值,实现链表的反转。而newhead 的值没有发生改变,为该链表的最后一个结点,所以,反转后,我们可以得到新链表的head。
}
ListNode* reverseList2(ListNode* head) {
    ListNode* prev = nullptr;
    ListNode* next ;
    while(head!= nullptr){
        next = head->next;
        head->next = prev;        
        prev = head;
        head = next;        
    }
    return prev;
    
}

相交链表

leetcode 160

ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
    
    ListNode *l1 = headA;
    ListNode *l2 = headB;
    while(l1!=l2){
        l1 = (l1 == nullptr) ? headB: l1->next;
        l2 = (l2 == nullptr) ? headA: l2->next;
    }
    return l1;
}

删除链表中的节点(非尾节点)

leetcode 237

将待删除节点的值赋值为下一个节点的值,然后将待删除节点的引用指向待删除节点的下下个节点。

void deleteNode(ListNode* node) {
    node->val = node->next->val;
    node->next = node->next->next;
}

环形链表1 判断是否有环

bool hasCycle(ListNode *head) {
    if (head==nullptr||head->next==nullptr) return false;
    ListNode* fast = head;
    ListNode* slow = head;
    while(fast->next !=nullptr && fast!=nullptr){
        fast = fast->next->next;
        slow = slow->next;
        if (fast==slow) return true;
     }
    return false;
}

中等难度

两数相加 M

leetcode 2

输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
输出:7 -> 0 -> 8
原因:342 + 465 = 807

ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
    ListNode* node = new ListNode(0);
    int carry = 0;
    ListNode* p = l1;
    ListNode* q = l2;
    ListNode* cur = node;
    while(p!= nullptr || q!=nullptr){
        int x = (p==nullptr)?0:p->val;
        int y = (q==nullptr)?0:q->val;
        int sum = x+y+carry;
        carry = sum/10;
        ListNode* newnode = new ListNode(sum%10);
        cur->next = newnode;
        cur = cur->next;
        if (p!= nullptr) p = p->next;
        if (q!= nullptr) q = q->next;
    }
    if (carry>0){
        cur->next =  new ListNode(carry);
}             return node->next;


​ }

删除链表的倒数第N个节点 M

leetcode 19

给定一个链表: 1->2->3->4->5, 和 n = 2.
当删除了倒数第二个节点后,链表变为 1->2->3->5.

ListNode* removeNthFromEnd(ListNode* head, int n) {
    ListNode* fast = head;
    for(int i=0;i<n;i++){
        fast = fast->next;
        
    }
    
    if (fast == nullptr) return head->next;//删除的是头节点	
    ListNode* slow = head;
    while(fast->next!= nullptr){
        fast = fast->next;
        slow = slow->next;
    }
    slow->next = slow->next->next;
    return head;        
}

两两交换链表中的节点 M

leetcode 24

给定 1->2->3->4, 你应该返回 2->1->4->3.

你的算法只能使用常数的额外空间。
你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换

ListNode* swapPairs(ListNode* head) {
    ListNode* node = new ListNode(-1);//新建一个空节点,永远连着头节点
    node->next = head;
    ListNode* pre = node;
    while (pre->next!= nullptr && pre->next->next != nullptr){
        ListNode* cur = pre->next;
        ListNode* next = pre->next->next;
        cur->next = next->next;            
        next->next = cur;
        pre->next = next;
        pre = cur;      // 1-2-3-4 变成 2-1-3-4 但cur仍是2,相当于每次前进两格了      
    }
    return node->next;
}

反转链表II M

leetcode 92

输入: 1->2->3->4->5->NULL, m = 2, n = 4
输出: 1->4->3->2->5->NULL

1->2->3->4->5->6->NULL node1 = 2 node2 = 3
1->3->2->4->5->6->NULL node1 = 2 node2 = 4
1->4->3->2->5->6->NULL node1 = 2 node2 = 5
1->5->4->3->2->6->NULL node1 = 2 node2 = 6
1->6->5->4->3->2->NULL

    ListNode* reverseBetween(ListNode* head, int m, int n) {
    ListNode *dummy = new ListNode(-1);
    dummy->next = head;//dummy->next获取新链表头结点
    if(head== nullptr ||head->next == nullptr)
        return dummy->next;
    ListNode *start = dummy;
    ListNode *node1,*node2;
    for(int i=0;i<m-1;i++){
        start = start->next;//从dummy开始遍历m次,获得m-1节点
    }        
    node1 = start->next; //指针1,它的值永远是第m个节点的值
    node2 = node1->next; //指针2
    for(int i=0;i<n-m;i++){//遍历(n-m)次
        node1->next = node2->next; 
        // node2后面的元素接在node1后面 
        node2->next = start->next;
        // start后面的元素放在node2后面
        start->next = node2;
        // node2放在start后面,反转
        // 其实就是调换start->next和node2,node1值不变,位置一直前进
        node2 = node1->next; 
        // node2前进
    }
    return dummy->next;
}

删除排序链表中的重复元素 II (重复的都删掉)

leetcode 82 + 剑指offer 18

    ListNode* deleteDuplication(ListNode* pHead)
    {
        ListNode* dummy = new ListNode(-1);
        dummy->next = pHead;
        ListNode* cur = pHead;
        ListNode* last = dummy; // 最后一个保存的节点
        while(cur!=nullptr&&cur->next!=nullptr)
        {
            if(cur->val==cur->next->val){
                int val = cur->val;
                while(cur!=nullptr&&cur->val == val){//遍历掉相同的节点
                    cur = cur->next;
                }
                last->next = cur;
            }
            else
            {
                last = cur;
                cur = cur->next;
            }
        }
        return dummy->next;
    }

环形链表2 返回入环节点(HashTable)

剑指offer

ListNode* EntryNodeOfLoop(ListNode* pHead)
{
    // hash table 
    if (pHead == nullptr) return nullptr;
    set<ListNode*> s;
    while(pHead!=nullptr)
    {
        if (s.find(pHead)!=s.end()) return pHead;
        else s.insert(pHead);
        pHead = pHead->next;
    }
    return nullptr;
}

难题

复杂链表的复制

  1. 直接复制 O(n2)
  2. 用空间换时间,哈希表 O(n)
    1. 复制每个节点,如:复制节点A得到A1,将A1插入节点A后面
    2. 遍历链表,A1->random = A->random->next;
    3. 将链表拆分成原链表和复制后的链表
    if (pHead == nullptr) return nullptr;
    RandomListNode* cur = pHead;
    while(cur!=nullptr){
        RandomListNode* n = new RandomListNode(cur->label);//初始化新建节点
        n->next = cur->next;
        cur->next = n;
        cur = n->next;
    }//在原节点后面复制节点
    cur = pHead;
    while(cur!=nullptr){
        RandomListNode* node = cur->next;
        if (cur->random!=nullptr){
            node->random = cur->random->next;
        }
        cur = node->next;
        // 复制random节点
    }
    RandomListNode* newhead = pHead->next;
    RandomListNode* tmp  = newhead;
    cur = pHead;
    while(cur!=nullptr){
        cur->next = cur->next->next;
        if(tmp->next!=nullptr) tmp->next = tmp->next->next;
        cur = cur->next;
        tmp = tmp->next;
    }
    return newhead;
}

排序链表(O(nlogn))

合并k个排序链表

环形链表II

分隔链表

二叉搜索树与双向链表

数组、排序与查找

基本排序算法

冒泡排序

每一轮迭代交换一次元素

def bubble_sort(seq):
	n = len(seq)
	for i in range(n-1):
		for j in range(n-1-i):
			if seq[j] > seq[j+1]:
				seq[j],seq[j+1] = seq[j+1],seq[j]
	return seq

选择排序

def select_sort(seq):
    n = len(seq)
    for i in range(n-1):
        min_idx = i
        for j in range(i+1,n):
            if seq[j]<seq[min_idx]:
                min_idx = j
        if min_idx ! = i:
            seq[i],seq[min_idx] = seq[min_idx],seq[i]
    return seq

插入排序

def insert_sort(seq):
	n = len(seq)
	for i in range(1,n):
		pos = i
		value = seq[i]
		while pos>0 and value < seq[pos-1]:
			seq[pos] = seq[pos-1]
			pos-=1
		seq[pos] = value
	return seq

高级排序算法

归并排序

O(nlg(n))

def merge_sort(seq):
	if len(seq)<= 1:
		return seq
	else:
		mid = int(len(seq)/2)
		left_half = merge_sort(seq[:mid])
		right_half = merge_sort(seq[mid:])

		new_seq = merge_sorted_list(left_half,right_half)
	return new_seq

def merge_sorted_list(left,right): #合并有序数组
	len_a = len(left)
	len_b = len(right)
	a = b = 0
	new = []
	while a < len_a and b < len_b:
		if left[a]<right[b]:
			new.append(left[a])
			a += 1
		else:
			new.append(right[b])
			b += 1
	new += right[b:]
	new += left[a:]
	return new

快速排序

def quicksort(seq,left,right):
    if left<right:
        pivot = partition(seq,left,right)
        quicksort(seq,left,pivot)
        quicksort(seq,pivot+1,right)
    return seq
        
def partition(seq,left,right):
    array = left-1
    pivot_index = right
    pivot = seq[right]
    for j in range(left,right):# 只遍历一遍
        if seq[j]<=pivot: # 比pivot小则array继续前进,同时交换元素 
            array += 1
            seq[j],seq[array] = seq[array],seq[j]
    seq[array+1],seq[pivot_index] = pivot,seq[array+1]  # 把pivot放到array+1的位置
    return array 
void swap(int &fir,int &sec) 
{
    int temp = fir;
    fir = sec;
    sec = temp;
}
int partition(vector<int> &input, int left, int right){//&input 很重要!!	 
    if(input.empty() || left>right) return -1; //+
    int array = left-1;
    int pivot = input[right];
    for(int i=left;i<right;i++){
        if (input[i]<=pivot){
            array++;
            swap(input[array],input[i]);// not necessarily
        }
    }
    swap(input[array+1],input[right]);
    return array+1;
}
void quicksort(vector<int>& input, int left, int right){
    if (left<right){
        int p = partition(input,left,right);
    	quicksort(input,p,right);
	    quicksort(input,left,p-1)
    }
}

堆排序

def heap_sort(seq):
    n = len(seq)
    for i in range(n//2-1,-1,-1):
        sift(seq,i,n-1)
    for i in range(n-1,-1,-1):
        seq[0],seq[i]= seq[i],seq[0]
        sift(seq,0,i-1)
        print(seq)
    return seq
def sift(seq,left,right):
    i = left
    j = 2*i+1  
    tmp = seq[i]
    while j<= right:
        if j<right and seq[j]<seq[j+1]:
            j +=1
        if tmp <seq[j]:
            seq[i] = seq[j]
            i = j
            j = 2*i+1
        else:
            break
    seq[i] = tmp
def heapSort2(alist):
    if alist == None or len(alist) == 0:
        return
    length = len(alist)
    output = []
    for i in range(length):
        tempLen = len(alist)
        for j in range(tempLen//2-1, -1, -1):
            preIndex = j
            preVal, heap = alist[preIndex], False
            while 2 * preIndex < tempLen - 1 and not heap:
                curIndex = 2 * preIndex + 1
                if curIndex < tempLen - 1:
                    if alist[curIndex] < alist[curIndex+1]:
                        curIndex += 1
                if preVal >= alist[curIndex]:
                    heap = True
                else:
                    alist[preIndex] = alist[curIndex]
                    preIndex = curIndex
            alist[preIndex] = preVal
        output.insert(0, alist.pop(0))
    return output

希尔排序

直接插入排序的升级

def shell_sort(seq):
    gap = len(seq)//2
    while gap >0:
        print(gap)
        for i in range(gap):
            for j in range(i+gap,len(seq),gap):
                value = seq[j] 
                pos = j
                while pos>=gap and seq[pos-gap]>value:
                    seq[pos] = seq[pos-gap]
                    pos -= gap
                seq[pos] =value 
        gap = gap//2
        print(seq)
    return seq

二分查找

注意溢出 mid = (left+right)/2 加法可能溢出 -> mid = left+(right-left)/2

public class Solution {
    public int GetNumberOfK(int [] array , int k) {
        int length = array.length;
        if(length == 0){
            return 0;
        }
        int firstK = getFirstK(array, k, 0, length-1);
        int lastK = getLastK(array, k, 0, length-1);
        if(firstK != -1 && lastK != -1){
             return lastK - firstK + 1;
        }
        return 0;
    }
    //递归写法
    private int getFirstK(int [] array , int k, int start, int end){
        if(start > end){
            return -1;
        }
        int mid = (start + end) >> 1; //使用>>1 防止溢出
        if(array[mid] > k){
            return getFirstK(array, k, start, mid-1);
        }else if (array[mid] < k){
            return getFirstK(array, k, mid+1, end);
        }else if(mid-1 >=0 && array[mid-1] == k){
            return getFirstK(array, k, start, mid-1);
        }else{
            return mid;
        }
    }
    //循环写法
    private int getLastK(int [] array , int k, int start, int end){
        int length = array.length;
        int mid = (start + end) >> 1;
        while(start <= end){
            if(array[mid] > k){
                end = mid-1;
            }else if(array[mid] < k){
                start = mid+1;
            }else if(mid+1 < length && array[mid+1] == k){
                start = mid+1;
            }else{
                return mid;
            }
            mid = (start + end) >> 1;
        }
        return -1;
    }
}

旋转排序数组系列

  1. 旋转排序数组的最小值

    int minNumberInRotateArray(vector<int> rotateArray) {
        int l = 0, r = rotateArray.size()-1,mid = l; //mid 初始化为l,考虑没有旋转的情况
        if (r==0) return 0;
        while(rotateArray[l]>=rotateArray[r]){
            if (r-l == 1){
                mid = r;
                break;
            }
            mid = (l+r)/2;
            if (rotateArray[l]<=rotateArray[mid]) l = mid;
            else if (rotateArray[mid]<=rotateArray[r]) r = mid;
        }
        return rotateArray[mid];
    }
    
  2. 搜索旋转排序数组

    bool search(vector<int>& nums, int target) {
        int l =0, r= nums.size()-1;
        if (r==-1) return false;
        if (r==0) return (nums[0]==target);
        while(l<r){
            int mid = (l+r)>>1;
            if (nums[mid]==target || nums[l] == target || nums[r] == target) return true;
            if (r-l == 1) break;
            if (nums[mid]<nums[r])
            {
                if (nums[mid]<target&&target<nums[r]) l = mid+1;
                else r = mid;
            }
            else if (nums[mid]>nums[l])
            {
                if (nums[l]<target && target<nums[mid]) r = mid// C++不要用a<t<b a==b==c !!!
                else l = mid+1;
            }            
        }
        return false;
        
    }
    
  3. 搜索旋转排序数组(有重复值)

    nums[r] = nums[m]=nums[l] 从r到l遍历

    ...        
    if (nums[mid] == nums[l] && nums[l] == nums[r]){//
                for(int j = l;j<=r;j++){
                    if (nums[j] == target) return true;
                }
                return false;
    ...
    
    

局部最小值(寻找峰值)

int findPeakElement(vector<int>& nums) {
    int l = 0, r = nums.size()-1,mid = 0;
    if(r==-1 or r ==0) return 0;
    else if (nums[r]>nums[r-1]) return r;
    else if (nums[0]>nums[1]) return 0;
    else
    {
        while(l<r)
        {
            mid = l+(r-l)/2;
            if (nums[mid]>nums[mid-1] and nums[mid]>nums[mid+1]) return mid;
            else if (nums[mid]>nums[mid-1]) l = mid+1; 
            else if (nums[mid]>nums[mid+1]) r = mid;
            else l = mid+1;//r = mid
        }
        return 0;
    }

k的n次方

double myPow(double x, int n) {
    double ans = 1.0;
    for(int i =n;i!=0;i=i/2){
        if(i%2!=0){
            ans = ans*x;
        }
        x = x*x;
    }
    return x<0?1/ans:ans;    
}
// i = 10 x = 2*2 i = 5 x = 2**4 ans = 2**2 i = 2 x = 2**8 ans = 2**2 i = 1 x = 2*16 ans =  2**(2+8)
//2 10  5 2 2 1  2 9 4  

k的平方根


                
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值