数组&数学(array&Math)

1 常见题目

数学类包括数字变换、计数以及数学公式;
数组类可能用到hash、循环遍历等等。

1.1 (lee-JZ-62) 圆圈中最后剩下的数字

经典的约瑟夫环的问题
原始问题:一个长度为n的环,起点为1,删除第m个元素,并使该元素之后的元素为起点,删除第m个元素,直至剩一个元素。
从原始问题出发,当第一次操作时,删除了第m个元素,起点为m+1,此时问题可转化为:长度为n-1的环,起点为m+1,每次删除第m个元素,求最终剩下的元素。
思路:利用数学公式反推 (当前index + m) % 上一轮剩余数字的个数。

输入: n = 5, m = 3
输出: 3

(1)数学+迭代

	/*
	 * 1.数学+迭代
	 * 时间复杂度:O(n)
	 * 空间复杂度:O(1)
	 */
	public int ysf (int n, int m) {
		int res = 0;
        for(int i = 2;i <= n;i++) {
        	res = (res + m) % i;
        }
		return res+1;				
    }

(2)数学+递归

	/*
	 * 2.数学+递归
	 * 时间复杂度:O(n)
	 * 空间复杂度:O(n)
	 */
	public int lastRemaining(int n, int m) {
        return f(n, m);
    }
    public int f(int n, int m) {
        if (n == 1) {
            return 0;
        }
        int x = f(n - 1, m);
        return (m + x) % n;
    }

(3)使用ArrayList

	public int ysf(int n,int m) {
		List<Integer> list = new ArrayList<Integer>();
		for(int i = 1;i<=n;i++) { //n个元素添加到循环链表中,用集合可以代替
			list.add(i);
		}
		int index = 0; 
		while(list.size() > 1) { //直到剩下一个元素的时候循环停止
			index = (index+m-1)%list.size(); 
			list.remove(index); //每次删除第m个元素
		}
		return list.get(0);    //返回最后剩下的元素
	}

(4)输出依次出局的人

	private  String ysf(int[] input) {
        int N = input[0];
        int M = input[1];
       // if(N<1 || M<1) return null;
        ArrayList<Integer> list = new ArrayList<Integer>();
        StringBuilder sb = new StringBuilder();
        for(int i=0;i<N;i++){
            list.add(i+1);
        } 
        int index=0;
        while(list.size()>0){
        	index = (index+M-1) % list.size(); 
            sb.append(list.get(index)).append(" ");
            list.remove(index);
        }
        return sb.delete(sb.length()-1,sb.length()).toString();
	}
	
	public static void main(String[] args) {
		Scanner input  = new Scanner(System.in);
		System.out.print("输入n:");
		int n = input.nextInt();
		System.out.print("输入m:");
		int m = input.nextInt();
		int[] in = new int[] {n,m};
		String res = ysf(in);
		System.out.print(res);
	}

1.2 (lee-48) 旋转图像

给定一个 n × n 的二维矩阵表示一个图像。将图像顺时针旋转 90 度。
说明:必须在原地旋转图像,这意味着你需要直接修改输入的二维矩阵。请不要使用另一个矩阵来旋转图像。
在这里插入图片描述

输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]
输出:[[7,4,1],[8,5,2],[9,6,3]]

	/**
	 * 思路: 先置换再反转矩阵每一行
	 * 时间复杂度:O(n^2)
	 * 空间复杂度:O(1)  要求原地旋转
	 * @param matrix
	 */
	 public void rotate(int[][] matrix) {
		 int n = matrix.length;
		//置换矩阵
		 for(int i = 0;i <n;i++) {       
			 for(int j = i;j < n;j++) {  //注意
				 int temp = matrix[i][j];
				 matrix[i][j] = matrix[j][i];
				 matrix[j][i] = temp;
			 }
		 }
		//反转矩阵每一行
		 for(int i = 0;i < n;i++) {       
			 for(int j = 0;j < n/2;j++) {
				 int temp = matrix[i][j];
				 matrix[i][j] = matrix[i][n-j-1];
				 matrix[i][n-j-1] = temp;
			 }
		 }
	 }
	 

1.3 (lee-448) 找到所有数组中消失的数字

给你一个含 n 个整数的数组 nums ,其中 nums[i] 在区间 [1, n] 内。请你找出所有在 [1, n] 范围内但没有出现在 nums 中的数字,并以数组的形式返回结果。
进阶:你能在不使用额外空间且时间复杂度为 O(n) 的情况下解决这个问题吗? 你可以假定返回的数组不算在额外空间内。

输入:nums = [4,3,2,7,8,2,3,1]
输出:[5,6]
输入:nums = [1,1]
输出:[2]

(1) 数组下标计数

	/*
     * 思路:利用数组下标计数实现对目标数组的每个元素的计数,随后在循环一次的循环中查找并添加计数为零的元素
     */
	public List<Integer> findDisappearedNumbers(int[] nums) {
		int[] count = new int[nums.length+1];
		for(int i  = 0;i < nums.length;i++) {
			count[nums[i]]++;
		}
		List<Integer> res = new ArrayList<>();
		for(int i = 1;i <= nums.length;i++) {
			if(count[i] == 0) {
				res.add(i);
			}
		}
		return res;
    }

(2) 遍历标记visited

	/*
	 * 思路:先遍历一遍数组,标记哪些出现过,如果nums[visited] < 0 , 表示i+1出现过
	 *     再遍历一遍数组,如果nums[i-1] > 0 ,说明i没出现过,加入结果集
	 * 例如:输入:nums = [4,3,2,7,8,2,3,1]
	 *     标记后为[-4,-3,-2,-7,8,2,-3,-1]
	 *     由于8,2都大于0,返回其下标5,6
	 *     输出:[5,6]
	 */
	public List<Integer> findDisappearedNumbers1(int[] nums) {
		for(int i = 0;i < nums.length;i++) {
			int visited = Math.abs(nums[i])-1;
			if(nums[visited] > 0) {
				nums[visited] *= -1;
			}
		}
		List<Integer> res = new ArrayList<>();
		for(int i = 1;i <= nums.length;i++) {
			if(nums[i-1] > 0) {
				res.add(i);
			}
		}
		return res;
	}
	

2 练习链接

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值