IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 【算法题—剑指Offer】详细解析:扑克牌顺子(消耗存储数法)、构建乘积数组(2 种方法) -> 正文阅读

[数据结构与算法]【算法题—剑指Offer】详细解析:扑克牌顺子(消耗存储数法)、构建乘积数组(2 种方法)

JZ45 扑克牌顺子

(简单)

题目

描述
现在有2副扑克牌,从扑克牌中随机五张扑克牌,我们需要来判断一下是不是顺子。
有如下规则:
1)A为1,J为11,Q为12,K为13,A不能视为14
2)大、小王为 0,0可以看作任意牌
3)如果给出的五张牌能组成顺子(即这五张牌是连续的)就输出true,否则就输出false。
例如:给出数据[6,0,2,0,4]
中间的两个0一个看作3,一个看作5 。即:[6,3,2,5,4]
这样这五张牌在[2,6]区间连续,输出true
数据保证每组5个数字,每组最多含有4个零,数组的数取值为 [0, 13]

示例1
输入:
[6,0,2,0,4]
返回值:true


示例2
输入:
[0,3,2,6,4]
返回值:true


示例3
输入:
[1,0,0,1,0]
返回值:false


示例4
输入:
[13,12,11,0,1]
返回值:false

思路

我做这道题时是没想到什么常规的解题方法,而是直接凭感觉写出来的,最后在考虑了所有可能的情况后,最后顺利通过了。

在通过这道题目后,我开始看题解看看有更好的方法没有,发现各位网友都有自己的方法,没有统一的标准方法,不少都是是代码量很少,但可读性差,当然也有很多不错的解法,而且也发现有一个人的代码和我的思维方式很像,总之,以下我将介绍一下我当时的思路和方法。

我打算将我的这种方法命名为:

消耗存储数法

我们拿到 5 张牌的数组后,若想检验是否为顺子,那么按正常的思维来说,我们就应该先让这组牌号序列往有序的方向先靠拢,也就是先进行排序,我这里使用的是冒泡排序(较少量数据的序列的排序,冒泡排序还是可以用一下的),之后大小王的数量,便对应着这个有序序列的前 m 个 0 ,其中 m 的范围是 4 >= m >= 0,因为题目中说了有两副牌,之后我们判断次序列是否为顺子,则可从第 m 个序列开始,因为前面都为大小王,可替代任意排,我们要优先考虑后面的,并通过已有的大小王,也就是 0 ,来弥补后续不能构成连续序列的情况,如果序列中两个数相差 2 ,则可消耗掉 1 个 0 来弥补,如果序列中两个数相等,则不能构成顺子,直接终止并返回 false 即可,因为总共数组中就 5 个数,如果序列中两个数相差数大于2,但此差 - 1 是小于等于 0 的当前剩余个数的,那么可以用 0 进行弥补,反之,则不能构成顺子,如果序列中两个数正好相差 1 ,那么本身两数已是连续数,可进行下一轮循环,如果最终循环结束,仍未退出函数,说明为此情况在循环中已经过充分检验,不满足任何一个不能构成顺子的条件,则返回 true 即可。

实现

public class JZ45扑克牌顺子 {
    public static boolean IsContinuous(int[] numbers) {
        bubbleSort(numbers);
        int len = numbers.length;
        int zeroNum = 0;

        //求出大小王的个数,即 0 的个数
        for (int i = 0; i < len; i++) {
            if (numbers[i] == 0) {
                zeroNum++;
            }
        }

        //判断顺子,从第 1 个不是 0 的数开始判断 i 与 i+1 的差值
        boolean result = false;
        for (int i = zeroNum; i < len - 1; i++) {
            if (numbers[i + 1] - numbers[i] == 2) {
                //情况:两个数直接缺一个数导致不连续

                if (zeroNum == 0) {
                    //不可以弥补这种情况
                    return false;
                }
                //消耗掉一个大小王来弥补这种情况的不连续,使之连续
                zeroNum--;
            } else if (numbers[i + 1] - numbers[i] == 1) {
                //情况:正好连续

            } else {
                //情况:出现两个相邻数相等或大于2的情况

                if (numbers[i + 1] == numbers[i]) {
                    //情况:出现两个相邻数相等
                    return false;
                }

                //情况:如果有两张及以上的0(因为题中说了是两副牌),可以弥补大于2的部分情况
                //相差2,需要1张0 ----> 相差n,需要n-1张0
                else if (zeroNum >= numbers[i + 1] - numbers[i] - 1) {
                    zeroNum -= (numbers[i + 1] - numbers[i] - 1);
                } else {
                    //情况:大于2中不能弥补的情况
                    return false;
                }
            }
        }

        return true;
    }

