Blogz

The subtitle of your website

0%

LeetCode 05 最长回文子串


题目:
给你一个字符串 s,找到 s 中最长的回文子串。

示例 1:

输入:s = "babad"
输出:"bab"
解释:"aba" 同样是符合题意的答案。
示例 2:

输入:s = "cbbd"
输出:"bb"
 

提示:

1 <= s.length <= 1000
s 仅由数字和英文字母组成
通过次数1,194,472提交次数3,217,315

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/longest-palindromic-substring
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

题解:
首先理解回文字符串,根据长度可分为两种:
长度为偶数的回文串,例:abba
长度为奇数的回文串,例:aba
那么我们可以这样理解,
如果是奇数回文串,可从中间位置依次往两边扫描,每次扫描左右位置字符相等
如果是偶数回文串,从中间两个位置依次两边扫描,每次扫描左右位置字符相等
每次扫描到最长位置后记录长度,取最大长度的回文串返回即可

图解:
过程如下图示: (橙色代表遍历奇数回文串位置,橙色和青色一起代表遍历偶数回文串位置)
aeceece
最长为 "a"
aeceece
最长为 "e"
aeceece
最长为 "ece"
aeceece
最长为 "e"
aeceece
最长为 "eceece"
aeceece
最长为 "e"
aeceece
最长为 "ece"
aeceece
最长为 "e"

因此返回最长回文串为 "eceece"

代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public String longestPalindrome(String s) {
if (s.length() == 0 || s.length() == 1) return s;
char[] chars = s.toCharArray();
String maxString = String.valueOf(chars[0]);
for (int i = 0; i < chars.length; i++) {
int n = 0;
int len = 1;
while (i - n - 1 >= 0 && i + n + 1 < chars.length && chars[i - n - 1] == chars[i + n + 1]) {
n++;
len += 2;
}
if (len > maxString.length()) {
maxString = s.substring(i - n, i + n + 1);
}
if (i + 1 < chars.length && chars[i] == chars[i + 1]) {
n = 0;
len = 2;
while (i - n - 1 >= 0 && i + 1 + n + 1 < chars.length && chars[i - n - 1] == chars[i + 1 + n + 1]) {
n++;
len += 2;
}
if (len > maxString.length()) {
maxString = s.substring(i - n, i + 1 + n + 1);
}
}
}
return maxString;
}

LeetCode 06 Z字型变换


题目:
将一个给定字符串 s 根据给定的行数 numRows ,以从上往下、从左到右进行 Z 字形排列。

比如输入字符串为 "PAYPALISHIRING" 行数为 3 时,排列如下:

P   A   H   N
A P L S I I G
Y   I   R
之后,你的输出需要从左往右逐行读取,产生出一个新的字符串,比如:"PAHNAPLSIIGYIR"。

请你实现这个将字符串进行指定行数变换的函数:

string convert(string s, int numRows);
 

示例 1:

输入:s = "PAYPALISHIRING", numRows = 3
输出:"PAHNAPLSIIGYIR"
示例 2:
输入:s = "PAYPALISHIRING", numRows = 4
输出:"PINALSIGYAHRPI"
解释:
P     I    N
A   L S  I G
Y A   H R
P     I
示例 3:

输入:s = "A", numRows = 1
输出:"A"
 

提示:

1 <= s.length <= 1000
s 由英文字母(小写和大写)、',' 和 '.' 组成
1 <= numRows <= 1000

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/zigzag-conversion
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

题解:
此题难点在于找规律,Z子型变化有以下规律
首先我们设总行数为 n,当前行为r, 字符数组为chars
设临时变量步长 step = (n-1)*2
规律如下表所示:
行数
0 step step*2 step*3...
rr+step-r*2r+stepr+step*2-r*2r+step*2r+step*3-r*2r+step*3...
n-1 n-1+step n-1+step*2 n-1+step*3...
后续只需按照规律遍历拼接即可得到新字符串

代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public String convert(String s, int numRows) {
if (numRows <= 1) return s;
char[] chars = s.toCharArray();
StringBuilder result = new StringBuilder();
int step = (numRows - 1) * 2;
for (int r = 0; r < numRows; r++) {
for (int i = 0; i < chars.length; i += step) {
int colum = i + r;
if (colum < chars.length) {
result.append(chars[colum]);
}
int offset = step - r * 2;
if (offset > 0 && offset < step && offset + colum < chars.length) {
result.append(chars[offset + colum]);
}
}
}
return result.toString();
}

LeetCode 04 寻找两个正序数组的中位数


题目:
给定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的 中位数 。
算法的时间复杂度应该为 O(log (m+n)) 。

示例 1:

输入:nums1 = [1,3], nums2 = [2]
输出:2.00000
解释:合并数组 = [1,2,3] ,中位数 2

示例 2:

输入:nums1 = [1,2], nums2 = [3,4]
输出:2.50000
解释:合并数组 = [1,2,3,4] ,中位数 (2 + 3) / 2 = 2.5
 
提示:

nums1.length == m
nums2.length == n
0 <= m <= 1000
0 <= n <= 1000
1 <= m + n <= 2000
-106 <= nums1[i], nums2[i] <= 106
通过次数806,656提交次数1,940,252

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/median-of-two-sorted-arrays
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

题解:
首先计算两数组总长度的中位置 (Len1+Len2)/2
如果总长度为偶数则取中位置两数求均值,如果是奇数直接返回中位置值
双指针从小到大开始遍历两数组,并且把每次遍历的值存在长度为2的临时数组nums
用一个指针指向临时数组后存入的数据等待替换新数据,每次存入后交替

图解:
过程如下图示: ( nums1=[1,2,3] nums2=[3,4,5] 中位置Center=2,3)
1 2 3
3 4 5
如果两数组都没遍历到边界,则比较大小,小指针向前移动,计数 Count,临时数组存储数据
1 2 3
3 4 5
count nums[0] nums[1] 临时数组下标
1 1 0 0

1 2 3
3 4 5
count nums[0] nums[1] 临时数组下标
2 1 2 1

1 2 3
3 4 5
count nums[0] nums[1] 临时数组下标
3 3 2 0

1 2 3
3 4 5
count nums[0] nums[1] 临时数组下标
4 3 3 1
遍历结束,总数6个数,取第3和第4个数求平均值返回,即 (nums[0]+nums[1])/2 = 3

代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
int len = nums1.length + nums2.length;
int center = len / 2;
boolean isOdd = (len % 2 == 1);
int[] nums = new int[2];
int cur = 0;
int p1 = 0;
int p2 = 0;
int count = 0;
while (true) {
if (p1 < nums1.length && p2 < nums2.length) {
if (nums1[p1] <= nums2[p2]) {
nums[cur] = nums1[p1++];
} else {
nums[cur] = nums2[p2++];
}
} else if (p1 < nums1.length) {
nums[cur] = nums1[p1++];
} else {
nums[cur] = nums2[p2++];
}
if (count++ == center) break;
cur = cur == 1 ? 0 : 1;
}
if (isOdd) {
return nums[cur];
}
return (nums[0] + nums[1]) / 2f;
}

LeetCode 02 两数相加


题目:
给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。
请你将两个数相加,并以相同形式返回一个表示和的链表
你可以假设除了数字 0 之外,这两个数都不会以 0 开头。

示例 1:

输入:l1 = [2,4,3], l2 = [5,6,4]
输出:[7,0,8]
解释:342 + 465 = 807.
示例 2:

输入:l1 = [0], l2 = [0]
输出:[0]
示例 3:

输入:l1 = [9,9,9,9,9,9,9], l2 = [9,9,9,9]
输出:[8,9,9,9,0,0,0,1]

提示:

每个链表中的节点数在范围 [1, 100] 内
0 <= Node.val <= 9
题目数据保证列表表示的数字不含前导零
通过次数1,496,165提交次数3,553,682

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/add-two-numbers
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

题解:
思路很简单,不需要额外空间,直接以两链表中一个作为结果的存储,最终返回即可
由于是逆序,就按照加法的方式按位相加,用一个临时变量存储进位即可

图解:

⬇(remain = 0)
3 -> 5 -> 7 -> null 
2 -> 6 -> 9 -> null 
 3+2+remain=5 得5进0
         ⬇(remain = 0)
5 -> 5 -> 7 -> null 
 2 -> 6 -> 9 -> null 
 5+6+remain=11 得1进1
                 ⬇(remain = 1)
5 -> 1 -> 7 -> null 
 2 -> 6 -> 9 -> null 
 7+9+remain=17 得7进1
                        ⬇(remain = 1)
5 -> 1 -> 7 -> null 
 2 -> 6 -> 9 -> null 
 0+0+remain=1 得1进0

 达到链表末尾则补一个节点表示进位即可
5 -> 1 -> 7 -> 1 -> null

代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
ListNode p1 = new ListNode(0);
p1.next = l1;
ListNode p2 = new ListNode(0);
p2.next = l2;
int remain = 0;
do {
p1 = p1.next;
int added = p1.val + remain;
if (p2.next != null) {
p2 = p2.next;
added += p2.val;
}
remain = added / 10;
p1.val = added % 10;

if (p1.next == null && p2.next != null) {
p1.next = p2.next;
p2.next = null;
} else if (p1.next == null) {
if (remain > 0) p1.next = new ListNode(remain);
break;
}
} while (true);
return l1;
}

