高频算法题(面试前刷,持续更新)

面试高频算法

704. 二分查找

难度简单585收藏分享切换为英文接收动态反馈

给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1

示例 1:

输入: nums = [-1,0,3,5,9,12], target = 9
输出: 4
解释: 9 出现在 nums 中并且下标为 4

示例 2:

输入: nums = [-1,0,3,5,9,12], target = 2
输出: -1
解释: 2 不存在 nums 中因此返回 -1

提示:

  1. 你可以假设 nums 中的所有元素是不重复的。
  2. n 将在 [1, 10000]之间。
  3. nums 的每个元素都将在 [-9999, 9999]之间。

题解:

class Solution {
    public int search(int[] nums, int target) {
        int nLength= nums.length;
        int low = 0;
        int high = nLength-1;
        while(high>=low){
            int mid = (high-low)/2+low;
            if(nums[mid]==target){
                return mid;
            }
            if(nums[mid]<target){
                low = mid+1;
                continue;
            }
            if(nums[mid]>target){
                high = mid-1;
                continue;
            }
        }
        return -1;

    }
}
//二分查找记住!!!int mid = (high-low)/2+low;
3. 无重复字符的最长子串

难度中等6744收藏分享切换为英文接收动态反馈

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

示例 1:

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

示例 2:

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

示例 3:

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

示例 4:

输入: s = ""
输出: 0

提示:

  • 0 <= s.length <= 5 * 104
  • s 由英文字母、数字、符号和空格组成

题解:

class Solution {
    public int lengthOfLongestSubstring(String s) {
        Map<Character,Integer> maptest = new HashMap<Character,Integer>();
        int i=0;
        int nLength = s.length();
        int max = 0;
        
        for(int j=0;j<nLength;j++){
            char word = s.charAt(j);
            if(maptest.containsKey(word)){
                i=Math.max(maptest.get(word),i);;
            }
            maptest.put(word,j+1);
            max = Math.max(max, j - i + 1);
        }
        return max;
    }
}
7. 整数反转

难度中等3352收藏分享切换为英文接收动态反馈

给你一个 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

题解:

class Solution {
    public int reverse(int x) {
        List<Integer> listTmp = new ArrayList<Integer>();
        int high = (int)Math.pow(2,31)-1;
        int low = (int)Math.pow(2,31)*-1;
        if (x > high  || x < low) {
                return 0;
        }
        int nbool = 1;
        if(x<0){
            nbool=-1;
            x = x *nbool;
        }
         

        while(x!=0){
            int nTmp = x%10;
             x = x/10;
            if(nTmp==0&&listTmp.size()<1){
                continue;
            }
            listTmp.add(nTmp);
           

        }
        int nLength = listTmp.size();
        double dResult =0;
        int j =nLength-1;
        for(int i=0;i<nLength;i++){
            double dTest = listTmp.get(i)*Math.pow(10,j);
            
            dResult = dResult +dTest ;
            j--;
            if (dResult > high  || dResult < low) {
                return 0;
            }
        }
        int nResult = (int)dResult;
        
        return nResult*nbool;



    }
}
5. 最长回文子串

难度中等4575收藏分享切换为英文接收动态反馈

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

示例 1:

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

示例 2:

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

示例 3:

输入:s = "a"
输出:"a"

示例 4:

输入:s = "ac"
输出:"a"

提示:

  • 1 <= s.length <= 1000
  • s 仅由数字和英文字母(大写和/或小写)组成

题解:

//暴力模拟,但是超时了
class Solution {
    public String Palindrome(int high,int low,String s) {
        int nLow = low;
        int nHigh = high;
        while(high>low){
            if(s.charAt(low++)!=s.charAt(high--)){
                return s.substring(0,1);
            }
        }
        
        return s.substring(nLow,nHigh+1);
    }
    public String longestPalindrome(String s) {
        Map<Integer,Character> maptest = new HashMap<Integer,Character>();
        int nLength = s.length();
        int nMax = 0;
        String sResult = s.substring(0,1);
        for(int i=0;i<nLength;i++){
            char cTmp = s.charAt(i);
            if(maptest.containsValue(cTmp)){
                int high = i;
                int low = 0;
                for(int j =0;j<i;j++){
                    if(maptest.get(j)==cTmp){
                        low = j;
                        //todo 判断回文
                        String sTmp = Palindrome(high,low,s);
                        if(nMax<sTmp.length()){
                            sResult = sTmp;
                            nMax=sTmp.length();
                        }
                    }

            }
                
                
            }
            maptest.put(i,cTmp);
            
        }
        return sResult;

    }
}