    public static void bubbleSort(int[] numbers) {
        int i = 0;
        int j = 0;
        int len = numbers.length - 1;
        boolean flag = true;
        for (i = 0; i < len && flag; i++) {
            flag = false;
            for (j = len - 1; j >= i; j--) {
                if (numbers[j] > numbers[j + 1]) {
                    swap(numbers, j, j + 1);
                    flag = true;
                }
            }
        }
    }

    public static void swap(int[] numbers, int x, int y) {
        int m = numbers[x];
        numbers[x] = numbers[y];
        numbers[y] = m;
    }

    public static void main(String[] args) {
        int[] arr1 = {6, 0, 2, 0, 4};
        int[] arr2 = {0, 3, 2, 6, 4};
        int[] arr3 = {1, 0, 0, 1, 0};
        int[] arr4 = {13, 12, 11, 0, 1};
        System.out.println("IsContinuous(arr1) = " + IsContinuous(arr1)); //T
        System.out.println("IsContinuous(arr2) = " + IsContinuous(arr2)); //T
        System.out.println("IsContinuous(arr3) = " + IsContinuous(arr3)); //F
        System.out.println("IsContinuous(arr4) = " + IsContinuous(arr4)); //F
    }
}

在这里插入图片描述

在这里插入图片描述

JZ51 构建乘积数组

(简单)

题目

描述
给定一个数组A[0,1,…,n-1],请构建一个数组B[0,1,…,n-1],其中B中的元素B[i]=A[0]A[1]…*A[i-1]A[i+1]…*A[n-1]。不能使用除法。(注意:规定B[0] = A[1] * A[2] * … * A[n-1],B[n-1] = A[0] * A[1] * … * A[n-2];)
对于A长度为1的情况,B无意义,故而无法构建,因此该情况不会存在。

示例
输入:
[1,2,3,4,5]
返回值:
[120,60,40,30,24]

思路

方法一:暴力解法

根据题目中给的公式条件,直接无脑地暴力计算出数组B中的各元素值。

【实现】

public class JZ51构建乘积数组 {
    public int[] multiply(int[] A) {
        int n = A.length;
        int[] B = new int[n];
        Arrays.fill(B, 1);
        for (int i = 1; i < n; i++) {
            B[0] *= A[i];
        }
        for (int i = 0; i < n - 1; i++) {
            B[n - 1] *= A[i];
        }
        for (int i = 1; i < n - 1; i++) {
            for (int j = 0; j < n; j++) {
                if (j == i) {
                    continue;
                }
                B[i] *= A[j];
            }
        }

        return B;
    }
}

在这里插入图片描述

方法二:数学推导

因为 B[i] = A[0]A[1]…A[i-1]*A[i+1]…A[n-1] ,所以另:

  • left[i] = A[0]*…*A[i-1]
  • right[i] = A[i+1]*…*A[n-1]

所以:

  • B[i] = left[i] * right[i]

又因为:
left[i+1] = A[0] *…A[i-1] * A[i]
right[i+1] = A{i+2] *…*A[n-1]

所以:
left[i+1] = left[i] * A[i] ——> left[i] = left[i-1] * A[i-1]
right[i] = right[i+1] * A[i+1]

【综上】:

  • left[i] = left[i-1] * A[i-1] ————(计算下标为 1 ~ n - 1)(说明:因为 B[n-1] = A[0] * A[1] * … * A[n-2] ,因此可直接计算出 B[n-1]
  • right[i] = right[i+1] * A[i+1] ————(计算下标为 n - 2 ~ 0)(说明:因为 B[0] = A[1] * A[2] * … * A[n-1] ,因此可直接计算出 B[0]

此方法十分巧妙,我是参考的官方的题解才知道的这种方法,算是数学推导的一种,两个临界情况 B[0] 和 B[n - 1],正好可以通过一右(right 公式)一左(left 公式)单独算出,而这中间的序号对应的数据则可先左乘积操作一遍,再右乘积操作一遍得出。

【实现】

public class JZ51构建乘积数组 {
    public int[] multiply(int[] A) {
  		int n = A.length;
        int[] B = new int[n];
        Arrays.fill(B, 1);

        for (int i = 1; i < n; i++) {
            B[i] = B[i - 1] * A[i - 1]; // left[i]用B[i]代替
        }
        int tmp = 1;
        for (int j = n - 2; j >= 0; j--) {
            tmp *= A[j + 1]; // right[i]用tmp代替
            B[j] *= tmp;
        }

        return B;
    }
}

在这里插入图片描述

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2021-07-26 12:18:24  更:2021-07-26 12:19:31 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 17:16:22-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码