LeetCode 03 无重复字符的最长子串


题目:
给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。

示例 1:

输入: s = "abcabcbb"
输出: 3 
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
示例 2:

输入: s = "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
示例 3:

输入: s = "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
     请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。

提示:

0 <= s.length <= 5 * 104
s 由英文字母、数字、符号和空格组成
通过次数1,978,441提交次数5,071,972

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/longest-substring-without-repeating-characters
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

图解:
从字符串头开始遍历,记录S
a b c d e c f g h
a没有重复,记录并且继续,此时 S=a
a b c d e c f g h
b没有重复,记录并且继续,此时 S=ab
... 
a b c d e c f g h
由于S=abcde,已经存在c,则记录此次字串长度为5,此时从已经存在的c处的下一位置重新记录,S清空
a b c d e c f g h
d没有重复,记录并且继续,此时 S=d
    ...
a b c d e c f g h
h没有重复,记录并且继续,此时 S=decfgh,结束,长度为6,与上一次计算的长度取最大值返回,因此返回6

代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public int lengthOfLongestSubstring(String s) {
if (s == null || s.length() == 0) return 0;
if (s.length() == 1) return 1;
char [] chars= s.toCharArray();
int start = 0;
int end = 1;
int maxLength = 1;
int curLength = 1;
while(end<chars.length){
for (int i = start; i < end; i++) {
if (chars[end] == chars[i]) {
maxLength = Math.max(curLength, maxLength);
start = i + 1;
curLength = end -start;
if(chars.length - start < maxLength){
return maxLength;
}
break;
}
}
curLength++;
end++;
}
return Math.max(maxLength,curLength);
}

排序算法 - 堆排序


思路

动图演示

代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public void sort(int[] arr) {
int len = arr.length;
int step = len/2;
while (step > 0) {
for (int i = 0; i < step; i++) {
for (int j = i + step; j < len; j += step) {
int n = j;
while (n - step >= 0) {
if (arr[n] >= arr[n - step]) break;
int temp = arr[n];
arr[n] = arr[n - step];
arr[n - step] = temp;
n -= step;
}
}
}
step /= 2;
}
}

LeetCode 01 两数之和


题目:
给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target  的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。

示例 1:

输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。
示例 2:

输入:nums = [3,2,4], target = 6
输出:[1,2]
示例 3:

输入:nums = [3,3], target = 6
输出:[0,1]


提示:

2 <= nums.length <= 104
-109 <= nums[i] <= 109
-109 <= target <= 109
只会存在一个有效答案
进阶:你可以想出一个时间复杂度小于 O(n2) 的算法吗?

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/two-sum
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

题解:

解法 1 循环遍历判断
代码很简单,不解释直接上代码

1
2
3
4
5
6
7
8
public int[] twoSum0(int[] nums, int target) {
for (int i = 0; i < nums.length; i++) {
for (int j = i + 1; j < nums.length; j++) {
if (nums[i] + nums[j] == target) return new int[]{i, j};
}
}
return new int[]{};
}

解法 2 在上一步循环的基础上加个缓存记录遍历过的结果
代码也比较简单,不解释直接上代码

1
2
3
4
5
6
7
8
9
10
11
12
public int[] twoSum(int[] nums, int target) {
Map<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
int remain = target - nums[i];
Integer num = map.get(remain);
if (num != null) {
return new int[]{i, num};
}
map.put(nums[i], i);
}
return null;
}

排序算法 - 冒泡排序


思路

动图演示

代码
1
2
3
4
5
6
7
8
9
10
11
public void sort(int[] arr) {
for (int i = arr.length - 1; i > 0; i--) {
for (int j = 0; j < i; j++) {
if (arr[j] > arr[j + 1]) {
arr[j] = arr[j] ^ arr[j + 1];
arr[j + 1] = arr[j] ^ arr[j + 1];
arr[j] = arr[j] ^ arr[j + 1];
}
}
}
}

排序算法 - 插入排序


思路

动图演示

代码
1
2
3
4
5
6
7
8
9
10
11
public void sort(int[] arr) {
for (int i = 1; i < arr.length; i++) {
for (int j = i; j > 0; j--) {
if (arr[j] < arr[j - 1]) {
swap(arr, j, j - 1);
} else {
break;
}
}
}
}

排序算法 - 选择排序


思路

动图演示

代码
1
2
3
4
5
6
7
8
9
public void sort(int[] arr) {
for (int i = 0; i < arr.length; i++) {
int n = i;
for (int j = i; j < arr.length; j++) {
if (arr[j] < arr[n]) n = j;
}
swap(arr, i, n);
}
}