codetop几道算法题


41. 缺失的第一个正数

给你一个未排序的整数数组 nums ,请你找出其中没有出现的最小的正整数。

请你实现时间复杂度为 O(n) 并且只使用常数级别额外空间的解决方案。

O(n)空间复杂度

class Solution {
    public int firstMissingPositive(int[] nums) {
        boolean[] exists = new boolean[nums.length+1];
        for(int n:nums) {
            if(n>nums.length||n<=0) {
                continue;
            }
            exists[n] = true;
        }
        for(int i=1;i<=nums.length;i++) {
            if(!exists[i]) return i;
        }
        return nums.length+1;
    }
}

但是要求常数级别复杂度,就只能原地那种了。

原地

class Solution {
    public int firstMissingPositive(int[] nums) {
        // 答案最多是n+1,
        for(int i=0;i<nums.length;i++) {
            int cur = i;
            int curNum = nums[cur];
            while(curNum!=cur+1) {
                int nextPos = curNum-1;
                if(nextPos>=nums.length||nextPos<0) break;
                int nextPosNum = nums[nextPos];
                nums[nextPos] = curNum;
                cur =nextPos;
                curNum = nextPosNum;
            }
        }
        for(int i=0;i<nums.length;i++) {
            if(nums[i]!=i+1) return i+1;
        }
        return nums.length+1;
    }
}

不要想着一开始就写最优代码,先能跑再优化。

98. 验证二叉搜索树

验证中序遍历

