LeetCode1-9

本文更多是作为一个习题笔记,没有太多讲解

1、两数之和

题目请点击链接 ↑

最先想到暴力解法,直接双循环,但是这样复杂度为n平方

public int[] twoSum(int[] nums, int target) {
for (int i = nums.length - 1; i >= 0; i--) {
for (int j = 0; j < i; j++) {
if (nums[i] + nums[j] == target) {
int[] twoSum = new int[]{j, i};
return twoSum;
}
}
}
return null;
}

优化:将内层循环变更为HashMap,可以将复杂度降为n

Map<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
int complement = target - nums[i];
if (map.containsKey(complement)) {//Map把O(N)降为O(1)
return new int[] { map.get(complement), i };
}
map.put(nums[i], i);
}
throw new IllegalArgumentException("No two sum solution");

小结:HashMap可以降低搜索复杂度

2、两数相加

题目请点击链接 ↑

public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
ListNode ans = new ListNode(0);//哑结点
ListNode p1 = l1, p2 = l2, curr = ans;//使用p=p.next方式迭代时必须重新声明
int flag = 0;
while (p1 != null || p2 != null) {
int x = (p1 == null) ? 0 : p1.val;
int y = (p2 == null) ? 0 : p2.val;
int sum = x + y + flag;
flag = sum / 10;
curr.next = new ListNode(sum % 10);
curr = curr.next;
if (p1 != null) p1 = p1.next;//必须声明p1,p2,若直接使用l1,l2,这一步会修改l1、l1的引用
if (p2 != null) p2 = p2.next;
}
if (flag > 0) curr.next = new ListNode(flag);
return ans.next;

小结:刚开始一直在纠结怎么返回,看了下答案发现了哑结点这种用法,对链表运用不太熟练,还需练习。。。

3、无重复字符的最长子串

题目请点击链接 ↑

暴力双循环这太蠢了

static int lengthOfLongestSubstring(String s) {
char[] cs = s.toCharArray();
List<Character> al = new ArrayList<>();
int max = 0;
int num = 0;
for (int i = 0; i < cs.length; i++) {
for (int j = i; j < cs.length; j++) {
if (!al.contains(cs[j])) {
al.add(cs[j]);
num++;
max = (num > max) ? num : max;
} else {
break;
}
}
al.clear();
num = 0;
}
return max;
}

滑窗思想:

static int lengthOfLongestSubstring2(String s) {
char[] cs = s.toCharArray();
int n = cs.length;
Set<Character> set = new HashSet<>();
int ans = 0, i = 0, j = 0;
while (i < n && j < n) {
// 滑窗 [i, j]
if (!set.contains(cs[j])) {
set.add(cs[j++]);
ans = Math.max(ans, j - i);
} else {
set.remove(cs[i++]);
}
}
return ans;
}

优化的滑窗:

//优化的滑动窗口
static int lengthOfLongestSubstring3(String s) {
char[] cs = s.toCharArray();
int n = cs.length, ans = 0;
Map<Character, Integer> map = new HashMap<>(); // current index of character
// try to extend the range [i, j]
for (int j = 0, i = 0; j < n; j++) {
if (map.containsKey(cs[j])) {
i = Math.max(map.get(cs[j]), i);
}
ans = Math.max(ans, j - i + 1);
map.put(cs[j], j + 1);
}
return ans;
}

不看别人思路我估计是想不出来滑窗这种思想的,还得多练练。

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

//再看自己以前写的代码居然不能一眼看懂了???看了下提交记录战胜77%
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
double ans;
int[] sum = new int[nums1.length + nums2.length];
//暴力构建新数组
for (int i = 0, j = 0, k = 0; k < sum.length; k++) {
if (i < nums1.length && j < nums2.length) {
if (nums1[i] < nums2[j]) {
sum[k] = nums1[i];
i++;
} else {
sum[k] = nums2[j];
j++;
}
} else if (i >= nums1.length && j < nums2.length) {
sum[k] = nums2[j];
j++;
} else if (i < nums1.length && j >= nums2.length) {
sum[k] = nums1[i];
i++;
}
}
//求中位数
if (sum.length % 2 == 1) {
ans = (double) sum[(sum.length - 1) / 2];
} else {
ans = (double) (sum[sum.length / 2] + sum[(sum.length - 1) / 2]) / 2;
}
return ans;