暴力解法
根据回文子串的定义,枚举所有长度大于等于 22 的子串,依次判断它们是否是回文;
可以只针对大于「当前得到的最长回文子串长度」的子串进行回文验证;
当得到了一个更长的回文时,不需要真的做截取。只需要记录「当前子串的起始位置」和「子串长度」。
参考代码 1:

public class Solution {

    public String longestPalindrome(String s) {
        int len = s.length();
        if (len < 2) {
            return s;
        }

        int maxLen = 1;
        int begin = 0;
        // s.charAt(i) 每次都会检查数组下标越界,因此先转换成字符数组
        char[] charArray = s.toCharArray();

        // 枚举所有长度大于 1 的子串 charArray[i..j]
        for (int i = 0; i < len - 1; i++) {
            for (int j = i + 1; j < len; j++) {
                if (j - i + 1 > maxLen && validPalindromic(charArray, i, j)) {
                    maxLen = j - i + 1;
                    begin = i;
                }
            }
        }
        return s.substring(begin, begin + maxLen);
    }

    /**
     * 验证子串 s[left..right] 是否为回文串
     */
    private boolean validPalindromic(char[] charArray, int left, int right) {
        while (left < right) {
            if (charArray[left] != charArray[right]) {
                return false;
            }
            left++;
            right--;
        }
        return true;
    }
}

217. 存在重复元素

难度简单

给定一个整数数组,判断是否存在重复元素。

如果存在一值在数组中出现至少两次,函数返回 true 。如果数组中每个元素都不相同,则返回 false

示例 1:

输入: [1,2,3,1]
输出: true

示例 2:

输入: [1,2,3,4]
输出: false

示例 3:

输入: [1,1,1,3,3,4,3,2,4,2]
输出: true

题解:

class Solution {
    public boolean containsDuplicate(int[] nums) {
        Map<Integer,Integer> mTmp = new HashMap<Integer,Integer>();
        for(int i=0;i<nums.length;i++){
            if(mTmp.containsKey(nums[i])){
                return true;
            }
            mTmp.put(nums[i],i);
        }
        return false;

    }
}
14. 最长公共前缀

难度简单

编写一个函数来查找字符串数组中的最长公共前缀。

如果不存在公共前缀,返回空字符串 ""

示例 1:

输入:strs = ["flower","flow","flight"]
输出:"fl"

示例 2:

输入:strs = ["dog","racecar","car"]
输出:""
解释:输入不存在公共前缀。

提示:

  • 1 <= strs.length <= 200
  • 0 <= strs[i].length <= 200
  • strs[i] 仅由小写英文字母组成

题解:

class Solution {
    public String longestCommonPrefix(String[] strs) {
        int nLength = strs.length;
        if (strs == null || strs.length == 0) {
            return "";
        }
        int nSzLength = strs[0].length();

        int nBool = 0;
        String strResult = "";
        String strTmp = strResult;
        for(int j=1;j<=nSzLength;j++){
            for(int i = 1;i<nLength;i++){
                strTmp = strs[0].substring(0,j);
                if(!strs[i].contains(strTmp)){
                    nBool=1;          
                }
            }
            if(nBool==0){
                strResult = strTmp;
            }
        }
        if(nLength==1&&nSzLength==1){
            return strs[0];
        }

        return strResult;
    }
}
//contains是包含,没法比判断前缀,这是错误写法,贴出来提醒一下
//["c","acc","ccc"]
class Solution {
    public String longestCommonPrefix(String[] strs) {
        if (strs == null || strs.length == 0) {
            return "";
        }
        int length = strs[0].length();
        int count = strs.length;
        for (int i = 0; i < length; i++) {
            char c = strs[0].charAt(i);
            for (int j = 1; j < count; j++) {
                if (i == strs[j].length() || strs[j].charAt(i) != c) {
                    return strs[0].substring(0, i);
                }
            }
        }
        return strs[0];
    }
}


70. 爬楼梯

难度简单2121收藏分享切换为英文接收动态反馈

假设你正在爬楼梯。需要 n 阶你才能到达楼顶。

每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?

**注意:**给定 n 是一个正整数。

示例 1:

输入: 2
输出: 2
解释: 有两种方法可以爬到楼顶。
1.  1 阶 + 1 阶
2.  2 阶

示例 2:

输入: 3
输出: 3
解释: 有三种方法可以爬到楼顶。
1.  1 阶 + 1 阶 + 1 阶
2.  1 阶 + 2 阶
3.  2 阶 + 1 阶
//动态规划dp
class Solution {
    public int climbStairs(int n) {
        int[] dp = new int[n+1];
        dp[0] = 1;
        dp[1] = 1;
        for(int i=2;i<=n;i++){
            dp[i] = dp[i-1]+dp[i-2];
        }
        return dp[n];
    }
}
175. 组合两个表 sql

难度简单1011收藏分享切换为英文接收动态反馈

SQL架构

表1: Person

+-------------+---------+
| 列名         | 类型     |
+-------------+---------+
| PersonId    | int     |
| FirstName   | varchar |
| LastName    | varchar |
+-------------+---------+
PersonId 是上表主键

表2: Address

+-------------+---------+
| 列名         | 类型    |
+-------------+---------+
| AddressId   | int     |
| PersonId    | int     |
| City        | varchar |
| State       | varchar |
+-------------+---------+
AddressId 是上表主键

编写一个 SQL 查询,满足条件:无论 person 是否有地址信息,都需要基于上述两表提供 person 的以下信息:

FirstName, LastName, City, State

题解:

select FirstName, LastName, City, State from Person  left join Address  on Person.PersonId = Address.PersonId    
15. 三数之和

难度中等4199收藏分享切换为英文接收动态反馈

给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 *a,b,c ,*使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。

**注意:**答案中不可以包含重复的三元组。

示例 1:

输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]

示例 2:

输入:nums = []
输出:[]

示例 3:

输入:nums = [0]
输出:[]

提示:

  • 0 <= nums.length <= 3000
  • -105 <= nums[i] <= 105

题解:

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        List<List<Integer>> listResult = new ArrayList<List<Integer>>();
        
        Arrays.sort(nums);
        int nLength = nums.length;
        for(int i =0;i<nLength;i++){
            if(nums[i] > 0) break; // 如果当前数字大于0,则三数之和一定大于0,所以结束循环
            if(i > 0 && nums[i] == nums[i-1]) continue; // 去重
            int L = i+1;
            int R = nLength-1;
            while(L<R){
                int sum = nums[i]+nums[L]+nums[R];
                
                if(sum==0){
                    List<Integer> listTmp = new ArrayList<Integer>();
                    listTmp.add(nums[i]);
                    listTmp.add(nums[L]);
                    listTmp.add(nums[R]);
                    listResult.add(listTmp);
                    while (L<R && nums[L] == nums[L+1]) L++; // 去重
                    while (L<R && nums[R] == nums[R-1]) R--; // 去重
                    L++;
                    R--;
                }
                else if (sum < 0) L++;
                else if (sum > 0) R--;
            }

        }
        return listResult;
    }
}
146. LRU 缓存

难度中等1847收藏分享切换为英文接收动态反馈

请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。

实现 LRUCache 类:

  • LRUCache(int capacity)正整数 作为容量 capacity 初始化 LRU 缓存
  • int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1
  • void put(int key, int value) 如果关键字 key 已经存在,则变更其数据值 value ;如果不存在,则向缓存中插入该组 key-value 。如果插入操作导致关键字数量超过 capacity ,则应该 逐出 最久未使用的关键字。

函数 getput 必须以 O(1) 的平均时间复杂度运行。

示例:

输入
["LRUCache", "put", "put", "get", "put", "get", "put", "get", "get", "get"]
[[2], [1, 1], [2, 2], [1], [3, 3], [2], [4, 4], [1], [3], [4]]
输出
[null, null, null, 1, null, -1, null, -1, 3, 4]

解释
LRUCache lRUCache = new LRUCache(2);
lRUCache.put(1, 1); // 缓存是 {1=1}
lRUCache.put(2, 2); // 缓存是 {1=1, 2=2}
lRUCache.get(1);    // 返回 1
lRUCache.put(3, 3); // 该操作会使得关键字 2 作废,缓存是 {1=1, 3=3}
lRUCache.get(2);    // 返回 -1 (未找到)
lRUCache.put(4, 4); // 该操作会使得关键字 1 作废,缓存是 {4=4, 3=3}
lRUCache.get(1);    // 返回 -1 (未找到)
lRUCache.get(3);    // 返回 3
lRUCache.get(4);    // 返回 4

提示:

  • 1 <= capacity <= 3000
  • 0 <= key <= 10000
  • 0 <= value <= 105
  • 最多调用 2 * 105getput

题解:

