LeetCode1-9

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

1、两数之和

题目请点击链接 ↑

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

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

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

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

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

2、两数相加

题目请点击链接 ↑

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

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

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

题目请点击链接 ↑

暴力双循环这太蠢了

  1. static int lengthOfLongestSubstring(String s) {
  2. char[] cs = s.toCharArray();
  3. List<Character> al = new ArrayList<>();
  4. int max = 0;
  5. int num = 0;
  6. for (int i = 0; i < cs.length; i++) {
  7. for (int j = i; j < cs.length; j++) {
  8. if (!al.contains(cs[j])) {
  9. al.add(cs[j]);
  10. num++;
  11. max = (num > max) ? num : max;
  12. } else {
  13. break;
  14. }
  15. }
  16. al.clear();
  17. num = 0;
  18. }
  19. return max;
  20. }

滑窗思想:

  1. static int lengthOfLongestSubstring2(String s) {
  2. char[] cs = s.toCharArray();
  3. int n = cs.length;
  4. Set<Character> set = new HashSet<>();
  5. int ans = 0, i = 0, j = 0;
  6. while (i < n && j < n) {
  7. // 滑窗 [i, j]
  8. if (!set.contains(cs[j])) {
  9. set.add(cs[j++]);
  10. ans = Math.max(ans, j - i);
  11. } else {
  12. set.remove(cs[i++]);
  13. }
  14. }
  15. return ans;
  16. }

