LeetCode分析与题解 31-40

LeetCode31 下一个排列

实现获取下一个排列的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列。
如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列)。
必须原地修改,只允许使用额外常数空间。
以下是一些例子,输入位于左侧列,其相应输出位于右侧列。
1,2,3 → 1,3,2
3,2,1 → 1,2,3
1,1,5 → 1,5,1

class Solution {
    public void nextPermutation(int[] nums) {
        if(nums == null || nums.length <= 1){
            return;
        }
        int t = nums.length - 1,p = t,temp;//t为标记从右往左第一个非降序排列
        while(--t >= 0){
            if(nums[t] < nums[t + 1]){
                break;
            }
        }
        if(t < 0){
            Arrays.sort(nums,0,nums.length);
        }else{
            while(p > t){
                if(nums[t] >= nums[p]){
                    p--;
                }else{
                    break;
                }
            }
            temp = nums[p];
            nums[p] = nums[t];
            nums[t] = temp;
            Arrays.sort(nums,t+1,nums.length);
        }
        
    }
}

LeetCode32 最长有效括号

给定一个只包含 ‘(’ 和 ‘)’ 的字符串,找出最长的包含有效括号的子串的长度。
示例 1:
输入: “(()”
输出: 2
解释: 最长有效括号子串为 “()”
示例 2:
输入: “)()())”
输出: 4
解释: 最长有效括号子串为 “()()”

class Solution {
    public int longestValidParentheses(String s) {
        if(s == null || s.length() == 0 || s.length() == 1){
            return 0;
        }
        int[] dp = new int [s.length()];
        int max = 0;
        for(int i = 1;i < s.length();i++){
            if(s.charAt(i) == '('){
                dp[i] = 0;
            }else if(s.charAt(i-1) == '('){
                dp[i] = i == 1 ? 2 : dp[i-2] + 2;
            }else if(i-1-dp[i-1] >= 0 && s.charAt(i-1-dp[i-1]) == '('){
                dp[i] = dp[i-1] + 2 + (i-2-dp[i-1] >= 0 ? dp[i-2-dp[i-1]] : 0);
            }
            max = max > dp[i] ? max : dp[i];
        }
        return max;
    }
}

LeetCode33 搜索旋转排序数组