class LRUCache {
    Map<Integer, Integer> mCache = new LinkedHashMap();
    int nCapacity;
    public LRUCache(int capacity) {
        this.nCapacity = capacity;
    }
    
    public int get(int key) {
        if(!mCache.containsKey(key)){
            return -1;
        }
        int nVal = mCache.remove(key);
        mCache.put(key,nVal);
        return nVal;
    }
    
    public void put(int key, int value) {
        if(mCache.containsKey(key)){
            mCache.remove(key);
        }
        mCache.put(key,value);
        if(mCache.size()>nCapacity){
            mCache.remove(mCache.entrySet().iterator().next().getKey());
        }
    }
}


20. 有效的括号

难度简单2895收藏分享切换为英文接收动态反馈

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

有效字符串需满足:

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

示例 1:

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

示例 2:

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

示例 3:

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

示例 4:

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

示例 5:

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

提示:

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

题解:

class Solution {
    public boolean isValid(String s) {
        int n = s.length();
        if(n%2!=0){
            return false;
        }
        Map<Character,Character> maptest = new HashMap<Character,Character>();
        maptest.put('}','{');
        maptest.put(')','(');
        maptest.put(']','[');
        Deque<Character> deTest = new LinkedList<Character>();
        for(int i=0;i<n;i++){
            char ch = s.charAt(i);
            if(maptest.containsKey(ch)){
                if(deTest.isEmpty()||deTest.peek() != maptest.get(ch)){
                    return false;
                }
                deTest.pop();
            }else{
                deTest.push(ch);
            }
        }
        return deTest.isEmpty();
    }
}


22. 括号生成

难度中等2287收藏分享切换为英文接收动态反馈

数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。

示例 1:

输入:n = 3
输出:["((()))","(()())","(())()","()(())","()()()"]

示例 2:

输入:n = 1
输出:["()"]

提示:

  • 1 <= n <= 8

题解:

class Solution {
    List<String> res = new ArrayList<>();

    public List<String> generateParenthesis(int n) {
        if (n <= 0) return null;

        def("", 0, 0, n);

        return res;
    }

    public void def(String paths, int left, int right, int n) {

        if (left > n || right > left) return;
        if (paths.length() == n * 2) {
            res.add(paths);
            return;
        }
        def(paths + "(", left + 1, right, n);
        def(paths + ")", left, right + 1, n);
    }
}
121. 买卖股票的最佳时机

难度简单2052收藏分享切换为英文接收动态反馈

给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。

你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。

返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0

示例 1:

输入:[7,1,5,3,6,4]
输出:5
解释:在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。
     注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格;同时,你不能在买入前卖出股票。

示例 2:

输入:prices = [7,6,4,3,1]
输出:0
解释:在这种情况下, 没有交易完成, 所以最大利润为 0。

提示:

  • 1 <= prices.length <= 105
  • 0 <= prices[i] <= 104

题解:

//暴力,但是超时
class Solution {
    public int maxProfit1(int[] prices) {
        int nLength = prices.length;
        int nMax =0;
        for(int i=0;i<nLength;i++){
            for(int j = nLength-1;j>i;j--){
                int sum = prices[j]-prices[i];
                if(sum>0){
                    nMax = Math.max(nMax,sum);
                }
            }
        }
        return nMax;
    }
}





 public int maxProfit(int[] prices) {
        int len = prices.length;
        int res = 0;
        // 前一天卖出可以获得的最大利润
        int pre = 0;
        for (int i = 1; i < len; i++) {
            // 利润差
            int diff = prices[i] - prices[i - 1];
           // 状态转移方程:第i天卖出可以获得的最大利润 = 第i-1天卖出的最大利润 + 利润差
            pre = Math.max(pre + diff, 0);
            res = Math.max(res, pre);
        }
        return res;
    }
11. 盛最多水的容器

难度中等3106收藏分享切换为英文接收动态反馈

给你 n 个非负整数 a1,a2,...,a``n,每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai)(i, 0) 。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。

**说明:**你不能倾斜容器。

示例 1:

img

输入:[1,8,6,2,5,4,8,3,7]
输出:49 
解释:图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。

示例 2:

输入:height = [1,1]
输出:1

示例 3:

输入:height = [4,3,2,1,4]
输出:16

示例 4:

输入:height = [1,2,1]
输出:2

提示:

  • n == height.length
  • 2 <= n <= 105
  • 0 <= height[i] <= 104

题解:

//暴力,但是超时间了
class Solution {
    public int maxArea(int[] height) {
        int nLength= height.length;
        int res = 0;
        for(int i=0;i<nLength;i++){
            for(int j = i+1;j<nLength;j++){
                int area = (j-i)*Math.min(height[j],height[i]);
                res = Math.max(res,area);
            }
        }
        return res;

    }
}
class Solution {
     public int maxArea(int[] height) {
        int i = 0, j = height.length - 1, res = 0;
        while(i < j) {
            res = height[i] < height[j] ? 
                Math.max(res, (j - i) * height[i++]): 
                Math.max(res, (j - i) * height[j--]); 
        }
        return res;
    }
}

在每个状态下,无论长板或短板向中间收窄一格,都会导致水槽 底边宽度 -1变短:

若向内 移动短板 ,水槽的短板 min(h[i], h[j])可能变大,因此下个水槽的面积 可能增大 。
若向内 移动长板 ,水槽的短板 min(h[i], h[j])不变或变小,因此下个水槽的面积 一定变小 。
因此,初始化双指针分列水槽左右两端,循环每轮将短板向内移动一格,并更新面积最大值,直到两指针相遇时跳出;即可获得最大面积。

13. 罗马数字转整数

难度简单1657收藏分享切换为英文接收动态反馈

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

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

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

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

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

给定一个罗马数字,将其转换成整数。

示例 1:

输入: s = "III"
输出: 3

示例 2:

输入: s = "IV"
输出: 4

示例 3:

输入: s = "IX"
输出: 9

示例 4:

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

示例 5:

输入: s = "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

题解:

class Solution {
    public int romanToInt(String s) {
        Map<Character,Integer> mapTest = new HashMap<Character,Integer>(){{
            put('I',1);
            put('V',5);
            put('X',10);
            put('L',50);
            put('C',100);
            put('D',500);
            put('M',1000);
        }};
        int nLength  = s.length();
        if(nLength==1){
            return mapTest.get(s.charAt(0));
        }
        int nSum =0;
        for(int i =0;i<nLength;i++){
            int cur = mapTest.get(s.charAt(i));
            if(i<nLength-1&&cur<mapTest.get(s.charAt(i+1))){
                nSum-=cur;
            }else{
                nSum+=cur;
            }

        }
        return nSum;

    }
}
16. 最接近的三数之和

难度中等1012收藏分享切换为英文接收动态反馈

给你一个长度为 n 的整数数组 nums 和 一个目标值 target。请你从 nums 中选出三个整数,使它们的和与 target 最接近。

返回这三个数的和。

假定每组输入只存在恰好一个解。

示例 1:

输入:nums = [-1,2,1,-4], target = 1
输出:2
解释:与 target 最接近的和是 2 (-1 + 2 + 1 = 2) 。

示例 2:

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

提示:

  • 3 <= nums.length <= 1000
  • -1000 <= nums[i] <= 1000
  • -104 <= target <= 104

题解:

//先排序,后三指针逻辑比较
class Solution {
    public int threeSumClosest(int[] nums, int target) {
        Arrays.sort(nums);
        int ans = nums[0] + nums[1] + nums[2];
        for(int i=0;i<nums.length;i++) {
            int start = i+1, end = nums.length - 1;
            while(start < end) {
                int sum = nums[start] + nums[end] + nums[i];
                if(Math.abs(target - sum) < Math.abs(target - ans))
                    ans = sum;
                if(sum > target)
                    end--;
                else if(sum < target)
                    start++;
                else
                    return ans;
            }
        }
        return ans;
    }
}

102. 二叉树的层序遍历

难度中等1153收藏分享切换为英文接收动态反馈

给你二叉树的根节点 root ,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)。

示例 1:

img

输入:root = [3,9,20,null,null,15,7]
输出:[[3],[9,20],[15,7]]

示例 2:

输入:root = [1]
输出:[[1]]

示例 3:

输入:root = []
输出:[]

提示:

  • 树中节点数目在范围 [0, 2000]
  • -1000 <= Node.val <= 1000

题解:

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        //用来存放最终结果
		List<List<Integer>> res = new ArrayList<List<Integer>>();
		if(root==null) {
			return res;
		}
		dfs(1,root,res);
		return res;
	}
	
	void dfs(int index,TreeNode root, List<List<Integer>> res) {
		//假设res是[ [1],[2,3] ], index是3,就再插入一个空list放到res中
		if(res.size()<index) {
			res.add(new ArrayList<Integer>());
		}
		//将当前节点的值加入到res中,index代表当前层,假设index是3,节点值是99
		//res是[ [1],[2,3] [4] ],加入后res就变为 [ [1],[2,3] [4,99] ]
		res.get(index-1).add(root.val);
		//递归的处理左子树,右子树,同时将层数index+1
		if(root.left!=null) {
			dfs(index+1, root.left, res);
		}
		if(root.right!=null) {
			dfs(index+1, root.right, res);
		}
	}

}
72. 编辑距离

