基礎部分
167. 兩數之和 II - 輸入有序數組
簡單
給定一個已按照*升序排列* 的有序數組,找到兩個數使得它們相加之和等於目標數。
函數應該返回這兩個下標值 index1 和 index2,其中 index1 必須小於 index2。
說明:
- 返回的下標值(index1 和 index2)不是從零開始的。
- 你可以假設每個輸入只對應唯一的答案,而且你不可以重復使用相同的元素。
示例:
輸入: numbers = [2, 7, 11, 15], target = 9
輸出: [1,2]
解釋: 2 與 7 之和等於目標數 9 。因此 index1 = 1, index2 = 2 。
class Solution {
public int[] twoSum(int[] numbers, int target) {
int i = 0;
int j = numbers.length - 1;
while (i < j){
if (numbers[i]+numbers[j] < target){
i++;
}else if (numbers[i]+numbers[j] > target){
j--;
}else {
return new int[]{i+1,j+1};
}
}
return new int[]{};
}
}
633. 平方數之和
簡單
給定一個非負整數 c
,你要判斷是否存在兩個整數 a
和 b
,使得 a2 + b2 = c。
示例1:
輸入: 5
輸出: True
解釋: 1 * 1 + 2 * 2 = 5
示例2:
輸入: 3
輸出: False
class Solution {
public boolean judgeSquareSum(int c) {
int i = 0;
int j = (int)Math.sqrt(c);
while (i <= j){
if (i*i+j*j < c){
i++;
}else if (i*i+j*j > c){
j--;
}else return true;
}
return false;
}
}
345. 反轉字符串中的元音字母
簡單
編寫一個函數,以字符串作為輸入,反轉該字符串中的元音字母。
示例 1:
輸入: "hello"
輸出: "holle"
示例 2:
輸入: "leetcode"
輸出: "leotcede"
說明:
元音字母不包含字母"y"。
class Solution {
public String reverseVowels(String s) {
char[] chars = s.toCharArray();
int i = 0;
int j = chars.length - 1;
Set<Character> set = new HashSet<>();
set.add('a');
set.add('e');
set.add('i');
set.add('o');
set.add('u');
set.add('A');
set.add('E');
set.add('I');
set.add('O');
set.add('U');
while (i < j){
while (i < j && !set.contains(chars[i])) i++;
while (i < j && !set.contains(chars[j])) j--;
if (chars[i] != chars[j]){
char tmp = chars[i];
chars[i] = chars[j];
chars[j] = tmp;
}
i++;
j--;
}
return String.valueOf(chars);
}
}
680. 驗證回文字符串 Ⅱ
簡單
給定一個非空字符串 s
,最多刪除一個字符。判斷是否能成為回文字符串。
示例 1:
輸入: "aba"
輸出: True
示例 2:
輸入: "abca"
輸出: True
解釋: 你可以刪除c字符。
注意:
- 字符串只包含從 a-z 的小寫字母。字符串的最大長度是50000。
class Solution {
public boolean validPalindrome(String s) {
char[] chars = s.toCharArray();
int i = 0;
int j = chars.length - 1;
while (i < j){
if (chars[i] == chars[j]){
i++;
j--;
}else return helper(chars,i+1,j) || helper(chars,i,j-1);
}
return true;
}
private boolean helper(char[] chars, int i, int j) {
while (i < j){
if (chars[i] != chars[j]) return false;
i++;
j--;
}
return true;
}
}
88. 合並兩個有序數組
簡單
給你兩個有序整數數組 nums1 和 nums2,請你將 nums2 合並到 nums1 中,使 nums1 成為一個有序數組。
說明:
- 初始化 nums1 和 nums2 的元素數量分別為 m 和 n 。
- 你可以假設 nums1 有足夠的空間(空間大小大於或等於 m + n)來保存 nums2 中的元素。
示例:
輸入:
nums1 = [1,2,3,0,0,0], m = 3
nums2 = [2,5,6], n = 3
輸出: [1,2,2,3,5,6]
class Solution {
public void merge(int[] nums1, int m, int[] nums2, int n) {
if (n==0) return;
int i = 0;
int j = 0;
while (i < m){
if (nums1[i] > nums2[j]){
int tmp = nums1[i];
nums1[i] = nums2[j];
nums2[j] = tmp;
for (int k = 0; k < n-1; k++) {
if (nums2[k] > nums2[k+1]){
tmp = nums2[k];
nums2[k] = nums2[k+1];
nums2[k+1] = tmp;
}else break;
}
}
i++;
}
while (j < n) nums1[i++] = nums2[j++];
}
}
141. 環形鏈表
簡單
給定一個鏈表,判斷鏈表中是否有環。
為了表示給定鏈表中的環,我們使用整數 pos
來表示鏈表尾連接到鏈表中的位置(索引從 0 開始)。 如果 pos
是 -1
,則在該鏈表中沒有環。
示例 1:
輸入:head = [3,2,0,-4], pos = 1
輸出:true
解釋:鏈表中有一個環,其尾部連接到第二個節點。
示例 2:
輸入:head = [1,2], pos = 0
輸出:true
解釋:鏈表中有一個環,其尾部連接到第一個節點。
示例 3:
輸入:head = [1], pos = -1
輸出:false
解釋:鏈表中沒有環。
進階:
你能用 O(1)(即,常量)內存解決此問題嗎?
public class Solution {
public boolean hasCycle(ListNode head) {
ListNode slow = head;
ListNode quick = head;
while (quick != null && quick.next != null){
slow = slow.next;
quick = quick.next.next;
if (quick == slow) return true;
}
return false;
}
}
524. 通過刪除字母匹配到字典里最長單詞
中等
給定一個字符串和一個字符串字典,找到字典里面最長的字符串,該字符串可以通過刪除給定字符串的某些字符來得到。如果答案不止一個,返回長度最長且字典順序最小的字符串。如果答案不存在,則返回空字符串。
示例 1:
輸入:
s = "abpcplea", d = ["ale","apple","monkey","plea"]
輸出:
"apple"
示例 2:
輸入:
s = "abpcplea", d = ["a","b","c"]
輸出:
"a"
說明:
- 所有輸入的字符串只包含小寫字母。
- 字典的大小不會超過 1000。
- 所有輸入的字符串長度不會超過 1000。
class Solution {
public String findLongestWord(String s, List<String> d) {
StringBuilder res = new StringBuilder();
char[] chars = s.toCharArray();
for (String s1 : d) {
char[] chs = s1.toCharArray();
int j = 0;
for (int i = 0; i < chars.length && j < chs.length; i++)
if (chars[i] == chs[j]) j++;
if (j == chs.length && chs.length > res.length()) //長度更長的
res.delete(0, res.length()).append(s1);
else if (j == chs.length && chs.length == res.length() && String.valueOf(chs).compareTo(String.valueOf(res)) < 0) //長度相同的,取字典前面的
res.delete(0, res.length()).append(s1);
}
return res.toString();
}
}
頻率排序
42. 接雨水
困難
給定 n 個非負整數表示每個寬度為 1 的柱子的高度圖,計算按此排列的柱子,下雨之后能接多少雨水。
上面是由數組 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度圖,在這種情況下,可以接 6 個單位的雨水(藍色部分表示雨水)。 感謝 Marcos 貢獻此圖。
示例:
輸入: [0,1,0,2,1,0,1,3,2,1,2,1]
輸出: 6
class Solution {
public int trap(int[] height) {
int res = 0;
int i = 0;
int j = height.length - 1;
int l = 0; // 左側最大值
int r = 0; // 右側最大值
while (i <= j){ // = 很關鍵
if (l < r){
if (height[i] < l) res += l - height[i];
else l = height[i];
i++;
}else {
if (height[j] < r) res += r - height[j];
else r = height[j];
j--;
}
}
return res;
}
}
3. 無重復字符的最長子串
中等
給定一個字符串,請你找出其中不含有重復字符的 最長子串 的長度。
示例 1:
輸入: "abcabcbb"
輸出: 3
解釋: 因為無重復字符的最長子串是 "abc",所以其長度為 3。
示例 2:
輸入: "bbbbb"
輸出: 1
解釋: 因為無重復字符的最長子串是 "b",所以其長度為 1。
示例 3:
輸入: "pwwkew"
輸出: 3
解釋: 因為無重復字符的最長子串是 "wke",所以其長度為 3。
請注意,你的答案必須是 子串 的長度,"pwke" 是一個子序列,不是子串。
class Solution {
public int lengthOfLongestSubstring(String s) {
Set<Character> set = new HashSet<>();
char[] chars = s.toCharArray();
int i = 0;
int j = 0;
int res = 0;
int len = 0;
while (i < chars.length && j < chars.length){
if (!set.contains(chars[j])){
set.add(chars[j]);
len++;
if (res < len) res = len;
}else {
while (chars[i] != chars[j]){
set.remove(chars[i]);
i++;
}
len = j - i; //去掉前面之后的新長度,肯定比max小,不用管
i++;
}
j++;
}
return res;
}
}
15. 三數之和
中等
給你一個包含 n 個整數的數組 nums
,判斷 nums
中是否存在三個元素 a,b,c ,使得 a + b + c = 0 ?請你找出所有滿足條件且不重復的三元組。
注意:答案中不可以包含重復的三元組。
示例:
給定數組 nums = [-1, 0, 1, 2, -1, -4],
滿足要求的三元組集合為:
[
[-1, 0, 1],
[-1, -1, 2]
]
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> lists = new LinkedList<>();
Set<List<Integer>> sets = new HashSet<>();
Arrays.sort(nums);
for (int i = 0; i < nums.length - 2; i++) {
if (i != 0 && nums[i-1] == nums[i]) continue; //去點重復的
int j = i + 1;
int k = nums.length - 1;
while (j < k){
if (nums[i] + nums[j] + nums[k] == 0){
sets.add(Arrays.asList(nums[i],nums[j],nums[k]));
j++;
k--;
}else if (nums[i] + nums[j] + nums[k] < 0) j++;
else k--;
}
}
lists.addAll(sets);
return lists;
}
}
763. 划分字母區間
中等
字符串 S
由小寫字母組成。我們要把這個字符串划分為盡可能多的片段,同一個字母只會出現在其中的一個片段。返回一個表示每個字符串片段的長度的列表。
示例 1:
輸入:S = "ababcbacadefegdehijhklij"
輸出:[9,7,8]
解釋:
划分結果為 "ababcbaca", "defegde", "hijhklij"。
每個字母最多出現在一個片段中。
像 "ababcbacadefegde", "hijhklij" 的划分是錯誤的,因為划分的片段數較少。
提示:
S
的長度在[1, 500]
之間。S
只包含小寫字母'a'
到'z'
。
class Solution {
public List<Integer> partitionLabels(String S) {
List<Integer> list = new LinkedList<>();
char[] chars = S.toCharArray();
int[] letters = new int[26];
for (int i = 0; i < chars.length; i++)
letters[chars[i]-'a'] = i; //記錄最右
int i = 0;
int j = 0;
int max = 0;
while (j < chars.length) {
do {
max = Math.max(max,letters[chars[j]-'a']);
j++;
}while (j <= max); //知道j超過max一位
list.add(j-i);
i = j;
}
return list;
}
}
845. 數組中的最長山脈
中等
我們把數組 A 中符合下列屬性的任意連續子數組 B 稱為 “山脈”:
B.length >= 3
- 存在
0 < i < B.length - 1
使得B[0] < B[1] < ... B[i-1] < B[i] > B[i+1] > ... > B[B.length - 1]
(注意:B 可以是 A 的任意子數組,包括整個數組 A。)
給出一個整數數組 A
,返回最長 “山脈” 的長度。
如果不含有 “山脈” 則返回 0
。
示例 1:
輸入:[2,1,4,7,3,2,5]
輸出:5
解釋:最長的 “山脈” 是 [1,4,7,3,2],長度為 5。
示例 2:
輸入:[2,2,2]
輸出:0
解釋:不含 “山脈”。
提示:
0 <= A.length <= 10000
0 <= A[i] <= 10000
class Solution {
public int longestMountain(int[] A) {
if (A.length < 3) return 0;
int[] arr = new int[A.length-1];
for (int i = 0; i < arr.length; i++) {
if (A[i] > A[i+1])arr[i] = -1; //下坡
else if (A[i] < A[i+1]) arr[i] = 1; //上坡
else arr[i] = 0; //平
}
int max = 0;
int i;
int j = 0;
while (j < arr.length){ //山脈=[1,1,-1,-1]
while (j < arr.length && arr[j]!=1) j++;
i = j;
while (j < arr.length && arr[j]==1) j++;
if (j >=arr.length || arr[j]==0) continue;
while (j < arr.length && arr[j]==-1) j++;
max = Math.max(max,j-i+1); //取最大
}
return max;
}
}
713. 乘積小於K的子數組
難度中等143
給定一個正整數數組 nums
。
找出該數組內乘積小於 k
的連續的子數組的個數。
示例 1:
輸入: nums = [10,5,2,6], k = 100
輸出: 8
解釋: 8個乘積小於100的子數組分別為: [10], [5], [2], [6], [10,5], [5,2], [2,6], [5,2,6]。
需要注意的是 [10,5,2] 並不是乘積小於100的子數組。
說明:
0 < nums.length <= 50000
0 < nums[i] < 1000
0 <= k < 10^6
class Solution {
public int numSubarrayProductLessThanK(int[] nums, int k) {
if (k <= 1) return 0;
int res = 0;
int mul = 1;
int left = 0;
for (int right = 0; right < nums.length; right++) {
mul *= nums[right];
while (mul >= k) mul /= nums[left++];
res += right - left + 1; //※※※很關鍵
// [1,2,3,4,5] 25
// 1,2,3,4都成了,以4結尾的其他的都能成,所以直接res加4-1+1=4
}
return res;
}
}
11. 盛最多水的容器
難度中等1653
給你 n 個非負整數 a1,a2,...,an,每個數代表坐標中的一個點 (i, ai) 。在坐標內畫 n 條垂直線,垂直線 i 的兩個端點分別為 (i, ai) 和 (i, 0)。找出其中的兩條線,使得它們與 x 軸共同構成的容器可以容納最多的水。
說明:你不能傾斜容器,且 n 的值至少為 2。
圖中垂直線代表輸入數組 [1,8,6,2,5,4,8,3,7]。在此情況下,容器能夠容納水(表示為藍色部分)的最大值為 49。
示例:
輸入:[1,8,6,2,5,4,8,3,7]
輸出:49
class Solution {
public int maxArea(int[] height) {
int res = 0;
int i = 0;
int j = height.length - 1;
while (i < j){ //誰短誰動
if (height[i] < height[j]){
res = Math.max(res,(j-i)*height[i]);
i++;
}else {
res = Math.max(res,(j-i)*height[j]);
j--;
}
}
return res;
}
}
1004. 最大連續1的個數 III
中等
給定一個由若干 0
和 1
組成的數組 A
,我們最多可以將 K
個值從 0 變成 1 。
返回僅包含 1 的最長(連續)子數組的長度。
示例 1:
輸入:A = [1,1,1,0,0,0,1,1,1,1,0], K = 2
輸出:6
解釋:
[1,1,1,0,0,1,1,1,1,1,1]
粗體數字從 0 翻轉到 1,最長的子數組長度為 6。
示例 2:
輸入:A = [0,0,1,1,0,0,1,1,1,0,1,1,0,0,0,1,1,1,1], K = 3
輸出:10
解釋:
[0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1]
粗體數字從 0 翻轉到 1,最長的子數組長度為 10。
提示:
1 <= A.length <= 20000
0 <= K <= A.length
A[i]
為0
或1
class Solution {
public int longestOnes(int[] A, int K) {
int res = 0;
for (int i = 0; i < A.length; i++) {
if (i > 0 && A[i-1] == 1) continue; //前一個是1,這個點肯定統計過了
if (i + K < A.length && A[i] == 0 && A[i+K] == 0) continue; //K步之內到不了1或者最后一位,沒必要算
int chance = K;
int j = i;
for (; j < A.length; j++) {
if (A[j] != 1) {
if (chance == 0) break;
chance--;
}
}
res = Math.max(res,j-i);
}
return res;
}
}
19. 刪除鏈表的倒數第N個節點
中等
給定一個鏈表,刪除鏈表的倒數第 n 個節點,並且返回鏈表的頭結點。
示例:
給定一個鏈表: 1->2->3->4->5, 和 n = 2.
當刪除了倒數第二個節點后,鏈表變為 1->2->3->5.
說明:
給定的 n 保證是有效的。
進階:
你能嘗試使用一趟掃描實現嗎?
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode first = head;
ListNode second = head;
while (n-->0) first = first.next;
if (first == null)
return head.next; //n是鏈表長度,刪掉頭結點
while (first.next != null){
first = first.next;
second = second.next;
}
ListNode p = second.next.next;
second.next = p;
return head;
}
}
76. 最小覆蓋子串
困難
給你一個字符串 S、一個字符串 T,請在字符串 S 里面找出:包含 T 所有字符的最小子串。
示例:
輸入: S = "ADOBECODEBANC", T = "ABC"
輸出: "BANC"
說明:
- 如果 S 中不存這樣的子串,則返回空字符串
""
。 - 如果 S 中存在這樣的子串,我們保證它是唯一的答案
class Solution {
public static String minWindow(String s, String t) {
int[] map = new int[256]; //char 256個
char[] tchars = t.toCharArray();
for (int i = 0; i < tchars.length; i++)
map[tchars[i]]++; //模擬的字典
int l = 0;
int r = -1;
char[] chars = s.toCharArray();
int begin = -1,end = chars.length; //結果的兩頭坐標
while (l < chars.length && r < chars.length){ //O(S)
boolean flag = true; //判斷是否都出現全了
for (char tchar : tchars) { //O(T)
if (map[tchar] > 0){ // 有一個大於0就不行,說明差東西
flag = false;
break;
}
}
if (flag){
if (end - begin > r - l){
begin = l;
end = r;
}
map[chars[l]]++;
l++;
}else {
if (++r >= chars.length) break;
map[chars[r]]--;
}
}
return begin == -1 ? "" : s.substring(begin,end+1);
}
}
838. 推多米諾
中等
一行中有 N
張多米諾骨牌,我們將每張多米諾骨牌垂直豎立。
在開始時,我們同時把一些多米諾骨牌向左或向右推。
每過一秒,倒向左邊的多米諾骨牌會推動其左側相鄰的多米諾骨牌。
同樣地,倒向右邊的多米諾骨牌也會推動豎立在其右側的相鄰多米諾骨牌。
如果同時有多米諾骨牌落在一張垂直豎立的多米諾骨牌的兩邊,由於受力平衡, 該骨牌仍然保持不變。
就這個問題而言,我們會認為正在下降的多米諾骨牌不會對其它正在下降或已經下降的多米諾骨牌施加額外的力。
給定表示初始狀態的字符串 "S" 。如果第 i 張多米諾骨牌被推向左邊,則 S[i] = 'L'
;如果第 i 張多米諾骨牌被推向右邊,則 S[i] = 'R'
;如果第 i 張多米諾骨牌沒有被推動,則 S[i] = '.'
。
返回表示最終狀態的字符串。
示例 1:
輸入:".L.R...LR..L.."
輸出:"LL.RR.LLRRLL.."
示例 2:
輸入:"RR.L"
輸出:"RR.L"
說明:第一張多米諾骨牌沒有給第二張施加額外的力。
提示:
0 <= N <= 10^5
- 表示多米諾骨牌狀態的字符串只含有
'L'
,'R'
; 以及'.'
;
class Solution {
public String pushDominoes(String dominoes) {
StringBuilder sb = new StringBuilder();
char[] chars = dominoes.toCharArray();
int len = chars.length;
double[] d1 = new double[len];
double[] d2 = new double[len];
for (int i = 0; i < len; i++) {
if (chars[i] == 'L'){
d1[i] = -1;
}else if (chars[i] == 'R'){
d1[i] = 1;
}else {
if (i == 0) d1[i] = 0;
else d1[i] = d1[i-1] > 0 ? d1[i-1] / 2 : 0;
//離得越遠,影響越小,所以減半
}
}
for (int i = len - 1; i >= 0; i--) {
if (chars[i] == 'L'){
d2[i] = -1;
}else if (chars[i] == 'R'){
d2[i] = 1;
}else {
if (i == len-1) d2[i] = 0;
else d2[i] = d2[i+1] <0 ? d2[i+1] / 2 : 0;
}
}
for (int i = 0; i < len; i++) {
if (d1[i] + d2[i] > 0){
sb.append('R');
}else if (d1[i] + d2[i] < 0){
sb.append('L');
}else {
sb.append('.');
}
}
return sb.toString();
}
}