19.删除链表的倒数第N个节点
给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。
示例:
给定一个链表: 1->2->3->4->5, 和 n = 2.
当删除了倒数第二个节点后,链表变为 1->2->3->5.
说明:
给定的 n 保证是有效的。
进阶:
你能尝试使用一趟扫描实现吗?
思路:
一个指针先走n-1步,然后两个指针一起走
走到要删除结点前面,删除即可
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode p = head;
ListNode q = head;
if(head == null || n < 1){
return head;
}
//向前走n-1步
while(--n > 0 && p.next != null){
p = p.next;
}
//如果删除头结点
if(p.next == null && n==0){
return head.next;
}
//如果n过大
else if(n > 0){
return head;
}
//一般情况
while(p.next.next!=null){
p = p.next;
q = q.next;
}
q.next = q.next.next;
return head;
}
}
给定一个只包括 ‘(’,’)’,’{’,’}’,’[’,’]’ 的字符串,判断字符串是否有效。
有效字符串需满足:
左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
注意空字符串可被认为是有效字符串。
示例:
输入: “()”
输出: true
输入: “()[]{}”
输出: true
输入: “(]”
输出: false
输入: “([)]”
输出: false
输入: “{[]}”
输出: true
备注:
参考CodeInterview上的解法,但是过不了([)]这样的情况
class Solution {
public boolean isValid(String s) {
if(s == null || s.equals("")){
return true;
}
Stack<Character> stack = new Stack<>();
char[] strArr = s.toCharArray();
for(int i = 0;i < strArr.length; i++){
//如果不是这三种有效字符
if(strArr[i] !='[' && strArr[i] !=']'
&& strArr[i] !='{' && strArr[i] !='}'
&& strArr[i] !='(' && strArr[i] !=')'){
return false;
}
if(stack.size() == 0){
stack.push(strArr[i]);
}else if(isMatch(stack.peek(),strArr[i])){
stack.pop();
}else{
stack.push(strArr[i]);
}
}
return stack.size() == 0;
}
public boolean isMatch(char c1,char c2){
return (c1 == '(' && c2 == ')')
|| (c1 == '[' && c2 == ']')
|| (c1 == '{' && c2 == '}');
}
}
讨论区看到的解法
class Solution:
def isValid(self, s):
while '{}' in s or '()' in s or '[]' in s:
s = s.replace('{}', '')
s = s.replace('[]', '')
s = s.replace('()', '')
return s == ''
将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例:
输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4
备注:
这种增加头结点的方法可以方便对链表的操作
class Solution {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
//如果有一个为null
if(l1 == null || l2 == null){
return l1 == null ? l2 : l1;
}
ListNode head = new ListNode(-1);
ListNode cur = head;
while(l1!=null && l2 !=null){
cur.next = l1.val <= l2.val ? l1 : l2;
if(cur.next == l1){
l1 = l1.next;
}else{
l2 = l2.next;
}
cur = cur.next;
}
cur.next = l1 == null ? l2 : l1;
return head.next;
}
}
给出 n 代表生成括号的对数,请你写出一个函数,使其能够生成所有可能的并且有效的括号组合。
例如,给出 n = 3,生成结果为:
[
“((()))”,
“(()())”,
“(())()”,
“()(())”,
“()()()”
]
class Solution {
public List<String> generateParenthesis(int n) {
List<String> ans = new ArrayList<>();
generateCore(ans, "", 0, 0, n);
return ans;
}
private void generateCore(List<String> ans, String tmsAns, int left, int right, int len) {
// 如果长度超过2*len 或者右括号比左括号多 则返回
if (left + right > (len << 1) || right > left) {
return;
}
// 左括号和右括号的长度相等且都达到了len
if ((left ^ right) == 0 && (left ^ len) == 0)
ans.add(tmsAns);
// 右括号大于左括号时,不是合法的括号
if (right <= left) {
generateCore(ans, tmsAns + "(", left + 1, right, len);
generateCore(ans, tmsAns + ")", left, right + 1, len);
}
}
}
23.合并K个有序链表
合并 k 个排序链表,返回合并后的排序链表。请分析和描述算法的复杂度。
示例:
输入:
[
1->4->5,
1->3->4,
2->6
]
输出: 1->1->2->3->4->4->5->6
思路:
分治,两两归并
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
if (lists.length == 0) {
return null;
} else if (lists.length == 1) {
return lists[0];
} else if (lists.length == 2) {
return mergeTwoLists(lists[0], lists[1]);
}
int mid = lists.length >> 1;
int high = lists.length;
ListNode[] l1 = new ListNode[mid];
for (int i = 0; i < mid; i++) {
l1[i] = lists[i];
}
ListNode[] l2 = new ListNode[high - mid];
for (int i = mid; i < high; i++) {
l2[i - mid] = lists[i];
}
return mergeTwoLists(mergeKLists(l1), mergeKLists(l2));
}
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
// 如果有一个为null
if (l1 == null || l2 == null) {
return l1 == null ? l2 : l1;
}
ListNode head = new ListNode(-1);
ListNode cur = head;
while (l1 != null && l2 != null) {
cur.next = l1.val <= l2.val ? l1 : l2;
if (cur.next == l1) {
l1 = l1.next;
} else {
l2 = l2.next;
}
cur = cur.next;
}
cur.next = l1 == null ? l2 : l1;
return head.next;
}
}