难度困难2053收藏分享切换为英文接收动态反馈

给你两个单词 word1word2,请你计算出将 word1 转换成 word2 所使用的最少操作数 。

你可以对一个单词进行如下三种操作:

  • 插入一个字符
  • 删除一个字符
  • 替换一个字符

示例 1:

输入:word1 = "horse", word2 = "ros"
输出:3
解释:
horse -> rorse (将 'h' 替换为 'r')
rorse -> rose (删除 'r')
rose -> ros (删除 'e')

示例 2:

输入:word1 = "intention", word2 = "execution"
输出:5
解释:
intention -> inention (删除 't')
inention -> enention (将 'i' 替换为 'e')
enention -> exention (将 'n' 替换为 'x')
exention -> exection (将 'n' 替换为 'c')
exection -> execution (插入 'u')

提示:

  • 0 <= word1.length, word2.length <= 500
  • word1word2 由小写英文字母组成

首先转换思路,题目给的三种操作插入,删除,替换;分配到两个字符串相当于有6个操作

对word1插入一个字符,其实就相当于在word2删除一个字符
例如 (word1)abc -> abcd 插入了d,相当于 (word2)abcd - > abc 删除了d 最终结果两者就是一样了
对word1删除一个字符,其实就相当于在word2中插入一个字符(和1解释一样)
对word1更换一个字符和对word2更换一个字符没什么区别
所以可以总结,其实一共就三种操作

对word1删除操作
对word2删除操作
对word1替换操作
初始化
首先我们要知道的是,如果其中有一个字符串为空串的话,那么编辑距离一定是另一个字符串的长度(只需要空串添加相应字符即可)
所以初始化数据 dp[i][0] 和 dp[0][i] 都是等于非0字符串长度值!

class Solution {
    public int minDistance(String word1, String word2) {
        int length1 = word1.length();
        int length2 = word2.length();
        int[][] dp = new int[length1 + 1][length2 + 1];
        // 第一行 dp[0][i] = 1 2 3 4 5 6 ... length2
        for (int j = 1; j <= length2; j++) {
            dp[0][j] = j;
        }
        // 第一列 dp[i][0] = 1 2 3 4 5 6 ... length1
        for (int i = 1; i <= length1; i++) {
            dp[i][0] = i;
        }
        /**
         * 开始循环遍历两个字符的一一匹配~
         */
        for (int i = 1; i <= length1; i++) {
            for (int j = 1; j <= length2; j++) {
                if (word1.charAt(i - 1) == word2.charAt(j - 1)) {
                    /**
                     * 如果两个字符串的第i个字符和另一字符串的第j字符相同
                     * 则编辑距离就等于两个字符串前i-1个字符和另一个字符的前j-1个字符的编辑距离(这个有点类似于公共子序列!)
                     */
                    dp[i][j] = dp[i - 1][j - 1];
                }else{
                    /**
                     * 如果两个字符不相等,A,B
                     * 在三种情形中取较小值!
                     * ①A前i-1个字符 和 B前j-1个字符的编辑距离 + 1,因为更换(A or B)第i个字符可以使得两个字符相等,所以加一步替换操作
                     * ②A前i个字符  和  B前j-1个字符的编辑距离 + 1,因为可以删除B的第i个字符,所以加一步删除操作
                     * ③A前i-1个字符 和 B前j个字符的  编辑距离 + 1,因为可以删除A的第i个字符,所以加一步删除操作
                     */
                    dp[i][j] = Math.min(Math.min(dp[i - 1][j - 1], dp[i][j - 1]), dp[i - 1][j]) + 1;
                }
            }
        }
        return dp[length1][length2];
    }
}


121. 买卖股票的最佳时机

难度简单2108收藏分享切换为英文接收动态反馈

给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。

你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。

返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0

示例 1:

输入:[7,1,5,3,6,4]
输出:5
解释:在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。
     注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格;同时,你不能在买入前卖出股票。

示例 2:

输入:prices = [7,6,4,3,1]
输出:0
解释:在这种情况下, 没有交易完成, 所以最大利润为 0。

提示:

  • 1 <= prices.length <= 105
  • 0 <= prices[i] <= 104
