阿俊带你用Kotlin刷算法(一),字节跳动历年校招Android面试真题解析

return new int[0];
}

/**

  • 方法二:哈希表
  • 时间复杂度:O(N),其中N是数组的元素数量
  • 空间复杂度:O(N),其中N是数组的元素数量
  • @param numbers int类型的数组
  • @param target 目标值
  • @return 结果
    */
    private static int[] hashTwoSum(int[] numbers, int target) {
    Map<Integer, Integer> hashMap = new HashMap<>();
    for (int i = 0, length = numbers.length; i < length; i++) {
    int other = target - numbers[i];
    if (hashMap.containsKey(other)) {
    return new int[]{hashMap.get(other), i};
    }
    hashMap.put(numbers[i], i);
    }
    return new int[0];
    }

}

Kotlin

/**

  • Created by TanJiaJun on 2021/6/5.
    1. 两数之和(Two Sum)
  • 难度:简单
  • @see Two Sum
    */
    object TwoSumKotlin {

@JvmStatic
fun main(args: Array) {
// 示例一
println(“示例一”)

val firstNumbers = intArrayOf(2, 7, 11, 15)
val firstTarget = 9
println(hashTwoSum(firstNumbers, firstTarget).contentToString())

print(“\n”)

// 示例二
println(“示例二”)

val secondNumbers = intArrayOf(3, 2, 4)
val secondTarget = 6
println(hashTwoSum(secondNumbers, secondTarget).contentToString())

print(“\n”)

// 示例三
println(“示例三”)
val thirdNumbers = intArrayOf(3, 3)
val thirdTarget = 6
println(hashTwoSum(thirdNumbers, thirdTarget).contentToString())
}

/**

  • 方法一:枚举算法
  • 时间复杂度:O(N^2),其中N是数组的元素数量
  • 空间复杂度:O(1)
  • @param numbers int类型的数组
  • @param target 目标值
  • @return 结果
    */
    private fun twoSum(numbers: IntArray, target: Int): IntArray {
    numbers.forEachIndexed { index, number ->
    for (i in index + 1 until numbers.size) {
    if (number + numbers[i] == target) {
    return intArrayOf(index, i)
    }
    }
    }
    return intArrayOf()
    }

/**

  • 方法二:哈希表
  • 时间复杂度:O(N),其中N是数组的元素数量
  • 空间复杂度:O(N),其中N是数组的元素数量
  • @param numbers int类型的数组
  • @param target 目标值
  • @return 结果
    */
    private fun hashTwoSum(numbers: IntArray, target: Int): IntArray {
    hashMapOf<Int, Int>().apply {
    numbers.forEachIndexed { index, number ->
    val other = target - number
    if (containsKey(other)) {
    val otherIndex = get(other) ?: 0
    return intArrayOf(otherIndex, index)
    }
    put(number, index)
    }
    }
    return intArrayOf()
    }

}

题解

枚举

/**

  • 方法一:枚举
  • 时间复杂度:O(N^2),其中N是数组的元素数量
  • 空间复杂度:O(1)
  • @param numbers int类型的数组
  • @param target 目标值
  • @return 结果
    */
    private fun twoSum(numbers: IntArray, target: Int): IntArray {
    numbers.forEachIndexed { index, number ->
    for (i in index + 1 until numbers.size) {
    if (number + numbers[i] == target) {
    return intArrayOf(index, i)
    }
    }
    }
    return intArrayOf()
    }

时间复杂度:O(N^2),其中N是数组的元素数量。

空间复杂度:O(1)。

暴力解法,遍历numbers数组中每一个元素,并且找到任意两个相加等于target的元素,要注意的是,假设当前元素的索引是ii前面的元素其实已经和i匹配过,我们就不需要再次匹配了。

哈希表

/**

  • 方法二:哈希表
  • 时间复杂度:O(N),其中N是数组的元素数量
  • 空间复杂度:O(N),其中N是数组的元素数量
  • @param numbers int类型的数组
  • @param target 目标值
  • @return 结果
    */
    private fun hashTwoSum(numbers: IntArray, target: Int): IntArray {
    hashMapOf<Int, Int>().apply {
    numbers.forEachIndexed { index, number ->
    val other = target - number
    if (containsKey(other)) {
    val otherIndex = get(other) ?: 0
    return intArrayOf(otherIndex, index)
    }
    put(number, index)
    }
    }
    return intArrayOf()
    }

时间复杂度:O(N),其中N是数组的元素数量。

时间复杂度:O(N),其中N是数组的元素数量。

