算法苦手
零矩阵
来源: https://leetcode-cn.com/problems/zero-matrix-lcci/
想法:
遍历矩阵,使用两个数组来记录矩阵中哪些行和列需要变为0,然后根据第一遍遍历完矩阵得出的数组,第二遍遍历矩阵,将需要改为0的元素修改。
class Solution {
public void setZeroes(int[][] matrix) {
int m = matrix.length, n = matrix[0].length;
boolean[] rows = new boolean[m];
boolean[] cols = new boolean[n];
for (int i = 0 ; i < m ; i++) {
for (int j = 0 ; j < n ; j++) {
if (matrix[i][j] == 0) {
rows[i] = true;
cols[j] = true;
}
}
}
for (int i = 0 ; i < m ; i++) {
for (int j = 0 ; j < n ; j++) {
if (rows[i] || cols[j]) {
matrix[i][j] = 0;
}
}
}
}
}
时间复杂度: O(mn)
空间复杂度: O(m + n)
优化:
可将矩阵的第一行和第一列作为记录需要修改为0的行和列的数据,额外使用两个标记变量来记录第一行和第一列是否需要修改为0即可。
时间复杂度: O(mn)
空间复杂度: O(1)
字符串轮转
来源: https://leetcode-cn.com/problems/string-rotation-lcci/
想法:
遍历字符串S1,以当前字符为分界点,判断S1分成的前后两个字符串与S2分成的两个字符串是否相同。
class Solution {
public boolean isFlipedString(String s1, String s2) {
if (s1.equals("") && s2.equals("")) return true;
if (s1.length() != s2.length()) return false;
char[] c1 = s1.toCharArray();
char[] c2 = s2.toCharArray();
int n = 0;
while(true) {
while (n < c1.length && c1[n] != c2[0]) n++;
if (n == c1.length) return false;
else {
int m = 0;
while (m + n < c1.length && c1[m + n] == c2[m]) m++;
if (m + n == c1.length) {
int k = 0;
int tmp = c2.length - n;
while (tmp + k < c2.length && c1[k] == c2[k + tmp]) k++;
if (k + tmp == c2.length) return true;
else n++;
}else n++;
}
}
}
}
时间复杂度: O(n²)
空间复杂度: O(n)
优化:
若将 $S_1$ 分成的两个子串视为 $L$ 和 $R$ , 可并凑字符串 $S_2 + S_2$ , 所得到的字符串即为 $L + R + L + R = L + S_1 + R$ ,则只需判断 $S_1$ 是否是 $S_2 + S_2$ 的子串即可。
时间复杂度: O(n) (KMP)
空间复杂度: O(n)
移除重复节点
来源: https://leetcode-cn.com/problems/remove-duplicate-node-lcci/
想法:
遍历链表途中,用哈希集合存储该节点的值是否出现过,出现过将节点移出即可。
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode removeDuplicateNodes(ListNode head) {
HashSet<Integer> nums = new HashSet<>();
if (head == null) return head;
nums.add(head.val);
ListNode pos = head;
while (pos.next != null) {
ListNode cur = pos.next;
if (nums.add(cur.val)) {
pos = pos.next;
} else {
pos.next = pos.next.next;
}
}
pos.next = null;
return head;
}
}
时间复杂度: O(n)
空间复杂度: O(n)
返回倒数第k个节点
来源: https://leetcode-cn.com/problems/kth-node-from-end-of-list-lcci/
想法:
使用两个指针,保持两个指针相隔的节点数为k,第一个指针到达链表尾部时,第二个指针即为倒数第k个节点。
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public int kthToLast(ListNode head, int k) {
ListNode p1 = head;
ListNode p2 = head;
int cnt = 0;
while (cnt < k) {
p1 = p1.next;
cnt++;
}
while (p1 != null) {
p1 = p1.next;
p2 = p2.next;
}
return p2.val;
}
}
时间复杂度: O(n)
空间复杂度: O(1)
分割链表
来源: https://leetcode-cn.com/problems/partition-list-lcci/
想法:
维护两个链表,一个为小于 x 的节点,一个为大于等于 x 的节点,在遍历完原始链表后,将两个链表连接起来即可。
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode partition(ListNode head, int x) {
if (head == null) return head;
ListNode p1 = null;
ListNode p2 = null;
ListNode p1_head = null;
ListNode p2_head = null;
while(head != null) {
if (head.val < x) {
if (p1_head == null) p1_head = head;
else p1.next = head;
p1 = head;
}else {
if (p2_head == null) p2_head = head;
else p2.next = head;
p2 = head;
}
head = head.next;
}
if (p2 != null) p2.next = null;
if (p1 == null) return p2_head;
p1.next = p2_head;
return p1_head;
}
}
时间复杂度: O(n)
空间复杂度: O(1)
链表求和
来源: https://leetcode-cn.com/problems/sum-lists-lcci/
想法:
按照竖式计算的方法,遍历两个链表,将处理完进位的结果连接成一个新的链表即可。
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
ListNode res = new ListNode(0);
ListNode head = res;
boolean sign = false;
while (l1 != null || l2 != null || sign) {
int tmp;
if (l1 == null && l2 == null) tmp = 0;
else if (l2 == null) tmp = l1.val;
else if (l1 == null) tmp = l2.val;
else tmp = l1.val + l2.val;
if (sign) tmp++;
if (tmp >= 10) {
sign = true;
res.next = new ListNode(tmp - 10);
}else {
sign = false;
res.next = new ListNode(tmp);
}
res = res.next;
if (l1 != null)l1 = l1.next;
if (l2 != null)l2 = l2.next;
}
return head.next;
}
}
时间复杂度: O(n)
空间复杂度: O(n)
回文链表
来源: https://leetcode-cn.com/problems/palindrome-linked-list-lcci/
想法:
简单的想法即通过遍历链表,将结果存储在数组中,然后判断是否为回文即可。
时间复杂度: O(n)
空间复杂度: O(n)
另一个想法就是找到回文的中心点,以此中心点将链表分为两个子链表,然后将前面一半的链表逆转,最后从这两个子链表的头开始遍历比较,如果元素都相同即为回文链表,如果找不到这样的中心点或者遍历比较时出现元素不同,即不为回文链表。
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public boolean isPalindrome(ListNode head) {
if (head == null || head.next == null) return true;
if (head.next.next == null) return head.val == head.next.val;
ListNode p1 = head;
ListNode p2 = head.next;
ListNode p3 = head.next.next;
if (p1.val == p3.val && p3.next == null) return true;
while (p3 != null && p1.val != p2.val && p1.val != p3.val) {
ListNode tmp = p1;
p1 = p2;
p2 = p2.next;
if (tmp == head) tmp.next = null;
p1.next = tmp;
p3 = p3.next;
}
if (p3 == null) return false;
if (p1.val == p3.val) {
while (p1 != null && p3 != null) {
if (p1.val != p3.val) return false;
p1 = p1.next;
p3 = p3.next;
}
if (p1 != p3) return false;
}
else{
while (p1 != null && p2 != null) {
if (p1.val != p2.val) return false;
p1 = p1.next;
p2 = p2.next;
}
if (p1 != p2) return false;
}
return true;
}
}
时间复杂度: O(n)
空间复杂度: O(1)
链表相交
来源: https://leetcode-cn.com/problems/intersection-of-two-linked-lists-lcci/
想法:
将两链表的公共部分长度设为c,若设置一个指针在遍历完链表a后遍历链表b,则在到达公共部分时,总共经过(a + b - c) 个节点,同理设置一个指针在遍历完链表b后遍历链表a,则在到达公共部分时,总共也经过(b + a - c) 个节点。
此时有两种情况:
1. 若两链表有公共部分,则两指针都指向公共部分的首节点。 2. 若两链表没有公共部分,则两指针都指向null。/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode A = headA, B = headB;
while (A != B) {
A = A != null ? A.next : headB;
B = B != null ? B.next : headA;
}
return A;
}
}
时间复杂度: O(m + n)
空间复杂度: O(1)