class Solution {
    public int maxProfit(int[] prices) {
        int nLength = prices.length;
        int res =0;
        int pre = 0;
        for(int i=1;i<nLength;i++){
            int def = prices[i] - prices[i-1];
            pre = Math.max(pre+def,0);
            res = Math.max(res,pre);
        }
        return res;
    }
    public int maxProfit1(int[] prices) {
        int nLength = prices.length;
        int nMax =0;
        for(int i=0;i<nLength;i++){
            for(int j = nLength-1;j>i;j--){
                int sum = prices[j]-prices[i];
                if(sum>0){
                    nMax = Math.max(nMax,sum);
                }
            }
        }
        return nMax;
    }
}
11. 盛最多水的容器

难度中等3173收藏分享切换为英文接收动态反馈

给你 n 个非负整数 a1,a2,...,a``n,每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai)(i, 0) 。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。

**说明:**你不能倾斜容器。

示例 1:

img

输入:[1,8,6,2,5,4,8,3,7]
输出:49 
解释:图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。

示例 2:

输入:height = [1,1]
输出:1

示例 3:

输入:height = [4,3,2,1,4]
输出:16

示例 4:

输入:height = [1,2,1]
输出:2

提示:

  • n == height.length
  • 2 <= n <= 105
  • 0 <= height[i] <= 104
class Solution {
     public int maxArea(int[] height) {
        int i = 0, j = height.length - 1, res = 0;
        while(i < j) {
            res = height[i] < height[j] ? 
                Math.max(res, (j - i) * height[i++]): 
                Math.max(res, (j - i) * height[j--]); 
        }
        return res;
    }


    public int maxArea1(int[] height) {
        int nLength= height.length;
        int res = 0;
        for(int i=0;i<nLength;i++){
            for(int j = i+1;j<nLength;j++){
                int area = (j-i)*Math.min(height[j],height[i]);
                res = Math.max(res,area);
            }
        }
        return res;

    }
}
136. 只出现一次的数字

难度简单2239收藏分享切换为英文接收动态反馈

给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。

说明:

你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?

示例 1:

输入: [2,2,1]
输出: 1

示例 2:

输入: [4,1,2,1,2]
输出: 4
class Solution {
    public int singleNumber(int[] nums) {
        int sign = 0;
        for(int num :nums){
            sign ^= num;
        }
        return sign;
        

    }
}
13. 罗马数字转整数

难度简单1689收藏分享切换为英文接收动态反馈

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

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

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

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

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

给定一个罗马数字,将其转换成整数。

示例 1:

输入: s = "III"
输出: 3

示例 2:

输入: s = "IV"
输出: 4

示例 3:

输入: s = "IX"
输出: 9

示例 4:

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

示例 5:

输入: s = "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
class Solution {
    public int romanToInt(String s) {
        Map<Character,Integer> mapTest = new HashMap<Character,Integer>(){{
            put('I',1);
            put('V',5);
            put('X',10);
            put('L',50);
            put('C',100);
            put('D',500);
            put('M',1000);
        }};
        int nLength  = s.length();
        if(nLength==1){
            return mapTest.get(s.charAt(0));
        }
        int nSum =0;
        for(int i =0;i<nLength;i++){
            int cur = mapTest.get(s.charAt(i));
            if(i<nLength-1&&cur<mapTest.get(s.charAt(i+1))){
                nSum-=cur;
            }else{
                nSum+=cur;
            }

        }
        return nSum;

    }
}
25. K 个一组翻转链表

难度困难1466收藏分享切换为英文接收动态反馈

给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表。

k 是一个正整数,它的值小于或等于链表的长度。

如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。

进阶:

  • 你可以设计一个只使用常数额外空间的算法来解决此问题吗?
  • 你不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。

示例 1:

img

输入:head = [1,2,3,4,5], k = 2
输出:[2,1,4,3,5]

示例 2:

img

输入:head = [1,2,3,4,5], k = 3
输出:[3,2,1,4,5]

示例 3:

输入:head = [1,2,3,4,5], k = 1
输出:[1,2,3,4,5]

示例 4:

输入:head = [1], k = 1
输出:[1]

