算法刷题[三]

文章目录寻找第K大链表倒数第k个链表相加寻找闭环入口每k个结点反转双指针找第一个共同节点递归法----合并k列表vector中最长无重复子串最长有效括号子串三元组为定值寻找第K大// 快排 + 二分搜索int quickSort(vector<int>& a, int l, int r, int k) { int i = l, j = r; int base = a[l]; while(j > i) {
摘要由CSDN通过智能技术生成

寻找第K大

// 快排 + 二分搜索
int quickSort(vector<int>& a, int l, int r, int k) {
        int i = l, j = r;
        int base = a[l];
        while(j > i) {
            while(j > i && base >= a[j]) j--;
            a[i] = a[j];
            while(j > i && base <= a[i]) i++;
            a[j] = a[i];
        }
        a[i] = base;
        if (i > k - 1)
            return quickSort(a, l, i-1, k);
        else if (i < k - 1)
            return quickSort(a, i+1, r, k);
        else
            return base;
    }

链表倒数第k个

// 返回倒数第k个元素
int kthToLast(ListNode* head, int k) {
        ListNode* slow = head;
        ListNode* fast = head;
        for (int i = 0; i < k - 1; i++) {
            fast = fast->next;
        }
        while(fast->next != NULL) {
            slow = slow->next;
            fast = fast->next;
        }
        return slow->val;
    }

// 删除倒数第k个元素
ListNode* removeNthFromEnd(ListNode* head, int n) {
        // write code here
        ListNode* new_root = new ListNode(0);
        new_root->next = head;
        ListNode* slow = new_root;
        ListNode* fast = new_root;
        for (int i = 0; i < n; i++) {
            fast = fast->next;
        }
        while(fast->next != NULL) {
            slow = slow->next;
            fast = fast->next;
        }
        slow->next = slow->next->next;
        // 只有一个元素删除第一个
        return new_root->next;
    }

链表相加

// 递归实现加法, k是进位
	void recur(ListNode* head1, ListNode* head2, ListNode* head, int k) {
        if (!head1 && !head2) {
        	// 最后一位
            head->next = (k == 0?NULL:new ListNode(k));
            head = head->next;
            return ;
        }
        // 少的部分全部补0
        int val1 = head1 == NULL?0:head1->val;
        int val2 = head2 == NULL?0:head2->val;
        int sum = val1 + val2 + k;
        int val = sum % 10;
        k = sum / 10;
        ListNode* node = new ListNode(val);
        head->next = node;
        head = head->next;
        head1 = head1==NULL?NULL:head1->next;
        head2 = head2==NULL?NULL:head2->next;
        recur(head1, head2, head, k);
    }
    ListNode* reverse(ListNode* head) {
        ListNode* cur = head, *pre = NULL;
        while(cur != NULL) {
            ListNode* temp = cur->next;
            cur->next = pre;
            pre = cur;
            cur = temp;
        }
        return pre;
    }
    ListNode* addInList(ListNode* head1, ListNode* head2) {
        // write code here
        ListNode* root = new ListNode(0);
        ListNode* res = root;
        recur(reverse(head1), reverse(head2), root, 0);
        return reverse(res->next);
    }

寻找闭环入口

在这里插入图片描述

class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        /* 集合插入失败, 就是入口点
        set<ListNode*> s;
        while(head != NULL) {
            auto it = s.insert(head);
            if (!it.second)
                return head;
            head = head->next;
        }
        return NULL;
        */
        
        ListNode* slow = head;
        ListNode* fast = head;
        while(fast != NULL && fast->next != NULL) {
            slow = slow->next;
            fast = fast->next->next;
            if (slow == fast) {
                ListNode* another_slow = head;
                while(another_slow != slow) {
                    slow = slow->next;
                    another_slow = another_slow->next;
                }
                return slow;
            }
        }
        
        return NULL;
    }
};

每k个结点反转

  • 需要三个指针, 一个用来记录开始位置, 两个用来反转
/**
 * struct ListNode {
 *	int val;
 *	struct ListNode *next;
 * };
 */

