格雷编码(Gray Code)

This commit is contained in:
YuCheng Hu 2023-11-08 21:43:12 -05:00
parent 8818823366
commit 207d5f1470
No known key found for this signature in database
GPG Key ID: 942395299055675C
3 changed files with 147 additions and 2 deletions

View File

@ -1,9 +1,11 @@
- [格雷编码](/algorithm/gray-code.md)
- [点积](/algorithm/dot-product.md)
- [二叉树](/algorithm/binary-tree.md)
- [二叉树的层次遍历]()
- [二叉树的层次遍历](/algorithm/binary-tree-level-order-traversal.md)
- [下一个斐波拉契数](/algorithm/next-fibonacci-number.md)
- [一个字符串包裹函数](/algorithm/a-word-wrap-functionality.md)
- [打印 100 以内的素数](/algorithm/prime-numbers-from-1-to-100.md)
- [二进制空白](/algorithm/binary-gap.md)
- [Lambda 偶数](/algorithm/lambda-evens-lambda.md)
- [上下计数](/algorithm/count-up-down.md)
- [上下计数](/algorithm/count-up-down.md)
- [展平嵌套数组](/algorithm/flatten-nested-arrays.md)

View File

@ -0,0 +1,54 @@
# 展平嵌套数组Flatten Nested Arrays
> 🔔 参与讨论https://www.isharkfly.com/t/flatten-nested-arrays/314这个题目是在
PillPack 现场面谈的时候的一个题目。
## 中文描述
题目要求比较简单:[1,2,[3],[[4]],5,6] -> [1,2,3,4,5,6]
就是数组中嵌套数组,考察一个数组[1,2,[3],[[4]],5,6]。 你怎么能够输出 1,2,3,4,5,6并不要求按照顺序输出
这里是一个嵌套数组,你需要将这个数组中的值全部取出来。
## 思路和点评
不清楚其他语言中这个数据结构怎么存储,我假设的是在 Java 中存储的对象。
可以采用队列的方式来实现,例如,在 Java 中存储了整数1 2 对象,[3] 为一个数组对象。
你可以先遍历一次 List将所有的 List 的对象都压入队列中,然后进行出队。
在出队时候,判断对象是否为整数对象,如果是整数对象,就输出,如果不是整数对象,然后将数组对象继续进行遍历,然后压入队列,然后再出队。
在这里讨论的问题比较多,还有 [[[2]5]] 这种多层嵌套的问题。
经过网站上的考古,这里有 2 个方法可以更快的实现。1 是递归的方法2 是 利用 Java 8 的 Stream 特性。
在写测试代码之前,你需要明白下数据结构的定义,要不然你没有办法测试。在 Java 中你可以定义为对象数组,如下:
`Object[] array = { ` `1` `, ` `2` `, ` `new` `Object[] { ` `3` `, ` `4` `, ` `new` `Object[] { ` `5` `, ` `new` `Object[] { ` `new` `Object[] { ` `6` `} } }, ` `7` `}, ` `8` `, ` `9` `, ` `10` `};`
然后可以利用递归,在对对象数组进行遍历的时候,如果你遇到了对象,那么你需要再次调用你的方法,对对象中的内容进行遍历,如果这个时候已经没有对象了,可以返回第二层遍历的结果,并且插入到上层 List 列表中。
如果你使用的 Java 8 的 Stream你需要对 Stream 的使用和方法比较了解才可以。这里也涉及到了递归,只是写法有点不同罢了。
还有一个更加简单粗暴的方法,当然我不认为这个方法是出题人希望考察的目标,在 Java 中你可以将数组直接转换成 String 字符串进行输出,比如说上面的对象队列,你可以转换为:` [1, 2, [3, 4, [5, [[6]]], 7], 8, 9, 10]` 字符串进行输出,然后使用 Java 的 Split 函数,进行按照逗号拆分后,然后将多余 [ 和 ] 符号去掉,然后再将内容重新放回 List。 这个有点简单粗暴,但是也一样能够达到目的。
## 源代码
源代码和有关代码的更新请访问 GitHub
https://github.com/cwiki-us/codebank-algorithm/blob/master/src/test/java/com/ossez/codebank/interview/tests/PillPackTest.java
## 测试类请参考:
https://github.com/cwiki-us/codebank-algorithm/blob/master/src/test/java/com/ossez/codebank/interview/tests/PillPackTest.java
## 测试结果
上面程序的测试结果如下:
```
2018/12/27 13:39:22 DEBUG [com.ossez.codebank.interview.tests.PillPackTest] - Test FlattenNestedArrays
2018/12/27 13:39:22 DEBUG [com.ossez.codebank.interview.tests.PillPackTest] - LOOP: [1, 2, [3, 4, [5, [[6]]], 7], 8, 9, 10] - > [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
2018/12/27 13:39:22 DEBUG [com.ossez.codebank.interview.tests.PillPackTest] - Java 8: [1, 2, [3, 4, [5, [[6]]], 7], 8, 9, 10] - > [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
```

