习题集上

1、给定一个长度为 n 的整数数组,你的任务是判断在最多改变 1 个元素的情况下,该数组能否变成一个非递减数列。
我们是这样定义一个非递减数列的: 对于数组中所有的 i (1 <= i < n),满足 array[i] <= array[i + 1]。
示例 1:
输入: [4,2,3]
输出: True
解释: 你可以通过把第一个4变成1来使得它成为一个非递减数列。
示例 2:
输入: [4,2,1]
输出: False
解释: 你不能在只改变一个元素的情况下将其变为非递减数列。

class Solution {
    public boolean checkPossibility(int[] nums) {
        if(nums.length < 3){
            return true;
        }
        int count = 0;
        for(int i=0;i<nums.length-1;i++){
            if(nums[i] > nums[i+1]){
                count++;
                if(count > 1){
                    break;
                }
                if(i-1 >=0&&nums[i-1] > nums[i+1]){
                    nums[i+1] = nums[i];
                }else{
                    nums[i] = nums[i+1];
                }
            }
        }
        return count <= 1;
    }
}


2、给定一个无序的整数数组,找到其中最长上升子序列的长度。

示例:

输入: [10,9,2,5,3,7,101,18]
输出: 4
解释: 最长的上升子序列是 [2,3,7,101],它的长度是 4。

说明:

可能会有多种最长上升子序列的组合,你只需要输出对应的长度即可。
你算法的时间复杂度应该为 O(n2) 。
public class Solution {
    public int lengthOfLIS(int[] nums) {
        if (nums.length == 0) {
            return 0;
        }
        int[] dp = new int[nums.length];
        dp[0] = 1;
        int maxans = 1;
        for (int i = 1; i < dp.length; i++) {
            int maxval = 0;
            for (int j = 0; j < i; j++) {
                if (nums[i] > nums[j]) {
                    maxval = Math.max(maxval, dp[j]);
                }
            }
            dp[i] = maxval + 1;
            maxans = Math.max(maxans, dp[i]);
        }
        return maxans;
    }
}


3、给定在 xy 平面上的一组点,确定由这些点组成的矩形的最小面积,其中矩形的边平行于 x 轴和 y 轴。

如果没有任何矩形,就返回 0。

示例 1:

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

示例 2:

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

class Solution {
    public int minAreaRect(int[][] points) {
        Map<Integer, List<Integer>> rows = new TreeMap();
        for (int[] point: points) {
            int x = point[0], y = point[1];
            rows.computeIfAbsent(x, z-> new ArrayList()).add(y);
        }

        int ans = Integer.MAX_VALUE;
        Map<Integer, Integer> lastx = new HashMap();
        for (int x: rows.keySet()) {
            List<Integer> row = rows.get(x);
            Collections.sort(row);
            for (int i = 0; i < row.size(); ++i)
                for (int j = i+1; j < row.size(); ++j) {
                    int y1 = row.get(i), y2 = row.get(j);
                    int code = 40001 * y1 + y2;
                    if (lastx.containsKey(code))
                        ans = Math.min(ans, (x - lastx.get(code)) * (y2-y1));
                    lastx.put(code, x);
                }
        }

        return ans < Integer.MAX_VALUE ? ans : 0;
    }
}


4、给定一个字符串 S,计算 S 的不同非空子序列的个数。

因为结果可能很大,所以返回答案模 10^9 + 7.

示例 1:

输入:“abc”
输出:7
解释:7 个不同的子序列分别是 “a”, “b”, “c”, “ab”, “ac”, “bc”, 以及 “abc”。

示例 2:

输入:“aba”
输出:6
解释:6 个不同的子序列分别是 “a”, “b”, “ab”, “ba”, “aa” 以及 “aba”。

示例 3:

输入:“aaa”
输出:3
解释:3 个不同的子序列分别是 “a”, “aa” 以及 “aaa”。