优化的滑窗:

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

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

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

  1. //再看自己以前写的代码居然不能一眼看懂了???看了下提交记录战胜77%
  2. public double findMedianSortedArrays(int[] nums1, int[] nums2) {
  3. double ans;
  4. int[] sum = new int[nums1.length + nums2.length];
  5. //暴力构建新数组
  6. for (int i = 0, j = 0, k = 0; k < sum.length; k++) {
  7. if (i < nums1.length && j < nums2.length) {
  8. if (nums1[i] < nums2[j]) {
  9. sum[k] = nums1[i];
  10. i++;
  11. } else {
  12. sum[k] = nums2[j];
  13. j++;
  14. }
  15. } else if (i >= nums1.length && j < nums2.length) {
  16. sum[k] = nums2[j];
  17. j++;
  18. } else if (i < nums1.length && j >= nums2.length) {
  19. sum[k] = nums1[i];
  20. i++;
  21. }
  22. }
  23. //求中位数
  24. if (sum.length % 2 == 1) {
  25. ans = (double) sum[(sum.length - 1) / 2];
  26. } else {
  27. ans = (double) (sum[sum.length / 2] + sum[(sum.length - 1) / 2]) / 2;
  28. }
  29. return ans;

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

5、最长回文子串

题目请点击链接 ↑

……

最初解法
  1. //现在看这个解法看恶心了……折叠折叠
  2. public String longestPalindrome(String s) {
  3. if (s.length() == 0) {
  4. return "";
  5. }
  6. char[] cs = s.toCharArray();
  7. int len = cs.length;
  8. int m = 0, n = 0, max = 0, p = 0, q = 0;
  9. int m1, n1, p1, q1;
  10. for (int i = 0; i < len; i++) {
  11. m1 = i - 1;
  12. n1 = i + 1;
  13. p1 = i;
  14. q1 = i + 1;
  15. while (m1 >= 0 && n1 >= 0 && m1 < len && n1 < len && cs[m1] == cs[n1]) {
  16. m1--;
  17. n1++;
  18. }
  19. while (p1 >= 0 && q1 >= 0 && p1 < len && q1 < len && cs[p1] == cs[q1]) {
  20. p1--;
  21. q1++;
  22. }
  23. if (n1 - m1 - 1 > max) {
  24. max = n1 - m1 - 1;
  25. m = m1 + 1;
  26. n = n1 - 1;
  27. }
  28. if (q1 - p1 - 1 > max) {
  29. max = q1 - p1 - 1;
  30. p = p1 + 1;
  31. q = q1 - 1;
  32. }
  33. }
  34. String s1 = s.substring(m, n + 1);
  35. String s2 = s.substring(p, q + 1);
  36. return s1.length() > s2.length() ? s1 : s2;

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

  1. public String longestPalindrome(String s) {
  2. if (s == null || s.length() < 1) return "";
  3. int start = 0, end = 0;
  4. for (int i = 0; i < s.length(); i++) {
  5. int len1 = expandAroundCenter(s, i, i);
  6. int len2 = expandAroundCenter(s, i, i + 1);
  7. int len = Math.max(len1, len2);
  8. if (len > end - start) {
  9. start = i - (len - 1) / 2;
  10. end = i + len / 2;
  11. }
  12. }
  13. return s.substring(start, end + 1);
  14. }
  15. private int expandAroundCenter(String s, int left, int right) {
  16. int L = left, R = right;
  17. while (L >= 0 && R < s.length() && s.charAt(L) == s.charAt(R)) {
  18. L--;
  19. R++;
  20. }
  21. return R - L - 1;
  22. }

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

6、Z字形变换

题目请点击链接 ↑

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

  1. public String convert(String s, int numRows) {
  2. if (numRows == 1) return s;
  3. StringBuilder sb = new StringBuilder();
  4. char[] cs = s.toCharArray();
  5. LinkedList[] lls = new LinkedList[numRows];
  6. for (int i = 0; i < numRows; i++) {
  7. lls[i] = new LinkedList<Character>();
  8. }
  9. int flag = 0, p = 0;
  10. for (int i = 0; i < cs.length; i++) {
  11. //flag=0表示从上往下挨个放,=1表示从下往上放
  12. if (flag == 0) {
  13. if (p < numRows - 1) {
  14. lls[p++].add(cs[i]);
  15. continue;
  16. } else {
  17. flag = 1;
  18. lls[p--].add(cs[i]);
  19. }
  20. } else {
  21. if (p > 0) {
  22. lls[p--].add(cs[i]);
  23. continue;
  24. } else {
  25. flag = 0;
  26. lls[p++].add(cs[i]);
  27. }
  28. }
  29. }
  30. for (int i = 0; i < numRows; i++) {
  31. while (lls[i].size() > 0)
  32. sb.append(lls[i].removeFirst());
  33. }
  34. return sb.toString();
  35. }

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

  1. public String convert(String s, int numRows) {
  2. if (numRows == 1) return s;
  3. List<StringBuilder> rows = new ArrayList<>();
  4. for (int i = 0; i < Math.min(numRows, s.length()); i++)
  5. rows.add(new StringBuilder());
  6. int curRow = 0;
  7. boolean goingDown = false;
  8. for (char c : s.toCharArray()) {
  9. rows.get(curRow).append(c);
  10. if (curRow == 0 || curRow == numRows - 1) goingDown = !goingDown;
  11. curRow += goingDown ? 1 : -1;
  12. }
  13. StringBuilder ret = new StringBuilder();
  14. for (StringBuilder row : rows) ret.append(row);
  15. return ret.toString();
  16. }

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

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

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

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

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

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

  1. public String convert(String s, int numRows) {
  2. if (numRows == 1) return s;
  3. StringBuilder ret = new StringBuilder();
  4. int n = s.length();
  5. int cycleLen = 2 * numRows - 2;
  6. for (int i = 0; i < numRows; i++) {
  7. for (int j = 0; j + i < n; j += cycleLen) {
  8. ret.append(s.charAt(j + i));
  9. if (i != 0 && i != numRows - 1 && j + cycleLen - i < n)
  10. ret.append(s.charAt(j + cycleLen - i));
  11. }
  12. }
  13. return ret.toString();
  14. }

7、整数反转

题目请点击链接 ↑

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

  1. public int reverse(int x) {
  2. if (x < 10 && x > -10) {
  3. return x;
  4. }
  5. int ans;
  6. boolean flag = false;
  7. if (x < 0) {
  8. x = -x;
  9. flag = true;
  10. }
  11. StringBuilder sb = new StringBuilder(String.valueOf(x));
  12. try {
  13. ans = Integer.valueOf(sb.reverse().toString());
  14. } catch (NumberFormatException e) {
  15. return 0;
  16. }
  17. if (flag) ans = -ans;
  18. return ans;
  19. }

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

  1. //pop operation:取出每位数
  2. pop = x % 10;
  3. x /= 10;
  4. //push operation:构建新数
  5. temp = rev * 10 + pop;
  6. rev = temp

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

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

还是觉得字符串更简单2333

8、字符串转整数

题目请点击链接 ↑

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

丑陋的最初解法
  1. public int myAtoi(String str) {
  2. char[] cs = str.toCharArray();
  3. StringBuilder sb = new StringBuilder();
  4. double ans = 0;
  5. boolean fir = true;
  6. boolean posiOrNega = true;
  7. boolean anotherFlag = true;
  8. for (int i = 0; i < cs.length; i++) {
  9. if (cs[i] == ' ' && fir == true) {
  10. continue;
  11. }
  12. fir = false;
  13. if (cs[i] == 43 && anotherFlag == true) {
  14. posiOrNega = true;
  15. anotherFlag = false;
  16. continue;
  17. } else if (cs[i] == 45 && anotherFlag == true) {
  18. posiOrNega = false;
  19. anotherFlag = false;
  20. continue;
  21. }
  22. if (cs[i] >= 48 && cs[i] <= 57) {
  23. sb.append(cs[i]);
  24. anotherFlag = false;
  25. continue;
  26. }
  27. break;
  28. }
  29. try {
  30. ans = Double.valueOf(sb.toString());
  31. if (posiOrNega)
  32. return (ans > Integer.MAX_VALUE) ? Integer.MAX_VALUE : (int) ans;
  33. else
  34. return (-ans < Integer.MIN_VALUE) ? Integer.MIN_VALUE : (int) -ans;
  35. } catch (NumberFormatException e) {
  36. return 0;
  37. }
  38. }

┓( ´∀` )┏

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

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

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

9、回文数

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

  1. public boolean isPalindrome(int x) {
  2. int count = 0;
  3. int y = x;
  4. boolean ans = false;
  5. if (x < 0) {
  6. return false;
  7. } else if (x >= 0 && x < 10) {
  8. return true;
  9. } else {
  10. while (y > 0) {
  11. y = y / 10;
  12. count++;
  13. }
  14. int[] ints = new int[count];
  15. y = x;
  16. for (int i = 0; i < ints.length; i++) {
  17. ints[i] = y % 10;
  18. y = y / 10;
  19. }
  20. for (int i = 0; i < count - i - 1; i++) {
  21. int j = count - i - 1;
  22. if (ints[i] == ints[j]) {
  23. ans = true;
  24. continue;
  25. } else {
  26. ans = false;
  27. break;
  28. }
  29. }
  30. return ans;
  31. }
  32. }

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


总结,作为一个菜鸟做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. SPFA和堆优化的Dijk

    朴素dijkstra时间复杂度$O(n^{2})$,通过使用堆来优化松弛过程可以使时间复杂度降到O((m+n)logn):dijkstra不能用于有负权边的情况,此时应使用SPFA,两者写法相似. 朴 ...

  2. firewalld学习-zone的使用和配置

    原文地址:http://www.excelib.com/article/290/show zone文件标签名词解释 target:目标,这个前面学生也已经给大家介绍过了,可以理解为默认行为,有四个可选 ...

  3. POJ 3268:Silver Cow Party 求单点的来回最短路径

    Silver Cow Party Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 15989   Accepted: 7303 ...

  4. HihoCoder第一周与POJ3974:最长回文字串

    这个题目是hihoCoder第一周的题目,自己打算从第一周开始做起,不知道能追上多少,更不知道这一篇写完,下一篇会是什么时候... 题意很简单. 输入: abababa aaaabaa acacdas ...

  5. shell教程——bash入门

    创建shell文件 vim test.sh 写内容 #!/bin/bash echo "Hello World !" 使脚本具有执行权限 chmod +x ./test.sh 执行 ...

  6. Day7 - J - Raising Modulo Numbers POJ - 1995

    People are different. Some secretly read magazines full of interesting girls' pictures, others creat ...

  7. Delphi 10.3.3 THTTPClient Post问题

    如果对于Post提交,需要对参数进行urlEncode处理的需要注意. 对于Post参数,可以用TString或者TStringStream两者.如果你采用的是用TStringStream,那么必须按 ...

  8. 045、Java中使用if语句进行判断

    01.代码如下: package TIANPAN; /** * 此处为文档注释 * * @author 田攀 微信382477247 */ public class TestDemo { public ...

  9. ①spring简介以及环境搭建(一)

    注*(IOC:控制反转.AOP:面向切面编程) spring官网:http://spring.io/ spring简介: spring是一个开源框架 spring为简化企业级应用开发而生,使用Spri ...

  10. Oracle--sqlplus--常用命令

    登陆:win+R输入sqlplus即可 如果前期没有用户可以输入sqlplus /nolog  记得sqlplus后有一个空格 --格式化命令 进行数据查询时,默认的方式排版会很乱,如果我们要解决这个 ...