假设按照升序排序的数组在预先未知的某个点上进行了旋转。
( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。
搜索一个给定的目标值,如果数组中存在这个目标值,则返回它的索引,否则返回 -1 。
你可以假设数组中不存在重复的元素。
你的算法时间复杂度必须是 O(log n) 级别。
示例 1:
输入: nums = [4,5,6,7,0,1,2], target = 0
输出: 4
示例 2:
输入: nums = [4,5,6,7,0,1,2], target = 3
输出: -1

class Solution {
    public int search(int[] nums, int target) {
        if(nums == null || nums.length == 0){
            return -1;
        }
        int left = 0,right = nums.length - 1,mid;
        while(right >= left){
            mid = (left + right) / 2;
            if(nums[mid] == target){
                return mid;
            }
            if(nums[mid] > nums[nums.length-1]){
                if(target < nums[mid] && target > nums[nums.length-1]){
                    right = mid - 1;
                }else{
                    left = mid + 1;
                }
            }else{
                if(target > nums[mid] && (target < nums[0] || nums[nums.length-1] > nums[0])){
                    left = mid + 1;
                }else{
                    right = mid - 1;
                }
            }
        }
        return -1;
    }
}

LeetCode34 在排序数组中查找元素的第一个和最后一个位置

给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位
置和结束位置。
你的算法时间复杂度必须是 O(log n) 级别。
如果数组中不存在目标值,返回 [-1, -1]。
示例 1:
输入: nums = [5,7,7,8,8,10], target = 8
输出: [3,4]
示例 2:
输入: nums = [5,7,7,8,8,10], target = 6
输出: [-1,-1]

class Solution {
    public int[] searchRange(int[] nums, int target) {
        if(nums == null || nums.length == 0){
            return new int[]{-1,-1};
        }
        int left = 0,right = nums.length - 1,midLeft = (left + right) / 2,midRight = midLeft;
        while(right >= left){
            midLeft = (left + right) / 2;
            if(nums[midLeft] == target){
                if(midLeft == 0 || nums[midLeft-1] != target){
                    break;
                }
                right = midLeft - 1;
            }else if(nums[midLeft] > target){
                right = midLeft - 1;
            }else{
                left = midLeft + 1;
            }
        }
        left = midLeft;
        right = nums.length - 1;
        while(right >= left){
            midRight = (left + right) / 2;
            if(nums[midRight] == target){
                if(midRight == nums.length - 1 || nums[midRight+1] != target){
                    break;
                }
                left = midRight + 1;
            }else if(nums[midRight] > target){
                right = midRight - 1;
            }else{
                left = midRight + 1;
            }
        }
        if(nums[midLeft] != target){
            return new int[]{-1,-1};
        }
        return new int[]{midLeft,midRight};
    }
}

LeetCode35 搜索插入位置

给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
你可以假设数组中无重复元素。
示例 1:
输入: [1,3,5,6], 5
输出: 2
示例 2:
输入: [1,3,5,6], 2
输出: 1
示例 3:
输入: [1,3,5,6], 7
输出: 4
示例 4:
输入: [1,3,5,6], 0
输出: 0

class Solution {
    public int searchInsert(int[] nums, int target) {
        if(nums == null || nums.length == 0){
            return 0;
        }
        int left = 0,right = nums.length - 1,mid = (left + right) / 2;
        while(right >= left){
            mid = (left + right) / 2;
            if(nums[mid] == target){
                return mid;
            }else if(nums[mid] > target){
                right = mid - 1;
            }else{
                left = mid + 1;
            }
        }
        return left;
    }
}

LeetCode36 有效的数独

判断一个 9x9 的数独是否有效。只需要根据以下规则,验证已经填入的数字是否有效即可。
数字 1-9 在每一行只能出现一次。
数字 1-9 在每一列只能出现一次。
数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。
在这里插入图片描述
上图是一个部分填充的有效的数独。
数独部分空格内已填入了数字,空白格用 ‘.’ 表示。
示例 1:
输入:
[
[“5”,“3”,".",".",“7”,".",".",".","."],
[“6”,".",".",“1”,“9”,“5”,".",".","."],
[".",“9”,“8”,".",".",".",".",“6”,"."],
[“8”,".",".",".",“6”,".",".",".",“3”],
[“4”,".",".",“8”,".",“3”,".",".",“1”],
[“7”,".",".",".",“2”,".",".",".",“6”],
[".",“6”,".",".",".",".",“2”,“8”,"."],
[".",".",".",“4”,“1”,“9”,".",".",“5”],
[".",".",".",".",“8”,".",".",“7”,“9”]
]
输出: true
示例 2:
输入:
[
[“8”,“3”,".",".",“7”,".",".",".","."],
[“6”,".",".",“1”,“9”,“5”,".",".","."],
[".",“9”,“8”,".",".",".",".",“6”,"."],
[“8”,".",".",".",“6”,".",".",".",“3”],
[“4”,".",".",“8”,".",“3”,".",".",“1”],
[“7”,".",".",".",“2”,".",".",".",“6”],
[".",“6”,".",".",".",".",“2”,“8”,"."],
[".",".",".",“4”,“1”,“9”,".",".",“5”],
[".",".",".",".",“8”,".",".",“7”,“9”]
]
输出: false
解释: 除了第一行的第一个数字从 5 改为 8 以外,空格内其他数字均与 示例1 相同。
但由于位于左上角的 3x3 宫内有两个 8 存在, 因此这个数独是无效的。
说明:
一个有效的数独(部分已被填充)不一定是可解的。
只需要根据以上规则,验证已经填入的数字是否有效即可。
给定数独序列只包含数字 1-9 和字符 ‘.’ 。
给定数独永远是 9x9 形式的。

class Solution {
    public boolean isValidSudoku(char[][] board) {
        boolean[][] line = new boolean[9][9];
        boolean[][] col = new boolean[9][9];
        boolean[][] palace  = new boolean[9][9];
        int num;
        for(int i = 0;i < 9;i++){
            for(int j = 0;j < 9;j++){
                if('.' == board[i][j]){
                    continue;
                }
                num = board[i][j] - '1';
                if(line[i][num] || col[j][num] || palace[i/3+j/3*3][num]){
                    return false;
                }
                line[i][num] = true;
                col[j][num] = true;
                palace[i/3+j/3*3][num] = true;
            }
        }
        return true;
    }
}

LeetCode37 解数独

编写一个程序,通过已填充的空格来解决数独问题。
一个数独的解法需遵循如下规则:
数字 1-9 在每一行只能出现一次。
数字 1-9 在每一列只能出现一次。
数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。
空白格用 ‘.’ 表示。
在这里插入图片描述
一个数独。
在这里插入图片描述
答案被标成红色。
Note:
给定的数独序列只包含数字 1-9 和字符 ‘.’ 。
你可以假设给定的数独只有唯一解。
给定数独永远是 9x9 形式的。

class Solution {
    public void solveSudoku(char[][] board) {
        boolean[][] box = new boolean [9][9];
        boolean[][] col = new boolean [9][9];
        boolean[][] palace =  new boolean [9][9];
        int num;

        for(int i = 0;i < 9;i++){
            for(int j = 0;j < 9;j++){
                if('.' != board[i][j]){
                    num = board[i][j] - '1';
                    box[i][num] = true;
                    col[j][num] = true;
                    palace[i/3+j/3*3][num] = true;
                }
            }
        }
        dfs(board,box,col,palace,0,0);//回溯
    }

    private boolean dfs(char[][] board,boolean[][] box,boolean[][] col,boolean[][] palace,int i,int j){
        while('.' != board[i][j]){//寻找第一个没有数字的节点
            j++;
            if(j >= 9){
                i++;
                j = 0;
            }
            if(i >= 9){
                return true;
            }
        }

        for(int k = 0;k < 9;k++){
            if(box[i][k] || col[j][k] || palace[i/3+j/3*3][k]){
                continue;
            }
            box[i][k] = true;
            col[j][k] = true;
            palace[i/3+j/3*3][k] = true;
            board[i][j] = (char)(k + '1');
            if(dfs(board,box,col,palace,i,j)){
                return true;
            }else{
                box[i][k] = false;
                col[j][k] = false;
                palace[i/3+j/3*3][k] = false;
                board[i][j] = '.';
            }
        }
        return false;
    }
}

LeetCode38 报数

报数序列是一个整数序列,按照其中的整数的顺序进行报数,得到下一个数。其前五项如下:
1 1
2 11
3 21
4 1211
5 111221
1 被读作 “one 1” (“一个一”) , 即 11。
11 被读作 “two 1s” (“两个一”), 即 21。
21 被读作 “one 2”, “one 1” (“一个二” , “一个一”) , 即 1211。
给定一个正整数 n(1 ≤ n ≤ 30),输出报数序列的第 n 项。
注意:整数顺序将表示为一个字符串。
示例 1:
输入: 1
输出: “1”
示例 2:
输入: 4
输出: “1211”

class Solution {
    public String countAndSay(int n) {
        String s = "1";
        char u;
        StringBuffer p;
        int num = 0;
        while(--n != 0){
            u = s.charAt(0);
            num = 1;
            p = new StringBuffer();
            for(int i = 1;i < s.length();i++){
                if(s.charAt(i) != u){
                    p.append(num).append(u);  
                    u = s.charAt(i);
                    num = 1;
                }else{
                    num++;
                }
            }
            p.append(num).append(u);
            s = p.toString();
        }
        return s;
    }
}

LeetCode39 组合总和

给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target的组合。
candidates 中的数字可以无限制重复被选取。
说明:
所有数字(包括 target)都是正整数。
解集不能包含重复的组合。
示例 1:
输入: candidates = [2,3,6,7], target = 7,
所求解集为:
[
[7],
[2,2,3]
]
示例 2:
输入: candidates = [2,3,5], target = 8,
所求解集为:
[
[2,2,2,2],
[2,3,3],
[3,5]
]

class Solution {
    public List<List<Integer>> combinationSum(int[] candidates, int target) {
        List<List<Integer>> list = new ArrayList<List<Integer>>();
        Arrays.sort(candidates);
        
        dfs(list,new ArrayList<Integer>(),candidates,target,0);
        return list;
    }

    private void dfs(List<List<Integer>> list,List<Integer> myList,int[] candidates,int target,int i){
        if(target < 0){
            return ;
        }else if(target == 0){
            list.add(new ArrayList<>(myList));
            return ;
        }
        for(int j = i;j < candidates.length;j++){ 
            if(target < candidates[j]){
                break;
            }
            myList.add(candidates[j]);
            dfs(list,myList,candidates,target-candidates[j],j);
            myList.remove((Integer)candidates[j]);
        }
        return ;
    }
}

LeetCode40 组合总和 II

给定一个数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。
candidates 中的每个数字在每个组合中只能使用一次。
说明:
所有数字(包括目标数)都是正整数。
解集不能包含重复的组合。
示例 1:
输入: candidates = [10,1,2,7,6,1,5], target = 8,
所求解集为:
[
[1, 7],
[1, 2, 5],
[2, 6],
[1, 1, 6]
]
示例 2:
输入: candidates = [2,5,2,1,2], target = 5,
所求解集为:
[
[1,2,2],
[5]
]

class Solution {
    public List<List<Integer>> combinationSum2(int[] candidates, int target) {
        List<List<Integer>> list = new ArrayList<List<Integer>>();
        Arrays.sort(candidates);
        
        dfs(list,new ArrayList<Integer>(),candidates,target,0);
        return list;
    }

    private void dfs(List<List<Integer>> list,List<Integer> myList,int[] candidates,int target,int i){
        if(target < 0){
            return ;
        }else if(target == 0){
            list.add(new ArrayList<>(myList));
            return ;
        }
        for(int j = i;j < candidates.length;j++){ 
            if(target < candidates[j]){
                break;
            }
            if(j > i && candidates[j] == candidates[j-1]){
                continue;
            }
            myList.add(candidates[j]);
            dfs(list,myList,candidates,target-candidates[j],j+1);
            myList.remove((Integer)candidates[j]);
        }
        return ;
    }
}
发布了113 篇原创文章 · 获赞 206 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/Geffin/article/details/103115409