leetcode数组面试题

文章介绍了LeetCode中涉及数组操作的几道经典问题,包括删除重复元素、求股票最佳买卖时机、数组旋转、检查重复元素、寻找只出现一次的数字以及求两个数组的交集。这些问题分别使用了双指针、动态规划、哈希映射等编程技巧来解决。
摘要由CSDN通过智能技术生成

the primary algorithm of leetcode

1. 数组

1.1删除重复数组中的排序项

    //双指针解决
    public int removeDuplicates(int[] A) {
        //边界条件判断
        if (A == null || A.length == 0)
            return 0;
        int left = 0;
        for (int right = 1; right < A.length; right++)
            //如果左指针和右指针指向的值一样,说明有重复的,
            //这个时候,左指针不动,右指针继续往右移。如果他俩
            //指向的值不一样就把右指针指向的值往前挪
            if (A[left] != A[right])
                A[++left] = A[right];//左指针先右移,再被赋值
        return ++left;
    }

1.2 买股票的最佳时期II

这里主要运用到的思想是动态规划。在以时间为序列的股票价格数组中,可进行任意的股票买入和卖出,因此买家在任意一天呈现两种状态,一个是持有股票(意味着只能进行股票的卖出或者继续持有),第二个是不持有股票(意味着可以保持不持有或者买入股票)。因此我们讲第 i 天的利润情况分成两个数组 dp[i][0],dp[i][1] 接着就可以结合前一天的状态推断出递推条件与初始边界条件,并在最终返回dp[length - 1][0](最右上角的数组,即代表最后一天卖出股票所有后最终的利润)
public int maxProfit(int[] prices) {
    if (prices == null || prices.length < 2)
        return 0;
    int length = prices.length;
    int[][] dp = new int[length][2];
    //初始条件
    dp[0][1] = -prices[0];
    dp[0][0] = 0;
    for (int i = 1; i < length; i++) {
        //递推公式
        dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1] + prices[i]);
        dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] - prices[i]);
    }
    //最后一天肯定是手里没有股票的时候,利润才会最大,
    //只需要返回dp[length - 1][0]即可
    return dp[length - 1][0];
}

1.3 旋转数组

    public void rotate(int nums[], int k) {
        int length = nums.length;
        int temp[] = new int[length];
        //把原数组值放到一个临时数组中,
        for (int i = 0; i < length; i++) {
            temp[i] = nums[i];
        }
        //然后在把临时数组的值重新放到原数组,并且往右移动k位
        for (int i = 0; i < length; i++) {
            nums[(i + k) % length] = temp[i];
        }
    }

1.4 存在重复元素(有重复即返回true,vice versa)

1.暴力法效率过低,由于返回的数据类型为布尔,所以可以在对原数组进行一定修改的基础上,进行检测。 因此第一种算法是利用Array.sort() 对数组进行排序,然后看相邻是否有相同的数值

2.使用Set集合。因为已知java 的 set集合中是不可以出现重复的元素。因此创建一个set,并在添加元素时候,如果出现了重复的元素时,添加就会返回false.

    public boolean containsDuplicate(int[] nums) {
        Set<Integer> set = new HashSet<>();
        for (int num : nums) {
            //因为集合set中不能有重复的元素,如果有重复的
            //元素添加,就会添加失败
            if (!set.add(num))
                return true;
        }
        return false;
    }

只出现一次的数字

思路1:利用异或运算去实现。 a^a=0;自己和自己异或等于0 a^0=a;任何数字和0异或还等于他自己 a^b^c=a^c^b;异或运算具有交换律 有了这3个规律,这题就很容易解了,我们只需要把所有的数字都异或一遍,最终的结果就是我们要求的那个数字。来看下代码
public int singleNumber(int nums[]) {
    int result = 0;
    for (int i = 0; i < nums.length; i++)
        result ^= nums[i];
    return result;
}

思路2:仍旧利用set集合的性质。如果添加一个元素,这个值存在则删去,因此成对出现的数值将在集合中消失。

public int singleNumber(int[] nums) {
    Set<Integer> set = new HashSet<>();
    for (int num : nums) {
        if (!set.add(num)) {
            //如果添加失败,说明这个值
            //在集合Set中存在,我们要
            //把他给移除掉
            set.remove(num);
        }
    }
    //最终集合Set中只有一个元素,我们直接返回
    return (int) set.toArray()[0];
}

1.5 两个数组中的交集II

