Leecode 刷题 简单题 个人汇总

博主分享了在LeetCode上刷简单题的心得,包括使用HashMap解决两数之和、整数反转、回文数等问题的方法,以及罗马数字转换、最长公共前缀、有效括号等算法的理解和技巧。强调了哈希表、反转字符串、判断回文、二分查找等常见技术的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

为了以后的工作,要开始刷题啦!!!!
技术宅拯救世界!!!!!!!!!!!
先从简单题开始,慢慢来~~~~~~~~~~~~
尽量保证每天至少一道题吧!!!!!!
https://www.bilibili.com/video/BV1BC4y187bZ/?spm_id_from=333.788.recommend_more_video.2
简单题的答案就不贴到这里了,一般大家都会,这里仅仅提供我的一些小总结。

方法

  1. hashMap的get put 实现存储和获取
  2. hashMap的containsKey 实现查找
  3. Integer.MAX_VALUE 最大边界
  4. StringBuilder(x + “”)).reverse() 缓冲字符串的倒转
  5. string,charAt(int index); 返回字符串中指定索引的的字符
  6. string,toCharArrayt(); 字符串转换成字符数组。

两数之和

给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 的那 两个 整数,并返回它们的数组下标。

你可以假设每种输入只会对应一个答案。但是,数组中同一个元素不能使用两遍。

你可以按任意顺序返回答案。

示例 1:

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

提示:

  • 2 <= nums.length <= 103
  • -109 <= nums[i] <= 109
  • -109 <= target <= 109
  • 只会存在一个有效答案

我的理解 1. 类似于二维数组求和一样的暴力求和算法 2.应用哈希表的的逆向求和算法

  1. 这里就不说了,小学二年级都会(滑稽)
  2. 这里说一下,在开始的hashtable中是没有键值对的,在后面循环中,慢慢向里面插入键值对。把后面的要插入的数字当作是num[i],在前面的数字中寻找target-num[i],直到到找到为止,和普通的遍历算法略有区别。
  • 小结: hashmap可以减小时间复杂度;在hashmap中用 containsKey(Object key)和containsValue(Object value) 来判断是否存在相应的键或值,同时配合 get(Object key)和put(K key, V value)来实现hashmap中的存取。

整数反转

给你一个 32 位的有符号整数 x ,返回将 x 中的数字部分反转后的结果。

如果反转后整数超过 32 位的有符号整数的范围 [−231, 231 − 1] ,就返回 0。

假设环境不允许存储 64 位整数(有符号或无符号)。

示例 1:

输入:x = 123
输出:321

示例 2:

输入:x = -123
输出:-321

示例 3:

输入:x = 120
输出:21

示例 4:

输入:x = 0
输出:0

提示:

  • -231 <= x <= 231 - 1

我的理解 1. 遇到有关数字的问题就直接差分成数字去进行处理会比较简单。 2.判断条件的确定
在判断条件这里有两点,一个是正常的不等式关系,另一个是溢出问题,因为都是int类型,当大于Integer.MAX_VALUE时会有溢出的现象发生,如果继续加得到的数会比其小,因此虽然是32位整数,但是比较的是第31位置和前31相同时的最后一位。对于正数为231-1=2147483647,末位为7,对于负数-232=-2147483648,末尾为8 所以多了判断条件。

回文数

给你一个整数 x ,如果 x 是一个回文整数,返回 true ;否则,返回 false

回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。例如,121 是回文,而 123 不是。

示例 1:

输入:x = 121
输出:true

示例 2:

输入:x = -121
输出:false
解释:从左向右读, 为 -121 。 从右向左读, 为 121- 。因此它不是一个回文数。

示例 3:

输入:x = 10
输出:false
解释:从右向左读, 为 01 。因此它不是一个回文数。

示例 4:

输入:x = -101
输出:false

提示:

  • -231 <= x <= 231 - 1