假设当前元素是number,方法一在查找另外一个元素的时候,也就是查找target - number的消耗太多时间了,我们可以使用HashMap存储,以元素作为key,以索引作为value,这样就可以通过containsKey方法快速地查找到这个元素对应的索引,至于为什么不用containsValue方法而使用containsKey方法,这是因为HashMap使用链地址法来解决哈希冲突的,简单来说,就是数组和链表的结合,每个数组元素都是一个链表结构,首先调用keyhashCode方法得到哈希值(该方法适用于每个Java对象),然后再通过哈希算法后两步运算(高位运算、取模运算)来定位该键值对对应的存储位置,所以通过key去查找元素的效率会比通过value的效率高,Oracle官方说,用这两个方法遍历HashMap中的所有元素,containsValue方法所需的时间比containsKey方法多出几个数量级,所以我们使用containsKey方法来再提升效率。

要注意的是,我们不要使用mutableMapOf方法,而是使用hashMapOf方法,因为mutableMapOf方法使用的是LinkedHashMap,而hashMapOf方法使用的是HashMapLinkedHashMap通过维护一个额外的双向链表来保证迭代顺序,但是在该题目其实是不需要的,不需要为此增加时间空间上的开销,源码如下所示:

// Maps.kt
/**

  • Returns an empty new [MutableMap].
  • The returned map preserves the entry iteration order.
  • @sample samples.collections.Maps.Instantiation.emptyMutableMap
    */
    @SinceKotlin(“1.1”)
    @kotlin.internal.InlineOnly
    public inline fun <K, V> mutableMapOf(): MutableMap<K, V> = LinkedHashMap()

两数相加(Add Two Numbers)

难度:中等

链接:Add Two Numbers

代码

Java

/**

  • Created by TanJiaJun on 2021/6/5.
    1. 两数相加(Add Two Numbers)
  • 难度:中等
  • @see Add Two Numbers
    */
    class AddTwoNumbers {

public static void main(String[] args) {
// 示例一
System.out.print(“示例一:”);

Node firstNode =
new Node(2,
new Node(4,
new Node(3)));
Node secondNode =
new Node(5,
new Node(6,
new Node(4)));
printNode(addTwoNumbers(firstNode, secondNode));

System.out.print(“\n”);

// 示例二
System.out.print(“示例二:”);

Node thirdNode = new Node(0);
Node fourthNode = new Node(0);
printNode(addTwoNumbers(thirdNode, fourthNode));

System.out.print(“\n”);

// 示例三
System.out.print(“示例三:”);

Node fifthNode =
new Node(9,
new Node(9,
new Node(9,
new Node(9,
new Node(9,
new Node(9,
new Node(9)))))));
Node sixthNode =
new Node(9,
new Node(9,
new Node(9,
new Node(9))));
printNode(addTwoNumbers(fifthNode, sixthNode));

System.out.print(“\n”);

// 示例四
System.out.print(“示例四:”);

Node seventhNode = new Node(2);
Node eightNode = new Node(8);
printNode(addTwoNumbers(seventhNode, eightNode));
}

/**

  • 时间复杂度:O(Max(m, n)),其中m是第一个结点的长度,n是第二个结点的长度
  • 空间复杂度:O(1)
  • @param firstNode 第一个结点
  • @param secondNode 第二个结点
  • @return 结果
    */
    private static Node addTwoNumbers(Node firstNode, Node secondNode) {
    Node dummyNode = new Node(-1);
    Node node = dummyNode;
    int carry = 0;
    // 遍历两个链表
    while (firstNode != null || secondNode != null) {
    // 如果两个链表的长度不相同的话,就在短的链表的后面通过添加若干个0
    int firstValue = firstNode != null ? firstNode.item : 0;
    int secondValue = secondNode != null ? secondNode.item : 0;
    int value = firstValue + secondValue + carry;
    int newItem = value % 10;
    // 相加后的进位值通过carry来存储
    carry = value / 10;
    Node newNode = new Node(newItem);
    if (firstNode != null) {
    firstNode = firstNode.next;
    }
    if (secondNode != null) {
    secondNode = secondNode.next;
    }
    // 如果在遍历完这两个链表后,carry的值大于0,那么就应该在链表的后面增加一个新的结点来存储这个值
    if (firstNode == null && secondNode == null && carry > 0) {
    newNode.next = new Node(carry);
    }
    node.next = newNode;
    node = node.next;
    }
    return dummyNode.next;
    }

/**

  • 打印结点
  • @param node 结点
    */
    private static void printNode(Node node) {
    System.out.print(“[”);
    while (node != null) {
    System.out.print(node.item);
    node = node.next;
    if (node != null) {
    System.out.print(“,”);
    }
    }
    System.out.print(“]”);
    }

private static class Node {

int item;
Node next;

Node(int item) {
this.item = item;
}

Node(int item, Node next) {
this.item = item;
this.next = next;
}

}

}

Kotlin

