Java入门编程练习题

题目来源:LeetCode



杨辉三角

1、第n行有n个数字
2、每一行的开始和结尾数字都为1
3、第n+1行的第i个数字等于第n行的i-1个数字加上第n行的i个数字

public class Main {
    
    
    private void print(int[][] arr){
    
    
        for (int i = 0; i < arr.length; i++) {
    
    
            for (int j = 0; j <= i; j++) {
    
    
                System.out.print(arr[i][j]+"\t");
            }
            System.out.println();
        }
    }

    private void rect(int rows){
    
    
        int[][] arr = new int[rows][rows];
        for (int i = 0; i < rows; i++) {
    
    
            for (int j = 0; j <= i; j++) {
    
    
                if (j==0 || i==j) {
    
    
                    arr[i][j] = 1;
                }else {
    
    
                    arr[i][j] = arr[i-1][j-1] + arr[i-1][j];
                }
            }
        }
        print(arr);
    }

    public static void main(String[] args) {
    
    
        Main main = new Main();
        main.rect(10);
    }
}

在这里插入图片描述


删除排序数组中的重复项

给定一个排序数组,你需要在 原地 删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。

示例 1: 给定数组 nums = [1,1,2], 函数应该返回新的长度 2, 并且原数组 nums 的前两个元素被修改为 1, 2。

示例 2: 给定 nums = [0,0,1,1,1,2,2,3,3,4],函数应该返回新的长度 5, 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4。
你不需要考虑数组中超出新长度后面的元素。

解答: 由于已经排序,只需一次遍历,将数字往前移,后面部分即使乱序也不用管

class Solution {
    
    
    public int removeDuplicates(int[] nums) {
    
    
        if (nums.length == 0) return 1;
        int max = nums[0];
        int index = 1;
        int temp = 0;
        for (int i = 1; i < nums.length; i++) {
    
    
            if (nums[i]>max){
    
    
                max = nums[i];
                temp = nums[i];
                nums[i] = nums[index];
                nums[index] = temp;
                index ++;
            }
        }
        return index;
    }
}

在这里插入图片描述
在这里插入图片描述

最后一个单词的长度

给定一个仅包含大小写字母和空格 ’ ’ 的字符串 s,返回其最后一个单词的长度。如果字符串从左向右滚动显示,那么最后一个单词就是最后出现的单词。 如果不存在最后一个单词,请返回 0 。

说明:一个单词是指仅由字母组成、不包含任何空格字符的 最大子字符串。

示例: 输入: “Hello World” ,输出: 5

解答:从后往前,先过滤无用空格

注意: 最后有多个空格的情况

class Solution {
    
    
    public int lengthOfLastWord(String s) {
    
    
        int count = 0;
        for (int i = s.length()-1; i >= 0; i--) {
    
    
            if (s.charAt(i) == ' '){
    
    
                if (count==0) continue;
                break;
            }else {
    
    
                count ++;
            }
        }
        return count;
    }
}

在这里插入图片描述

加一

给定一个由整数组成的非空数组所表示的非负整数,在该数的基础上加一。 最高位数字存放在数组的首位, 数组中每个元素只存储单个数字。 你可以假设除了整数 0 之外,这个整数不会以零开头。

示例 : 输入: [1,2,3] ,输出: [1,2,4],解释: 输入数组表示数字 123。

解答:从后往前,逢10进1

注意: 首位是9的情况

class Solution {
    
    
    public int[] plusOne(int[] digits) {
    
    
        for (int i = digits.length-1; i >= 0; i--) {
    
    
            digits[i] = (digits[i]+1)%10;
            if (digits[i] != 0) {
    
    
                break;
            }
        }
        if(digits[0] == 0){
    
    
            //int[] arr = new int[digits.length+1];
            //arr[0] = 1;
            //System.arraycopy(arr,0,digits,0,digits.length);
            //digits = arr;
            digits = new int[digits.length+1];
            digits[0] = 1;
        }
        return digits;
    }
}

在这里插入图片描述

爬梯子

假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢? 注意:给定 n 是一个正整数。