class Solution {
public:
    /**
     * 
     * @param head ListNode类 
     * @param k int整型 
     * @return ListNode类
     */
    void reverse(ListNode* base, ListNode* pre, ListNode* cur, int k) {
        ListNode* test = cur;
        // 判断最后剩余的不能被反转的
        for (int i = 0; i < k - 1; i++){
            if (test == NULL) return ;
            test = test->next;
        }
        for (int i = 0; i < k - 1; i++){
            ListNode* temp = cur->next;
            cur->next = pre;
            pre = cur;
            cur = temp;
        }
        ListNode* temp = base->next;
        base->next = pre;
        pre = temp;
        pre->next = cur;
        // 最后剩余的不能被反转的
        if (cur == NULL) return;
        reverse(pre, cur, cur->next, k);
    }
    ListNode* reverseKGroup(ListNode* head, int k) {
        // write code here
        if (head == NULL)
            return head;
        ListNode* new_root = new ListNode(0);
        new_root->next = head;
        ListNode* temp = new_root;
        reverse(temp, head, head->next, k);
        return new_root->next;
    }
};

双指针找第一个共同节点

// 只要有共同节点, 总会相遇
class Solution {
public:
    ListNode* FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2) {
        ListNode* slow = pHead1;
        ListNode* fast = pHead2;
        while(slow != fast) {
            slow = slow==NULL?pHead1:slow->next;
            fast = fast==NULL?pHead2:fast->next;
        }
        return slow;
    }
};

// set
class Solution {
public:
    ListNode* FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2) {
		set<ListNode*> s;
		while(headA != NULL) {
		    s.insert(headA);
		    headA = headA->next;
		}
		while(headB != NULL) {
		    auto it = s.insert(headB);
		    if (!it.second)
		        return headB;
		    headB = headB->next;
		}
		return NULL;
	}
};

递归法----合并k列表

// 每次对比所有头指针, 最小的头指针后移
void recurMerge(vector<ListNode*>& lists, ListNode* new_head) {
        int count = 0;
        for (ListNode* head : lists) {
            if (head == NULL)
                count++;
        }
        if (count == lists.size())
            return;
        int min = INT_MAX;
        int index = -1;
        for (int i = 0; i < lists.size(); i++) {
            if (lists[i] != NULL) {
                if (lists[i]->val < min) {
                    min = lists[i]->val;
                    index = i;
                }
            }
        }
        new_head->next = lists[index];
        new_head = new_head->next;
        lists[index] = lists[index]->next;
        recurMerge(lists, new_head);
    }
    ListNode* mergeKLists(vector<ListNode*>& lists) {
        ListNode* new_root = new ListNode(0);
        ListNode* temp = new_root;
        recurMerge(lists, temp);
        return new_root->next;
    }

// 合并k个列表, 就是两两合并
class Solution {
public:
    ListNode* recurMerge(ListNode* l1, ListNode* l2) {
         ListNode* root = new ListNode(0);
         ListNode* temp = root;
        while (l1 && l2) {
            if (l1->val < l2->val) {
                temp->next = l1;
                l1 = l1->next;
            }
            else {
                temp->next = l2;
                l2 = l2->next;
            }
            temp = temp->next;
        }
        temp->next = (l1 == NULL?l2:l1);
        return root->next;
    }

    ListNode* mergeKLists(vector<ListNode*>& lists) {
        if (lists.size() == 0)
            return NULL;
        ListNode* ans = NULL;
        for (int i = 0; i < lists.size(); i++) {
            ans = recurMerge(ans, lists[i]);
        }
        return ans;
    }
};

// 分治
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
        ListNode* root = new ListNode(0);
        ListNode* temp = root;
        while(l1 && l2) {
            if (l1->val < l2->val) {
                temp->next = l1;
                l1 = l1->next;
            } else {
                temp->next = l2;
                l2 = l2->next;
            }
            temp = temp->next;
        }
        temp->next = (l1 == NULL?l2:l1);
        return root->next;
    }
    
    ListNode* merge(vector<ListNode*>& lists, int l, int r) {
        if (l == r) return lists[l];
        if (l > r) return NULL;  //输入[]
        int mid = l + (r - l) / 2;
        return mergeTwoLists(merge(lists, l, mid), merge(lists, mid + 1, r));
    }
    ListNode* mergeKLists(vector<ListNode*>& lists) {
        return merge(lists, 0, lists.size() - 1);
    }