89
algorithm/gray-code.md Normal file
View File

@ -0,0 +1,89 @@
# 格雷编码Gray Code
> 🔔 参与讨论https://www.isharkfly.com/t/gray-code/15120
## 描述
格雷编码是一个二进制数字系统,在该系统中,两个连续的数值仅有一个二进制的差异。
给定一个非负整数 `n` ,表示该代码中所有二进制的总数,请找出其格雷编码顺序。一个格雷编码顺序必须以 `0` 开始,并覆盖所有的 2n 个整数。
对于给定的 `n`,其格雷编码顺序并不唯一。
根据以上定义, `[0,2,3,1]` 也是一个有效的格雷编码顺序。
## 样例
给定 `n = 2` 返回 `[0,1,3,2]`。其格雷编码顺序为:
```
00 - 0
01 - 1
11 - 3
10 - 2
```
## 挑战
O(2n) 时间复杂度。
## 代码
```
/**
* 411 https://www.lintcode.com/problem/gray-code/description
*/
@Test
public void test0411GrayCode() {
int n = 2;
List<Integer> retArray = new ArrayList<>();
if (n == 0) {
retArray.add(0);
}
for (int i = 0; i < (2 << (n - 1)); i++) {
int g = i ^ (i / 2);
retArray.add(g);
}
System.out.println(retArray);
}
```
## 点评
你需要对 Java 的位运算之间的关系和数据结构有比较深的了解。
在计算机语言中,数字的存储是按照位存储的。比如说 int 数据类型,在 Java 中定义的是 32 位。
那么 int 能在 Java 中存储的 2 进制格式为:
0000 0000 0000 0000 0000 0000 0000 0000
这里一共是 8 组,一共是 32 位。
如果你希望了解 Java int 是如何在 2 进制中表示的你可以使用方法Integer.toBinaryString(0)
这个方法不会输出完整的 32 位字符串,你需要在前面补上 0。
【0】 转换为 2 进制为【0000 0000 0000 0000 0000 0000 0000 0000】
【2】 转换为 2 进制为【0000 0000 0000 0000 0000 0000 0000 0010】
【5】 转换为 2 进制为【0000 0000 0000 0000 0000 0000 0000 0101】
在这个题目中哟 2 个地方比较关键,第一个地方是需要循环多少次,就是 2 的 n 次方,应该是多少?第二个地方就是进行位运算了,你需要需要什么样的位运算符。
对于 2 的 n 次方的结果,基本上可以使用下面的公式 2 << (n-1),比如说 2 的 3 次方,那么就需要将 2 向左位移 2 位。
移动前:
【2】 转换为 2 进制为【0000 0000 0000 0000 0000 0000 0000 0010】
移动后
【0000 0000 0000 0000 0000 0000 0000 1000】这个 2 进制转换后的结果就是 【8】 正好是 2 的 3 次方。
随后,对 i 取整后进行一次异或运算就可以得到你要的结果的 2 进制结果了。