示例 1: 输入: 2,输出: 2;解释: 有两种方法可以爬到楼顶。
示例 2: 输入: 3,输出: 3;解释: 有三种方法可以爬到楼顶。

解答: 爬到第 xx 级台阶的方案数是爬到第 x - 1x−1 级台阶的方案数和爬到第 x - 2x−2 级台阶的方案数的和:f(x)=f(x−1)+f(x−2)

class Solution {
    
    
    public int climbStairs(int n) {
    
    
        int p = 0;
        int q = 1;
        int res = 0;
        for (int i = 0; i < n; i++) {
    
    
            res = p + q;
            p = q;
            q = res;
        }
        return res;
    }
}

在这里插入图片描述

合并两个有序数组

给你两个有序整数数组 nums1 和 nums2,请你将 nums2 合并到 nums1 中,使 nums1 成为一个有序数组。

说明: 初始化 nums1 和 nums2 的元素数量分别为 m 和 n 。 你可以假设 nums1 有足够的空间(空间大小大于或等于 m + n)来保存 nums2 中的元素。

示例:
输入:nums1 = [1,2,3,0,0,0], m = 3;nums2 = [2,5,6], n = 3
输出: [1,2,2,3,5,6]

解答:三指针从后往前
注意:如[4,5,6,0,0,0]、[1,2,3]的情况
在这里插入图片描述

class Solution {
    
    
    public void merge(int[] nums1, int m, int[] nums2, int n) {
    
    
        int p1 = m - 1;
        int p2 = n - 1;
        int p = m + n - 1;
        while (p1>=0 && p2>=0){
    
    
            if (nums1[p1] >= nums2[p2]){
    
    
                nums1[p] = nums1[p1];
                p1 --;
            }else {
    
    
                nums1[p] = nums2[p2];
                p2 --;
            }
            p --;
        }
        System.arraycopy(nums2,0,nums1,0,p2+1);
    }
}

删除排序链表中的重复元素

给定一个排序链表,删除所有重复的元素,使得每个元素只出现一次。

示例 : 输入: 1->1->2->3->3;输出: 1->2->3

解答:由于已排序,可以只考虑比较相邻节点的值

class Solution {
    
    
    public ListNode deleteDuplicates(ListNode head) {
    
    
        ListNode node = head;
        while (node != null && node.next != null){
    
    
            if (node.val == node.next.val){
    
    
                node.next = node.next.next;
            }else {
    
    
                node = node.next;
            }
        }
        return head;
    }
}

解答成功:执行耗时:1 ms,击败了73.94% 的Java用户;内存消耗:39.5 MB,击败了42.35% 的Java用户

相同的树

给定两个二叉树,编写一个函数来检验它们是否相同。 如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。

示例 :
在这里插入图片描述
解答
递归地判断两个二叉树是否相同。
1、如果两个二叉树都为空,则两个二叉树相同。
2、如果两个二叉树中有且只有一个为空,则两个二叉树一定不相同。
3、如果两个二叉树都不为空,那么首先判断它们的根节点的值是否相同,若不相同则两个二叉树一定不同,若相同,再分别判断两个二叉树的左子树是否相同以及右子树是否相同。

class Solution {
    
    
    public boolean isSameTree(TreeNode p, TreeNode q) {
    
    
        if (p==null && q==null){
    
    
            return true;
        }else if (p==null || q==null){
    
    
            return false;
        }else if (p.val != q.val){
    
    
            return false;
        }else {
    
    
            return isSameTree(p.left, q.left) && isSameTree(p.right, q.right);
        }
    }
}

解答成功: 执行耗时:0 ms,击败了100.00% 的Java用户;内存消耗:37.3 MB,击败了39.50% 的Java用户

对称二叉树

给定一个二叉树,检查它是否是镜像对称的。

实例:二叉树 [1,2,2,3,4,4,3] 是对称的。
在这里插入图片描述
解答
通过「同步移动」两个指针的方法来遍历这棵树,pp 指针和 qq 指针一开始都指向这棵树的根,随后 pp 右移时,qq 左移,pp 左移时,qq 右移。每次检查当前 pp 和 qq 节点的值是否相等,如果相等再判断左右子树是否对称。