/**

  • Created by TanJiaJun on 2021/6/6.
    1. 两数相加(Add Two Numbers)
  • 难度:中等
  • @see Add Two Numbers
    */
    object AddTwoNumbersKotlin {

@JvmStatic
fun main(args: Array) {
// 示例一
print(“示例一:”)
val firstNode =
Node(
2,
Node(
4,
Node(3)
)
)
val secondNode =
Node(
5,
Node(
6,
Node(4)
)
)
printNode(addTwoNumbers(firstNode, secondNode))

print(“\n”)

// 示例二
print(“示例二:”)
val thirdNode = Node(0)
val fourthNode = Node(0)
printNode(addTwoNumbers(thirdNode, fourthNode))

print(“\n”)

// 示例三
print(“示例三:”)
val fifthNode =
Node(
9,
Node(
9,
Node(
9,
Node(
9,
Node(
9,
Node(
9,
Node(9)
)
)
)
)
)
)
val sixthNode =
Node(
9,
Node(
9,
Node(
9,
Node(9)
)
)
)
printNode(addTwoNumbers(fifthNode, sixthNode))

print(“\n”)

// 示例四
print(“示例四:”)
val seventhNode = Node(2)
val eightNode = Node(8)
printNode(addTwoNumbers(seventhNode, eightNode))
}

/**

  • 时间复杂度:O(Max(m, n)),其中m是第一个结点的长度,n是第二个结点的长度
  • 空间复杂度:O(1)
  • @param first 第一个结点
  • @param second 第二个结点
  • @return 结果
    */
    private fun addTwoNumbers(first: Node?, second: Node?): Node {
    var firstNode = first
    var secondNode = second
    val dummy = Node(-1)
    var node: Node = dummy
    var carry = 0
    // 遍历两个链表
    while (firstNode != null || secondNode != null) {
    // 如果两个链表的长度不相同的话,就在短的链表的后面通过添加若干个0
    val firstValue = firstNode?.item ?: 0
    val secondValue = secondNode?.item ?: 0
    val value = firstValue + secondValue + carry
    val newItem = value.rem(10)
    // 相加后的进位值通过carry来存储
    carry = value.div(10)
    val newNode = Node(newItem)
    firstNode?.let { firstNode = it.next }
    secondNode?.let { secondNode = it.next }
    // 如果在遍历完这两个链表后,carry的值大于0,那么就应该在链表的后面增加一个新的结点来存储这个值
    if (firstNode == null && secondNode == null && carry > 0) {
    newNode.next = Node(carry)
    }

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
img

建议

当我们出去找工作,或者准备找工作的时候,我们一定要想,我面试的目标是什么,我自己的技术栈有哪些,近期能掌握的有哪些,我的哪些短板 ,列出来,有计划的去完成,别看前两天掘金一些大佬在驳来驳去 ,他们的观点是他们的,不要因为他们的观点,膨胀了自己,影响自己的学习节奏。基础很大程度决定你自己技术层次的厚度,你再熟练框架也好,也会比你便宜的,性价比高的替代,很现实的问题但也要有危机意识,当我们年级大了,有哪些亮点,与比我们经历更旺盛的年轻小工程师,竞争。

  • 无论你现在水平怎么样一定要 持续学习 没有鸡汤,别人看起来的毫不费力,其实费了很大力,这四个字就是我的建议!!!!!!!!!

  • 准备想说怎么样写简历,想象算了,我觉得,技术就是你最好的简历

  • 我希望每一个努力生活的it工程师,都会得到自己想要的,因为我们很辛苦,我们应得的。

  • 有什么问题想交流,欢迎给我私信,欢迎评论

【附】相关架构及资料

Android高级技术大纲

面试资料整理

内含往期Android高级架构资料、源码、笔记、视频。高级UI、性能优化、架构师课程、NDK、混合式开发(ReactNative+Weex)微信小程序、Flutter全方面的Android进阶实践技术

度决定你自己技术层次的厚度,你再熟练框架也好,也会比你便宜的,性价比高的替代,很现实的问题但也要有危机意识,当我们年级大了,有哪些亮点,与比我们经历更旺盛的年轻小工程师,竞争。

  • 无论你现在水平怎么样一定要 持续学习 没有鸡汤,别人看起来的毫不费力,其实费了很大力,这四个字就是我的建议!!!!!!!!!

  • 准备想说怎么样写简历,想象算了,我觉得,技术就是你最好的简历

  • 我希望每一个努力生活的it工程师,都会得到自己想要的,因为我们很辛苦,我们应得的。

  • 有什么问题想交流,欢迎给我私信,欢迎评论

【附】相关架构及资料

[外链图片转存中…(img-G01ELh8a-1712037965372)]

[外链图片转存中…(img-5kyooYt3-1712037965373)]

内含往期Android高级架构资料、源码、笔记、视频。高级UI、性能优化、架构师课程、NDK、混合式开发(ReactNative+Weex)微信小程序、Flutter全方面的Android进阶实践技术

本文已被CODING开源项目:《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》收录

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值