提示:

  • 列表中节点的数量在范围 sz
  • 1 <= sz <= 5000
  • 0 <= Node.val <= 1000
  • 1 <= k <= sz
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode reverseKGroup(ListNode head, int k) {
    ListNode dummy = new ListNode(0);
    dummy.next = head;

    ListNode pre = dummy;
    ListNode end = dummy;

    while (end.next != null) {
        for (int i = 0; i < k && end != null; i++) end = end.next;
        if (end == null) break;
        ListNode start = pre.next;
        ListNode next = end.next;
        end.next = null;
        pre.next = reverse(start);
        start.next = next;
        pre = start;

        end = pre;
    }
    return dummy.next;
}
    public ListNode reverse(ListNode head){
        ListNode cur=head,nxt=head,pre=null;
        while(cur!=null){
            nxt = cur.next;
            cur.next = pre;
            pre = cur;
            cur = nxt;
        }
        return pre;
    }

}
    
53. 最大子数组和

难度简单4331收藏分享切换为英文接收动态反馈

给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

子数组 是数组中的一个连续部分。

示例 1:

输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
输出:6
解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。

示例 2:

输入:nums = [1]
输出:1

示例 3:

输入:nums = [5,4,-1,7,8]
输出:23

提示:

  • 1 <= nums.length <= 105
  • -104 <= nums[i] <= 104

**进阶:**如果你已经实现复杂度为 O(n) 的解法,尝试使用更为精妙的 分治法 求解。

class Solution {
    public int maxSubArray(int[] nums) {
        int nLength = nums.length;
        int[] dp = new int[nLength];
        dp[0] = nums[0];
        int res = dp[0];
        for(int i=1;i<nLength;i++){
            if(dp[i-1]>0){
                dp[i] = dp[i-1] + nums[i];
            }else{
                dp[i] = nums[i];
            }
            res = Math.max(res,dp[i]);
        }
        return res;

    }
}
283. 移动零

难度简单1427收藏分享切换为英文接收动态反馈

给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。

请注意 ,必须在不复制数组的情况下原地对数组进行操作。

示例 1:

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

示例 2:

输入: nums = [0]
输出: [0]

提示:

  • 1 <= nums.length <= 104
  • -231 <= nums[i] <= 231 - 1

**进阶:**你能尽量减少完成的操作次数吗?

class Solution {
    public void moveZeroes(int[] nums) {
        if(nums==null) {
			return;
		}
		//两个指针i和j
		int j = 0;
        int nLength = nums.length;
        for(int i=0;i<nLength;i++){
            if(nums[i]!=0) {
				int tmp = nums[i];
				nums[i] = nums[j];
				nums[j++] = tmp;
			}

        }

    }
}
剑指 Offer 22. 链表中倒数第k个节点

难度简单323收藏分享切换为英文接收动态反馈

输入一个链表,输出该链表中倒数第k个节点。为了符合大多数人的习惯,本题从1开始计数,即链表的尾节点是倒数第1个节点。

例如,一个链表有 6 个节点,从头节点开始,它们的值依次是 1、2、3、4、5、6。这个链表的倒数第 3 个节点是值为 4 的节点。

示例:

给定一个链表: 1->2->3->4->5, 和 k = 2.

返回链表 4->5.
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode getKthFromEnd(ListNode head, int k) {
          int n = 0;
       for(ListNode p = head; p != null; p = p.next) n++;
       if(k > n) return null;
        int count = n-k+1;
        ListNode cur = head;
        while(count>1){
            count--;
            cur = cur.next;
        }
        return cur;
    }
}
21. 合并两个有序链表

难度简单2183收藏分享切换为英文接收动态反馈

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

示例 1:

img

输入: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 均按 非递减顺序 排列
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        if(l1 == null){
            return l2;
        }
        if(l2 == null){
            return l1;
        }
        ListNode tmp = new ListNode(-1);
        ListNode l3=tmp;
        while(l1!=null&&l2!=null){
            if(l1.val>=l2.val){
                l3.next=l2;
                l2 = l2.next;
            }else{
                l3.next=l1;
                l1 = l1.next;
            } 
            
            l3 = l3.next;
        }
        l3.next=l1==null ? l2:l1;
        return tmp.next;
    }
}
剑指 Offer 03. 数组中重复的数字

难度简单695收藏分享切换为英文接收动态反馈

找出数组中重复的数字。

在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。

示例 1:

输入:
[2, 3, 1, 0, 2, 5, 3]
输出:2 或 3 

限制:

2 <= n <= 100000
class Solution {
    public int findRepeatNumber(int[] nums) {
        int length = nums.length;
        int[] temp = new int[length];
        for(int i=0;i<length;i++){
            temp[nums[i]]++;
            if(temp[nums[i]]>1){
                return nums[i];
            }
        }
        return -1;
    }
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值