/**
 * 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 boolean isValidBST(TreeNode root) {
        if(root==null) return true;
        int lastNodeValue = Integer.MIN_VALUE;
        Deque<TreeNode> stack = new LinkedList<>();
        stack.addLast(root);
        TreeNode cur = root;
        boolean firstMeet = true;
        while(!stack.isEmpty()) {
            if(cur.left!=null) {
                stack.addLast(cur.left);
                cur = cur.left;
                continue;
            }
            do {
                if(stack.isEmpty()) return true;
                cur = stack.pollLast();
                if(cur.val>lastNodeValue) {
                    lastNodeValue = cur.val;
                } else if(cur.val==lastNodeValue) {
                    if(!firstMeet) {
                        return false;
                    }
                } else {
                    return false;
                }
                firstMeet = false;
            }  while(cur.right==null);
            stack.addLast(cur.right);
            cur = cur.right;
        }
        return true;
    }
}

递归出神入化写法

我是想不出来。

class Solution {
    private long pre = Long.MIN_VALUE;
    public boolean isValidBST(TreeNode root) {
        if(root==null) return true;
        if(!isValidBST(root.left)) {
            return false;
        }
        if(root.val<=pre) {
            return false;
        }
        pre = root.val;
        if(!isValidBST(root.right)) {
            return false;
        }
        return true;
    }
}

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

class Solution {
    public int lengthOfLongestSubstring(String s) {
        int[] count = new int[128];
        int left = 0;
        int maxLen = -1;
        for(int i=0;i<s.length();i++) {
            if(count[s.charAt(i)]==0) {
                count[s.charAt(i)]++;
            } else {
                maxLen = Math.max(maxLen,i-left);
                while(left<i) {
                    count[s.charAt(left)]--;
                    left++;
                    if(count[s.charAt(i)]==0) {
                        break;
                    }
                }
                count[s.charAt(i)]=1;
            }
        }
        maxLen = Math.max(maxLen,s.length()-left);
        return maxLen;
    }
}

139. 单词拆分

class Solution {
    public boolean wordBreak(String s, List<String> wordDict) {
        boolean[] dp = new boolean[s.length()+1];
        dp[0] = true;
        int cur;
        for(int i=0;i<s.length();i++) {
            cur = i+1;
            for(String word:wordDict) {
                if(cur-word.length()<0) continue;
                if(s.substring(cur-word.length(),cur).equals(word)) {
                    dp[cur] |= dp[cur-word.length()];
                } else {
                    dp[cur] |= false;
                }
            }
        }
        //System.out.println(Arrays.toString(dp));
        return dp[s.length()];
    }
}

209. 长度最小的子数组

class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        int left = 0;
        int minLen = Integer.MAX_VALUE;
        int sum = 0;
        for(int i=0;i<nums.length;i++) {
            sum += nums[i];
            while(sum>=target) {
                minLen = Math.min(minLen,i-left+1);
                sum-=nums[left];
                left++;
            }
        }
        return minLen==Integer.MAX_VALUE?0:minLen;
    }
}

224. 基本计算器

class Solution {
    public int calculate(String s) {
        s = s.trim();
        if(s.length()==0) return 0;
        int i = s.length()-1;
        for(;i>=0;i--) {
            if(s.charAt(i)=='(') break;
        }
        int left = i;
        i = Math.max(left,0);
        for(;i<s.length();i++) {
            if(s.charAt(i)==')') break;
        }
        int right = i;
        int n = s.length();
        int sig = 1;
        int cur = 0;
        int result = 0;
        if(left==-1&&right==n) {
            for(i=0;i<s.length();i++) {
                if(s.charAt(i)==' ') continue;
                if(s.charAt(i)>='0'&&s.charAt(i)<='9') cur = cur*10+s.charAt(i)-'0';
                else {
                    result += sig*cur;
                    cur = 0;
                    sig = s.charAt(i)=='+'?1:-1;
                }
            }
            result += sig*cur;
            return result;
        }
        int mm = calculate(s.substring(left+1,right));
        if(mm>=0) return calculate(s.substring(0,left)+String.valueOf(mm)+s.substring(right+1,s.length()));
        else {
            String le = s.substring(0,left).trim();
            String ri = s.substring(right+1,s.length());
            if(ri.length()==0) ri="+0";
            if(le.length()==0) le="0+";
            char cc = le.charAt(le.length()-1);
            le = le.substring(0,le.length()-1);
            if(cc=='-') {
                return calculate(le+"+"+String.valueOf(0-mm)+ri);
            } else {
                return calculate(le+String.valueOf(mm)+ri);
            }
        }
    }
}

166. 分数到小数



import java.util.HashMap;
import java.util.Map;

class Solution {
    public String fractionToDecimal(long numerator, long denominator) {
        if(numerator==0) return "0";
        if(numerator<0&&denominator<0) return fractionToDecimal(-numerator,-denominator);
        if(numerator<0) return "-"+fractionToDecimal(-numerator,denominator);
        if(denominator<0) return "-"+fractionToDecimal(numerator,-denominator);
        String result = "0.";
        if(numerator%denominator==0) return String.valueOf(numerator/denominator);
        if(numerator>denominator) result= numerator / denominator +".";
        numerator = numerator%denominator;
        long oriNumerator = numerator;
        Map<Long,Integer> pos = new HashMap<>();
        pos.put(oriNumerator,result.length());
        numerator*=10;

        while(numerator<denominator) {
            result+="0";
            numerator*=10;
        }


         while(true) {
            result+=String.valueOf(numerator/denominator);
            numerator = numerator%denominator;
            if(numerator==0) return result;
            if(pos.containsKey(numerator)) {
            //if(numerator==oriNumerator) {
                int dotPos = result.lastIndexOf('.');
                return result.substring(0,dotPos+1)+result.substring(dotPos+1,pos.get(numerator))+"(" +result.substring(pos.get(numerator),result.length())+")";
            }
            pos.put(numerator,result.length());
            numerator*=10;
            while(numerator<denominator) {
                result+="0";
                numerator*=10;
            }
        }
    }

    public static void main(String[] args) {
        //System.out.println(new Solution().fractionToDecimal(4,2));
        System.out.println(new Solution().fractionToDecimal(12,6));
        System.out.println(new Solution().fractionToDecimal(4,123));
    }
}

121. 买卖股票的最佳时机

class Solution {
    public int maxProfit(int[] prices) {
        int[] rightMax = new int[prices.length];
        int m = 0;
        for(int i=prices.length-1;i>=0;i--) {
            m = Math.max(m,prices[i]);
            rightMax[i] = m;
        }

        int[] leftMin = new int[prices.length];
        int n = 10001;
        for(int i=0;i<prices.length;i++) {
            n = Math.min(n,prices[i]);
            leftMin[i] = n;
        }
        int result = 0;
        for(int i=0;i<prices.length;i++) {
            result = Math.max(result,rightMax[i]-leftMin[i]);
        }
        return result;
    }
}

1049. 最后一块石头的重量 II

该题可以抽象为将n块石头分为两堆,而后求两堆石头重量总和的最小差值。因此便可看为01背包问题,背包最大容量为这n块石头总重量的一半。那么理想情况下,如果可以刚好装满背包,两堆石头重量总和的最小差值便可为零。

class Solution {
    public int lastStoneWeightII(int[] stones) {
        int sum = 0;
        for(int stone:stones) {
            sum+=stone;
        }
        int target = sum/2;
        // dp[i][j] j块石头,容量为i最多能放
        // dp[i][j]: max(dp[i][j],dp[i-stone][j]+stone)
        int[][] dp = new int[target+1][stones.length+1];
        dp[0][0] = 0;
        for(int i=1;i<=target;i++) {
            for(int j=1;j<=stones.length;j++) {
                if(i>=stones[j-1]) dp[i][j] = Math.max(dp[i][j-1],dp[i-stones[j-1]][j-1]+stones[j-1]);
                else dp[i][j]=dp[i][j-1];
            }
        }
        return sum-2*dp[target][stones.length];
    }
}

二维、一维。

image-20220309220241333