看了下官方解题没看太明白,应该是利用了中位数的性质。

5、最长回文子串

题目请点击链接 ↑

……

最初解法
//现在看这个解法看恶心了……折叠折叠
public String longestPalindrome(String s) {
if (s.length() == 0) {
return "";
}
char[] cs = s.toCharArray();
int len = cs.length;
int m = 0, n = 0, max = 0, p = 0, q = 0;
int m1, n1, p1, q1;
for (int i = 0; i < len; i++) {
m1 = i - 1;
n1 = i + 1;
p1 = i;
q1 = i + 1;
while (m1 >= 0 && n1 >= 0 && m1 < len && n1 < len && cs[m1] == cs[n1]) {
m1--;
n1++;
}
while (p1 >= 0 && q1 >= 0 && p1 < len && q1 < len && cs[p1] == cs[q1]) {
p1--;
q1++;
}
if (n1 - m1 - 1 > max) {
max = n1 - m1 - 1;
m = m1 + 1;
n = n1 - 1;
}
if (q1 - p1 - 1 > max) {
max = q1 - p1 - 1;
p = p1 + 1;
q = q1 - 1;
}
}
String s1 = s.substring(m, n + 1);
String s2 = s.substring(p, q + 1);
return s1.length() > s2.length() ? s1 : s2;

这是我最初的解法,向两边扫描,一堆变量差点没把自己绕晕,看看官方的中心扩展,够简洁:

public String longestPalindrome(String s) {
if (s == null || s.length() < 1) return "";
int start = 0, end = 0;
for (int i = 0; i < s.length(); i++) {
int len1 = expandAroundCenter(s, i, i);
int len2 = expandAroundCenter(s, i, i + 1);
int len = Math.max(len1, len2);
if (len > end - start) {
start = i - (len - 1) / 2;
end = i + len / 2;
}
}
return s.substring(start, end + 1);
} private int expandAroundCenter(String s, int left, int right) {
int L = left, R = right;
while (L >= 0 && R < s.length() && s.charAt(L) == s.charAt(R)) {
L--;
R++;
}
return R - L - 1;
}

其实这个题是典型的动态规划,不过我的动态区划是弱点,接下来准备集中练习动态规划

6、Z字形变换

题目请点击链接 ↑

看到这一题我最先想到的是将改变后的字符串从右向左横着看,变换就是一串字符串挨个往4行里面放(设行为4),这样两边比中间的行字符少

public String convert(String s, int numRows) {
if (numRows == 1) return s;
StringBuilder sb = new StringBuilder();
char[] cs = s.toCharArray();
LinkedList[] lls = new LinkedList[numRows];
for (int i = 0; i < numRows; i++) {
lls[i] = new LinkedList<Character>();
}
int flag = 0, p = 0;
for (int i = 0; i < cs.length; i++) {
//flag=0表示从上往下挨个放,=1表示从下往上放
if (flag == 0) {
if (p < numRows - 1) {
lls[p++].add(cs[i]);
continue;
} else {
flag = 1;
lls[p--].add(cs[i]);
} } else {
if (p > 0) {
lls[p--].add(cs[i]);
continue;
} else {
flag = 0;
lls[p++].add(cs[i]);
} }
}
for (int i = 0; i < numRows; i++) {
while (lls[i].size() > 0)
sb.append(lls[i].removeFirst());
}
return sb.toString();
}

官方解法基本上也是这种思路:

public String convert(String s, int numRows) {

    if (numRows == 1) return s;

    List<StringBuilder> rows = new ArrayList<>();
for (int i = 0; i < Math.min(numRows, s.length()); i++)
rows.add(new StringBuilder()); int curRow = 0;
boolean goingDown = false; for (char c : s.toCharArray()) {
rows.get(curRow).append(c);
if (curRow == 0 || curRow == numRows - 1) goingDown = !goingDown;
curRow += goingDown ? 1 : -1;
} StringBuilder ret = new StringBuilder();
for (StringBuilder row : rows) ret.append(row);
return ret.toString();
}

通过当前行和当前下标进行追踪。

还有种思路是按行访问,也就是:

行 0 中的字符位于索引k(2⋅numRows−2) 处;

行 numRows−1 中的字符位于索引k(2⋅numRows−2)+numRows−1 处;

内部的 行 i 中的字符位于索引i(k+1)(2⋅numRows−2)−i 处;

道理是很简单,不过当时对每个字符的位置规律没怎么想,这个思路的难点就在找到每个字符的位置规律。下面贴代码

public String convert(String s, int numRows) {

    if (numRows == 1) return s;

    StringBuilder ret = new StringBuilder();
int n = s.length();
int cycleLen = 2 * numRows - 2; for (int i = 0; i < numRows; i++) {
for (int j = 0; j + i < n; j += cycleLen) {
ret.append(s.charAt(j + i));
if (i != 0 && i != numRows - 1 && j + cycleLen - i < n)
ret.append(s.charAt(j + cycleLen - i));
}
}
return ret.toString();
}

7、整数反转

题目请点击链接 ↑

对于这种反转题目最先想到就是变化为字符串,从官方解题思路下边的评论看大多数人也都是这样23333

public int reverse(int x) {
if (x < 10 && x > -10) {
return x;
} int ans;
boolean flag = false;
if (x < 0) {
x = -x;
flag = true;
}
StringBuilder sb = new StringBuilder(String.valueOf(x));
try {
ans = Integer.valueOf(sb.reverse().toString());
} catch (NumberFormatException e) {
return 0;
}
if (flag) ans = -ans;
return ans;
}

官方给的解法是从后往前取出原数组的每个数,然后构建新的数:

//pop operation:取出每位数
pop = x % 10;
x /= 10; //push operation:构建新数
temp = rev * 10 + pop;
rev = temp

不过构建新数是很容易溢出,官方给出了这样的解释:

public int reverse(int x) {
int rev = 0;
while (x != 0) {
int pop = x % 10;
x /= 10;
if (rev > Integer.MAX_VALUE/10 || (rev == Integer.MAX_VALUE / 10 && pop > 7)) return 0;
if (rev < Integer.MIN_VALUE/10 || (rev == Integer.MIN_VALUE / 10 && pop < -8)) return 0;
rev = rev * 10 + pop;
}
return rev;
}

还是觉得字符串更简单2333

8、字符串转整数

题目请点击链接 ↑

现在看到我当时的解法……emmm……这写的都是啥?完全暴力破解??连trim()方法都没用?判断字符不用char直接用ASCII码23333,没眼看了,折叠折叠。

丑陋的最初解法
public int myAtoi(String str) {
char[] cs = str.toCharArray();
StringBuilder sb = new StringBuilder();
double ans = 0;
boolean fir = true;
boolean posiOrNega = true;
boolean anotherFlag = true;
for (int i = 0; i < cs.length; i++) {
if (cs[i] == ' ' && fir == true) {
continue;
}
fir = false;
if (cs[i] == 43 && anotherFlag == true) {
posiOrNega = true;
anotherFlag = false;
continue;
} else if (cs[i] == 45 && anotherFlag == true) {
posiOrNega = false;
anotherFlag = false;
continue;
}
if (cs[i] >= 48 && cs[i] <= 57) {
sb.append(cs[i]);
anotherFlag = false;
continue;
}
break;
}
try {
ans = Double.valueOf(sb.toString());
if (posiOrNega)
return (ans > Integer.MAX_VALUE) ? Integer.MAX_VALUE : (int) ans;
else
return (-ans < Integer.MIN_VALUE) ? Integer.MIN_VALUE : (int) -ans;
} catch (NumberFormatException e) {
return 0;
}
}

┓( ´∀` )┏

有空还是仔细看看正则吧,像这种能用正则的……

看了下大佬们的解法,果然思路清晰了好多:

public int myAtoi(String str) {
//去除掉前后的空格
String strr = str.trim();
//存储最终过滤出来的字符串
String strrr = null;
//字符串不为空时并且字符串不全是空白字符串时才转换
if(strr != null && strr.isEmpty() == false){
char f = strr.charAt(0);
//判断字符串中的第一个非空格字符是不是一个有效整数字符
if(f >= '0' && f <= '9' || f == '+'|| f == '-'){
strrr = strr.substring(0,1); // 把第一位放进去(只能是数字、正负号)
//这时候循环只要数字,因为正负号只能出现在第一位
for(int i = 1; i<strr.length();i++){
if(strr.charAt(i) >= '0' && strr.charAt(i) <= '9'){
strrr = strr.substring(0,i+1);
}
//这是遇到不符合要求的字符,直接忽略剩余元素
else{break;}
}
}
}
//判断最终字符串是否为空或则只有一个正负号
if(strrr == null || strrr.equals("+") || strrr.equals("-"))
//此时strrr是String对象,如果使用==比较则比较的时内存地址
return 0;
//最终转换成的数字
int num = 0;
//使用异常机制打印结果
try{
num = Integer.parseInt(strrr);
}catch (Exception e){
if(strrr.charAt(0) == '-')
return Integer.MIN_VALUE;
return Integer.MAX_VALUE;
}
return num;
}

9、回文数

最开始的思路居然不是转化字符串反转再比较,而是转化数组再比较,居然战胜98.95%(原来是下边有要求不能将整数转化为字符串):

public boolean isPalindrome(int x) {
int count = 0;
int y = x;
boolean ans = false;
if (x < 0) {
return false;
} else if (x >= 0 && x < 10) {
return true;
} else {
while (y > 0) {
y = y / 10;
count++;
}
int[] ints = new int[count];
y = x;
for (int i = 0; i < ints.length; i++) {
ints[i] = y % 10;
y = y / 10;
}
for (int i = 0; i < count - i - 1; i++) {
int j = count - i - 1;
if (ints[i] == ints[j]) {
ans = true;
continue;
} else {
ans = false;
break;
}
}
return ans;
}
}

这里有一个讲解,对这题说的很清楚,这是链接


总结,作为一个菜鸟做LeetCode还是有点吃力的,接下来需要看看动态规划和正则,此文仅作为习题笔记而已。

LeetCode刷题笔记(1-9)的更多相关文章

  1. LeetCode刷题笔记和想法(C++)

    主要用于记录在LeetCode刷题的过程中学习到的一些思想和自己的想法,希望通过leetcode提升自己的编程素养 :p 高效leetcode刷题小诀窍(这只是目前对我自己而言的小方法,之后会根据自己 ...

  2. 18.9.10 LeetCode刷题笔记

    本人算法还是比较菜的,因此大部分在刷基础题,高手勿喷 选择Python进行刷题,因为坑少,所以不太想用CPP: 1.买股票的最佳时期2 给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格. ...

  3. LeetCode刷题笔记 - 12. 整数转罗马数字

    学好算法很重要,然后要学好算法,大量的练习是必不可少的,LeetCode是我经常去的一个刷题网站,上面的题目非常详细,各个标签的题目都有,可以整体练习,本公众号后续会带大家做一做上面的算法题. 官方链 ...

  4. Leetcode刷题笔记(双指针)

    1.何为双指针 双指针主要用来遍历数组,两个指针指向不同的元素,从而协同完成任务.我们也可以类比这个概念,推广到多个数组的多个指针. 若两个指针指向同一数组,遍历方向相同且不会相交,可以称之为滑动窗口 ...

  5. leetcode刷题笔记

    (1)Best Time to Buy and Sell Stock Total Accepted: 10430 Total Submissions: 33800My Submissions Say ...

  6. leetcode刷题笔记08 字符串转整数 (atoi)

    题目描述 实现 atoi,将字符串转为整数. 在找到第一个非空字符之前,需要移除掉字符串中的空格字符.如果第一个非空字符是正号或负号,选取该符号,并将其与后面尽可能多的连续的数字组合起来,这部分字符即 ...

  7. LeetCode刷题笔记-回溯法-分割回文串

    题目描述: 给定一个字符串 s,将 s 分割成一些子串,使每个子串都是回文串. 返回 s 所有可能的分割方案. 示例: 输入: "aab"输出:[ ["aa", ...

  8. leetcode刷题笔记231 2的幂

    题目描述: 给定一个整数,写一个函数来判断它是否是2的幂. 题目分析: 判断一个整数是不是2的幂,可根据二进制来分析.2的幂如2,4,8,等有一个特点: 二进制数首位为1,其他位为0,如2为10,4为 ...

  9. leetcode刷题笔记342 4的幂

    题目描述: 给定一个整数 (32位有符整数型),请写出一个函数来检验它是否是4的幂. 示例:当 num = 16 时 ,返回 true . 当 num = 5时,返回 false. 问题进阶:你能不使 ...

随机推荐

  1. Net Core3.1 添加 Swagger

    一.为什么使用Swagger 随着互联网技术的发展,现在的网站架构基本都由原来的后端渲染,变成了:前端渲染.后端分离的形态,而且前端技术和后端技术在各自的道路上越走越远. 前端和后端的唯一联系,变成了 ...

  2. Dubbo的配置过程,实现原理及架构详解

    一. Dubbo是什么?Dubbo能做什么? 随着互联网的发展,市场需求快速变更,业务持续高速增长,网站早已从单一应用架构演变为分布式服务架构及流动计算架构.在分布式架构的背景下,在本地调用非本进程内 ...

  3. jq插件和jq

    封装一个jq (function(win) { var jQuery = function(selecter) { this.version = '1.0.1'; //版本号 this.selecte ...

  4. Day6 - D - Tree 园丁的烦恼 HYSBZ - 1935

    很久很久以前,在遥远的大陆上有一个美丽的国家.统治着这个美丽国家的国王是一个园艺爱好者,在他的皇家花园里种植着各种奇花异草.有一天国王漫步在花园里,若有所思,他问一个园丁道: “最近我在思索一个问题, ...

  5. CentOS7 防火墙设置

    CentOS7 防火墙命令 最近在公司服务器上安装了oracle12c数据库,在用数据库客户端连接的时候,连接不了.最后查找资料的原因是因为oracle的服务端口未开放. 首先还是还是输入以往的开启某 ...

  6. ASP.NETCore -----导出Excel文件并下载

    本事例分为nopi(安装DotNetCore.NPOI)下载和EPPlus(EPPlus.Core.dll)下载,其中npoi下载演示的是根据执行的模板进行数据下载 npoi帮助类NpoiExcelU ...

  7. Codeforces 459E Roland and Rose

    本以为是个树形DP,按照树形DP的方法在那里dfs,结果WA到死,因为它存在有向环,不是树,凡是存在环的情况切记不要用树形的方法去做 题目的突破点在于将边排完序之后,用点表示以该点为边结尾的最大长度, ...

  8. Web application architecture overview

  9. Most simple basic of internet programming based on two different machines sharing the same local net

    This blog is just shown for the most simple basic of internet programming based on two different mac ...

  10. win10下pip3安装tesserocr时报错

    使用pip3在线安装tesserocr时报错,刚开始报错内容是提示未安装vs2014,安装完以后报错内容如下 ERROR: Command errored out with exit status 1 ...