我的理解 1. 遇到有关数字的问题就直接差分成数字去进行处理会比较简单。但是也要尽量不使用数组,因为数组是开辟一块固定的空间。

		// 通过”/div“和来取左边的数字,通过“%10”来取右边的数字。
		int div = 1;
		while (x / div >= 10) div *= 10;
		while (x > 0) {
		      int left = x / div;
		      int right = x % 10;
		      if (left != right) return false;
		      x = (x % div) / 10;
		      div /= 100;
		}

2 字符串缓冲暴力法 通过使用StringBuilder的reverse实现字符串的调转 以及equals 进行比较

 public boolean isPalindrome(int x) {
        String reversedStr = (new StringBuilder(x + "")).reverse().toString();
        return (x + "").equals(reversedStr);
    }

RomanToInteger

罗马数字包含以下七种字符: IVXLCDM

字符          数值
I             1
V             5
X             10
L             50
C             100
D             500
M             1000

例如, 罗马数字 2 写做 II ,即为两个并列的 1。12 写做 XII ,即为 X + II 。 27 写做 XXVII, 即为 XX + V + II

通常情况下,罗马数字中小的数字在大的数字的右边。但也存在特例,例如 4 不写做 IIII,而是 IV。数字 1 在数字 5 的左边,所表示的数等于大数 5 减小数 1 得到的数值 4 。同样地,数字 9 表示为 IX。这个特殊的规则只适用于以下六种情况:

    <li><code>I</code> 可以放在 <code>V</code> (5) 和 <code>X</code> (10) 的左边,来表示 4 和 9。</li>
    <li><code>X</code> 可以放在 <code>L</code> (50) 和 <code>C</code> (100) 的左边,来表示 40 和 90。 </li>
    <li><code>C</code> 可以放在 <code>D</code> (500) 和 <code>M</code> (1000) 的左边,来表示 400 和 900。</li>
    

    给定一个罗马数字,将其转换成整数。输入确保在 1 到 3999 的范围内。

    示例 1:

    输入: "III"
    输出: 3

    示例 2:

    输入: "IV"
    输出: 4

    示例 3:

    输入: "IX"
    输出: 9

    示例 4:

    输入: "LVIII"
    输出: 58
    解释: L = 50, V= 5, III = 3.
    

    示例 5:

    输入: "MCMXCIV"
    输出: 1994
    解释: M = 1000, CM = 900, XC = 90, IV = 4.

    提示:

    • 1 <= s.length <= 15
    • s 仅含字符 ('I', 'V', 'X', 'L', 'C', 'D', 'M')
    • 题目数据保证 s 是一个有效的罗马数字,且表示整数在范围 [1, 3999]
    • 题目所给测试用例皆符合罗马数字书写规则,不会出现跨位等情况。
    • IL 和 IM 这样的例子并不符合题目要求,49 应该写作 XLIX,999 应该写作 CMXCIX 。
    • 关于罗马数字的详尽书写规则,可以参考 罗马数字 - Mathematics

    我的理解 : 1. 映射的关系,如何将罗马字符映射到整形数字上。有两种映射方式:hashMap 和Switch 2.罗马字符的计算方式:把一个小值放在大值的左边,就是做减法,否则为加法。

    最长公共前缀

    • 自己瞎写的 感觉还可以
    class Solution {
            public String longestCommonPrefix(String[] strs) {
                if (strs.length == 0){
                    return "";
                }
    
                int minLen = minStrLen(strs);
    
                for (int i = 0; i < minLen; i++) {
                    if (!sameStr(strs, i)) {
                        return strs[0].substring(0, i );
                    }
                }
                return strs[0].substring(0, minLen);
            }
    
            private int minStrLen(String[] strs) {
                int minLen = strs[0].length();
                for (int i = 1; i < strs.length; i++) {
                    if (minLen > strs[i].length()) {
                        minLen = strs[i].length();
                    }
                }
                return minLen;
            }
    
            private boolean sameStr(String[] strs, int num) {
    
                char prefixChar = strs[0].charAt(num);
                for (int i = 1; i < strs.length; i++) {
                    if (prefixChar != strs[i].charAt(num)) {
                        return false;
                    }
                }
                return true;
    
            }
    

    有效的括号(回看)

    给定一个只包括 '('')''{''}', code>'[',']' 的字符串 s ,判断字符串是否有效。

    有效字符串需满足:

    1. 左括号必须用相同类型的右括号闭合。
    <li>左括号必须以正确的顺序闭合。</li>
    

    示例 1:

    输入:s = "()"
    输出:true
    

    示例 2:

    输入:s = "()[]{}"
    输出:true
    

    示例 3:

    输入:s = "(]"
    输出:false
    

    示例 4:

    输入:s = "([)]"
    输出:false
    

    示例 5:

    输入:s = "{[]}"
    输出:true

    提示:

    • 1 <= s.length <= 104
    • s 仅由括号 '()[]{}' 组成

    这个题目需要使用堆栈,我的堆栈之类的还没有系统的学,后面再系统的做这个题。

    合并两个有序链表

    将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。

    示例 1:

    输入:l1 = [1,2,4], l2 = [1,3,4]
    输出:[1,1,2,3,4,4]
    

    示例 2:

    输入:l1 = [], l2 = []
    输出:[]
    

    示例 3:

    输入:l1 = [], l2 = [0]
    输出:[0]
    

    提示:

    • 两个链表的节点数目范围是 [0, 50]
    • -100 <= Node.val <= 100
    • l1l2 均按 非递减顺序 排列
    // 本题目中仅仅加入了一个哑节点,所用的所有节点还是原链表中的。
    // 当prev的next改变时,原链表节点中的指针就已经改变了。
    // 因此可以合并到一个链表中。
     public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
                ListNode prehead = new ListNode(-1);
    
                ListNode prev = prehead;
    
                while (l1 != null && l2 != null) {
                    if (l1.val <= l2.val) {
                        prev.next = l1;
                        l1 = l1.next;
                    } else {
                        prev.next = l2;
                        l2 = l2.next;
                    }
                    prev = prev.next;
                }
    
                prev.next = l1 == null ? l2:l1;
    
                return prehead.next;
    
    

    删除有序数组中的重复项

    给你一个有序数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。

    不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。

    说明:

    为什么返回数值是整数,但输出的答案是数组呢?

    请注意,输入数组是以「引用」方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。

    你可以想象内部操作如下:

    // nums 是以“引用”方式传递的。也就是说,不对实参做任何拷贝
    int len = removeDuplicates(nums);
    
    // 在函数里修改输入数组对于调用者是可见的。
    // 根据你的函数返回的长度, 它会打印出数组中 该长度范围内 的所有元素。
    for (int i = 0; i < len; i++) {
        print(nums[i]);
    }
    
    // 自己写的 有点啰嗦
    // 考虑了在前后数值相同时的情况,比较啰嗦
            public int removeDuplicates(int[] nums) {
    
                int i = 0;
                int len = nums.length;
                for (;i < len - 1; ) {
                    if (nums[i] == nums[i + 1]) {
    
                        for (int j = i + 1; j < nums.length - 1; j++) {
                            nums[j] = nums[j + 1];
    
                        }
                        len--;
                    } else i++;
    
                }
                return len;
            }
    // 答案的精简版
    // 考虑了在前后数值不同时的情况,比较简单
     	public int removeDuplicates(int[] nums) {
            int i = 0;
            for(int j = 0; j < nums.length; j++){
                if(nums[j] != nums[i]){
                    nums[++i] = nums[j];
                }
            }
            return i + 1;
        }
    

    移除元素

    给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。

    不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组

    元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。

    说明:

    为什么返回数值是整数,但输出的答案是数组呢?

    请注意,输入数组是以「引用」方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。

    你可以想象内部操作如下:

    // nums 是以“引用”方式传递的。也就是说,不对实参作任何拷贝
    int len = removeElement(nums, val);
    
    // 在函数里修改输入数组对于调用者是可见的。
    // 根据你的函数返回的长度, 它会打印出数组中 该长度范围内 的所有元素。
    for (int i = 0; i < len; i++) {
        print(nums[i]);
    }
    

    示例 1:

    输入:nums = [3,2,2,3], val = 3
    输出:2, nums = [2,2]
    解释:函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。你不需要考虑数组中超出新长度后面的元素。例如,函数返回的新长度为 2 ,而 nums = [2,2,3,3] 或 nums = [2,2,0,0],也会被视作正确答案。
    

    示例 2:

    输入:nums = [0,1,2,2,3,0,4,2], val = 2
    输出:5, nums = [0,1,4,0,3]
    解释:函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。注意这五个元素可为任意顺序。你不需要考虑数组中超出新长度后面的元素。
    

    提示:

    • 0 <= nums.length <= 100
    • 0 <= nums[i] <= 50
    • 0 <= val <= 100
    	// 我认为本题的本质和上一道题一样。
    	// 原地是重点,使用两个下标数字来模拟两个数组。
    	public int removeElement(int[] nums, int val) {
                int i = 0;
                for (int j = 0; j < nums.length; j++) {
                    if (nums[j] != val) {
                        System.out.println("i"+nums[i]);
                        System.out.println("j"+nums[j]);
    
                        nums[i]=nums[j];
                        i++;
                    }
                }
                return i;
            }
    

    实现strStr()

    实现 strStr() 函数。

    给定一个 haystack 字符串和一个 needle 字符串,在 haystack 字符串中找出 needle 字符串出现的第一个位置 (从0开始)。如果不存在,则返回  -1

    示例 1:

    输入: haystack = "hello", needle = "ll"
    输出: 2
    

    示例 2:

    输入: haystack = "aaaaa", needle = "bba"
    输出: -1
    

    说明:

    当 needle 是空字符串时,我们应当返回什么值呢?这是一个在面试中很好的问题。

    对于本题而言,当 needle 是空字符串时我们应当返回 0 。这与C语言的 strstr() 以及 Java的 indexOf() 定义相符。

    // 这个很简单 就不多说了
     public int strStr(String haystack, String needle) {
    
                for (int i = 0; i <= (haystack.length() - needle.length()); i++) {
                    if (needle.equals(haystack.substring(i, i + needle.length())))
                        return i;
                }
                return -1;
            }
    

    搜索插入位置(二分查找)

    二分查找没啥好说的 就一个算法 然后勤加练习
    (摘抄自力扣大佬)

    1. 分析题意,挖掘题目中隐含的 单调性;
    2. while (left < right) 退出循环的时候有 left == right 成立,因此无需考虑返回 left 还是 right;
    3. 始终思考下一轮搜索区间是什么,如果是 [mid, right] 就对应 left = mid ,如果是 [left, mid - 1] 就对应 right = mid - 1,是保留 mid 还是 +1+1、-1−1 就在这样的思考中完成;
    4. 从一个元素什么时候不是解开始考虑下一轮搜索区间是什么 ,把区间分为 22 个部分(一个部分肯定不存在目标元素,另一个部分有可能存在目标元素),问题会变得简单很多,这是一条 非常有用 的经验;
    5. 每一轮区间被划分成 22 部分,理解 区间划分 决定中间数取法( 无需记忆,需要练习 + 理解 ),在调试的过程中理解 区间和中间数划分的配对关系:
      划分 [left, mid] 与 [mid + 1, right] ,mid 被分到左边,对应 int mid = left + (right - left) / 2;;
      划分 [left, mid - 1] 与 [mid, right] ,mid 被分到右边,对应 int mid = left + (right - left + 1) / 2;。
      至于为什么划分是这种对应关系,原因在于区间只有 22 个数的时候,如果中间数的取法不对,一旦进入的分支不能使得区间缩小,会出现 死循环。暂时不理解问题不大,需要在练习中进行调试;

    退出循环的时候有 left == right 成立,此时如果能确定问题一定有解,返回 left 即可,如果不能确定,需要单独判断一次。

            public int searchInsert(int[] nums, int target) {
                int n = nums.length;
                int left = 0, right = n - 1, ans = n;
                while (left <= right) {
                    int mid = ((right - left) >> 1) + left;
                    if (target <= nums[mid]) {
                        ans = mid;
                        right = mid - 1;
                    } else {
                        left = mid + 1;
                    }
                }
                return ans;
            }
    

    外观数组

    给定一个正整数 n ,输出外观数列的第 n 项。

    「外观数列」是一个整数序列,从数字 1 开始,序列中的每一项都是对前一项的描述。

    你可以将其视作是由递归公式定义的数字字符串序列:

    • countAndSay(1) = "1"
    • countAndSay(n) 是对 countAndSay(n-1) 的描述,然后转换成另一个数字字符串。

    前五项如下:

    1.     1
    2.     11
    3.     21
    4.     1211
    5.     111221
    第一项是数字 1 
    描述前一项,这个数是 1 即 “ 一 个 1 ”,记作 "11"
    描述前一项,这个数是 11 即 “ 二 个 1 ” ,记作 "21"
    描述前一项,这个数是 21 即 “ 一 个 2 + 一 个 1 ” ,记作 "1211"
    描述前一项,这个数是 1211 即 “ 一 个 1 + 一 个 2 + 二 个 1 ” ,记作 "111221"
    

    描述 一个数字字符串,首先要将字符串分割为 最小 数量的组,每个组都由连续的最多 相同字符 组成。然后对于每个组,先描述字符的数量,然后描述字符,形成一个描述组。要将描述转换为数字字符串,先将每组中的字符数量用数字替换,再将所有描述组连接起来。

    例如,数字字符串 "3322251" 的描述如下图:

      示例 1:

      输入:n = 1
      输出:"1"
      解释:这是一个基本样例。
      

      示例 2:

      输入:n = 4
      输出:"1211"
      解释:
      countAndSay(1) = "1"
      countAndSay(2) = 读 "1" = 一 个 1 = "11"
      countAndSay(3) = 读 "11" = 二 个 1 = "21"
      countAndSay(4) = 读 "21" = 一 个 2 + 一 个 1 = "12" + "11" = "1211"
      

      提示:

      • 1 <= n <= 30
      public String countAndSay(int n) {
      	StringBuffer res = new StringBuffer();
      	res.append(1);
      	for (int i = 1; i < n; i++) {
      		StringBuffer sbf = new StringBuffer();
              int start = 0;
      		for (int j = 1; j < res.length(); j++) {
      			if (res.charAt(j) != res.charAt(start)) {
      				sbf.append(j-start).append(res.charAt(start));
      				start = j;
                      }
              	}
      		sbf.append(res.length() - start).append(res.charAt(start));
      		res = sbf;
          }
              return res.toString();
      }
      

      要点:嵌套循环,外层循环是每次都会被直接更新而不是补充,你曾循环包括两个下标,一个是扫描的下标,一个是重复位的开始下标。

      评论
      添加红包

      请填写红包祝福语或标题

      红包个数最小为10个

      红包金额最低5元

      当前余额3.43前往充值 >
      需支付:10.00
      成就一亿技术人!
      领取后你会自动成为博主和红包主的粉丝 规则
      hope_wisdom
      发出的红包
      实付
      使用余额支付
      点击重新获取
      扫码支付
      钱包余额 0

      抵扣说明:

      1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
      2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

      余额充值