public static int distinctSubseqII(String s) {
		int mod = (int)1e9+7;//因为字符串会很长,子串个数很多,取模保存,不会越界
		char[] strTochar = s.toCharArray();
		int[] dp = new int[s.length()];//保存读取到该字符时候字符串的子串个数
		for(int i=0;i<s.length();i++) {
			if(i==0)
				dp[i] = 1;//如果字符串长度是1,直接返回1.
			else {
				dp[i] = (2*dp[i-1]+1)%mod;
				for(int j=i-1;j>=0;j--) {
					if(strTochar[j]==strTochar[i]) {//找到在[0,i-1]区间内距离此时字符相同最近的字符
						/*三元运算符,来判断是不是查找到起始位置了,
						 * 如果此时的字符与起始字符一致,那么就只需要
						 * 减去一个该字符即可。
				            */
						dp[i] = j==0?(dp[i]+mod-1)%mod:(dp[i]+mod-dp[j-1]-1)%mod;
						break;//找到直接跳出循环,因为我们只找最近的那个相同的字符。
					}
				}
			}
		}
		return dp[s.length()-1]%mod;//返回结果
	}

5、
在经典汉诺塔问题中,有 3 根柱子及 N 个不同大小的穿孔圆盘,盘子可以滑入任意一根柱子。一开始,所有盘子自上而下按升序依次套在第一根柱子上(即每一个盘子只能放在更大的盘子上面)。移动圆盘时受到以下限制:
(1) 每次只能移动一个盘子;
(2) 盘子只能从柱子顶端滑出移到下一根柱子;
(3) 盘子只能叠在比它大的盘子上。

请编写程序,用栈将所有盘子从第一根柱子移到最后一根柱子。

你需要原地修改栈。

示例1:

输入:A = [2, 1, 0], B = [], C = []
输出:C = [2, 1, 0]

示例2:

输入:A = [1, 0], B = [], C = []
输出:C = [1, 0]

class Hanno{
    public static void main(String[] args){
        //盘子的个数 出发 中间 目的
        hanno(3,"X","Y","Z");
    }                                     
    public static void hanno(int n,String begin,String mid,String end){
        if(n==1){
            System.out.println(begin+" -> "+end);
        }else{
            hanno(n-1,begin,end,mid);//第二个盘子从x出发,目的地是y
            System.out.println(begin+" -> "+end);
            hanno(n-1,mid,begin,end);//前两个盘子,从y到z
        }
    }
}


6、递归乘法。 写一个递归函数,不使用 * 运算符, 实现两个正整数的相乘。可以使用加号、减号、位移,但要吝啬一些。

示例1:

输入:A = 1, B = 10
输出:10

示例2:

输入:A = 3, B = 4
输出:12

class Solution {
    public int multiply(int A, int B) {
        if(A < 1000){
            if(A == 1)
                return B;
            return multiply(--A, B)+B;
        }else{
            if(B == 1)
                return A;
            return multiply(A, --B)+A;
        }
    }
}


7、给定一个非负整数 numRows,生成杨辉三角的前 numRows 行。

class Solution {
    public List<List<Integer>> generate(int numRows) {
        
        List<List<Integer>> ans = new ArrayList<List<Integer>>();
       
        for(int i = 0; i < numRows; i++){
             List<Integer> array = new ArrayList<Integer>();
            for(int j = 0; j <= i; j++){
                if(j == 0 || j == i){
                    array.add(1);
                }else{
                    array.add(ans.get(i-1).get(j-1) + ans.get(i-1).get(j));
                }
            }
            ans.add(array);
        }
        return ans;
    }
    
}


8、给定一副牌,每张牌上都写着一个整数。

此时,你需要选定一个数字 X,使我们可以将整副牌按下述规则分成 1 组或更多组:

每组都有 X 张牌。
组内所有的牌上都写着相同的整数。

仅当你可选的 X >= 2 时返回 true。

示例 1:

输入:[1,2,3,4,4,3,2,1]
输出:true
解释:可行的分组是 [1,1],[2,2],[3,3],[4,4]

示例 2:

输入:[1,1,1,2,2,2,3,3]
输出:false
解释:没有满足要求的分组。

示例 3:

输入:[1]
输出:false
解释:没有满足要求的分组。

示例 4:

输入:[1,1]
输出:true
解释:可行的分组是 [1,1]

示例 5:

输入:[1,1,2,2,2,2]
输出:true
解释:可行的分组是 [1,1],[2,2],[2,2]