在这里插入图片描述
在这里插入图片描述

  • 递归多少次就有多少代价的栈空间

vector中最长无重复子串

class Solution {
public:
    /**
     * 
     * @param arr int整型vector the array
     * @return int整型
     */
   /*
	* 
	* 一左一右双指针, 一起从头出发, 结果初始化为1, r不到最后一个元素, r++, 判断下一个元素在不在前面的子串中, 在的话, 移动l, 不在的话, 更新结果
	* find函数找不到元素的话, 迭代器返回的是第二个参数
	*/
    int maxLength(vector<int>& arr) {
        // write code here
        auto l = arr.begin();
        auto r = arr.begin();
        int res = 1;
        // 不等于最后一个元素的迭代器, 迭代器是可以+-, 但不能比大小
        while(r != arr.end()-1) {
            r++;
            auto it = find(l, r, *r);
            if (it != r) {
                // 每次都是在上一次的l开始增加
                l = l + distance(l, it) + 1;
            } else {
                // distance不是int类型
                res = max(res, int(distance(l, r)) + 1);
            }
        }
        
        return res;
    }
};

最长有效括号子串

class Solution {
public:
    /**
     * 
     * @param s string字符串 
     * @return int整型
     */
    int longestValidParentheses(string s) {
        // write code here
        int n = s.size();
        int res = 0;
        // dp[i]表示以i结尾的最长有效子串, 所以要找dp中最大的一个. 如果没有结尾, 就是dp[n-1]
        vector<int> dp(n, 0);
        for (int i = 0; i < n; i++) {
            if (s[i] == ')') {
                if (s[i-1] == '(')
                    dp[i] = (i-2>=0?dp[i-2]:0) + 2;
                else if (i - dp[i-1] > 0 && s[i - dp[i-1] -1] =='(')
                    dp[i] = dp[i - 1] + 2 + (i-dp[i-1]>=2?dp[i - dp[i - 1] - 2]:0);
                res = max(res, dp[i]);
            }
        }
        return res;
    }
};

在这里插入图片描述

三元组为定值

/**
 * (1)首先对数组进行排序(从小到大)
 * (2)依次取出第 i 个数(i从0开始),并且不重复的选取(跳过重复的数)
 * (3)这样问题就转换为 2 个数求和的问题(可以用双指针解决方法)
 *  2 数求和问题
 *     (4)定义两个指针:左指针(left) 和 右指针(right)
 *     (5)指向排序数组的一头一尾, 两个数的和为定值, 其中一个增大另一个比减少.
 *     (6)根据和结果的对比, 进行left++, right--相关操作
 *     (7)时间复杂度:O(nlogn) + O(n)
*/
class Solution {
public:
    vector<vector<int> > threeSum(vector<int> &num) {
        vector<vector<int>> res;
        int n = num.size();
        // 方便之后操作
        sort(num.begin(), num.end());
        for (int i = 0; i < n; i++) {
            // 因为和是0, 并且num[i]是最小的一个
            if (num[i] > 0)
                break;
            // 去掉重复的结果
            if (i >= 1 && num[i] == num[i-1])
                continue;
            int temp = -num[i];
            // 两个数字相加为定值, 其中一个增大, 另一个只能减少, 才有可能还等于这个定植
            int l = i + 1, r = num.size() - 1;
            while(l < r) {
                if (num[r] + num[l] == temp) {
                    // vector底层就是数组, 以后就不用再创建一个临时vector了
                    res.push_back({num[i], num[l], num[r]});
                    // 去掉重复的结果
                    while(l < r && num[l] == num[l+1]) l++;
                    while(l < r && num[r] == num[r-1]) r--;
                    l++;r--;
                }
                else if (num[r] + num[l] > temp) r--;
                else if (num[r] + num[l] < temp) l++;
            }
        }
        return res;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值