class Solution {
    
    
    public boolean check(TreeNode p, TreeNode q){
    
    
        if (p==null && q==null) return true;
        else if (p==null || q==null) return false;
        else return p.val==q.val && check(p.left, q.right) && check(p.right, q.left);
    }

    public boolean isSymmetric(TreeNode root) {
    
    
        return check(root, root);
    }
}

解答成功: 执行耗时:1 ms,击败了29.43% 的Java用户 内存消耗:38.2 MB,击败了26.57% 的Java用户

二叉树的层次遍历-正/反序

给定一个二叉树,返回其节点值自底向上的层次遍历。 (即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历)
例如
给定二叉树 [3,9,20,null,null,15,7],
3
/ \
9 20
/ \
15 7
返回其自底向上的层次遍历为: [[15, 7], [9, 20], [3]]

解答
广度优先遍历,核心是用一个queue队列存节点信息。

class Solution {
    
    
    public List<List<Integer>> levelOrderBottom(TreeNode root) {
    
    
        // 用于存最终结果
        List<List<Integer>> ret = new ArrayList<>();
        // 队列,用于存储节点信息
        Queue<TreeNode> queue = new LinkedList<>();
        if (root == null){
    
    
            return ret;
        }
        // 先将head节点添加入队列,然后开始while循环。
        queue.offer(root);
        // 辅助作用的节点,用于指向出队的节点信息
        TreeNode node;
        while (!queue.isEmpty()){
    
    
            // 临时的列表,存某一层的所有节点。
            ArrayList<Integer> temp = new ArrayList<>();
            // 得到队列的长度,此时队列的长度=这一层的节点数(后面可以发现)
            int len = queue.size();
            // 由于输出结果是二维数组结构,第二维的数组内数量就是该层的全部节点。
            // 所以可以通过for循环填入某一层的所以节点。
            for (int i = 0; i < len; i++) {
    
    
                // 先出队第一个节点
                node = queue.poll();
                // 将该节点的值加入
                temp.add(node.val);
                // 如果左边子节点存在,则加入队列
                if (node.left != null){
    
    
                    queue.offer(node.left);
                }
                // 如果右边子节点存在,则加入队列
                if (node.right != null){
    
    
                    queue.offer(node.right);
                }
            }
            // for循环完成,表示这一层的节点都已获取到,将此接入到结果列表中
            ret.add(temp);
        }
        // 如果是倒序层次遍历,反转一下即可
        Collections.reverse(ret);
        return ret;
    }
}

有序数组转换为二叉搜索树

将一个按照升序排列的有序数组,转换为一棵高度平衡二叉搜索树。 一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1。
例如
给定有序数组: [-10,-3,0,5,9],一个可能的答案是:[0,-3,9,-10,null,5],它可以表示下面这个高度平衡二叉搜索树:

      0
     / \
   -3   9
   /   /
 -10  5

解答

class Solution {
    
    
    public TreeNode tempFunc(int[] nums, int left, int right){
    
    
        // left=right时,区间内只有一个元素
        // left>right时,说明已没有元素,返回null节点
        if (left > right) {
    
    
            return null;
        }
        // 选择中间位置左边的元素作为根节点(因为整除:5/2=2)
        int mid = (left + right)/2;
        // 将元素的值作为中间节点
        TreeNode root = new TreeNode(nums[mid]);
        // 左子节点通过递归调用获得
        // 返回的是中间节点左边区间里,中间元素的节点,让root.left指向它
        // 递归里相当于不断把大区间二分成小区间
        // 简单的情况如“1,2,3,4,5”,
        // 首次进来1:left=0,mid=2,right=4;左边“1,2”,根节点“3”,右边“4,5”。
        // left递归1:left=0,mid=0,right=1;左边“”,根节点“1”,右边“2”。
        // left递归2:left=0,right=-1;不符合,返回null。
        // right递归1:left=3,mid=3,right=4;左边“”,根节点“4”,右边“5”。
        // right递归2:left=4,mid=4,right=4;左边“”,根节点“5”,右边“”。
        // right递归3:left=5,right=4;不符合,返回null。
        // 最终:(二叉搜索树的中序遍历是升序序列)
        //     3
        //    / \
        //    1  4
        //    \   \
        //     2   5
        root.left = tempFunc(nums, left, mid-1);
        // 同上
        root.right = tempFunc(nums, mid+1, right);
        // 返回根节点(相对于当前节点而言是根节点)
        return root;
    }