class Solution {
    public boolean hasGroupsSizeX(int[] deck) {
        int N = deck.length;
        int[] count = new int[10000];
        for (int c: deck)
            count[c]++;

        List<Integer> values = new ArrayList();
        for (int i = 0; i < 10000; ++i)
            if (count[i] > 0)
                values.add(count[i]);

        search: for (int X = 2; X <= N; ++X)
            if (N % X == 0) {
                for (int v: values)
                    if (v % X != 0)
                        continue search;
                return true;
            }

        return false;
    }
}


9、给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在四个元素 a,b,c 和 d ,使得 a + b + c + d 的值与 target 相等?找出所有满足条件且不重复的四元组。

注意:

答案中不可以包含重复的四元组。

示例:

给定数组 nums = [1, 0, -1, 0, -2, 2],和 target = 0。

满足要求的四元组集合为:

[-1, 0, 0, 1],
[-2, -1, 1, 2],
[-2, 0, 0, 2]

class Solution {
    public List<List<Integer>> fourSum(int[] nums, int target) {
        List<List<Integer>> ans=new ArrayList<List<Integer>>();
        Arrays.sort(nums);
        for(int i=0;i<nums.length-2;i++)
        {
        	if(i!=0 && nums[i]==nums[i-1])
        		continue;
        	for(int j=i+1;j<nums.length;j++)
        	{
        		if(j!=i+1 && nums[j]==nums[j-1])
        			continue;
        		int l=j+1,r=nums.length-1;
        		while(l<r)
        		{
        			if(l!=j+1 && nums[l]==nums[l-1] || nums[i]+nums[j]+nums[l]+nums[r]<target)
        				l++;
        			else if(r!=nums.length-1 && nums[r]==nums[r+1] || nums[i]+nums[j]+nums[l]+nums[r]>target)
        				r--;
        			else
        			{
        		        List<Integer> temp=new ArrayList<Integer>();
        		        temp.add(nums[i]);
        		        temp.add(nums[j]);
        		        temp.add(nums[l]);
        		        temp.add(nums[r]);
        		        ans.add(temp);
        		        l++;r--;
        			}
        		}
        	}
        }
        return ans;
    }
}

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

不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。

示例 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 == null || nums.length == 0) return 0;
    int p = 0;
    int q = 1;
    while(q < nums.length){
        if(nums[p] != nums[q]){
            nums[p + 1] = nums[q];
            p++;
        }
        q++;
    }
    return p + 1;
}
}

11、给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。

不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。

元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。

示例 1:

给定 nums = [3,2,2,3], val = 3,

函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。

你不需要考虑数组中超出新长度后面的元素。

class Solution {
    public int removeElement(int[] nums, int val) {
        int ans = 0;
        for(int num: nums) {
            if(num != val) {
                nums[ans] = num;
                ans++;
            }
        }
        return ans;
    }
}


12、给定一个按照升序排列的整数数组 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:
    vector<int> searchRange(vector<int>& nums, int target) 
    {
        vector<int> res={-1,-1};
        int low=0,high=nums.size()-1;
        while(low<=high)
        {
            int mid= low+(high-low)/2;
            if(target==nums[mid])
            {
                if(mid==nums.size()-1) res[1]=mid;            ///找上边界
                else if(nums[mid+1]>target) res[1]=mid;
            }
            if(target<nums[mid]) high=mid-1;
            else if(target>=nums[mid]) low=mid+1;
        }

        int low1=0,high1=nums.size()-1;
        while(low1<=high1)
        {
            int mid1= low1+(high1-low1)/2;
            if(target==nums[mid1])
            {
                if(mid1==0)res[0]=mid1;
                else if(nums[mid1-1]<target)res[0]=mid1;   ///找下边界
            }
            if(target<=nums[mid1]) high1=mid1-1;
            else if(target>nums[mid1]) low1=mid1+1;
        }
        return res;
    }



13、给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。

你可以假设数组中无重复元素。

示例 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) {
        int ans = 0;
        for(int i = 0; i < nums.length; i++) {
            if (nums[i] < target) ans = i+1;
            if (nums[i] >= target) return i;
        };
        return ans;
    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值