思路1:nums1,nums2。两个数组共同进行排序,并利用两个指针开始依次比对。 当指针所指数值不相同时,数值较小的指针++,若相同时,则两个指针均++。直至其中一方数组遍历结束为止。
    public int[] intersect(int[] nums1, int[] nums2) {
        // 先对两个数组进行排序
        Arrays.sort(nums1);
        Arrays.sort(nums2);
        int i = 0;
        int j = 0;
        List<Integer> list = new ArrayList<>();
        while (i < nums1.length && j < nums2.length) {
            if (nums1[i] < nums2[j]) {
                // 如果i指向的值小于j指向的值,,说明i指向
                // 的值小了,i往后移一步
                i++;
            } else if (nums1[i] > nums2[j]) {
                // 如果i指向的值大于j指向的值,说明j指向的值
                // 小了,j往后移一步
                j++;
            } else {
                // 如果i和j指向的值相同,说明这两个值是重复的,
                // 把他加入到集合list中,然后i和j同时都往后移一步
                list.add(nums1[i]);
                i++;
                j++;
            }
        }
        //把list转化为数组
        int index = 0;
        int[] res = new int[list.size()];
        for (int k = 0; k < list.size(); k++) {
            res[index++] = list.get(k);
        }
        return res;
    }

思路2:使用map解决。
首先遍历所有nums1中的元素,将他们存放到map中,其中key就是nums1中的元素;value就是在num1中出现的次数。
然后遍历nums2,并在map中一一进行对照,没有对应上的则进行删除,进行对照上的就留下并添加到新的数组当中,并最终返回这个数组。

public int[] intersect(int[] nums1,int[] nums2){
	HashMap<Integer,Integer> map = new HashMap<>();
	ArrayList<Integer> list = new ArrayList<>();
	for(int i=0;i<nums1.length;i++){
		map.put(nums1[i],map.getOrDefault(nums1[i],0)+1);//getOrDefault() 方法获取指定 key 对应对 value,如果找不到 key ,则返回设置的默认值
	}
	for(int i=0;i<nums2.length;i++){
		if(map.getOrDefault(nums2[i],0)>0){
			list.add(nums2[i]);
			map.put(nums2[i],map.get(nums2[i])-1)
		}
	}
	//把集合list转换为数组
	int res[] = new int[list.size()];
	for (int i=0;i<list.size();i++){
		res[i] = list.get(i);
	}
	return res;
} 

1.6 两数之和

这类问题一般可以直接用暴力算法直接进行暴力解决,但是占用的内存等空间会过多。因此我们会选择利用java的hashmap模块去进行解决。
class Solution {
    public int[] twoSum(int[] nums, int target) {
        HashMap<Integer,Integer> map = new HashMap<>();
        for(int i = 0;i<nums.length;i++){
            if(map.get(target-nums[i])!=null){
            //map.get()函数可以get到一个哈希表里面特定数值的位置索引,若未有找到该值,则返回空null
                return new int[]{map.get(target-nums[i]),i};
            }
            map.put(nums[i],i);
        }
        return new int[]{0,0};
    }
}

hashmap用法总结

1.7 有效的数独

请你判断一个 9 x 9 的数独是否有效。只需要 根据以下规则 ,验证已经填入的数字是否有效即可。

数字 1-9 在每一行只能出现一次。
数字 1-9 在每一列只能出现一次。
数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。(请参考示例图)

    public boolean isValidSudoku(char board[][]) {
        int length = board.length;
        //二维数组line表示的是对应的行中是否有对应的数字,比如line[0][3]
        //表示的是第0行(实际上是第1行,因为数组的下标是从0开始的)是否有数字3
        int line[][] = new int[length][length];
        int column[][] = new int[length][length];
        int cell[][] = new int[length][length];
        for (int i = 0; i < length; ++i)
            for (int j = 0; j < length; ++j) {
                //如果还没有填数字,直接跳过
                if (board[i][j] == '.')
                    continue;
                //num是当前格子的数字
                int num = board[i][j] - '0' - 1;
                //k是第几个单元格,9宫格数独横着和竖着都是3个单元格
                int k = i / 3 * 3 + j / 3;
                //如果当前数字对应的行和列以及单元格,只要一个由数字,说明冲突了,直接返回false。
                //举个例子,如果line[i][num]不等于0,说明第i(i从0开始)行有num这个数字。
                if (line[i][num] != 0 || column[j][num] != 0 || cell[k][num] != 0)
                    return false;
                //表示第i行有num这个数字,第j列有num这个数字,对应的单元格内也有num这个数字
                line[i][num] = column[j][num] = cell[k][num] = 1;
            }
        return true;
    }

参考内容:
作者:力扣 (LeetCode)
链接:https://leetcode.cn/leetbook/read/top-interview-questions-easy/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

参考链接:https://www.bilibili.com/video/BV1iT41157a7/?spm_id_from=333.337.search-card.all.click&vd_source=9b226b0c66c354e394eae99edb289b69
(作者B站:博哥的数据结构和算法)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值