    public TreeNode sortedArrayToBST(int[] nums) {
    
    
        TreeNode node = tempFunc(nums, 0, nums.length-1);
        return node;
    }
}

平衡二叉树

给定一个二叉树,判断它是否是高度平衡的二叉树。 一棵高度平衡二叉树定义为: 一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过1。
示例:
给定二叉树 [3,9,20,null,null,15,7]

    3
   / \
  9  20
    /  \
  15   7 

返回 true

解答

class Solution {
    
    
    // 将大的树拆成若干个深度<=1的子树
    // 每次判断当前父节点的左右子树的高度差是否>1
    // 每次递归,如果不平衡,返回-1;如果平衡,返回子树的深度(1或0<空节点>)
    // 叠加递归的结果,就是该父节点的深度
    public int tempFunc(TreeNode root){
    
    
        if (root == null){
    
    
            return 0;
        }
        // 自底而上,先递归到最底层的左子树
        int leftHeight = tempFunc(root.left);
        // 左子树完,递归右子树
        int rightHeight = tempFunc(root.right);
        // 如果左右子树的高度差>1,则说明不平衡
        // 如果左或右子树的高度=-1,则说明已经有子树不平衡了
        if (leftHeight==-1 || rightHeight==-1 || Math.abs(leftHeight-rightHeight)>1){
    
    
            return -1;
        }
        // 否则,一切正常,返回左右子树的最大值+1
        else{
    
    
            return Math.max(leftHeight, rightHeight) + 1;
        }
    }

    // 返回结果如果=-1,则表示其中某一个节点的子树不平衡,则总的也不平衡
    // 返回结果如果>=0,则表示全部平衡,则总的也平衡
    public boolean isBalanced(TreeNode root) {
    
    
        return tempFunc(root)>=0;
    }
}

二叉树的最小深度

给定一个二叉树,找出其最小深度。 最小深度是从根节点到最近叶子节点的最短路径上的节点数量。
说明: 叶子节点是指没有子节点的节点。
示例: 给定二叉树 [3,9,20,null,null,15,7],

    3
   / \
  9  20
    /  \
   15   7 

返回它的最小深度: 2.

解答



买卖股票的最佳时机

给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。 如果你最多只允许完成一笔交易(即买入和卖出一支股票一次),设计一个算法来计算你所能获取的最大利润。 注意:你不能在买入股票前卖出股票。

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

解答:
在这里插入图片描述

一次遍历,寻找最小值,作为买入点。若不是最小值,则比较利润是否最大。

class Solution {
    
    
    public int maxProfit(int prices[]) {
    
    
        // 预先设置一个最低价格
        int minprice = Integer.MAX_VALUE;
        // 预先设置利润=0
        int maxprofit = 0;
        for (int i = 0; i < prices.length; i++) {
    
    
            // 判断当前价格是否小于最低价格
            if (prices[i] < minprice) {
    
    
                // 更新最低价格
                minprice = prices[i];
            // 否则判断是否利润更大
            } else if (prices[i] - minprice > maxprofit) {
    
    
                // 更新最大利润
                maxprofit = prices[i] - minprice;
            }
        }
        return maxprofit;
    }
}

本来以为这种解法在“最低价格在后面的情况下会出错,如[7,6,5,3,1,4]”,后来想了想发现不会。因为是一次遍历,当找到最低价格后,前面的已经抛弃了,从之后再开始比较if(prices[i] - minprice > maxprofit)。

猜你喜欢

转载自blog.csdn.net/sxf1061700625/article/details/108229633