21. 合并两个有序链表
难度简单1259
将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例:
输入:1->2->4, 1->3->4 输出:1->1->2->3->4->4
class Solution {
public:
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
ListNode* l3=new ListNode(0);//哑结点
ListNode* ans=l3;
while(l1||l2){
if(l1&&l2){
if(l1->val<=l2->val){
l3->next =l1; l1=l1->next;
}else{
l3->next= l2;l2=l2->next;
}
l3=l3->next;
}else if(l1){
l3->next=l1;
l1=NULL;
}else{
l3->next=l2;
l2=NULL;
}
// l3=l3->next;
}
return ans->next;
}
};
22. 括号生成
难度中等1292
数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。
示例:
输入:n = 3 输出:[ "((()))", "(()())", "(())()", "()(())", "()()()" ]
回溯法,这题还可以用动态规划做啊....
vector generateParenthesis(int n) {
vector res;
get(n,0,0,"",res);
return res;
}
void get(int n,int r,int l,string a,vector &res){
if(r>n||l>n||l>r) return;
if(r==n&&l==n){
res.push_back(a);return;
}
get(n,r+1,l,a+"(",res);
get(n,r,l+1,a+")",res);
}
23. 合并K个升序链表
难度困难898
给你一个链表数组,每个链表都已经按升序排列。
请你将所有链表合并到一个升序链表中,返回合并后的链表。
示例 1:
输入:lists = [[1,4,5],[1,3,4],[2,6]] 输出:[1,1,2,3,4,4,5,6] 解释:链表数组如下: [ 1->4->5, 1->3->4, 2->6 ] 将它们合并到一个有序链表中得到。 1->1->2->3->4->4->5->6
示例 2:
输入:lists = [] 输出:[]
示例 3:
输入:lists = [[]] 输出:[]
顺序合并、分治合并、优先队列
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
if (lists == null || lists.length == 0) return null;
return merge(lists, 0, lists.length - 1);
}
private ListNode merge(ListNode[] lists, int left, int right) {
if (left == right) return lists[left];
int mid = left + (right - left) / 2;
ListNode l1 = merge(lists, left, mid);
ListNode l2 = merge(lists, mid + 1, right);
return mergeTwoLists(l1, l2);
}
private ListNode mergeTwoLists(ListNode l1, ListNode l2) {
if (l1 == null) return l2;
if (l2 == null) return l1;
if (l1.val < l2.val) {
l1.next = mergeTwoLists(l1.next, l2);
return l1;
} else {
l2.next = mergeTwoLists(l1,l2.next);
return l2;
}
}
}
class Solution {
public:
ListNode* mergeKLists(vector& lists) {
// if(lists.size()==0||lists[0].size()==0&&lists.size()==1) return NULL;
priority_queue,greater> q;
int num=lists.size();
ListNode* ans=new ListNode(0);
ListNode* tmp=ans;
for(int i=0;ival);
lists[i]=lists[i]->next;
}
}
while(!q.empty()){
int i=q.top();q.pop();
ans->next=new ListNode(i);
ans=ans->next;
}
return tmp->next;
}
};
24. 两两交换链表中的节点
难度中等618
给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。
你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
示例:
给定1->2->3->4
, 你应该返回2->1->4->3
.
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
if(head==NULL||head->next==NULL) return head;
ListNode* h1=head;ListNode* h2=head->next;
h1->next=swapPairs(h2->next);
h2->next=h1;
return h2;
}
};
迭代写法:
class Solution {
public ListNode swapPairs(ListNode head) {
ListNode pre = new ListNode(0);
pre.next = head;
ListNode temp = pre;
while(temp.next != null && temp.next.next != null) {
ListNode start = temp.next;
ListNode end = temp.next.next;
temp.next = end;
start.next = end.next;
end.next = start;
temp = start;
}
return pre.next;
}
}
作者:guanpengchn
链接:https://leetcode-cn.com/problems/swap-nodes-in-pairs/solution/hua-jie-suan-fa-24-liang-liang-jiao-huan-lian-biao/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
25. K 个一组翻转链表
难度困难720
给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表。
k 是一个正整数,它的值小于或等于链表的长度。
如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。
示例:
给你这个链表:1->2->3->4->5
当 k = 2 时,应当返回: 2->1->4->3->5
当 k = 3 时,应当返回: 3->2->1->4->5
说明:
这个要不再看看啊,反正我就会写递归.....
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* reverseKGroup(ListNode* head, int k) {
ListNode* tmp=head;
int cnt=0;
while(tmp!=NULL&&cntnext;cnt++;
}
if(cntnext;
now->next=pre;
pre=now;now=tmp;
}
head->next=reverseKGroup(now,k);
return pre;
}
};
26. 删除排序数组中的重复项
难度简单1625
给定一个排序数组,你需要在 原地 删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。
不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。
示例 1:
给定数组 nums = [1,1,2], 函数应该返回新的长度 2, 并且原数组 nums 的前两个元素被修改为1
,2
。 你不需要考虑数组中超出新长度后面的元素。
示例 2:
给定 nums = [0,0,1,1,1,2,2,3,3,4], 函数应该返回新的长度 5, 并且原数组 nums 的前五个元素被修改为0
,1
,2
,3
,4
。 你不需要考虑数组中超出新长度后面的元素。
class Solution {
public:
int removeDuplicates(vector& nums) {
int index=1;
if(nums.size()==0) return 0;
if(nums.size()==1) return 1;
for(int i=1;i
27. 移除元素
难度简单646
给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。
不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
示例 1:
给定 nums = [3,2,2,3], val = 3, 函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。 你不需要考虑数组中超出新长度后面的元素。
示例 2:
给定 nums = [0,1,2,2,3,0,4,2], val = 2, 函数应该返回新的长度5
, 并且 nums 中的前五个元素为0
,1
,3
,0
, 4。 注意这五个元素可为任意顺序。 你不需要考虑数组中超出新长度后面的元素。
class Solution {
public:
int removeElement(vector& nums, int val) {
int index=0;
if(nums.size()==0) return 0;
for(int i=0;i
28. 实现 strStr()
难度简单565
实现 strStr() 函数。
给定一个 haystack 字符串和一个 needle 字符串,在 haystack 字符串中找出 needle 字符串出现的第一个位置 (从0开始)。如果不存在,则返回 -1。
示例 1:
输入: haystack = "hello", needle = "ll" 输出: 2
示例 2:
输入: haystack = "aaaaa", needle = "bba" 输出: -1
说明:
当 needle
是空字符串时,我们应当返回什么值呢?这是一个在面试中很好的问题。
对于本题而言,当 needle
是空字符串时我们应当返回 0 。这与C语言的 strstr() 以及 Java的 indexOf() 定义相符。
KMP算法,来学习
KMP 算法永不回退 txt 的指针 i,不走回头路(不会重复扫描 txt),而是借助 dp 数组中储存的信息把 pat 移到正确的位置继续匹配,时间复杂度只需 O(N),用空间换时间,所以我认为它是一种动态规划算法。
public class KMP {
private int[][] dp;
private String pat;
public KMP(String pat) {
this.pat = pat;
// 通过 pat 构建 dp 数组
// 需要 O(M) 时间
}
public int search(String txt) {
// 借助 dp 数组去匹配 txt
// 需要 O(N) 时间
}
}
作者:labuladong
链接:https://leetcode-cn.com/problems/implement-strstr/solution/kmp-suan-fa-xiang-jie-by-labuladong/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
为什么说 KMP 算法和状态机有关呢?是这样的,我们可以认为 pat 的匹配就是状态的转移。比如当 pat = "ABABC":
如上图,圆圈内的数字就是状态,状态 0 是起始状态,状态 5(pat.length)是终止状态。开始匹配时 pat 处于起始状态,一旦转移到终止状态,就说明在 txt 中找到了 pat。比如说当前处于状态 2,就说明AB匹配
另外,处于不同状态时,pat 状态转移的行为也不同。比如说假设现在匹配到了状态 4,如果遇到字符 A 就应该转移到状态 3,遇到字符 C 就应该转移到状态 5,如果遇到字符 B 就应该转移到状态 0:
KMP 算法最关键的步骤就是构造这个状态转移图。要确定状态转移的行为,得明确两个变量,一个是当前的匹配状态,另一个是遇到的字符;确定了这两个变量后,就可以知道这个情况下应该转移到哪个状态。
dp[j][c] = next
0 <= j < M,代表当前的状态
0 <= c < 256,代表遇到的字符(ASCII 码)
0 <= next <= M,代表下一个状态
dp[4]['A'] = 3 表示:
当前是状态 4,如果遇到字符 A,
pat 应该转移到状态 3
dp[1]['B'] = 2 表示:
当前是状态 1,如果遇到字符 B,
pat 应该转移到状态 2
算了好晕啊,换个人的看
因为已经匹配成功的字符串abc
中没有相同的前后缀,所以下一次比对要从abcdabcy
的首位开始比较。
让我们看看方块内的字符处于abc
中的什么位置
在黄色框内,bc
属于abc
的后缀,ab
属于abc
的前缀,所以如果条件符合的话,abc
需要有相同的前后缀。
如果有相同的前后缀,我们就需要把前缀移动到后缀的位置上。
我们发现每当我们匹配失败,就需要寻找匹配成功的字符串中有没有相同的前后缀(最长的前后缀),然后再判定下一次比较要从哪一位开始。
代码再看看考研书。