#yyds干货盘点# LeetCode刷题集:1-10

2021年11月24日 阅读数:5
这篇文章主要向大家介绍#yyds干货盘点# LeetCode刷题集:1-10,主要内容包括基础应用、实用技巧、原理机制等方面,希望对大家有所帮助。

博主私藏的LeetCode刷题集合git

有些较难的问题都有思路和注释正则表达式

2. 两数相加

给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,而且它们的每一个节点只能存储 一位 数字。 若是,咱们将这两个数相加起来,则会返回一个新的链表来表示它们的和。 您能够假设除了数字 0 以外,这两个数都不会以 0 开头。 示例: 输入:(2 -> 4 -> 3) + (5 -> 6 -> 4) 输出:7 -> 0 -> 8 缘由:342 + 465 = 807 来源:力扣(LeetCode) 连接:https://leetcode-cn.com/problems/add-two-numbers 著做权归领扣网络全部。商业转载请联系官方受权,非商业转载请注明出处。算法

/**

* 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) {

if(l2 == null) {

return l1;

}else if(l1 == null && l2 != null){

return l2;
}else {
l1.val = l1.val+l2.val;
jinwei(l1);

l1.next = addTwoNumbers(l1.next,l2.next);
return l1;

}

}

public void jinwei(ListNode l1) {

if(l1.val>9) {
if(l1.next == null){

l1.next = new ListNode(l1.val/10);

}else{

l1.next.val += l1.val/10;

jinwei(l1.next);

}

l1.val %= 10;

}

}

}

4. 寻找两个有序数组的中位数

给定两个大小为 m 和 n 的有序数组 nums1 和 nums2。 请你找出这两个有序数组的中位数,而且要求算法的时间复杂度为 O(log(m + n))。 你能够假设 nums1 和 nums2 不会同时为空。 示例 1: nums1 = [1, 3] nums2 = [2] 则中位数是 2.0 示例 2: nums1 = [1, 2] nums2 = [3, 4] 则中位数是 (2 + 3)/2 = 2.5 来源:力扣(LeetCode) 连接:https://leetcode-cn.com/problems/median-of-two-sorted-arrays 著做权归领扣网络全部。商业转载请联系官方受权,非商业转载请注明出处。 PS: 这道题让咱们求两个有序数组的中位数,并且限制了时间复杂度为O(log (m+n)),看到这个时间复杂度,天然而然的想到了应该使用二分查找法来求解。那么回顾一下中位数的定义,若是某个有序数组长度是奇数,那么其中位数就是最中间那个,若是是偶数,那么就是最中间两个数字的平均值。这里对于两个有序数组也是同样的,假设两个有序数组的长度分别为m和n,因为两个数组长度之和 m+n 的奇偶不肯定,所以须要分状况来讨论,对于奇数的状况,直接找到最中间的数便可,偶数的话须要求最中间两个数的平均值。为了简化代码,不分状况讨论,咱们使用一个小trick,咱们分别找第 (m+n+1) / 2 个,和 (m+n+2) / 2 个,而后求其平均值便可,这对奇偶数均适用。加入 m+n 为奇数的话,那么其实 (m+n+1) / 2 和 (m+n+2) / 2 的值相等,至关于两个相同的数字相加再除以2,仍是其自己。 这里咱们须要定义一个函数来在两个有序数组中找到第K个元素,下面重点来看如何实现找到第K个元素。首先,为了不产生新的数组从而增长时间复杂度,咱们使用两个变量i和j分别来标记数组nums1和nums2的起始位置。而后来处理一些边界问题,好比当某一个数组的起始位置大于等于其数组长度时,说明其全部数字均已经被淘汰了,至关于一个空数组了,那么实际上就变成了在另外一个数组中找数字,直接就能够找出来了。还有就是若是K=1的话,那么咱们只要比较nums1和nums2的起始位置i和j上的数字就能够了。难点就在于通常的状况怎么处理?由于咱们须要在两个有序数组中找到第K个元素,为了加快搜索的速度,咱们要使用二分法,对K二分,意思是咱们须要分别在nums1和nums2中查找第K/2个元素,注意这里因为两个数组的长度不定,因此有可能某个数组没有第K/2个数字,因此咱们须要先检查一下,数组中到底存不存在第K/2个数字,若是存在就取出来,不然就赋值上一个整型最大值。若是某个数组没有第K/2个数字,那么咱们就淘汰另外一个数字的前K/2个数字便可。有没有可能两个数组都不存在第K/2个数字呢,这道题里是不可能的,由于咱们的K不是任意给的,而是给的m+n的中间值,因此一定至少会有一个数组是存在第K/2个数字的。最后就是二分法的核心啦,比较这两个数组的第K/2小的数字midVal1和midVal2的大小,若是第一个数组的第K/2个数字小的话,那么说明咱们要找的数字确定不在nums1中的前K/2个数字,因此咱们能够将其淘汰,将nums1的起始位置向后移动K/2个,而且此时的K也自减去K/2,调用递归。反之,咱们淘汰nums2中的前K/2个数字,并将nums2的起始位置向后移动K/2个,而且此时的K也自减去K/2,调用递归便可。 ——一位大佬留下的(奥里给!!!)express

class Solution {

public double findMedianSortedArrays(int[] nums1, int[] nums2) {

int m = nums1.length;

int n = nums2.length;

int left = (m + n + 1) / 2;

int right = (m + n + 2) / 2;

return (findKth(nums1, 0, nums2, 0, left) + findKth(nums1, 0, nums2, 0, right)) / 2.0;

}

//i: nums1的起始位置 j: nums2的起始位置

public int findKth(int[] nums1, int i, int[] nums2, int j, int k){

if( i >= nums1.length) return nums2[j + k - 1];//nums1为空数组

if( j >= nums2.length) return nums1[i + k - 1];//nums2为空数组

if(k == 1){

return Math.min(nums1[i], nums2[j]);

}

int midVal1 = (i + k / 2 - 1 < nums1.length) ? nums1[i + k / 2 - 1] : Integer.MAX_VALUE;

int midVal2 = (j + k / 2 - 1 < nums2.length) ? nums2[j + k / 2 - 1] : Integer.MAX_VALUE;

if(midVal1 < midVal2){

return findKth(nums1, i + k / 2, nums2, j , k - k / 2);

}else{

return findKth(nums1, i, nums2, j + k / 2 , k - k / 2);

}

}

}

5. 最长回文子串

给定一个字符串 s,找到 s 中最长的回文子串。你能够假设 s 的最大长度为 1000。 示例 1: 输入: "babad" 输出: "bab" 注意: "aba" 也是一个有效答案。 示例 2: 输入: "cbbd" 输出: "bb" 来源:力扣(LeetCode) 连接:https://leetcode-cn.com/problems/longest-palindromic-substring 著做权归领扣网络全部。商业转载请联系官方受权,非商业转载请注明出处。数组

class Solution {

public String longestPalindrome(String s) {

if (s == null || s.length() == 0) {

return "";

}

// 保存起始位置,测试了用数组彷佛能比全局变量稍快一点

int[] range = new int[2];

char[] str = s.toCharArray();

for (int i = 0; i < s.length(); i++) {

// 把回文当作中间的部分全是同一字符,左右部分相对称

// 找到下一个与当前字符不一样的字符

i = findLongest(str, i, range);

}

return s.substring(range[0], range[1] + 1);

}



public static int findLongest(char[] str, int low, int[] range) {

// 查找中间部分 防止abbba

int high = low;

while (high < str.length - 1 && str[high + 1] == str[low]) {

high++;

}

// 定位中间部分的最后一个字符

int ans = high;

// 从中间向左右扩散

while (low > 0 && high < str.length - 1 && str[low - 1] == str[high + 1]) {

low--;

high++;

}

// 记录最大长度

if (high - low > range[1] - range[0]) {

range[0] = low;

range[1] = high;

}

return ans;

}

}

6. Z 字形变换

将一个给定字符串根据给定的行数,以从上往下、从左到右进行 Z 字形排列。 好比输入字符串为 "LEETCODEISHIRING" 行数为 3 时,排列以下: L C I R E T O E S I I G E D H N 以后,你的输出须要从左往右逐行读取,产生出一个新的字符串,好比:"LCIRETOESIIGEDHN"。 请你实现这个将字符串进行指定行数变换的函数: string convert(string s, int numRows); 示例 1: 输入: s = "LEETCODEISHIRING", numRows = 3 输出: "LCIRETOESIIGEDHN" 示例 2: 输入: s = "LEETCODEISHIRING", numRows = 4 输出: "LDREOEIIECIHNTSG" 解释: L D R E O E I I E C I H N T S G 来源:力扣(LeetCode) 连接:https://leetcode-cn.com/problems/zigzag-conversion 著做权归领扣网络全部。商业转载请联系官方受权,非商业转载请注明出处。 PS: 这里我采用的是记下标进行存储网络

class Solution {

public String convert(String s, int numRows) {



if(numRows == 1) return s;

int[] rowIdx = new int[numRows];

char[] chars = new char[s.length()];

int n = 0;

int burketSize = numRows * 2 - 2;

int burketNum = chars.length / burketSize;
int rem = chars.length % burketSize;

for(int i = 1; i < numRows; i ++){

int flag = i == 1 ? 1 : 2;

n = flag * burketNum + (rem >= i ? ( 1 + (burketSize - rem + 1 < i ? 1 : 0)) : 0);

rowIdx[i] = rowIdx[i-1] + n;

}

int flag = -1;

int curRow = 0;

for(char c : s.toCharArray()){

chars[rowIdx[curRow]] = c;

rowIdx[curRow] = rowIdx[curRow] + 1;

if (curRow == 0 || curRow == numRows - 1) flag = -flag;

curRow += flag;

}

return new String(chars);

}

}

7. 整数反转

给出一个 32 位的有符号整数,你须要将这个整数中每位上的数字进行反转。 示例 1: 输入: 123 输出: 321 示例 2: 输入: -123 输出: -321 示例 3: 输入: 120 输出: 21 注意: 假设咱们的环境只能存储得下 32 位的有符号整数,则其数值范围为 [−231, 231 − 1]。请根据这个假设,若是反转后整数溢出那么就返回 0。 来源:力扣(LeetCode) 连接:https://leetcode-cn.com/problems/reverse-integer 著做权归领扣网络全部。商业转载请联系官方受权,非商业转载请注明出处。ide

class Solution {

public int reverse(int x) {

int max = Integer.MAX_VALUE, min = Integer.MIN_VALUE;//int的最大值最小值

long rs = 0;//用long类型判断溢出

for(;x!=0;rs = rs*10+x%10,x/=10);//逆序,正负通吃,不用单独考虑负值

return Integer.valueOf(( rsmax?0:rs)+"");//超了最大值低于最小值就返回0

}

}

8. 字符串转换整数 (atoi)

请你来实现一个 atoi 函数,使其能将字符串转换成整数。 首先,该函数会根据须要丢弃无用的开头空格字符,直到寻找到第一个非空格的字符为止。 当咱们寻找到的第一个非空字符为正或者负号时,则将该符号与以后面尽量多的连续数字组合起来,做为该整数的正负号;假如第一个非空字符是数字,则直接将其与以后连续的数字字符组合起来,造成整数。 该字符串除了有效的整数部分以后也可能会存在多余的字符,这些字符能够被忽略,它们对于函数不该该形成影响。 注意:假如该字符串中的第一个非空格字符不是一个有效整数字符、字符串为空或字符串仅包含空白字符时,则你的函数不须要进行转换。 在任何状况下,若函数不能进行有效的转换时,请返回 0。 说明: 假设咱们的环境只能存储 32 位大小的有符号整数,那么其数值范围为 [−231, 231 − 1]。若是数值超过这个范围,请返回 INT_MAX (231 − 1) 或 INT_MIN (−231) 。 示例 1: 输入: "42" 输出: 42 示例 2: 输入: " -42" 输出: -42 解释: 第一个非空白字符为 '-', 它是一个负号。 咱们尽量将负号与后面全部连续出现的数字组合起来,最后获得 -42 。 示例 3: 输入: "4193 with words" 输出: 4193 解释: 转换截止于数字 '3' ,由于它的下一个字符不为数字。 示例 4: 输入: "words and 987" 输出: 0 解释: 第一个非空字符是 'w', 但它不是数字或正、负号。 所以没法执行有效的转换。 示例 5: 输入: "-91283472332" 输出: -2147483648 解释: 数字 "-91283472332" 超过 32 位有符号整数范围。 所以返回 INT_MIN (−231) 。 来源:力扣(LeetCode) 连接:https://leetcode-cn.com/problems/string-to-integer-atoi 著做权归领扣网络全部。商业转载请联系官方受权,非商业转载请注明出处。函数

class Solution {

public int myAtoi(String str) {

str = str.trim();

if (str == null || str.length() == 0) return 0;



// + - 号

char firstChar = str.charAt(0);

int sign = 1;

int start = 0;

long res = 0;

if (firstChar == '+') {

sign = 1;

start++;

} else if (firstChar == '-') {

sign = -1;

start++;

}



for (int i = start; i < str.length(); i++) {

if (!Character.isDigit(str.charAt(i))) {

return (int) res * sign;

}

res = res * 10 + str.charAt(i) - '0';

if (sign == 1 && res > Integer.MAX_VALUE) return Integer.MAX_VALUE;

if (sign == -1 && res > Integer.MAX_VALUE) return Integer.MIN_VALUE;

}

return (int) res * sign;

}

}

9. 回文数

判断一个整数是不是回文数。回文数是指正序(从左向右)和倒序(从右向左)读都是同样的整数。 示例 1: 输入: 121 输出: true 示例 2: 输入: -121 输出: false 解释: 从左向右读, 为 -121 。 从右向左读, 为 121- 。所以它不是一个回文数。 示例 3: 输入: 10 输出: false 解释: 从右向左读, 为 01 。所以它不是一个回文数。 进阶: 你能不将整数转为字符串来解决这个问题吗? 来源:力扣(LeetCode) 连接:https://leetcode-cn.com/problems/palindrome-number 著做权归领扣网络全部。商业转载请联系官方受权,非商业转载请注明出处。 PS:两种方法,一种转换成StringBuilder,另外一种使用整数类型进行处理测试

class Solution {

public boolean isPalindrome(int x) {

// String reverseNumber = new StringBuilder(String.valueOf(x)).reverse().toString();

// return reverseNumber.equals(String.valueOf(x));



if(x<0)

return false;

int rem=0,y=0;

int quo=x;

while(quo!=0){

rem=quo%10;

y=y*10+rem;

quo=quo/10;

}

return y==x;

}

}

10. 正则表达式匹配

给你一个字符串 s 和一个字符规律 p,请你来实现一个支持 '.' 和 '*' 的正则表达式匹配。 '.' 匹配任意单个字符 '*' 匹配零个或多个前面的那一个元素 所谓匹配,是要涵盖 整个 字符串 s的,而不是部分字符串。 说明: s 可能为空,且只包含从 a-z 的小写字母。 p 可能为空,且只包含从 a-z 的小写字母,以及字符 . 和 *。 示例 1: 输入: s = "aa" p = "a" 输出: false 解释: "a" 没法匹配 "aa" 整个字符串。 示例 2: 输入: s = "aa" p = "a*" 输出: true 解释: 由于 '*' 表明能够匹配零个或多个前面的那一个元素, 在这里前面的元素就是 'a'。所以,字符串 "aa" 可被视为 'a' 重复了一次。 示例 3: 输入: s = "ab" p = ".*" 输出: true 解释: ".*" 表示可匹配零个或多个('*')任意字符('.')。 示例 4: 输入: s = "aab" p = "c*a*b" 输出: true 解释: 由于 '*' 表示零个或多个,这里 'c' 为 0 个, 'a' 被重复一次。所以能够匹配字符串 "aab"。 示例 5: 输入: s = "mississippi" p = "mis*is*p*." 输出: false 来源:力扣(LeetCode) 连接:https://leetcode-cn.com/problems/regular-expression-matching 著做权归领扣网络全部。商业转载请联系官方受权,非商业转载请注明出处。ui

class Solution {

public boolean isMatch(String s, String p) {

int sLen = s.length(), pLen = p.length();

boolean[][] memory = new boolean[2][pLen+1];

memory[0][0] = true;

int cur = 0, pre = 0;

for(int i = 0; i <= sLen; i++) {

cur = i % 2;

pre = (i + 1) % 2;

if(i > 1) {

for(int j = 0; j <= pLen; j++) {

memory[cur][j] = false;

}

}

for(int j = 1; j <= pLen; j++) {

if(p.charAt(j-1) == '*') {


memory[cur][j] = memory[cur][j-2] || (i > 0 && (s.charAt(i-1) == p.charAt(j-2) ||
p.charAt(j-2) == '.') && memory[pre][j]);

}else {

memory[cur][j] = i > 0 && (s.charAt(i-1) == p.charAt(j-1) || p.charAt(j-1) == '.')

&& memory[pre][j-1];

}

}

}

return memory[cur][pLen];



}

}