目录
面试题 01.01. 判定字符是否唯一
面试题 01.02. 判定是否互为字符重排
面试题 01.03. URL 化
面试题 01.04. 回文排列
面试题 01.05. 一次编辑
面试题 01.06. 字符串压缩
面试题 01.07. 旋转矩阵
面试题 01.08. 零矩阵
面试题 01.09. 字符串轮转
面试题 02.01. 移除重复节点
面试题 02.02. 返回倒数第 k 个节点
面试题 02.03. 删除中间节点
面试题 02.04. 分割链表
面试题 02.05. 链表求和
面试题 02.06. 回文链表
面试题 02.08. 环路检测
面试题 03.01. 三合一
面试题 03.02. 栈的最小值
面试题 03.04. 化栈为队
面试题 03.05. 栈排序
面试题 03.06. 动物收容所
面试题 04.04. 检查平衡性
面试题 04.05. 合法二叉搜索树
面试题 04.08. 首个共同祖先
面试题 04.10. 检查子树
面试题 04.12. 求和路径
面试题 05.01. 插入
面试题 05.06. 整数转换
面试题 05.07. 配对交换
面试题 08.01. 三步问题
面试题 08.09. 括号
面试题 08.10. 颜色填充
面试题 10.09. 排序矩阵查找
面试题 16.01. 交换数字
面试题 16.06. 最小差
面试题 16.10. 生存人数
面试题 16.11. 跳水板
面试题 16.21. 交换和
面试题 17.01. 不用加号的加法
面试题 17.04. 消失的数字
面试题 17.12. BiNode
面试题 17.13. 恢复空格
面试题 17.19. 消失的两个数字
面试题 17.20. 连续中值
boolean empty() 测试堆栈是否为空。
E peek() 查看堆栈顶部的对象,但不从堆栈中移除它。
E pop() 移除堆栈顶部的对象,并作为此函数的值返回该对象。
E push(E item) 把项压入堆栈顶部。
int search(Object o) 返回对象在堆栈中的位置,以 1 为基数。
boolean add(E e) 将指定的元素插入此队列(如果立即可行且不会违反容量限制),在成功时返回 true,如果当前没有可用的空间,则抛出 IllegalStateException。
E element() 获取,但是不移除此队列的头。
boolean offer(E e) 将指定的元素插入此队列(如果立即可行且不会违反容量限制),当使用有容量限制的队列时,此方法通常要优于 add(E),后者可能无法插入元素,而只是抛出一个异常。
E peek() 获取但不移除此队列的头;如果此队列为空,则返回 null。
E poll() 获取并移除此队列的头,如果此队列为空,则返回 null。
E remove() 获取并移除此队列的头。
English Version
实现一个算法,确定一个字符串 s
的所有字符是否全都不同。
示例 1:
输入: s
= "leetcode"
输出: false
示例 2:
输入: s
= "abc"
输出: true
限制:
0 <= len(s) <= 100
class Solution:
def isUnique(self, astr: str) -> bool:
sets = set(astr)
return len(sets) == len(astr)
class Solution {
public boolean isUnique(String astr) {
char[] chars = astr.toCharArray();
int len = chars.length;
for (int i = 0; i < len - 1; ++i) {
for (int j = i + 1; j < len; ++j) {
if (chars[i] == chars[j]) {
return false;
}
}
}
return true;
}
}
English Version
给定两个字符串 s1
和 s2
,请编写一个程序,确定其中一个字符串的字符重新排列后,能否变成另一个字符串。
示例 1:
输入:s1
= "abc",s2
= "bca" 输出: true
示例 2:
输入:s1
= "abc",s2
= "bad" 输出: false
说明:
0 <= len(s1) <= 100
0 <= len(s2) <= 100
class Solution:
def CheckPermutation(self, s1: str, s2: str) -> bool:
return sorted(s1) == sorted(s2)
class Solution {
public boolean checkPermutation(String s1, String s2) {
if (s1 == null || s2 == null || s1.length() != s2.length()) {
return false;
}
char[] c1 = s1.toCharArray();
char[] c2 = s2.toCharArray();
Arrays.sort(c1);
Arrays.sort(c2);
return Arrays.equals(c1, c2);
}
}
English Version
URL化。编写一种方法,将字符串中的空格全部替换为%20
。假定该字符串尾部有足够的空间存放新增字符,并且知道字符串的“真实”长度。(注:用Java
实现的话,请使用字符数组实现,以便直接在数组上操作。)
示例1:
输入:"Mr John Smith ", 13 输出:"Mr%20John%20Smith"
示例2:
输入:" ", 5 输出:"%20%20%20%20%20"
提示:
class Solution:
def replaceSpaces(self, S: str, length: int) -> str:
S = S[:length] if length < len(S) else S
return S.replace(' ', '%20')
class Solution {
public String replaceSpaces(String S, int length) {
char[] c = S.toCharArray();
int j = c.length;
for (int i = length - 1; i >= 0; i--) {
if (c[i] == ' ') {
c[--j] = '0';
c[--j] = '2';
c[--j] = '%';
} else {
c[--j] = c[i];
}
}
return new String(c, j, c.length - j);
}
}
//拓展: 方法说明
//从数组下标为offset开始顺序取出数组codePoints[]中count个整数,并根据此uncode代码点所对应的字符创建一个string对象
public String(int[] codePoints, int offset, int count) {
}
English Version
给定一个字符串,编写一个函数判定其是否为某个回文串的排列之一。
回文串是指正反两个方向都一样的单词或短语。排列是指字母的重新排列。
回文串不一定是字典当中的单词。
示例1:
输入:"tactcoa" 输出:true(排列有"tacocat"、"atcocta",等等)
用哈希表存储每个字符出现的次数。若次数为奇数的字符超过 1 个,则不是回文排列。
class Solution:
def canPermutePalindrome(self, s: str) -> bool:
if s is None or len(s) < 2:
return True
cache = {
}
for ch in s:
cache[ch] = 1 if cache.get(ch) is None else cache[ch] + 1
cnt = 0
for k, v in cache.items():
if (v & 1) == 1:
cnt += 1
if cnt > 1:
return False
return cnt <= 1
class Solution {
public boolean canPermutePalindrome(String s) {
if (s == null || s.length() < 2) {
return true;
}
char[] chars = s.toCharArray();
Map<Character, Integer> counter = new HashMap<>();
for (char ch : chars) {
counter.put(ch, counter.get(ch) == null ? 1 : counter.get(ch) + 1);
}
int cnt = 0;
for (Map.Entry<Character, Integer> entry : counter.entrySet()) {
if ((entry.getValue() & 1) == 1) {
++cnt;
}
if (cnt > 1) {
return false;
}
}
return cnt <= 1;
}
}
English Version
字符串有三种编辑操作:插入一个字符、删除一个字符或者替换一个字符。 给定两个字符串,编写一个函数判定它们是否只需要一次(或者零次)编辑。
示例 1:
输入: first = "pale" second = "ple" 输出: True
示例 2:
输入: first = "pales" second = "pal" 输出: False
遍历两个字符串,逐个字符比较判断。
class Solution:
def oneEditAway(self, first: str, second: str) -> bool:
n1, n2 = len(first), len(second)
if abs(n1 - n2) > 1:
return False
if n1 + n2 <= 2:
return True
if first[0] != second[0]:
if n1 == n2:
return first[1:] == second[1:]
else:
return first[1:] == second or second[1:] == first
else:
return self.oneEditAway(first[1:], second[1:])
class Solution {
public boolean oneEditAway(String first, String second) {
int n1 = first.length(), n2 = second.length();
int differ = Math.abs(n1 - n2);
if (differ > 1) {
return false;
}
if (n1 + n2 <= 2) {
return true;
}
if (first.charAt(0) != second.charAt(0)) {
if (n1 == n2) {
return first.substring(1).equals(second.substring(1));
} else {
return first.substring(1).equals(second) || second.substring(1).equals(first);
}
} else {
return oneEditAway(first.substring(1), second.substring(1));
}
}
}
English Version
字符串压缩。利用字符重复出现的次数,编写一种方法,实现基本的字符串压缩功能。比如,字符串aabcccccaaa
会变为a2b1c5a3
。若“压缩”后的字符串没有变短,则返回原先的字符串。你可以假设字符串中只包含大小写英文字母(a至z)。
示例1:
输入:"aabcccccaaa" 输出:"a2b1c5a3"
示例2:
输入:"abbccd" 输出:"abbccd" 解释:"abbccd"压缩后为"a1b2c2d1",比原字符串长度更长。
提示:
双指针遍历字符串求解。
class Solution:
def compressString(self, S: str) -> str:
if len(S) < 2:
return S
p, q = 0, 1
res = ''
while q < len(S):
if S[p] != S[q]:
res += (S[p] + str(q - p))
p = q
q += 1
res += (S[p] + str(q - p))
return res if len(res) < len(S) else S
class Solution {
public String compressString(String S) {
if (S == null || S.length() < 2) {
return S;
}
char[] chars = S.toCharArray();
int p = 0, q = 1, n = chars.length;
StringBuilder sb = new StringBuilder();
while (q < n) {
if (chars[p] != chars[q]) {
sb.append(chars[p]).append(q - p);
p = q;
}
q += 1;
}
sb.append(chars[p]).append(q - p);
String res = sb.toString();
return res.length() < n ? res : S;
}
}
English Version
给定一幅由N × N矩阵表示的图像,其中每个像素的大小为4字节,编写一种方法,将图像旋转90度。
不占用额外内存空间能否做到?
示例 1:
给定 matrix = [ [1,2,3], [4,5,6], [7,8,9] ], 原地旋转输入矩阵,使其变为: [ [7,4,1], [8,5,2], [9,6,3] ]
示例 2:
给定 matrix = [ [ 5, 1, 9,11], [ 2, 4, 8,10], [13, 3, 6, 7], [15,14,12,16] ], 原地旋转输入矩阵,使其变为: [ [15,13, 2, 5], [14, 3, 4, 1], [12, 6, 8, 9], [16, 7,10,11] ]
原地旋转,i 的范围是 [0, n/2)
,j 的范围是 [i, n-1-i)
。
class Solution:
def rotate(self, matrix: List[List[int]]) -> None:
"""
Do not return anything, modify matrix in-place instead.
"""
n = len(matrix)
for i in range(n // 2):
for j in range(i, n - 1 - i):
t = matrix[i][j]
matrix[i][j] = matrix[n - j - 1][i]
matrix[n - j - 1][i] = matrix[n - i - 1][n - j - 1]
matrix[n - i - 1][n - j - 1] = matrix[j][n - i - 1]
matrix[j][n - i - 1] = t
class Solution {
public void rotate(int[][] matrix) {
int n = matrix.length;
for (int i = 0; i < n / 2; ++i) {
for (int j = i; j < n - 1 - i; ++j) {
int t = matrix[i][j];
matrix[i][j] = matrix[n - j - 1][i];
matrix[n - j - 1][i] = matrix[n - i - 1][n - j - 1];
matrix[n - i - 1][n - j - 1] = matrix[j][n - i - 1];
matrix[j][n - i - 1] = t;
}
}
}
}
English Version
编写一种算法,若M × N矩阵中某个元素为0,则将其所在的行与列清零。
示例 1:
输入: [ [1,1,1], [1,0,1], [1,1,1] ] 输出: [ [1,0,1], [0,0,0], [1,0,1] ]
示例 2:
输入: [ [0,1,2,0], [3,4,5,2], [1,3,1,5] ] 输出: [ [0,0,0,0], [0,4,5,0], [0,3,1,0] ]
用 set 记录需要清零的行 zero_rows
跟列 zero_cols
,之后分别将需要清零的行、列上的所有元素清零。
class Solution:
def setZeroes(self, matrix: List[List[int]]) -> None:
"""
Do not return anything, modify matrix in-place instead.
"""
rows, cols = len(matrix), len(matrix[0])
zero_rows, zero_cols = set(), set()
for i in range(rows):
for j in range(cols):
if matrix[i][j] == 0:
zero_rows.add(i)
zero_cols.add(j)
# 行清零
for i in zero_rows:
for j in range(cols):
matrix[i][j] = 0
# 列清零
for j in zero_cols:
for i in range(rows):
matrix[i][j] = 0
return matrix
class Solution {
public void setZeroes(int[][] matrix) {
int rows = matrix.length, cols = matrix[0].length;
Set<Integer> zeroRows = new HashSet<>();
Set<Integer> zeroCols = new HashSet<>();
for (int i = 0; i < rows; ++i) {
for (int j = 0; j < cols; ++j) {
if (matrix[i][j] == 0) {
zeroRows.add(i);
zeroCols.add(j);
}
}
}
// 行清零
for (int row : zeroRows) {
for (int j = 0; j < cols; ++j) {
matrix[row][j] = 0;
}
}
// 列清零
for (int col : zeroCols) {
for (int i = 0; i < rows; ++i) {
matrix[i][col] = 0;
}
}
}
}
English Version
字符串轮转。给定两个字符串s1
和s2
,请编写代码检查s2
是否为s1
旋转而成(比如,waterbottle
是erbottlewat
旋转后的字符串)。
示例1:
输入:s1 = "waterbottle", s2 = "erbottlewat" 输出:True
示例2:
输入:s1 = "aa", "aba" 输出:False
提示:
说明:
class Solution:
def isFlipedString(self, s1: str, s2: str) -> bool:
return len(s1) == len(s2) and s1 in (s2 * 2)
class Solution {
public boolean isFlipedString(String s1, String s2) {
return s1.length() == s2.length() && (s2 + s2).indexOf(s1) != -1;
//等价于 return s1.length() == s2.length() && (s2 + s2).contains(s1);
}
}
English Version
编写代码,移除未排序链表中的重复节点。保留最开始出现的节点。
示例1:
输入:[1, 2, 3, 3, 2, 1] 输出:[1, 2, 3]
示例2:
输入:[1, 1, 1, 1, 2] 输出:[1, 2]
提示:
进阶:
如果不得使用临时缓冲区,该怎么解决?
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def removeDuplicateNodes(self, head: ListNode) -> ListNode:
if head is None or head.next is None:
return head
cache = set()
cache.add(head.val)
cur, p = head, head.next
while p:
if p.val not in cache:
cur.next = p
cur = cur.next
cache.add(p.val)
p = p.next
cur.next = None
return head
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode removeDuplicateNodes(ListNode head) {
if (head == null || head.next == null) {
return head;
}
Set<Integer> s = new HashSet<>();
s.add(head.val);
ListNode p = head.next, cur = head;
while (p != null) {
if (!s.contains(p.val)) {
cur.next = p;
cur = cur.next;
s.add(p.val);
}
p = p.next;
}
cur.next = null;
return head;
}
}
English Version
实现一种算法,找出单向链表中倒数第 k 个节点。返回该节点的值。
注意:本题相对原题稍作改动
示例:
输入: 1->2->3->4->5 和 k = 2 输出: 4
说明:
给定的 k 保证是有效的。
定义 p
、q
指针指向 head
。
p
先向前走 k
步,接着 p
、q
同时向前走,当 p
指向 null
时,q
指向的节点即为链表的倒数第 k
个节点。
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def kthToLast(self, head: ListNode, k: int) -> int:
p = q = head
for _ in range(k):
q = q.next
while q:
p, q = p.next, q.next
return p.val
/**
* 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 p = head, q = head;
while (k-- > 0) {
q = q.next;
}
while (q != null) {
q = q.next;
p = p.next;
}
return p.val;
}
}
English Version
实现一种算法,删除单向链表中间的某个节点(除了第一个和最后一个节点,不一定是中间节点),假定你只能访问该节点。
示例:
输入:单向链表a->b->c->d->e->f中的节点c 结果:不返回任何数据,但该链表变为a->b->d->e->f
把 node 的下一个节点的值赋给 node,然后改变 node 的 next 指向。
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def deleteNode(self, node):
"""
:type node: ListNode
:rtype: void Do not return anything, modify node in-place instead.
"""
node.val = node.next.val
node.next = node.next.next
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public void deleteNode(ListNode node) {
node.val = node.next.val;
node.next = node.next.next;
}
}
English Version
编写程序以 x 为基准分割链表,使得所有小于 x 的节点排在大于或等于 x 的节点之前。如果链表中包含 x,x 只需出现在小于 x 的元素之后(如下所示)。分割元素 x 只需处于“右半部分”即可,其不需要被置于左右两部分之间。
示例:
输入: head = 3->5->8->5->10->2->1, x = 5 输出: 3->1->2->10->5->5->8
创建两个链表,一个存放小于 x
的节点,另一个存放大于等于 x
的节点,之后进行拼接即可。
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def partition(self, head: ListNode, x: int) -> ListNode:
if head is None or head.next is None:
return head
left, right = ListNode(-1), ListNode(-1)
p, q = left, right
while head:
t = head.next
head.next = None
if head.val < x:
p.next = head
p = p.next
else:
q.next = head
q = q.next
head = t
p.next = right.next
return left.next
/**
* 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 || head.next == null) {
return head;
}
ListNode left = new ListNode(-1);
ListNode right = new ListNode(-1);
ListNode p = left, q = right;
while (head != null) {
ListNode t = head.next;
head.next = null;
if (head.val < x) {
p.next = head;
p = p.next;
} else {
q.next = head;
q = q.next;
}
head = t;
}
p.next = right.next;
return left.next;
}
}
English Version
给定两个用链表表示的整数,每个节点包含一个数位。
这些数位是反向存放的,也就是个位排在链表首部。
编写函数对这两个整数求和,并用链表形式返回结果。
示例:
输入:(7 -> 1 -> 6) + (5 -> 9 -> 2),即617 + 295 输出:2 -> 1 -> 9,即912
进阶:假设这些数位是正向存放的,请再做一遍。
示例:
输入:(6 -> 1 -> 7) + (2 -> 9 -> 5),即617 + 295 输出:9 -> 1 -> 2,即912
同时遍历两链表,求节点的和与进位。
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
p = ListNode(-1)
carry, t = 0, p
while l1 or l2:
s = (0 if l1 is None else l1.val) + (0 if l2 is None else l2.val) + carry
carry = 1 if s > 9 else 0
t.next = ListNode(s % 10)
t = t.next
l1 = l1.next if l1 else l1
l2 = l2.next if l2 else l2
t.next = None if carry == 0 else ListNode(carry)
return p.next
/**
* 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 p = new ListNode(-1);
int carry = 0;
ListNode t = p;
while (l1 != null || l2 != null) {
int s = (l1 == null ? 0 : l1.val) + (l2 == null ? 0 : l2.val) + carry;
t.next = new ListNode(s % 10);
carry = s > 9 ? 1 : 0;
t = t.next;
l1 = l1 == null ? l1 : l1.next;
l2 = l2 == null ? l2 : l2.next;
}
t.next = carry == 0 ? null : new ListNode(carry);
return p.next;
}
}
English Version
编写一个函数,检查输入的链表是否是回文的。
示例 1:
输入: 1->2 输出: false
示例 2:
输入: 1->2->2->1 输出: true
进阶:
你能否用 O(n) 时间复杂度和 O(1) 空间复杂度解决此题?
先用快慢指针找到链表的中点,接着反转右半部分的链表。然后同时遍历前后两段链表,若前后两段链表节点对应的值不等,说明不是回文链表,否则说明是回文链表。
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def isPalindrome(self, head: ListNode) -> bool:
if head is None or head.next is None:
return True
slow, fast = head, head.next
while fast and fast.next:
slow, fast = slow.next, fast.next.next
pre, cur = None, slow.next
while cur:
t = cur.next
cur.next = pre
pre, cur = cur, t
while pre:
if pre.val != head.val:
return False
pre, head = pre.next, head.next
return True
/**
* 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;
}
ListNode slow = head;
ListNode fast = head.next;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
}
ListNode cur = slow.next;
slow.next = null;
ListNode pre = null;
while (cur != null) {
ListNode t = cur.next;
cur.next = pre;
pre = cur;
cur = t;
}
while (pre != null) {
if (pre.val != head.val) {
return false;
}
pre = pre.next;
head = head.next;
}
return true;
}
}
English Version
给定一个有环链表,实现一个算法返回环路的开头节点。
有环链表的定义:在链表中某个节点的next元素指向在它前面出现过的节点,则表明该链表存在环路。
示例 1:
输入:head = [3,2,0,-4], pos = 1
输出:tail connects to node index 1
解释:链表中有一个环,其尾部连接到第二个节点。
示例 2:
输入:head = [1,2], pos = 0
输出:tail connects to node index 0
解释:链表中有一个环,其尾部连接到第一个节点。
示例 3:
输入:head = [1], pos = -1
输出:no cycle
解释:链表中没有环。
进阶:
你是否可以不用额外空间解决此题?
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def detectCycle(self, head: ListNode) -> ListNode:
fast = slow = p = head
while fast and fast.next:
fast = fast.next.next
slow = slow.next
if fast == slow:
break
if fast is None or fast.next is None:
return None
while slow != p:
p = p.next
slow = slow.next
return p
/**
* Definition for singly-linked list.
* class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public ListNode detectCycle(ListNode head) {
ListNode fast = head, slow = head;
while (fast != null && fast.next != null) {
fast = fast.next.next;
slow = slow.next;
if (fast == slow) break;
}
if (fast == null || fast.next == null) return null;
ListNode p = head;
while (p != slow) {
p = p.next;
slow = slow.next;
}
return p;
}
}
English Version
三合一。描述如何只用一个数组来实现三个栈。
你应该实现push(stackNum, value)
、pop(stackNum)
、isEmpty(stackNum)
、peek(stackNum)
方法。stackNum
表示栈下标,value
表示压入的值。
构造函数会传入一个stackSize
参数,代表每个栈的大小。
示例1:
输入: ["TripleInOne", "push", "push", "pop", "pop", "pop", "isEmpty"] [[1], [0, 1], [0, 2], [0], [0], [0], [0]] 输出: [null, null, null, 1, -1, -1, true] 说明:当栈为空时`pop, peek`返回-1,当栈满时`push`不压入元素。
示例2:
输入: ["TripleInOne", "push", "push", "push", "pop", "pop", "pop", "peek"] [[2], [0, 1], [0, 2], [0, 3], [0], [0], [0], [0]] 输出: [null, null, null, null, 2, 1, -1, -1]
二维数组解决;也可以使用一维数组,以下标 0,3,6,..
、1,4,7,..
、2,5,8,..
区分,一维数组最后三个元素记录每个栈的元素个数。
class TripleInOne:
def __init__(self, stackSize: int):
self._capacity = stackSize
self._s = [[], [], []]
def push(self, stackNum: int, value: int) -> None:
if len(self._s[stackNum]) < self._capacity:
self._s[stackNum].append(value)
def pop(self, stackNum: int) -> int:
return -1 if self.isEmpty(stackNum) else self._s[stackNum].pop()
def peek(self, stackNum: int) -> int:
return -1 if self.isEmpty(stackNum) else self._s[stackNum][-1]
def isEmpty(self, stackNum: int) -> bool:
return len(self._s[stackNum]) == 0
# Your TripleInOne object will be instantiated and called as such:
# obj = TripleInOne(stackSize)
# obj.push(stackNum,value)
# param_2 = obj.pop(stackNum)
# param_3 = obj.peek(stackNum)
# param_4 = obj.isEmpty(stackNum)
class TripleInOne {
private int[] s;
private int capacity;
public TripleInOne(int stackSize) {
s = new int[stackSize * 3 + 3];
capacity = stackSize;
}
public void push(int stackNum, int value) {
if (s[stackNum + 3 * capacity] < capacity) {
s[s[stackNum + 3 * capacity] * 3 + stackNum] = value;
++s[stackNum + 3 * capacity];
}
}
public int pop(int stackNum) {
if (isEmpty(stackNum)) {
return -1;
}
--s[stackNum + 3 * capacity];
return s[s[stackNum + 3 * capacity] * 3 + stackNum];
}
public int peek(int stackNum) {
return isEmpty(stackNum) ? -1 : s[(s[stackNum + 3 * capacity] - 1) * 3 + stackNum];
}
public boolean isEmpty(int stackNum) {
return s[stackNum + 3 * capacity] == 0;
}
}
/**
* Your TripleInOne object will be instantiated and called as such:
* TripleInOne obj = new TripleInOne(stackSize);
* obj.push(stackNum,value);
* int param_2 = obj.pop(stackNum);
* int param_3 = obj.peek(stackNum);
* boolean param_4 = obj.isEmpty(stackNum);
*/
English Version
请设计一个栈,除了常规栈支持的pop与push函数以外,还支持min函数,该函数返回栈元素中的最小值。执行push、pop和min操作的时间复杂度必须为O(1)。
示例:
MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.getMin(); --> 返回 -3.
minStack.pop();
minStack.top(); --> 返回 0.
minStack.getMin(); --> 返回 -2.
利用辅助栈存放栈的最小元素。
class MinStack:
def __init__(self):
"""
initialize your data structure here.
"""
self._s1 = []
self._s2 = []
def push(self, x: int) -> None:
self._s1.append(x)
self._s2.append(x if len(self._s2) == 0 or self._s2[-1] >= x else self._s2[-1])
def pop(self) -> None:
self._s1.pop()
self._s2.pop()
def top(self) -> int:
return self._s1[-1]
def getMin(self) -> int:
return self._s2[-1]
# Your MinStack object will be instantiated and called as such:
# obj = MinStack()
# obj.push(x)
# obj.pop()
# param_3 = obj.top()
# param_4 = obj.getMin()
class MinStack {
private Stack<Integer> s1;
private Stack<Integer> s2;
/** initialize your data structure here. */
public MinStack() {
s1 = new Stack<>();
s2 = new Stack<>();
}
public void push(int x) {
s1.push(x);
s2.push(s2.empty() || s2.peek() >= x ? x : s2.peek());
}
public void pop() {
s1.pop();
s2.pop();
}
public int top() {
return s1.peek();
}
public int getMin() {
return s2.empty() ? -1 : s2.peek();
}
}
/**
* Your MinStack object will be instantiated and called as such:
* MinStack obj = new MinStack();
* obj.push(x);
* obj.pop();
* int param_3 = obj.top();
* int param_4 = obj.getMin();
*/
English Version
实现一个MyQueue类,该类用两个栈来实现一个队列。
示例:
MyQueue queue = new MyQueue();
queue.push(1);
queue.push(2);
queue.peek(); // 返回 1
queue.pop(); // 返回 1
queue.empty(); // 返回 false
说明:
push to top
, peek/pop from top
, size
和 is empty
操作是合法的。class MyQueue:
def __init__(self):
"""
Initialize your data structure here.
"""
self._s1, self._s2 = [], []
def push(self, x: int) -> None:
"""
Push element x to the back of queue.
"""
self._s1.append(x)
def pop(self) -> int:
"""
Removes the element from in front of queue and returns that element.
"""
if len(self._s2) == 0:
while self._s1:
self._s2.append(self._s1.pop())
return self._s2.pop()
def peek(self) -> int:
"""
Get the front element.
"""
if len(self._s2) == 0:
while self._s1:
self._s2.append(self._s1.pop())
return self._s2[-1]
def empty(self) -> bool:
"""
Returns whether the queue is empty.
"""
return len(self._s1) + len(self._s2) == 0
# Your MyQueue object will be instantiated and called as such:
# obj = MyQueue()
# obj.push(x)
# param_2 = obj.pop()
# param_3 = obj.peek()
# param_4 = obj.empty()
class MyQueue {
private Stack<Integer> s1;
private Stack<Integer> s2;
/** Initialize your data structure here. */
public MyQueue() {
s1 = new Stack<>();
s2 = new Stack<>();
}
/** Push element x to the back of queue. */
public void push(int x) {
s1.push(x);
}
/** Removes the element from in front of queue and returns that element. */
public int pop() {
if (s2.empty()) {
while (!s1.empty()) {
s2.push(s1.pop());
}
}
return s2.pop();
}
/** Get the front element. */
public int peek() {
if (s2.empty()) {
while (!s1.empty()) {
s2.push(s1.pop());
}
}
return s2.peek();
}
/** Returns whether the queue is empty. */
public boolean empty() {
return s1.empty() && s2.empty();
}
}
/**
* Your MyQueue object will be instantiated and called as such:
* MyQueue obj = new MyQueue();
* obj.push(x);
* int param_2 = obj.pop();
* int param_3 = obj.peek();
* boolean param_4 = obj.empty();
*/
English Version
栈排序。 编写程序,对栈进行排序使最小元素位于栈顶。最多只能使用一个其他的临时栈存放数据,但不得将元素复制到别的数据结构(如数组)中。该栈支持如下操作:push
、pop
、peek
和 isEmpty
。当栈为空时,peek
返回 -1。
示例1:
输入: ["SortedStack", "push", "push", "peek", "pop", "peek"] [[], [1], [2], [], [], []] 输出: [null,null,null,1,null,2]
示例2:
输入: ["SortedStack", "pop", "pop", "push", "pop", "isEmpty"] [[], [], [], [1], [], []] 输出: [null,null,null,null,null,true]
说明:
利用辅助栈实现 push
操作,其余操作不变。
class SortedStack:
def __init__(self):
self.s = []
def push(self, val: int) -> None:
t = []
while not self.isEmpty() and self.s[-1] < val:
t.append(self.s.pop())
self.s.append(val)
while len(t) > 0:
self.s.append(t.pop())
def pop(self) -> None:
if not self.isEmpty():
self.s.pop()
def peek(self) -> int:
return -1 if self.isEmpty() else self.s[-1]
def isEmpty(self) -> bool:
return len(self.s) == 0
class SortedStack {
private Stack<Integer> s;
public SortedStack() {
s = new Stack<>();
}
public void push(int val) {
Stack<Integer> t = new Stack<>();
while (!isEmpty() && s.peek() < val) {
t.push(s.pop());
}
s.push(val);
while (!t.isEmpty()) {
s.push(t.pop());
}
}
public void pop() {
if (!isEmpty()) {
s.pop();
}
}
public int peek() {
return isEmpty() ? -1 : s.peek();
}
public boolean isEmpty() {
return s.isEmpty();
}
}
/**
* Your SortedStack object will be instantiated and called as such:
* SortedStack obj = new SortedStack();
* obj.push(val);
* obj.pop();
* int param_3 = obj.peek();
* boolean param_4 = obj.isEmpty();
*/
English Version
动物收容所。有家动物收容所只收容狗与猫,且严格遵守“先进先出”的原则。在收养该收容所的动物时,收养人只能收养所有动物中“最老”(由其进入收容所的时间长短而定)的动物,或者可以挑选猫或狗(同时必须收养此类动物中“最老”的)。换言之,收养人不能自由挑选想收养的对象。请创建适用于这个系统的数据结构,实现各种操作方法,比如enqueue
、dequeueAny
、dequeueDog
和dequeueCat
。允许使用Java内置的LinkedList数据结构。
enqueue
方法有一个animal
参数,animal[0]
代表动物编号,animal[1]
代表动物种类,其中 0 代表猫,1 代表狗。
dequeue*
方法返回一个列表[动物编号, 动物种类]
,若没有可以收养的动物,则返回[-1,-1]
。
示例1:
输入: ["AnimalShelf", "enqueue", "enqueue", "dequeueCat", "dequeueDog", "dequeueAny"] [[], [[0, 0]], [[1, 0]], [], [], []] 输出: [null,null,null,[0,0],[-1,-1],[1,0]]
示例2:
输入: ["AnimalShelf", "enqueue", "enqueue", "enqueue", "dequeueDog", "dequeueCat", "dequeueAny"] [[], [[0, 0]], [[1, 0]], [[2, 1]], [], [], []] 输出: [null,null,null,null,[2,1],[0,0],[1,0]]
说明:
双队列存储。
class AnimalShelf:
def __init__(self):
self.cats = []
self.dogs = []
def enqueue(self, animal: List[int]) -> None:
if animal[1] == 0:
self.cats.insert(0, animal[0])
else:
self.dogs.insert(0, animal[0])
def dequeueAny(self) -> List[int]:
if len(self.dogs) == 0: return self.dequeueCat()
if len(self.cats) == 0: return self.dequeueDog()
return self.dequeueDog() if self.dogs[-1] < self.cats[-1] else self.dequeueCat()
def dequeueDog(self) -> List[int]:
return [-1, -1] if len(self.dogs) == 0 else [self.dogs.pop(), 1]
def dequeueCat(self) -> List[int]:
return [-1, -1] if len(self.cats) == 0 else [self.cats.pop(), 0]
# Your AnimalShelf object will be instantiated and called as such:
# obj = AnimalShelf()
# obj.enqueue(animal)
# param_2 = obj.dequeueAny()
# param_3 = obj.dequeueDog()
# param_4 = obj.dequeueCat()
class AnimalShelf {
Queue<Integer> cats;
Queue<Integer> dogs;
public AnimalShelf() {
cats = new LinkedList<>();
dogs = new LinkedList<>();
}
public void enqueue(int[] animal) {
if (animal[1] == 0) {
cats.offer(animal[0]);
} else {
dogs.offer(animal[0]);
}
}
public int[] dequeueAny() {
return dogs.isEmpty() ? dequeueCat() : (cats.isEmpty() ? dequeueDog() : (dogs.peek() < cats.peek() ? dequeueDog() : dequeueCat()));
}
public int[] dequeueDog() {
return dogs.isEmpty() ? new int[]{
-1, -1} : new int[]{
dogs.poll(), 1};
}
public int[] dequeueCat() {
return cats.isEmpty() ? new int[]{
-1, -1} : new int[]{
cats.poll(), 0};
}
}
/**
* Your AnimalShelf object will be instantiated and called as such:
* AnimalShelf obj = new AnimalShelf();
* obj.enqueue(animal);
* int[] param_2 = obj.dequeueAny();
* int[] param_3 = obj.dequeueDog();
* int[] param_4 = obj.dequeueCat();
*/
English Version
实现一个函数,检查二叉树是否平衡。在这个问题中,平衡树的定义如下:任意一个节点,其两棵子树的高度差不超过 1。
给定二叉树 [3,9,20,null,null,15,7]示例 2:
3
/ \
9 20
/ \
15 7
返回 true 。
给定二叉树 [1,2,2,3,3,null,null,4,4]
1
/ \
2 2
/ \
3 3
/ \
4 4
返回 false 。
递归法。
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def isBalanced(self, root: TreeNode) -> bool:
if not root:
return True
l, r = self._height(root.left), self._height(root.right)
return abs(l - r) < 2 and self.isBalanced(root.left) and self.isBalanced(root.right)
def _height(self, node):
if not node:
return 0
return 1 + max(self._height(node.left), self._height(node.right))
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public boolean isBalanced(TreeNode root) {
if (root == null) {
return true;
}
int l = height(root.left), r = height(root.right);
return Math.abs(l - r) < 2 && isBalanced(root.left) && isBalanced(root.right);
}
private int height(TreeNode node) {
if (node == null) {
return 0;
}
return 1 + Math.max(height(node.left), height(node.right));
}
}
English Version
实现一个函数,检查一棵二叉树是否为二叉搜索树。
示例 1:输入:示例 2:
2
/ \
1 3
输出: true
输入:
5
/ \
1 4
/ \
3 6
输出: false
解释: 输入为: [5,1,4,null,null,3,6]。
根节点的值为 5 ,但是其右子节点值为 4 。
一棵合法的二叉搜索树,其中序遍历的结果应该升序排列。
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
res, t = True, None
def isValidBST(self, root: TreeNode) -> bool:
self.isValid(root)
return self.res
def isValid(self, root):
if not root:
return
self.isValid(root.left)
if self.t is None or self.t < root.val:
self.t = root.val
else:
self.res = False
return
self.isValid(root.right)
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
private boolean res = true;
private Integer t = null;
public boolean isValidBST(TreeNode root) {
isValid(root);
return res;
}
private void isValid(TreeNode root) {
if (root == null) {
return;
}
isValid(root.left);
if (t == null || t < root.val) {
t = root.val;
} else {
res = false;
return;
}
isValid(root.right);
}
}
English Version
设计并实现一个算法,找出二叉树中某两个节点的第一个共同祖先。不得将其他的节点存储在另外的数据结构中。注意:这不一定是二叉搜索树。
例如,给定如下二叉树: root = [3,5,1,6,2,0,8,null,null,7,4]
3示例 1:
/ \
5 1
/ \ / \
6 2 0 8
/ \
7 4
输入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1示例 2:
输入: 3
解释: 节点 5 和节点 1 的最近公共祖先是节点 3。
输入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4说明:
输出: 5
解释: 节点 5 和节点 4 的最近公共祖先是节点 5。因为根据定义最近公共祖先节点可以为节点本身。
所有节点的值都是唯一的。
p、q 为不同节点且均存在于给定的二叉树中。
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def lowestCommonAncestor(self, root: TreeNode, p: TreeNode, q: TreeNode) -> TreeNode:
if root is None or root == p or root == q:
return root
left = self.lowestCommonAncestor(root.left, p, q)
right = self.lowestCommonAncestor(root.right, p, q)
return right if left is None else (left if right is None else root)
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if (root == null || root == p || root == q) {
return root;
}
TreeNode left = lowestCommonAncestor(root.left, p, q);
TreeNode right = lowestCommonAncestor(root.right, p, q);
return left == null ? right : (right == null ? left : root);
}
}
English Version
检查子树。你有两棵非常大的二叉树:T1,有几万个节点;T2,有几万个节点。设计一个算法,判断 T2 是否为 T1 的子树。
如果 T1 有这么一个节点 n,其子树与 T2 一模一样,则 T2 为 T1 的子树,也就是说,从节点 n 处把树砍断,得到的树与 T2 完全相同。
示例1:
输入:t1 = [1, 2, 3], t2 = [2] 输出:true
示例2:
输入:t1 = [1, null, 2, 4], t2 = [3, 2] 输出:false
提示:
先找 t1 中 t2 结点,找到后进行 DFS,确认子树和 t2 的子树完全相同,否则返回 FALSE。
class Solution:
def checkSubTree(self, t1: TreeNode, t2: TreeNode) -> bool:
if t1 == None:
return False
if t2 == None:
return True
return self.dfs(t1,t2) or self.checkSubTree(t1.left,t2) or self.checkSubTree(t1.right,t2)
def dfs(self, t1: TreeNode, t2: TreeNode) -> bool:
if not t1 and t2 :
return False
if not t2 and not t1:
return True
if t1.val != t2.val:
return False
else:
return self.dfs(t1.left,t2.left) and self.dfs(t1.right,t2.right)
class Solution {
public boolean checkSubTree(TreeNode t1, TreeNode t2) {
if (t2 == null)
return true;
if (t1 == null)
return false;
return isSubTree(t1, t2) || checkSubTree(t1.left, t2) || checkSubTree(t1.right, t2);
}
public boolean isSubTree(TreeNode t1, TreeNode t2){
if (t2 == null)
return true;
if (t1 == null)
return false;
if (t1.val != t2.val)
return false;
return isSubTree(t1.left,t2.left) && isSubTree(t1.right,t2.right);
}
}
English Version
给定一棵二叉树,其中每个节点都含有一个整数数值(该值或正或负)。设计一个算法,打印节点数值总和等于某个给定值的所有路径的数量。注意,路径不一定非得从二叉树的根节点或叶节点开始或结束,但是其方向必须向下(只能从父节点指向子节点方向)。
示例:
给定如下二叉树,以及目标和 sum = 22
,
5 / \ 4 8 / / \ 11 13 4 / \ / \ 7 2 5 1
返回:
3 解释:和为 22 的路径有:[5,4,11,2], [5,8,4,5], [4,11,7]
提示:
节点总数 <= 10000
DFS 深度优先搜索
采用递归的思想,每递归到某个节点时:
root.val-sum == 0
,结果加 1特殊情况:若此节点的父节点在路径中,此节点必纳入路径(路径不能断)
class Solution:
def pathSum(self, root: TreeNode, sum: int) -> int:
def dfs(root, sum, flag):
nonlocal ans
if not root:
return 0
if sum-root.val == 0:
ans += 1
if flag == 0:
dfs(root.left, sum, 0)
dfs(root.right, sum, 0)
dfs(root.left, sum-root.val, 1)
dfs(root.right, sum-root.val, 1)
if not root:
return 0
ans = 0
dfs(root, sum, 0)
return ans
使用到 2 个递归过程:
需要注意,节点值有正有负,需要穷尽所有的可能路径。
class Solution {
int ans = 0;
public int pathSum(TreeNode root, int sum) {
traverse(root, sum);
return ans;
}
void traverse(TreeNode root, int sum) {
if (root == null) return;
ans += dfs(root, sum, 0);
traverse(root.left, sum);
traverse(root.right, sum);
}
// check if sum of path is sum.
int dfs(TreeNode root, int sum, int cur) {
if (root == null) return 0;
cur += root.val;
int res = 0;
if (cur == sum) res++;
res += dfs(root.left, sum, cur);
res += dfs(root.right, sum, cur);
return res;
}
}
English Version
插入。给定两个32位的整数N
与M
,以及表示比特位置的i
与j
。编写一种方法,将M
插入N
,使得M从N的第j位开始,到第i
位结束。假定从j
位到i
位足以容纳M
,也即若M = 10 011,那么j和i之间至少可容纳5个位。例如,不可能出现j = 3和i = 2的情况,因为第3位和第2位之间放不下M。
示例1:
输入:N = 10000000000, M = 10011, i = 2, j = 6 输出:N = 10001001100
示例2:
输入: N = 0, M = 11111, i = 0, j = 4 输出:N = 11111
class Solution {
public int insertBits(int N, int M, int i, int j) {
for (int k = i; k <= j; k++) {
N &= ~(1 << k);
}
return N ^ (M << i);
}
}
延伸:
3.位异或运算(^)
运算规则是:两个数转为二进制,然后从高位开始比较,如果相同则为0,不相同则为1。
比如:8^11.
8转为二进制是1000,11转为二进制是1011.从高位开始比较得到的是:0011.然后二进制转为十进制,就是Integer.parseInt("0011",2)=3;
4.位与运算符(&)
运算规则:两个数都转为二进制,然后从高位开始比较,如果两个数都为1则为1,否则为0。
比如:129&128.
129转换成二进制就是10000001,128转换成二进制就是10000000。从高位开始比较得到,得到10000000,即128.
5.位或运算符(|)
运算规则:两个数都转为二进制,然后从高位开始比较,两个数只要有一个为1则为1,否则就为0。
比如:129|128.
129转换成二进制就是10000001,128转换成二进制就是10000000。从高位开始比较得到,得到10000001,即129.
6.位非运算符(~)
运算规则:如果位为0,结果是1,如果位为1,结果是0.
比如:~37
在Java中,所有数据的表示方法都是以补码的形式表示,如果没有特殊说明,Java中的数据类型默认是int,int数据类型的长度是8位,一位是四个字节,就是32字节,32bit.
8转为二进制是100101.
补码后为: 00000000 00000000 00000000 00100101
取反为: 11111111 11111111 11111111 11011010
因为高位是1,所以原码为负数,负数的补码是其绝对值的原码取反,末尾再加1。
因此,我们可将这个二进制数的补码进行还原: 首先,末尾减1得反码:11111111 11111111 11111111 11011001 其次,将各位取反得原码:
00000000 00000000 00000000 00100110,此时二进制转原码为38
所以~37 = -38. ```
### **...**
# [面试题 05.06. 整数转换](https://leetcode-cn.com/problems/convert-integer-lcci)
[English Version](/lcci/05.06.Convert%20Integer/README_EN.md)
## 题目描述
整数转换。编写一个函数,确定需要改变几个位才能将整数A转成整数B。
示例1:
输入:A = 29 (或者0b11101), B = 15(或者0b01111)
输出:2
示例2:
输入:A = 1,B = 2
输出:2
提示:
- A,B范围在[-2147483648, 2147483647]之间
## 解法
### **Python3**
```python
class Solution {
public int convertInteger(int A, int B) {
//bitCount实现的功能是计算一个(byte,short,char,int统一按照int方法计算)int,long类型的数值在二进制下“1”的数量。
return Integer.bitCount(A ^ B);
}
}
English Version
配对交换。编写程序,交换某个整数的奇数位和偶数位,尽量使用较少的指令(也就是说,位0与位1交换,位2与位3交换,以此类推)。
示例1:
输入:num = 2(或者0b10) 输出 1 (或者 0b01)
示例2:
输入:num = 3 输出:3
提示:
num
的范围在[0, 2^30 - 1]之间,不会发生整数溢出。
class Solution {
public int exchangeBits(int num) {
int t1 = num >> 1;
int t2 = num << 1;
return t1 & 0x55555555 | t2 & 0xaaaaaaaa;
}
}
English Version
三步问题。有个小孩正在上楼梯,楼梯有n阶台阶,小孩一次可以上1阶、2阶或3阶。实现一种方法,计算小孩有多少种上楼梯的方式。结果可能很大,你需要对结果模1000000007。
示例1:
输入:n = 3 输出:4 说明: 有四种走法
示例2:
输入:n = 5 输出:13
提示:
递推法。f(n)=f(n-1)+f(n-2)+f(n-3)
class Solution:
def waysToStep(self, n: int) -> int:
if n < 3:
return n
a, b, c = 1, 2, 4
for _ in range(4, n + 1):
a, b, c = b, c, (a + b + c) % 1000000007
return c
class Solution {
public int waysToStep(int n) {
if (n < 3) {
return n;
}
int a = 1, b = 2, c = 4;
for (int i = 4; i <= n; ++i) {
int t = a;
a = b;
b = c;
c = ((a + b) % 1000000007 + t) % 1000000007;
}
return c;
}
}
class Solution {
public:
int waysToStep(int n) {
if (n < 3) {
return n;
}
int a = 1, b = 2, c = 4, i = 4;
while (i++ <= n) {
int t = ((a + b) % 1000000007 + c) % 1000000007;
a = b;
b = c;
c = t;
}
return c;
}
};
English Version
括号。设计一种算法,打印n对括号的所有合法的(例如,开闭一一对应)组合。
说明:解集不能包含重复的子集。
例如,给出 n = 3,生成结果为:
[ "((()))", "(()())", "(())()", "()(())", "()()()" ]
递归求解。其中,left
表示剩余的 (
,right
表示剩余的 )
。
left
> right
时,说明 state 中 (
少于 )
,不是合法组合,直接剪枝;right
== 0 时,说明 state 组合完毕;left
> 0 时,此时可往 state 添加一个 (
;right
> 0 时,此时可往 state 添加一个 )
。class Solution:
def generateParenthesis(self, n: int) -> List[str]:
res = []
def generate(state, left, right):
# 剩余的`(`多于`)`
if left > right:
return
if right == 0:
res.append(state)
return
if left > 0:
generate(state + '(', left - 1, right)
if right > 0:
generate(state + ')', left, right - 1)
generate('', n, n)
return res
class Solution {
List<String> res;
public List<String> generateParenthesis(int n) {
res = new ArrayList<>();
generate("", n, n);
return res;
}
private void generate(String state, int left, int right) {
if (left > right) {
return;
}
if (right == 0) {
res.add(state);
return;
}
if (left > 0) {
generate(state + "(", left - 1, right);
}
if (right > 0) {
generate(state + ")", left, right - 1);
}
}
}
English Version
颜色填充。编写函数,实现许多图片编辑软件都支持的“颜色填充”功能。给定一个屏幕(以二维数组表示,元素为颜色值)、一个点和一个新的颜色值,将新颜色值填入这个点的周围区域,直到原来的颜色值全都改变。
示例1:
输入: image = [[1,1,1],[1,1,0],[1,0,1]] sr = 1, sc = 1, newColor = 2 输出:[[2,2,2],[2,2,0],[2,0,1]] 解释: 在图像的正中间,(坐标(sr,sc)=(1,1)), 在路径上所有符合条件的像素点的颜色都被更改成2。 注意,右下角的像素没有更改为2, 因为它不是在上下左右四个方向上与初始点相连的像素点。
说明:
class Solution {
public int[][] floodFill(int[][] image, int sr, int sc, int newColor) {
int oldColor = image[sr][sc];
dfs(image, sr, sc, oldColor, newColor);
return image;
}
private void dfs(int[][] image, int sr, int sc, int oldColor, int newColor) {
if (sr < 0 || sc < 0 || sr >= image.length || sc >= image[0].length) {
return;
}
int color = image[sr][sc];
if (color != newColor && color == oldColor) {
image[sr][sc] = newColor;
// up down left right
dfs(image, sr, sc + 1, oldColor, newColor);
dfs(image, sr, sc - 1, oldColor, newColor);
dfs(image, sr + 1, sc, oldColor, newColor);
dfs(image, sr - 1, sc, oldColor, newColor);
}
}
}
English Version
给定M×N矩阵,每一行、每一列都按升序排列,请编写代码找出某元素。
示例:
现有矩阵 matrix 如下:
[ [1, 4, 7, 11, 15], [2, 5, 8, 12, 19], [3, 6, 9, 16, 22], [10, 13, 14, 17, 24], [18, 21, 23, 26, 30] ]
给定 target = 5
,返回 true
。
给定 target = 20
,返回 false
。
从左下角(或右上角)开始查找即可。
class Solution:
def searchMatrix(self, matrix: List[List[int]], target: int) -> bool:
if not matrix or not matrix[0]:
return False
rows, cols = len(matrix), len(matrix[0])
i, j = rows - 1, 0
while i >= 0 and j < cols:
if matrix[i][j] == target:
return True
if matrix[i][j] > target:
i -= 1
else:
j += 1
return False
class Solution {
public boolean searchMatrix(int[][] matrix, int target) {
if (matrix == null || matrix.length == 0 || matrix[0] == null || matrix[0].length == 0) {
return false;
}
int rows = matrix.length, cols = matrix[0].length;
int i = rows - 1, j = 0;
while (i >= 0 && j < cols) {
if (matrix[i][j] == target) {
return true;
}
if (matrix[i][j] > target) {
--i;
} else {
++j;
}
}
return false;
}
}
English Version
编写一个函数,不用临时变量,直接交换numbers = [a, b]
中a
与b
的值。
示例:
输入: numbers = [1,2] 输出: [2,1]
提示:
numbers.length == 2
异或运算。
class Solution:
def swapNumbers(self, numbers: List[int]) -> List[int]:
numbers[0], numbers[1] = numbers[1], numbers[0]
return numbers
class Solution {
public int[] swapNumbers(int[] numbers) {
numbers[0] = numbers[0] ^ numbers[1]; //3
numbers[1] = numbers[0] ^ numbers[1]; //1
numbers[0] = numbers[0] ^ numbers[1]; //2
return numbers;
}
}
English Version
给定两个整数数组a
和b
,计算具有最小差绝对值的一对数值(每个数组中取一个值),并返回该对数值的差
示例:
输入:{1, 3, 15, 11, 2}, {23, 127, 235, 19, 8} 输出: 3,即数值对(11, 8)
提示:
1 <= a.length, b.length <= 100000
-2147483648 <= a[i], b[i] <= 2147483647
class Solution:
def smallestDifference(self, a: List[int], b: List[int]) -> int:
a.sort()
b.sort()
i, j, res = 0, 0, 2147483647
m, n = len(a), len(b)
while i < m and j < n:
if a[i] == b[j]: return 0
res = min(res, abs(a[i] - b[j]))
if a[i] > b[j]: j += 1
else: i += 1
return res
class Solution {
public int smallestDifference(int[] a, int[] b) {
Arrays.sort(a);
Arrays.sort(b);
int m = a.length, n = b.length;
int i = 0, j = 0;
long res = Long.MAX_VALUE;
while (i < m && j < n) {
if (a[i] == b[j]) return 0;
res = Math.min(res, Math.abs((long) a[i] - (long) b[j]));
if (a[i] > b[j]) ++j;
else ++i;
}
return (int) res;
}
}
English Version
给定N个人的出生年份和死亡年份,第i
个人的出生年份为birth[i]
,死亡年份为death[i]
,实现一个方法以计算生存人数最多的年份。
你可以假设所有人都出生于1900年至2000年(含1900和2000)之间。如果一个人在某一年的任意时期都处于生存状态,那么他们应该被纳入那一年的统计中。例如,生于1908年、死于1909年的人应当被列入1908年和1909年的计数。
如果有多个年份生存人数相同且均为最大值,输出其中最小的年份。
示例:
输入: birth = {1900, 1901, 1950} death = {1948, 1951, 2000} 输出: 1901
提示:
0 < birth.length == death.length <= 10000
birth[i] <= death[i]
class Solution:
def maxAliveYear(self, birth: List[int], death: List[int]) -> int:
years = [0] * 101
for i in range(len(birth)):
start = birth[i] - 1900
end = death[i] - 1900
for j in range(start, end + 1):
years[j] += 1
max_v = years[0]
res = 0
for i in range(1, 101):
if years[i] > max_v:
max_v = years[i]
res = i
return 1900 + res
class Solution {
public int maxAliveYear(int[] birth, int[] death) {
int[] years = new int[101];
int n = birth.length;
for (int i = 0; i < n; ++i) {
int start = birth[i] - 1900;
int end = death[i] - 1900;
for (int j = start; j <= end; ++j) {
++years[j];
}
}
int max = years[0];
int res = 0;
for (int i = 1; i < 101; ++i) {
if (years[i] > max) {
max = years[i];
res = i;
}
}
return 1900 + res;
}
}
English Version
你正在使用一堆木板建造跳水板。有两种类型的木板,其中长度较短的木板长度为shorter
,长度较长的木板长度为longer
。你必须正好使用k
块木板。编写一个方法,生成跳水板所有可能的长度。
返回的长度需要从小到大排列。
示例:
输入: shorter = 1 longer = 2 k = 3 输出: {3,4,5,6}
提示:
class Solution {
public int[] divingBoard(int shorter, int longer, int k) {
if (k == 0) {
return new int[0];
}
if (longer == shorter) {
return new int[]{
longer * k};
}
int[] ans = new int[k + 1];
for (int i = 0;i <= k;i++) {
ans[i] = longer * i + shorter * (k - i);
}
return ans;
}
}
English Version
给定两个整数数组,请交换一对数值(每个数组中取一个数值),使得两个数组所有元素的和相等。
返回一个数组,第一个元素是第一个数组中要交换的元素,第二个元素是第二个数组中要交换的元素。若有多个答案,返回任意一个均可。若无满足条件的数值,返回空数组。
示例:
输入: array1 = [4, 1, 2, 1, 1, 2], array2 = [3, 6, 3, 3] 输出: [1, 3]
示例:
输入: array1 = [1, 2, 3], array2 = [4, 5, 6]
输出: []
提示:
1 <= array1.length, array2.length <= 100000
先计算两个数组的差值 diff
,若 diff
为奇数,则说明无满足条件的数值,返回空数组。否则,将 array2
转为 set
。然后遍历 array1
中的每个数 e
,若值 e - diff
在 set
中,则说明找到满足条件的数值对。
class Solution:
def findSwapValues(self, array1: List[int], array2: List[int]) -> List[int]:
diff = sum(array1) - sum(array2)
if diff & 1: return []
diff >>= 1
s = set(array2)
for e in array1:
if (e - diff) in s: return [e, e - diff]
return []
class Solution {
public int[] findSwapValues(int[] array1, int[] array2) {
int diff = sum(array1) - sum(array2);
if ((diff & 1) == 1) {
return new int[]{
};
}
diff >>= 1;
Set<Integer> s = Arrays.stream(array2).boxed().collect(Collectors.toSet());
for (int e : array1) {
if (s.contains((e - diff))) {
return new int[]{
e, e - diff};
}
}
return new int[]{
};
}
private int sum(int[] array) {
int res = 0;
for (int e : array) {
res += e;
}
return res;
}
}s
English Version
设计一个函数把两个数字相加。不得使用 + 或者其他算术运算符。
示例:
输入: a = 1, b = 1 输出: 2
提示:
a
, b
均可能是负数或 0
class Solution {
public int add(int a, int b) {
int sum = 0, carry = 0;
while (b != 0) {
sum = a ^ b;
carry = (a & b) << 1;
a = sum;
b = carry;
}
return a;
}
}
English Version
数组nums
包含从0
到n
的所有整数,但其中缺了一个。请编写代码找出那个缺失的整数。你有办法在O(n)时间内完成吗?
注意:本题相对书上原题稍作改动
示例 1:
输入:[3,0,1] 输出:2
示例 2:
输入:[9,6,4,2,3,5,7,0,1] 输出:8
利用异或的特性,res = res ^ x ^ x
。对同一个值异或两次,结果等于它本身。最后异或的结果,就是只出现一次的数字,即数组中缺失的整数。
class Solution:
def missingNumber(self, nums: List[int]) -> int:
res = 0
for i, num in enumerate(nums):
res ^= i
res ^= num
res ^= len(nums)
return res
class Solution {
public int missingNumber(int[] nums) {
int res = 0, n = nums.length;
for (int i = 0; i < n; ++i) {
res ^= i;
res ^= nums[i];
}
res ^= n;
return res;
}
}
English Version
二叉树数据结构TreeNode
可用来表示单向链表(其中left
置空,right
为下一个链表节点)。实现一个方法,把二叉搜索树转换为单向链表,要求值的顺序保持不变,转换操作应是原址的,也就是在原始的二叉搜索树上直接修改。
返回转换后的单向链表的头节点。
注意:本题相对原题稍作改动
示例:
输入: [4,2,5,1,3,null,6,0] 输出: [0,null,1,null,2,null,3,null,4,null,5,null,6]
提示:
递归将左子树、右子树转换为左、右链表 left 和 right。然后将左链表 left 的最后一个结点的 right 指针指向 root,root 的 right 指针指向右链表 right,并将 root 的 left 指针值为空。
同 897. 递增顺序查找树。
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def convertBiNode(self, root: TreeNode) -> TreeNode:
if root is None:
return None
left = self.convertBiNode(root.left)
right = self.convertBiNode(root.right)
if left is None:
root.right = right
return root
res = left
while left and left.right:
left = left.right
left.right = root
root.right = right
root.left = None
return res
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public TreeNode convertBiNode(TreeNode root) {
if (root == null) return null;
TreeNode left = convertBiNode(root.left);
TreeNode right = convertBiNode(root.right);
if (left == null) {
root.right = right;
return root;
}
TreeNode res = left;
while (left != null && left.right != null) {
left = left.right;
}
left.right = root;
root.right = right;
root.left = null;
return res;
}
}
English Version
哦,不!你不小心把一个长篇文章中的空格、标点都删掉了,并且大写也弄成了小写。像句子"I reset the computer. It still didn’t boot!"
已经变成了"iresetthecomputeritstilldidntboot"
。在处理标点符号和大小写之前,你得先把它断成词语。当然了,你有一本厚厚的词典dictionary
,不过,有些词没在词典里。假设文章用sentence
表示,设计一个算法,把文章断开,要求未识别的字符最少,返回未识别的字符数。
注意:本题相对原题稍作改动,只需返回未识别的字符数
示例:
输入: dictionary = ["looked","just","like","her","brother"] sentence = "jesslookedjustliketimherbrother" 输出: 7 解释: 断句后为"jess looked just like tim her brother",共7个未识别字符。
提示:
0 <= len(sentence) <= 1000
dictionary
中总字符数不超过 150000。dictionary
和sentence
中只包含小写字母。
class Solution {
public int respace(String[] dictionary, String sentence) {
Set<String> set = new HashSet<>(dictionary.length);
set.addAll(Arrays.asList(dictionary));
int[] dp = new int[sentence.length() + 1];
for (int i = 1; i <= sentence.length(); i++) {
dp[i] = dp[i - 1] + 1;
for (int j = 0;j < i;j++) {
if (set.contains(sentence.substring(j, i))) {
dp[i] = Math.min(dp[i], dp[j]);
}
}
}
return dp[sentence.length()];
}
}
English Version
给定一个数组,包含从 1 到 N 所有的整数,但其中缺了两个数字。你能在 O(N) 时间内只用 O(1) 的空间找到它们吗?
以任意顺序返回这两个数字均可。
示例 1:
输入: [1]
输出: [2,3]
示例 2:
输入: [2,3]
输出: [1,4]
提示:
nums.length <= 30000
异或运算。与面试题 56 - I. 数组中数字出现的次数 类似。
class Solution:
def missingTwo(self, nums: List[int]) -> List[int]:
res, n = 0, len(nums)
for i in range(n):
res ^= nums[i]
res ^= (i + 1)
res ^= (n + 1)
res ^= (n + 2)
pos = 0
while (res & 1) == 0:
pos += 1
res >>= 1
a = b = 0
for num in nums:
t = num >> pos
if (t & 1) == 0:
a ^= num
else:
b ^= num
for i in range(1, n + 3):
t = i >> pos
if (t & 1) == 0:
a ^= i
else:
b ^= i
return [a, b]
class Solution {
public int[] missingTwo(int[] nums) {
int res = 0, n = nums.length;
for (int i = 0; i < n; ++i) {
res ^= nums[i];
res ^= (i + 1);
}
res ^= (n + 1);
res ^= (n + 2);
int pos = 0;
while ((res & 1) == 0) {
pos += 1;
res >>= 1;
}
int a = 0, b = 0;
for (int num : nums) {
int t = num >> pos;
if ((t & 1) == 0) {
a ^= num;
} else {
b ^= num;
}
}
for (int i = 1; i <= n + 2; ++i) {
int t = i >> pos;
if ((t & 1) == 0) {
a ^= i;
} else {
b ^= i;
}
}
return new int[]{
a, b};
}
}
English Version
随机产生数字并传递给一个方法。你能否完成这个方法,在每次产生新值时,寻找当前所有值的中间值(中位数)并保存。
中位数是有序列表中间的数。如果列表长度是偶数,中位数则是中间两个数的平均值。
例如,
[2,3,4] 的中位数是 3
[2,3] 的中位数是 (2 + 3) / 2 = 2.5
设计一个支持以下两种操作的数据结构:
示例:
addNum(1) addNum(2) findMedian() -> 1.5 addNum(3) findMedian() -> 2
class MedianFinder:
def __init__(self):
"""
initialize your data structure here.
"""
self.max_heap = []
self.min_heap = []
def addNum(self, num: int) -> None:
if len(self.max_heap) == len(self.min_heap):
heapq.heappush(self.min_heap, -heapq.heappushpop(self.max_heap, -num))
else:
heapq.heappush(self.max_heap, -heapq.heappushpop(self.min_heap, num))
def findMedian(self) -> float:
return (-self.max_heap[0] + self.min_heap[0]) / 2 if len(self.max_heap) == len(self.min_heap) else self.min_heap[0]
# Your MedianFinder object will be instantiated and called as such:
# obj = MedianFinder()
# obj.addNum(num)
# param_2 = obj.findMedian()
class MedianFinder {
private Queue<Integer> minHeap;
private Queue<Integer> maxHeap;
/** initialize your data structure here. */
public MedianFinder() {
//PriorityQueue是基于优先堆的一个无界队列,这个优先队列中的元素可以默认自然排序或者通过提供的Comparator(比较器)在队列实例化的时排序。
minHeap = new PriorityQueue<>();
maxHeap = new PriorityQueue<>((a, b) -> b - a);
}
public void addNum(int num) {
if (minHeap.size() == maxHeap.size()) {
maxHeap.offer(num);
minHeap.offer(maxHeap.poll());
} else {
minHeap.offer(num);
maxHeap.offer(minHeap.poll());
}
}
public double findMedian() {
return minHeap.size() == maxHeap.size() ? (minHeap.peek() + maxHeap.peek()) / 2.0 : minHeap.peek();
}
}
/**
* Your MedianFinder object will be instantiated and called as such:
* MedianFinder obj = new MedianFinder();
* obj.addNum(num);
* double param_2 = obj.findMedian();
*/