搜索旋转排序数组、买卖股票、岛屿数量


33. 搜索旋转排序数组

递归,考虑子数组所有可能情况,代码看着不够优雅:

class Solution {
    public int search(int[] nums, int target) {
        return search(nums,target,0,nums.length-1);
    }

    private int search(int[] nums,int target,int left,int right) {
        if(left>right) return -1;
        int mid = (left+right)/2;
        if(nums[left]==target) return left;
        if(nums[right]==target) return right;
        if(nums[mid]==target) return mid;
        if(nums[right]>nums[left]) {
            if(nums[mid]>target) return search(nums,target,left,mid-1);
            else return search(nums,target,mid+1,right);
        }
        if(nums[mid]>nums[left]) {
            if(target<nums[left]||target>nums[mid]) return search(nums,target,mid+1,right);
            else return search(nums,target,left,mid-1);
        }
        if(target<nums[mid]) return search(nums,target,left,mid-1);
        else if(target<=nums[right]) return search(nums,target,mid+1,right);
        else return search(nums,target,left,mid-1);
    }
}

其实也就是这个思想,代码简洁的就是把里面的情况整合了一下。

123. 买卖股票的最佳时机 III

能想到用动态规划,但是第二次交易可能会在第一次交易没成的时候把0认为交易后的,从而导致错误,所以用了个最小值判断。

class Solution {
    public int maxProfit(int[] prices) {
        int n = prices.length;
        int[][][] dp = new int[n][3][2];
        for(int i=0;i<n;i++) {
            for(int j=0;j<3;j++) {
                for(int k=0;k<2;k++) {
                    dp[i][j][k] = Integer.MIN_VALUE;
                }
            }
        }

        // prices遍历,第几次交易,1持有0不持有
        dp[0][0][1] = -prices[0];
        dp[0][0][0] = 0;

        // dp[i][j][1] = max(dp[i-1][j][1],dp[i-1][j][0]-prices[i])
        // dp[i][j][0] = max(dp[i-1][j-1][1]+prices[j],dp[i-1][j][0])

        for(int i=1;i<n;i++) {
            for(int j=0;j<=2;j++) {
                dp[i][j][1] = dp[i-1][j][1];
                if(dp[i-1][j][0]!=Integer.MIN_VALUE) {
                    dp[i][j][1] = Math.max(dp[i-1][j][1],dp[i-1][j][0]-prices[i]);
                }
                
                dp[i][j][0] = dp[i-1][j][0];
                if(j>=1 && dp[i-1][j-1][1]!=Integer.MIN_VALUE) {
                    dp[i][j][0] = Math.max(dp[i][j][0],dp[i-1][j-1][1]+prices[i]);
                }
            }
        }
        //System.out.println(Arrays.deepToString(dp));
        return Math.max(dp[n-1][1][0],Math.max(dp[n-1][2][0],0));
    }
}

一看答案,这么简洁的。。。

OK,一状态压缩,我的也挺简洁:

class Solution {
    public int maxProfit(int[] prices) {
        int n = prices.length;
        int[][] dp = new int[3][2];
        for(int j=0;j<3;j++) {
            for(int k=0;k<2;k++) {
                dp[j][k] = Integer.MIN_VALUE;
            }
        }

        // prices遍历,第几次交易,1持有0不持有
        dp[0][1] = -prices[0];
        dp[0][0] = 0;

        // dp[i][j][1] = max(dp[i-1][j][1],dp[i-1][j][0]-prices[i])
        // dp[i][j][0] = max(dp[i-1][j-1][1]+prices[j],dp[i-1][j][0])

        for(int i=1;i<n;i++) {
            for(int j=0;j<=2;j++) {
                if(dp[j][0]!=Integer.MIN_VALUE) {
                    dp[j][1] = Math.max(dp[j][1],dp[j][0]-prices[i]);
                }
                
                if(j>=1 && dp[j-1][1]!=Integer.MIN_VALUE) {
                    dp[j][0] = Math.max(dp[j][0],dp[j-1][1]+prices[i]);
                }
            }
        }
        //System.out.println(Arrays.deepToString(dp));
        return Math.max(dp[1][0],Math.max(dp[2][0],0));
    }
}

200. 岛屿数量

深搜

直接深搜,遍历过加上标志。

class Solution {
    public int numIslands(char[][] grid) {
        int m = grid.length;
        int n = grid[0].length;

        int result = 0;
        for(int i=0;i<m;i++) {
            for(int j=0;j<n;j++) {
                if(grid[i][j]!='1') continue;
                dfs(grid,i,j);
                result++;
            }
        }
        return result;
    }

    private void dfs(char[][] grid,int i,int j) {
        if(i<0||i>=grid.length||j<0||j>=grid[0].length||grid[i][j]!='1') return;
        grid[i][j] = '#';
        dfs(grid,i+1,j);
        dfs(grid,i-1,j);
        dfs(grid,i,j-1);
        dfs(grid,i,j+1);
    }
}

并查集

好久没写过并查集了,也练练手吧。

class Solution {
    private int[] getFather(int[][][] father,int i,int j) {
        int[] f = father[i][j];
        if(f[0]==i&&f[1]==j) return f;
        return getFather(father,f[0],f[1]);
    }

    private void union(int[][][] father,int i,int j,int a,int b) {
        int[] f = getFather(father,i,j);
        int[] f2 = getFather(father,a,b);
        father[f2[0]][f2[1]][0] = f[0];
        father[f2[0]][f2[1]][1] = f[1];
    }

    public int numIslands(char[][] grid) {
        int m = grid.length;
        int n = grid[0].length;
        int[][][] father = new int[m][n][2];
        for(int i=0;i<m;i++) {
            for(int j=0;j<n;j++) {
                father[i][j][0] = i;
                father[i][j][1] = j;
            }
        }

        for(int i=0;i<m;i++) {
            for(int j=0;j<n;j++) {
                if(grid[i][j]=='1') {
                    if(i>0&&grid[i-1][j]=='1') union(father,i,j,i-1,j);
                    if(j>0&&grid[i][j-1]=='1') union(father,i,j,i,j-1);
                }
            }
        }

        int result = 0;
        for(int i=0;i<m;i++) {
            for(int j=0;j<n;j++) {
                if(grid[i][j]=='1') {
                    int[] f = getFather(father,i,j);
                    if(i==f[0]&&j==f[1]) result++;
                }
                
            }
        }
        return result;
    }
}

遇到的问题:union的时候,

union(father,i,j,i-1,j);
union(father,i,j,i,j-1);

private void union(int[][][] father,int i,int j,int a,int b) {
    int[] f = getFather(father,i,j);
    int[] f2 = getFather(father,a,b);
    father[f2[0]][f2[1]][0] = f[0];
    father[f2[0]][f2[1]][1] = f[1];
}

应该统一把后者挂到前面,也就是父节点挂到父节点。