├── 2020面试专题.png ├── 2020面试专题目录.png ├── 23种设计模式.png ├── README.md ├── android ├── AndResGuard.md ├── ams.md ├── anr.md ├── aop.md ├── artordalvik.md ├── binder.md ├── binder1.md ├── binder2.md ├── butterknife.md ├── cert.md ├── commpont.md ├── commpontrounter.md ├── dalvik.md ├── dex.md ├── dexclassloader.md ├── eventbus.md ├── glide.md ├── herms.md ├── herms2.md ├── https.md ├── img │ ├── 1.png │ ├── 130847m1o6fg1rd90g6n9d.png │ ├── 1566387241(1).jpg │ ├── 161865a89847b0e7.jpg │ ├── 161865a89847b0e7.png │ ├── 1655a4f534dc8fb6.jpg │ ├── 1655a4f534e024c6.jpg │ ├── 1655a4f5366fbe43.jpg │ ├── 1655a4f536a8b660.jpg │ ├── 1655a4f549b03944.jpg │ ├── 1655a4f54b59c234.jpg │ ├── 1655a4f54bea299a.jpg │ ├── 192464-a424e528aac2482c.png │ ├── 1ve95nlrxf.png │ ├── 2012110216160766.jpg │ ├── 20150803122537096.png │ ├── 20150803123218950.png │ ├── 20150803123243623.png │ ├── 20150803123419737.png │ ├── 20150803123437322.png │ ├── 20150803123540420.png │ ├── 20161127145544347.png │ ├── 20161127155718976.png │ ├── 20161201221246459.jpg │ ├── 20161202102718240.jpg │ ├── 20161202110002525.jpg │ ├── 20161202110101073.jpg │ ├── 20161202131930082.jpg │ ├── 20161202134525362.jpg │ ├── 20161202162958308.jpg │ ├── 20161202211441457.jpg │ ├── 20161202212137323.jpg │ ├── 20161202212848209.jpg │ ├── 20161205101608390.jpg │ ├── 20170226155010743.png │ ├── 20170226155700222.png │ ├── 20170423115204640.png │ ├── 20180402165147710.png │ ├── 20180719205053545.jpg │ ├── 20180719222136564.jpg │ ├── 20180719222406350.jpg │ ├── 20180719223334476.jpg │ ├── 2354823-41f1d82670b9c29e.png │ ├── 2a4z6irjta.jpeg │ ├── 4.jpeg │ ├── 40ynwk2zm8.png │ ├── 634s0xqd0f.png │ ├── 6z1lhuu5db.png │ ├── 790890-15063f3b0f373d87.png │ ├── 8h2prbshhw.jpeg │ ├── EventBus.png │ ├── MP4.png │ ├── QQ图片20190722165308.png │ ├── abfoa2nmea.png │ ├── aop2.png │ ├── aspectj_class.jpeg │ ├── butter-1.png │ ├── butter-2.png │ ├── butter-4.png │ ├── butter-5.png │ ├── comm-1.png │ ├── comm-2.png │ ├── dexpacktool.png │ ├── douyin-1.png │ ├── ei93h0bbre.jpeg │ ├── encoderProcess.png │ ├── flow.png │ ├── frame_compress.png │ ├── gcpsa58ytp.gif │ ├── herms.png │ ├── ir080ekpca.png │ ├── jiangzao.png │ ├── jiangzao2.png │ ├── jqwogox7n7.png │ ├── jxgxogvp0u.png │ ├── live_meiyan.jpg │ ├── live_meiyan2.jpg │ ├── mediacodec_buffers.png │ ├── mgkrutqhwe.png │ ├── mjulal4104.png │ ├── modifiedapk.png │ ├── package_manager_service.jpg │ ├── packapk.png │ ├── plugin.jpg │ ├── process-1.jpg │ ├── process-10.jpg │ ├── process-11.jpg │ ├── process-12.gif │ ├── process-2.jpg │ ├── process-3.jpg │ ├── process-4.jpg │ ├── process-5.jpg │ ├── process-6.jpg │ ├── process-7.jpg │ ├── process-8.jpg │ ├── process-9.jpg │ ├── res-1.png │ ├── res-10.png │ ├── res-11.png │ ├── res-12.png │ ├── res-13.png │ ├── res-3.gif │ ├── res-4.png │ ├── res-6.png │ ├── res-7.png │ ├── res-8.png │ ├── res-9.png │ ├── result.png │ ├── rx4e89iq54.png │ ├── source_apk.png │ ├── start_activity_process.jpg │ ├── start_service_processes.jpg │ ├── timg.jpg │ ├── ur6c5swx9g.png │ ├── v2-13361906ecda16e36a3b9cbe3d38cbc1_hd.jpg │ ├── v2-16d210bd4d3607f9196581f5154c4dbd_hd.jpg │ ├── v2-38e2ea1d22660b237e17d2a7f298f3d6_hd.jpg │ ├── v2-3c719337413b9c5c4ad0b6c6b8eb0291_hd.jpg │ ├── v2-48d61b481f25319d76df689f8ab9bc6d_hd.jpg │ ├── v2-5b27b769965544fb297a12c7f162e588_hd.jpg │ ├── v2-5d58112c4ead326066a836941a2857c2_hd.jpg │ ├── v2-6316d7bd07a4cc541da4866b632aa559_hd.jpg │ ├── v2-67854cdf14d07a6a4acf9d675354e1ff_hd.jpg │ ├── v2-67dc4599167db6cf2592d418f12f5dc5_hd.jpg │ ├── v2-729b3444cd784d882215a24067893d0e_hd.jpg │ ├── v2-7c68928e26f5b96b8b3471ebb1927107_hd.jpg │ ├── v2-7ca457119bd700a5acf7f69bb0c07e51_hd.jpg │ ├── v2-85cce26769b1d9584e4af2048880307b_hd.jpg │ ├── v2-a814b6fcc7521ec6c53cbf6b5e65092a_hd.jpg │ ├── v2-aab2affe42958a659ea8a517ffaff5a0_hd.jpg │ ├── v2-cbd7d2befbed12d4c8896f236df96dbf_hd.jpg │ ├── v2-f038bb24708478e76d2240267bec56bf_hd.jpg │ ├── video-encoding-interframe-before.jpg │ ├── video.png │ ├── video1.png │ ├── video2.png │ ├── w5mpbpexhh.jpeg │ ├── yuanli.png │ ├── 下载.png │ └── 组件化.png ├── live-optimitor.md ├── live.md ├── live_meiyan.md ├── load.md ├── mediacodec.md ├── net.md ├── play_ffmpeg.md ├── plugin.md ├── plugin2.md ├── pms.md ├── process.md ├── router.md ├── sqlite.md ├── synchronize.md ├── temp.txt ├── tersorflow.md ├── thread.md ├── thread1.md ├── traked.md ├── videoencode.md ├── videowhy.md ├── voice.md └── volatile.md ├── basic ├── 1-algo │ ├── 1-algo.md │ ├── 1-tree.md │ ├── 2-hash.md │ ├── 3-mst.md │ ├── 4-path.md │ ├── 5-kmp.md │ ├── 6-search.md │ ├── 7-sort.md │ ├── 8-questions.md │ ├── 9-skip_list.md │ ├── README.md │ └── images │ │ ├── 9d89be415d4f099d1eb4042af706f278.png │ │ ├── algo_question_1.jpg │ │ ├── b+.png │ │ ├── b-.png │ │ ├── e3ccf6537c3a42f6c6f1e8d7e26ba0ed.png │ │ ├── hashmap-structure.png │ │ ├── prim.jpg │ │ ├── red_black_tree.png │ │ ├── sort.png │ │ └── tree.jpg ├── 2-op │ ├── 1-arch.md │ ├── 2-os.md │ ├── 3-concurrency.md │ ├── 4-memory.md │ ├── 5-disk.md │ ├── 6-linux.md │ ├── 7-interrupt.md │ ├── 8-device.md │ ├── 9-io.md │ ├── 9-questions.md │ ├── README.md │ └── images │ │ ├── 076dcab40e2b43efa5d1aa97d96a85e2.png │ │ ├── 359a774ea7d5d1e6ac08845023993796.png │ │ ├── 3b385bdf805241ee6cd0d4634bd7510a.png │ │ ├── c6d2db53d71a8c76c2c9a546c5811773.png │ │ ├── kernel_thread.jpg │ │ ├── memory_1.png │ │ ├── mix_thread.jpg │ │ ├── page.png │ │ ├── process_status.jpg │ │ ├── segment-page.png │ │ ├── segment.png │ │ └── user_thread.jpg ├── 3-net │ ├── 1-osi.md │ ├── 10-questions.md │ ├── 2-base_protocol.md │ ├── 3-tcp.md │ ├── 4-ip.md │ ├── 5-http.md │ ├── 6-https.md │ ├── README.md │ └── images │ │ ├── 0be933dd6159a4a907245547ceab5cda.png │ │ ├── 44e2b283e89f3fbe81b280df04d2feeb.png │ │ ├── arq.png │ │ ├── tcp_finish.jpg │ │ ├── tcp_head.png │ │ ├── tcp_slow_begin.png │ │ └── tcp_traffic_control.png ├── README.md └── cryptology.md ├── img ├── 2020Android最新技术详解.png ├── 2020面试专题.png ├── 2020面试专题目录.png ├── 23种设计模式.png ├── Kotlin.png ├── Kotlin_副本.png ├── MS.png ├── PDF.png ├── VX.png ├── flutter.png ├── flutter大全.png ├── 面试.png └── 音视频开发1-10视频.png ├── java ├── 1-oop.md ├── 10-serilaser.md ├── 17-questions.md ├── 2-operator.md ├── 3-exception.md ├── 4-generics.md ├── 5-object.md ├── 6-StringBuilder.md ├── 7-proxy.md ├── 8-annotation.md ├── README.md ├── collection │ ├── 1-collection.md │ ├── 2-HashMap.md │ ├── 3-Concurrenthashmap.md │ ├── 4-BlockQueue.md │ ├── README.md │ └── images │ │ ├── 2-HashMap-03719.png │ │ ├── 2-HashMap-4d03d.png │ │ ├── 2-HashMap-4fb68.png │ │ ├── 2-HashMap-7bdc9.png │ │ ├── ConcurrentHashMap.png │ │ ├── collection.png │ │ └── map.png ├── concurrent │ ├── 1-thread.md │ ├── 2-volatile.md │ ├── 3-synchronized.md │ ├── 4-AQS.md │ ├── 5-threadlocal.md │ ├── 6-interrupt.md │ ├── 7-CountDownLatch.md │ ├── README.md │ └── images │ │ ├── 4-AQS-cef7a.png │ │ ├── 7-CountDownLatch-29ecd.png │ │ ├── synchronized_1.png │ │ ├── synchronized_2.gif │ │ ├── thread_1.jpg │ │ ├── thread_2.jpg │ │ ├── thread_3.jpg │ │ ├── thread_4.jpg │ │ ├── volatile_1.jpg │ │ └── volatile_2.jpg ├── gc │ ├── 11-jvm-gc.md │ ├── 12-jvm-object-life-cycle.md │ ├── README.md │ └── images │ │ ├── hotspot-jvm-1.6-garbage-collector.jpg │ │ └── jvm-gc-1.jpg ├── images │ ├── error.png │ ├── exception.png │ ├── oop.gif │ └── touch-class-instance.png └── jvm │ ├── 1-jvm-class-load-init.md │ ├── 2-jvm-class-loader.md │ ├── 3-dispatcher.md │ ├── 4-jvm-architecture.md │ ├── 5-memory-model.md │ ├── 6-string-constant-pool.md │ ├── README.md │ └── images │ ├── 2019-04-12-09-49-38.png │ ├── 2019-04-12-10-01-01.png │ ├── 2019-04-12-10-06-01.png │ ├── 2019-04-12-11-21-50.png │ ├── class-loader-proxy-partten.png │ ├── dispatcher.bmp │ ├── java-class-loader.png │ ├── java-default-value.png │ ├── jvm-architecture.png │ ├── jvm-data-arrange.png │ ├── jvm-data-type.png │ ├── jvm-method-const-area.png │ └── jvm-thread-data-area.png ├── leetcode ├── AllOne.md ├── LRUCache.md ├── MinStack.md ├── README.md ├── StringMultiply.md ├── addTwoNumbers.md ├── checkInclusion.md ├── detectCycle.md ├── findCircleNum.md ├── findKthLargest.md ├── findLengthOfLCIS.md ├── getIntersectionNode.md ├── images │ └── 5981c540e595049ee84429c3f4a7face.png ├── lengthOfLongestSubstring.md ├── longestCommonPrefix.md ├── longestConsecutive.md ├── lowestCommonAncestor.md ├── maxAreaOfIsland.md ├── maxProfit.md ├── maxProfit2.md ├── maxSubArray.md ├── mergeKLists.md ├── mergeRagen.md ├── mergeTwoLists.md ├── mySqrt.md ├── restoreIpAddresses.md ├── reverseList.md ├── reverseWords.md ├── salary.md ├── searchRote.md ├── simplifyPath.md ├── sortList.md ├── threeSum.md ├── trap.md ├── validUtf8.md └── zigzagLevelOrder.md ├── offer ├── Add.md ├── BST-Link-Convert.md ├── BSTKthNode.md ├── CloneLink.md ├── CountOfSortedArray.md ├── CutRope.md ├── Duplicate.md ├── EntryNodeOfLoop.md ├── FindContinuousSequence.md ├── FindFirstCommonNode.md ├── FindGreatestSumOfSubArray.md ├── FindKthToTail.md ├── FindNumbersWithSum.md ├── FindNumsAppearOnce.md ├── FindPath.md ├── FirstNotRepeatingChar.md ├── GetLeastNumbers.md ├── GetLeastNumbersSolution.md ├── GetNext.md ├── GetNumberOfK.md ├── GetUglyNumber.md ├── HasSubtree.md ├── InversePairs.md ├── IsNumeric.md ├── IsPopOrder.md ├── IsSymmetrical.md ├── LastRemaining.md ├── LeftRotateString.md ├── LongestNoRepeatSubString.md ├── MaxGift.md ├── MaxInWindows.md ├── MaxProfit.md ├── MinStack.md ├── MoreThanHalfNum.md ├── MovingCount.md ├── NOfNumberSerialize.md ├── NumberOfOneBetweenOneAndN.md ├── O1DeleteNode.md ├── PatternMatch.md ├── Permutation.md ├── PrintFromTopToBottom.md ├── PrintMatrix.md ├── PrintMinNumber.md ├── README.md ├── ReverseSentence.md ├── SerializeTree.md ├── Singleton.md ├── StreamMid.md ├── SumOfNDice.md ├── TranslateNumToStr.md ├── TreeDepth.md ├── VerifySquenceOfBST.md ├── fibonacci.md ├── find-minimum-in-rotated-sorted-array.md ├── hasPath.md ├── images │ ├── 07ce2975ccdf288110e897a00f76f43f.png │ └── d59a892b85e600aecc22e2eca74d517f.png ├── isContinuous.md ├── merge-sort-link.md ├── mirror-tree.md ├── number-of-one.md ├── power.md ├── print-link-from-tail.md ├── printn.md ├── reConstructBinaryTree.md ├── reOrderArray.md ├── replay-space.md ├── revert-link.md ├── search-a-2d-matrix.md ├── sum.md └── two-stack-fifo.md ├── study ├── framework │ ├── Android消息机制.md │ └── Handler机制源码.md ├── java │ ├── art │ │ ├── ART虚拟机:ART虚拟机概述.md │ │ ├── ART虚拟机:OAT文件的加载流程.md │ │ ├── ART虚拟机:垃圾收集.md │ │ ├── ART虚拟机:机器指令的查找流程.md │ │ └── ART虚拟机:类与方法的查找流程.md │ └── davik │ │ ├── Java虚拟机:Java虚拟机概述.md │ │ ├── Java虚拟机:垃圾收集器与内存分配策略.md │ │ ├── Java虚拟机:类加载机制.md │ │ └── Java虚拟机:自动内存管理机制.md └── optimize │ └── APK瘦身.md ├── tencent ├── img │ ├── 4758234-70cc79184055aedb.png │ ├── 4758234-7b0707c5a07f0bc1.png │ ├── 4758234-9e2b054d0907c188.png │ ├── 4758234-eba2d00b4718cf19.png │ └── 4758234-ee5027bfe92f6515.png ├── sqlite.md ├── tinker.md └── update.md └── 音视频副本.png /2020面试专题.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/2020面试专题.png -------------------------------------------------------------------------------- /2020面试专题目录.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/2020面试专题目录.png -------------------------------------------------------------------------------- /23种设计模式.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/23种设计模式.png -------------------------------------------------------------------------------- /android/cert.md: -------------------------------------------------------------------------------- 1 | #### 腾讯---什么是对称加密,什么是非对称加密,公钥与私钥属于对称加密吗 2 | 3 | 本专栏专注分享大型Bat面试知识,后续会持续更新,喜欢的话麻烦点击一个star 4 | 5 | > **面试官: 什么是对称加密,什么是非对称加密,公钥与私钥属于对称加密吗** 6 | 7 | 8 | 9 | > **心理分析**:密码学一般是大学计算机专业学的,面试官在靠这个问题的时候 并不会深入密码学底层的内容,知识考到对称与非对称的区别。这个问题一般不会深入问道,但是会问道关于https,https目前使用了非对称加密。但是求职者千万别陷入坑中,说没听过对称与非对称。 10 | 11 | > **求职者:**应该从 加解密入手 12 | 13 | 公钥和私钥就是俗称的不对称加密方式,是从以前的对称加密(使用用户名与密码)方式的提高。我用电子邮件的方式说明一下原理。 14 | 使用公钥与私钥的目的就是实现安全的电子邮件,必须实现如下目的: 15 | 1. 我发送给你的内容必须加密,在邮件的传输过程中不能被别人看到。 16 | 2. 必须保证是我发送的邮件,不是别人冒充我的。 17 | 要达到这样的目标必须发送邮件的两人都有公钥和私钥。 18 | 公钥,就是给大家用的,你可以通过电子邮件发布,可以通过网站让别人下载,公钥其实是用来加密/验章用的。私钥,就是自己的,必须非常小心保存,最好加上密码,私钥是用来解密/签章,首先就Key的所有权来说,私钥只有个人拥有。公钥与私钥的作用是:用公钥加密的内容只能用私钥解密,用私钥加密的内容只能用公钥解密。 19 | 比如说,我要给你发送一个加密的邮件。首先,我必须拥有你的公钥,你也必须拥有我的公钥。 20 | 首先,我用你的公钥给这个邮件加密,这样就保证这个邮件不被别人看到,而且保证这个邮件在传送过程中没有被修改。你收到邮件后,用你的私钥就可以解密,就能看到内容。 21 | 其次我用我的私钥给这个邮件加密,发送到你手里后,你可以用我的公钥解密。因为私钥只有我手里有,这样就保证了这个邮件是我发送的。 22 | 当A->B资料时,A会使用B的公钥加密,这样才能确保只有B能解开,否则普罗大众都能解开加密的讯息,就是去了资料的保密性。验证方面则是使用签验章的机制,A传资料给大家时,会以自己的私钥做签章,如此所有收到讯息的人都可以用A的公钥进行验章,便可确认讯息是由 A 发出来的了 -------------------------------------------------------------------------------- /android/commpont.md: -------------------------------------------------------------------------------- 1 | #### 腾讯--组件化如何实现,组件化与插件化的差别在哪里,该怎么选型 2 | 3 | 本专栏专注分享大型Bat面试知识,后续会持续更新,喜欢的话麻烦点击一个star 4 | 5 | > **面试官: 组件化如何实现,组件化与插件化的差别在哪里,该怎么选型** 6 | 7 | 8 | 9 | > **心理分析**:面试官从架构层次 了解求职者是否用过 模块化 组件化 和插件化,在过去经验有没有运用过这些技术到项目中,这道题属于一个连环炮。求职者该格外小心 10 | 11 | > **求职者:**应该从App开发的需求来定义技术选型,分别说说模块化,组件化 插件化的优势和区别 12 | 13 | ##### 一、组件化 14 | 15 | 组件化,就是把APP拆分成不同功能模块,形成独立组件,让宿主调用。 16 | 组件化不一定是插件化,组件化是一个更大的概念:把模块解耦,组件之间代码不依赖,宿主可以依赖组件;而插件化则具体到了技术点上,宿主通过 动态加载 来调用组件,宿主不依赖组件,达到 完全解耦 的目的(比如图片缓存就可以看成一个组件被多个 App 共用)**。** 17 | 18 | **适合于项目大 但是功能相对集中**。比如 一个金融类的App 里面只包含金融的功能,金融功能又会有 借贷,理财,线下交易,把这些模块抽成单独的组件 19 | 20 | ##### 二、插件化 21 | 22 | Android程序每次更新都要下载一个完整的apk,而很多时候软件只是更新了一个小功能而已,这样的话,就显得很麻烦。如果把android程序做成主程序+插件化的形式呢,这样才利于小功能的扩展(比如一般 App 的皮肤样式就可以看成一个插件)。 23 | 24 | > 通过 gradle 配置的方式,将打 debug 包和 release 包分开。这样会有一个好处,开发一个模块,在 debug 的时候,可以打成一个 apk ,独立运行测试,可以完全独立于整个宿主 APP 的其他所有组件;待到要打 release 包的时候,再把这个模块作为一个 library ,打成 aar ,作为整个宿主 APP 的一部分。而 debug 和 release 的切换都是通过 gradle 配置,可以做到无缝切换。至于模块之间的跳转,可以用别名的方式,而不是用 Activity 和 Fragment 类名。这样所有的模块和宿主 APP 都是完全解耦的,彻底解决了并行开发的可能造成的交叉依赖等问题。 25 | 26 | 主要原理是:主要利用 Java ClassLoader 的原理,如 Android 的 DexClassLoader,可动态加载的内容包括 apk、dex、jar 等。如下 27 | 28 | 29 | 30 | ###### 插件化的优势: 31 | 32 | - 适应并行开发,解耦各个模块,避免模块之间的交叉依赖,加快编译速度,从而提高并行开发效率。 33 | - 满足产品随时上线的需求 34 | - 修复因为我们对自己要求不严格而写出来的 bug。 35 | - 插件化的结果:分为稳定的 release 版本和不稳定的 snapshot 版本,每个模块都高度解耦,没有交叉依赖,不会出现一个模块依赖了另一个模块,其中一个人改了这个模块的代码,对另一个模块造成影响。 36 | 37 | 淘宝的框架是用了osgi的bundle概念,整个应用框架生命周期完整。 38 | 39 | **适合于项目超级大 但是功能相对不集中。**比如 一个支付宝App 里面即包含共享单车 也包含 电影票。这种与本业务完全不同的 可以做成插件的形式 40 | 41 | ###### 插件化弊端: 42 | 43 | 每一个插件都是一个apk,插件多的时候管理起来也麻烦。 44 | 45 | 46 | 47 | 48 | 49 | ----------------- 50 | 51 | -------------------------------------------------------------------------------- /android/herms2.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/herms2.md -------------------------------------------------------------------------------- /android/img/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/1.png -------------------------------------------------------------------------------- /android/img/130847m1o6fg1rd90g6n9d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/130847m1o6fg1rd90g6n9d.png -------------------------------------------------------------------------------- /android/img/1566387241(1).jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/1566387241(1).jpg -------------------------------------------------------------------------------- /android/img/161865a89847b0e7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/161865a89847b0e7.jpg -------------------------------------------------------------------------------- /android/img/161865a89847b0e7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/161865a89847b0e7.png -------------------------------------------------------------------------------- /android/img/1655a4f534dc8fb6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/1655a4f534dc8fb6.jpg -------------------------------------------------------------------------------- /android/img/1655a4f534e024c6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/1655a4f534e024c6.jpg -------------------------------------------------------------------------------- /android/img/1655a4f5366fbe43.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/1655a4f5366fbe43.jpg -------------------------------------------------------------------------------- /android/img/1655a4f536a8b660.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/1655a4f536a8b660.jpg -------------------------------------------------------------------------------- /android/img/1655a4f549b03944.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/1655a4f549b03944.jpg -------------------------------------------------------------------------------- /android/img/1655a4f54b59c234.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/1655a4f54b59c234.jpg -------------------------------------------------------------------------------- /android/img/1655a4f54bea299a.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/1655a4f54bea299a.jpg -------------------------------------------------------------------------------- /android/img/192464-a424e528aac2482c.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/192464-a424e528aac2482c.png -------------------------------------------------------------------------------- /android/img/1ve95nlrxf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/1ve95nlrxf.png -------------------------------------------------------------------------------- /android/img/2012110216160766.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/2012110216160766.jpg -------------------------------------------------------------------------------- /android/img/20150803122537096.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/20150803122537096.png -------------------------------------------------------------------------------- /android/img/20150803123218950.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/20150803123218950.png -------------------------------------------------------------------------------- /android/img/20150803123243623.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/20150803123243623.png -------------------------------------------------------------------------------- /android/img/20150803123419737.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/20150803123419737.png -------------------------------------------------------------------------------- /android/img/20150803123437322.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/20150803123437322.png -------------------------------------------------------------------------------- /android/img/20150803123540420.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/20150803123540420.png -------------------------------------------------------------------------------- /android/img/20161127145544347.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/20161127145544347.png -------------------------------------------------------------------------------- /android/img/20161127155718976.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/20161127155718976.png -------------------------------------------------------------------------------- /android/img/20161201221246459.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/20161201221246459.jpg -------------------------------------------------------------------------------- /android/img/20161202102718240.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/20161202102718240.jpg -------------------------------------------------------------------------------- /android/img/20161202110002525.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/20161202110002525.jpg -------------------------------------------------------------------------------- /android/img/20161202110101073.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/20161202110101073.jpg -------------------------------------------------------------------------------- /android/img/20161202131930082.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/20161202131930082.jpg -------------------------------------------------------------------------------- /android/img/20161202134525362.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/20161202134525362.jpg -------------------------------------------------------------------------------- /android/img/20161202162958308.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/20161202162958308.jpg -------------------------------------------------------------------------------- /android/img/20161202211441457.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/20161202211441457.jpg -------------------------------------------------------------------------------- /android/img/20161202212137323.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/20161202212137323.jpg -------------------------------------------------------------------------------- /android/img/20161202212848209.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/20161202212848209.jpg -------------------------------------------------------------------------------- /android/img/20161205101608390.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/20161205101608390.jpg -------------------------------------------------------------------------------- /android/img/20170226155010743.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/20170226155010743.png -------------------------------------------------------------------------------- /android/img/20170226155700222.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/20170226155700222.png -------------------------------------------------------------------------------- /android/img/20170423115204640.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/20170423115204640.png -------------------------------------------------------------------------------- /android/img/20180402165147710.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/20180402165147710.png -------------------------------------------------------------------------------- /android/img/20180719205053545.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/20180719205053545.jpg -------------------------------------------------------------------------------- /android/img/20180719222136564.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/20180719222136564.jpg -------------------------------------------------------------------------------- /android/img/20180719222406350.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/20180719222406350.jpg -------------------------------------------------------------------------------- /android/img/20180719223334476.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/20180719223334476.jpg -------------------------------------------------------------------------------- /android/img/2354823-41f1d82670b9c29e.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/2354823-41f1d82670b9c29e.png -------------------------------------------------------------------------------- /android/img/2a4z6irjta.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/2a4z6irjta.jpeg -------------------------------------------------------------------------------- /android/img/4.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/4.jpeg -------------------------------------------------------------------------------- /android/img/40ynwk2zm8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/40ynwk2zm8.png -------------------------------------------------------------------------------- /android/img/634s0xqd0f.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/634s0xqd0f.png -------------------------------------------------------------------------------- /android/img/6z1lhuu5db.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/6z1lhuu5db.png -------------------------------------------------------------------------------- /android/img/790890-15063f3b0f373d87.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/790890-15063f3b0f373d87.png -------------------------------------------------------------------------------- /android/img/8h2prbshhw.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/8h2prbshhw.jpeg -------------------------------------------------------------------------------- /android/img/EventBus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/EventBus.png -------------------------------------------------------------------------------- /android/img/MP4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/MP4.png -------------------------------------------------------------------------------- /android/img/QQ图片20190722165308.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/QQ图片20190722165308.png -------------------------------------------------------------------------------- /android/img/abfoa2nmea.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/abfoa2nmea.png -------------------------------------------------------------------------------- /android/img/aop2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/aop2.png -------------------------------------------------------------------------------- /android/img/aspectj_class.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/aspectj_class.jpeg -------------------------------------------------------------------------------- /android/img/butter-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/butter-1.png -------------------------------------------------------------------------------- /android/img/butter-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/butter-2.png -------------------------------------------------------------------------------- /android/img/butter-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/butter-4.png -------------------------------------------------------------------------------- /android/img/butter-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/butter-5.png -------------------------------------------------------------------------------- /android/img/comm-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/comm-1.png -------------------------------------------------------------------------------- /android/img/comm-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/comm-2.png -------------------------------------------------------------------------------- /android/img/dexpacktool.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/dexpacktool.png -------------------------------------------------------------------------------- /android/img/douyin-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/douyin-1.png -------------------------------------------------------------------------------- /android/img/ei93h0bbre.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/ei93h0bbre.jpeg -------------------------------------------------------------------------------- /android/img/encoderProcess.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/encoderProcess.png -------------------------------------------------------------------------------- /android/img/flow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/flow.png -------------------------------------------------------------------------------- /android/img/frame_compress.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/frame_compress.png -------------------------------------------------------------------------------- /android/img/gcpsa58ytp.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/gcpsa58ytp.gif -------------------------------------------------------------------------------- /android/img/herms.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/herms.png -------------------------------------------------------------------------------- /android/img/ir080ekpca.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/ir080ekpca.png -------------------------------------------------------------------------------- /android/img/jiangzao.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/jiangzao.png -------------------------------------------------------------------------------- /android/img/jiangzao2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/jiangzao2.png -------------------------------------------------------------------------------- /android/img/jqwogox7n7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/jqwogox7n7.png -------------------------------------------------------------------------------- /android/img/jxgxogvp0u.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/jxgxogvp0u.png -------------------------------------------------------------------------------- /android/img/live_meiyan.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/live_meiyan.jpg -------------------------------------------------------------------------------- /android/img/live_meiyan2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/live_meiyan2.jpg -------------------------------------------------------------------------------- /android/img/mediacodec_buffers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/mediacodec_buffers.png -------------------------------------------------------------------------------- /android/img/mgkrutqhwe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/mgkrutqhwe.png -------------------------------------------------------------------------------- /android/img/mjulal4104.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/mjulal4104.png -------------------------------------------------------------------------------- /android/img/modifiedapk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/modifiedapk.png -------------------------------------------------------------------------------- /android/img/package_manager_service.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/package_manager_service.jpg -------------------------------------------------------------------------------- /android/img/packapk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/packapk.png -------------------------------------------------------------------------------- /android/img/plugin.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/plugin.jpg -------------------------------------------------------------------------------- /android/img/process-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/process-1.jpg -------------------------------------------------------------------------------- /android/img/process-10.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/process-10.jpg -------------------------------------------------------------------------------- /android/img/process-11.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/process-11.jpg -------------------------------------------------------------------------------- /android/img/process-12.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/process-12.gif -------------------------------------------------------------------------------- /android/img/process-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/process-2.jpg -------------------------------------------------------------------------------- /android/img/process-3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/process-3.jpg -------------------------------------------------------------------------------- /android/img/process-4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/process-4.jpg -------------------------------------------------------------------------------- /android/img/process-5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/process-5.jpg -------------------------------------------------------------------------------- /android/img/process-6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/process-6.jpg -------------------------------------------------------------------------------- /android/img/process-7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/process-7.jpg -------------------------------------------------------------------------------- /android/img/process-8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/process-8.jpg -------------------------------------------------------------------------------- /android/img/process-9.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/process-9.jpg -------------------------------------------------------------------------------- /android/img/res-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/res-1.png -------------------------------------------------------------------------------- /android/img/res-10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/res-10.png -------------------------------------------------------------------------------- /android/img/res-11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/res-11.png -------------------------------------------------------------------------------- /android/img/res-12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/res-12.png -------------------------------------------------------------------------------- /android/img/res-13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/res-13.png -------------------------------------------------------------------------------- /android/img/res-3.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/res-3.gif -------------------------------------------------------------------------------- /android/img/res-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/res-4.png -------------------------------------------------------------------------------- /android/img/res-6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/res-6.png -------------------------------------------------------------------------------- /android/img/res-7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/res-7.png -------------------------------------------------------------------------------- /android/img/res-8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/res-8.png -------------------------------------------------------------------------------- /android/img/res-9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/res-9.png -------------------------------------------------------------------------------- /android/img/result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/result.png -------------------------------------------------------------------------------- /android/img/rx4e89iq54.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/rx4e89iq54.png -------------------------------------------------------------------------------- /android/img/source_apk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/source_apk.png -------------------------------------------------------------------------------- /android/img/start_activity_process.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/start_activity_process.jpg -------------------------------------------------------------------------------- /android/img/start_service_processes.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/start_service_processes.jpg -------------------------------------------------------------------------------- /android/img/timg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/timg.jpg -------------------------------------------------------------------------------- /android/img/ur6c5swx9g.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/ur6c5swx9g.png -------------------------------------------------------------------------------- /android/img/v2-13361906ecda16e36a3b9cbe3d38cbc1_hd.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/v2-13361906ecda16e36a3b9cbe3d38cbc1_hd.jpg -------------------------------------------------------------------------------- /android/img/v2-16d210bd4d3607f9196581f5154c4dbd_hd.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/v2-16d210bd4d3607f9196581f5154c4dbd_hd.jpg -------------------------------------------------------------------------------- /android/img/v2-38e2ea1d22660b237e17d2a7f298f3d6_hd.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/v2-38e2ea1d22660b237e17d2a7f298f3d6_hd.jpg -------------------------------------------------------------------------------- /android/img/v2-3c719337413b9c5c4ad0b6c6b8eb0291_hd.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/v2-3c719337413b9c5c4ad0b6c6b8eb0291_hd.jpg -------------------------------------------------------------------------------- /android/img/v2-48d61b481f25319d76df689f8ab9bc6d_hd.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/v2-48d61b481f25319d76df689f8ab9bc6d_hd.jpg -------------------------------------------------------------------------------- /android/img/v2-5b27b769965544fb297a12c7f162e588_hd.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/v2-5b27b769965544fb297a12c7f162e588_hd.jpg -------------------------------------------------------------------------------- /android/img/v2-5d58112c4ead326066a836941a2857c2_hd.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/v2-5d58112c4ead326066a836941a2857c2_hd.jpg -------------------------------------------------------------------------------- /android/img/v2-6316d7bd07a4cc541da4866b632aa559_hd.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/v2-6316d7bd07a4cc541da4866b632aa559_hd.jpg -------------------------------------------------------------------------------- /android/img/v2-67854cdf14d07a6a4acf9d675354e1ff_hd.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/v2-67854cdf14d07a6a4acf9d675354e1ff_hd.jpg -------------------------------------------------------------------------------- /android/img/v2-67dc4599167db6cf2592d418f12f5dc5_hd.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/v2-67dc4599167db6cf2592d418f12f5dc5_hd.jpg -------------------------------------------------------------------------------- /android/img/v2-729b3444cd784d882215a24067893d0e_hd.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/v2-729b3444cd784d882215a24067893d0e_hd.jpg -------------------------------------------------------------------------------- /android/img/v2-7c68928e26f5b96b8b3471ebb1927107_hd.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/v2-7c68928e26f5b96b8b3471ebb1927107_hd.jpg -------------------------------------------------------------------------------- /android/img/v2-7ca457119bd700a5acf7f69bb0c07e51_hd.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/v2-7ca457119bd700a5acf7f69bb0c07e51_hd.jpg -------------------------------------------------------------------------------- /android/img/v2-85cce26769b1d9584e4af2048880307b_hd.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/v2-85cce26769b1d9584e4af2048880307b_hd.jpg -------------------------------------------------------------------------------- /android/img/v2-a814b6fcc7521ec6c53cbf6b5e65092a_hd.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/v2-a814b6fcc7521ec6c53cbf6b5e65092a_hd.jpg -------------------------------------------------------------------------------- /android/img/v2-aab2affe42958a659ea8a517ffaff5a0_hd.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/v2-aab2affe42958a659ea8a517ffaff5a0_hd.jpg -------------------------------------------------------------------------------- /android/img/v2-cbd7d2befbed12d4c8896f236df96dbf_hd.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/v2-cbd7d2befbed12d4c8896f236df96dbf_hd.jpg -------------------------------------------------------------------------------- /android/img/v2-f038bb24708478e76d2240267bec56bf_hd.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/v2-f038bb24708478e76d2240267bec56bf_hd.jpg -------------------------------------------------------------------------------- /android/img/video-encoding-interframe-before.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/video-encoding-interframe-before.jpg -------------------------------------------------------------------------------- /android/img/video.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/video.png -------------------------------------------------------------------------------- /android/img/video1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/video1.png -------------------------------------------------------------------------------- /android/img/video2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/video2.png -------------------------------------------------------------------------------- /android/img/w5mpbpexhh.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/w5mpbpexhh.jpeg -------------------------------------------------------------------------------- /android/img/yuanli.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/yuanli.png -------------------------------------------------------------------------------- /android/img/下载.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/下载.png -------------------------------------------------------------------------------- /android/img/组件化.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/img/组件化.png -------------------------------------------------------------------------------- /android/temp.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/android/temp.txt -------------------------------------------------------------------------------- /android/thread.md: -------------------------------------------------------------------------------- 1 | #### 干货正在创造中 尽情期待,觉得内容可以的话 可以在右上方点击个小小的start 2 | 3 | 作者:[涂程]() 4 | 5 | 校对:[David]() 6 | 7 | 文章状态:编辑中 8 | 9 | **关于项目** 10 | 11 | > [AndroidInterView]()项目旨在通过提供一系列最新的Android高级面试题,最顶尖的行业干货。降低面试Android岗位的门槛,让更多的Android工程师理解Android系统,掌握Android系统。 12 | 13 | **文章目录** 14 | 15 | 16 | 17 | 文章正文 18 | 19 | 20 | 21 | > 本篇文章到这里就结束了,欢迎关注我们的AndroidInterView微信公众平台,AndroidInterView致力于分享Android系统源码的设计与实现相关文章,也欢迎开源爱好者参与到AndroidInterView项目中来。 22 | 23 | 24 | 25 | ##### 后续持续更新中,添加QQ群:4112676, 备注github 26 | 27 | ##### 加微信号,获取Android 2019年面试视频。发送"面试 "即可领取 另附企业内推,架构设计资料,相关视频资料 28 | 29 | 微信号 30 | 31 | [![image](../img/img.jpg)]( -------------------------------------------------------------------------------- /android/videowhy.md: -------------------------------------------------------------------------------- 1 | #### 腾讯-音视频是什么,视频为什么需要压缩 2 | 3 | 本专栏专注分享大型Bat面试知识,后续会持续更新,喜欢的话麻烦点击一个star 4 | 5 | > **面试官: 音视频是什么,视频为什么需要压缩** 6 | 7 | 8 | 9 | > **心理分析**:很多人对音视频的概念停留在 苍老师的小电影上,只能理解他是一个视频文件。面试官考的对视频文件下的封装格式,视频文件组成和音视频开发有没相关的概念 10 | 11 | > **求职者:**首先需要从视频文件组成开始讲解,慢慢深入到视频编码 12 | 13 | #### 1.1 视频的构成 14 | 15 | 16 | 17 | ![video](img/video.png) 18 | 19 | 一个完整的视频文件是由**音频和视频两部分组成**封装格式和编码格式 20 | 21 | 外壳类似于"苍老师.mp4"文件,外壳的核心还有一层编码文件,编码文件经过封装后,才成为我们现在看到的.mp4 .avi等视频。 22 | 23 | 苍老师的激战的画面内容被编码成了H264或mpeg-4,我们把H264视频编码格式, 24 | 25 | 苍老师的销魂声音编码成MP3、AAC, 我们把MP3称为音频编码格式。 26 | 27 | **例如:**将一个H.264视频编码文件和一个MP3视频编码文件按MP4封装标准封装以后,就得到一个MP4后缀的视频文件,这个就是我们常见的AVI视频文件了。 28 | 29 | 部分技术先进的容器还可以同时封装多个视频、音频编码文件,甚至同时封装进字幕,如MKV封装格式。MKV文件可以做到一个文件包括多语种发音、多语种字幕,适合不同人的需要。 30 | 31 | 32 | 33 | #### 1.2 封装格式 34 | 35 | ![](img/790890-15063f3b0f373d87.png) 36 | 37 | ``` 38 | (1)封装格式(也叫容器)就是将已经编码压缩好的视频轨和音频轨按照一定的格式放到一个文件中,也就是说仅仅是一个外壳,可以把它当成一个放视频轨和音频轨的文件夹也可以。 39 | (2)通俗点说视频轨相当于饭,而音频轨相当于菜,封装格式就是一个碗,或者一个锅,用来盛放饭菜的容器。 40 | (3)封装格式和专利是有关系的,关系到推出封装格式的公司的盈利。 41 | (4)有了封装格式,才能把字幕,配音,音频和视频组合起来。 42 | (5)常见的AVI、RMVB、MKV、ASF、WMV、MP4、3GP、FLV等文件都指的是一种封装格式。 43 | ``` 44 | 45 | 举例MKV格式的封装: 46 | 47 | ![](img/MP4.png) 48 | 49 | 50 | 51 | ### 1.3 视频为什么需要压缩 52 | 53 | - 未经压缩的数字视频的数据量巨大 54 | - 存储困难:一张DVD只能存储几秒钟的未压缩数字视频。 55 | - 传输困难 1兆的带宽传输一秒的数字电视视频需要大约4分钟。 56 | 57 | 58 | 59 | ![即时通讯音视频开发(一):视频编解码之理论概述_1.png](img/130847m1o6fg1rd90g6n9d.png) -------------------------------------------------------------------------------- /basic/1-algo/1-algo.md: -------------------------------------------------------------------------------- 1 | # 常用算法 2 | -------------------------------------------------------------------------------- /basic/1-algo/2-hash.md: -------------------------------------------------------------------------------- 1 | # Hash 2 | 3 | 哈希表(Hash Table,也叫散列表),是根据关键码值 (Key-Value) 而直接进行访问的数据结构。也就是说,**它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度**。哈希表的实现主要需要解决两个问题,哈希函数和冲突解决。 4 | 5 | 6 | ### 哈希函数 7 | 8 | 哈希函数也叫散列函数,它对不同的输出值得到一个固定长度的消息摘要。理想的哈希函数对于不同的输入应该产生不同的结构,**同时散列结果应当具有同一性(输出值尽量均匀)和雪崩效应(微小的输入值变化使得输出值发生巨大的变化)**。 9 | 10 | ### 冲突解决 11 | 12 | - `开放地址法`:**以发生冲突的哈希地址为输入,通过某种哈希冲突函数得到一个新的空闲的哈希地址的方法**。有以下几种方式: 13 | - `线性探查法`:从发生冲突的地址开始,依次探查下一个地址,直到找到一个空闲单元。 14 | - `平方探查法`:设冲突地址为d0,则探查序列为:d0+1^2,d0-1^2,d0+2^2... 15 | - `拉链法`:把所有的同义词用单链表链接起来。在这种方法下,哈希表每个单元中存放的不再是元素本身,而是相应同义词单链表的头指针。`HashMap`就是使用这种方法解决冲突的。 16 | 17 | ![](images/hashmap-structure.png) 18 | -------------------------------------------------------------------------------- /basic/1-algo/3-mst.md: -------------------------------------------------------------------------------- 1 | # 最小生成树算法 2 | 3 | - `连通图`:在无向图G中,若从顶点i到顶点j有路径,则称顶点i和顶点j是连通的。若图G中任意两个顶点都连通,则称G为连通图。 4 | 5 | - `生成树`:一个连通图的生成树是该连通图的一个极小连通子图,它含有全部顶点,但只有构成一个数的`(n-1)`条边。 6 | 7 | - `最小生成树`:对于一个带权连通无向图G中的不同生成树,各树的边上的 **权值之和最小**。构造最小生成树的准则有三条: 8 | - 必须只使用该图中的边来构造最小生成树。 9 | - 必须使用且仅使用`(n-1)`条边来连接图中的n个顶点。 10 | - 不能使用产生回路的边。 11 | 12 | ### Prim算法 13 | 14 | 假设G=(V,E)是一个具有n个顶点的带权连通无向图,T(U,TE)是G的最小生成树,其中U是T的顶点集,TE是T的边集,则由G构造从起始顶点v出发的最小生成树T的步骤为: 15 | 16 | - 初始化U={v},以v到其他顶点的所有边为候选边(U中所有点到其他顶点的边)。 17 | 18 | - 重复以下步骤(n-1)次,使得其他(n-1)个顶点被加入到U中。 19 | 20 | - 从候选边中挑选权值最小的边加入TE,设该边在`V-U`(这里是集合减)中的顶点是k,将k加入U中。 21 | 22 | - 考察当前V-U中的所有顶点j,修改候选边,若边(k,j)的权值小于原来和顶点j关联的候选边,则用(k,j)取代后者作为候选边。 23 | 24 | ![](images/prim.jpg) 25 | 26 | ### Kruskal算法 27 | 28 | 假设G=(V,E)是一个具有n个顶点的带权连通无向图,T(U,TE)是G的最小生成树,其中U是T的顶点集,TE是T的边集,则由G构造从起始顶点v出发的最小生成树T的步骤为: 29 | 30 | - 置U的初始值等于V(即包含G中的全部顶点),TE的初始值为空 31 | 32 | - 将图G中的边按权值从小到大的顺序依次选取,若选取的边未使生成树T形成回路,则加入TE,否则放弃,知道TE中包含(n-1)条边为止。 33 | -------------------------------------------------------------------------------- /basic/1-algo/4-path.md: -------------------------------------------------------------------------------- 1 | # 最短路径算法 2 | 3 | ## Dijkstra —— 贪心算法 4 | 5 | > 从一个顶点到其余顶点的最短路径 6 | 7 | 设`G=(V,E)`是一个带权有向图,把图中顶点集合V分成两组,第1组为已求出最短路径的顶点(用S表示,初始时S只有一个源点,以后每求得一条最短路径`v,...k`,就将k加到集合S中,直到全部顶点都加入S)。第2组为其余未确定最短路径的顶点集合(用U表示),按最短路径长度的递增次序把第2组的顶点加入S中。 8 | 9 | ``` 10 | 步骤: 11 | 12 | 1. 初始时,S只包含源点,即`S={v}`,顶点v到自己的距离为0。U包含除v外的其他顶点,v到U中顶点i的距离为边上的权。 13 | 2. 从U中选取一个顶点u,顶点v到u的距离最小,然后把顶点u加入S中。 14 | 3. 以顶点u为新考虑的中间点,修改v到U中各个点的距离。 15 | 4. 重复以上步骤知道S包含所有顶点。 16 | ``` 17 | 18 | ## Floyd —— 动态规划 19 | 20 | Floyd 算法是解决任意两点间的最短路径的一种算法,可以正确处理有向图或负权(但不可存在负权回路)的最短路径问题。该算法的时间复杂度为 $$O(N^{3})$$,空间复杂度为 $$O(N^{2})$$ 21 | 22 | 设 $$D_{i,j,k}$$ 为从 $$i$$ 到 $$j$$ 的只以 $$(1..k)$$ 集合中的节点为中间节点的最短路径的长度。 23 | 24 | $$ 25 | D_{i,j,k}=\begin{cases} 26 | D_{i,j,k-1} & 最短路径不经过 k\\ 27 | D_{i,k,k-1}+D_{k,j,k-1} & 最短路径经过 k 28 | \end{cases} 29 | $$ 30 | 31 | 因此, $$D_{i,j,k}=min(D_{i,k,k-1}+D_{k,j,k-1},D_{i,j,k-1})$$。伪代码描述如下: 32 | 33 | ``` 34 | // let dist be a |V| × |V| array of minimum distances initialized to ∞ (infinity) 35 | for each vertex v 36 | dist[v][v] ← 0 37 | for each edge (u,v) 38 | dist[u][v] ← w(u,v) // the weight of the edge (u,v) 39 | for k from 1 to |V| 40 | for i from 1 to |V| 41 | for j from 1 to |V| 42 | if dist[i][j] > dist[i][k] + dist[k][j] 43 | dist[i][j] ← dist[i][k] + dist[k][j] 44 | end if 45 | ``` 46 | -------------------------------------------------------------------------------- /basic/1-algo/5-kmp.md: -------------------------------------------------------------------------------- 1 | # [KMP算法](https://zh.wikipedia.org/wiki/%E5%85%8B%E5%8A%AA%E6%96%AF-%E8%8E%AB%E9%87%8C%E6%96%AF-%E6%99%AE%E6%8B%89%E7%89%B9%E7%AE%97%E6%B3%95) 2 | 3 | KMP算法解决的问题是字符匹配,这个算法把字符匹配的时间复杂度缩小到`O(m+n)`,而空间复杂度也只有O(m),n是target的长度,m是pattern的长度。 4 | 5 | - 部分匹配表(Next数组):表的作用是 **让算法无需多次匹配S中的任何字符**。能够实现线性时间搜索的关键是 **在不错过任何潜在匹配的情况下,我们"预搜索"这个模式串本身并将其译成一个包含所有可能失配的位置对应可以绕过最多无效字符的列表**。 6 | 7 | - Next数组(前缀和前缀的比较):t为模式串,j为下标 8 | - `Next[0] = -1` 9 | - `Next[j] = MAX{ k | 0 < k < j | " t0 t1 ... tk " = "t ( j-k ) t ( j-k+1 ) ... t( j-1 )" }` 10 | 11 | |i| 0| 1| 2| 3| 4| 5 |6| 12 | |--| 13 | | t[i]| A| B| C| D| A| B| D| 14 | |next[i]| -1| 0 |0 |0 |0 |1 |2| 15 | 16 | - NextVal数组:是一种优化后的Next数组,是为了解决类似`aaaab`这种模式串的匹配,减少重复的比较。 17 | 如果`t[next[j]]=t[j]`:`nextval[j]=nextval[next[j]]`,否则`nextval[j]=next[j]`。 18 | 19 | |i| 0| 1| 2| 3| 4| 5 |6| 20 | |--| 21 | | t | a| b| c| a| b| a |a| 22 | |next[j] | -1| 0 |0 |0 |1 |2 |1| 23 | |nextval[j] | -1| 0 |0 |-1 |0 |2 |1| 24 | 25 | 在上面的表格中,`t[next[4]]=t[4]=b`,所以`nextval[4]=nextval[next[4]]=0` 26 | -------------------------------------------------------------------------------- /basic/1-algo/6-search.md: -------------------------------------------------------------------------------- 1 | # 查找算法 2 | 3 | ## ASL 4 | 5 | 由于查找算法的主要运算是关键字的比较,所以通常把查找过程中对关键字的平均比较次数(平均查找长度)作为衡量一个查找算法效率的标准。`ASL= ∑(n,i=1) Pi*Ci`,其中`n`为元素个数,`Pi`是查找第`i`个元素的概率,一般为`Pi=1/n`,`Ci`是找到第`i`个元素所需比较的次数。 6 | 7 | 8 | ## 顺序查找 9 | 10 | 原理是让关键字与队列中的数从最后一个开始逐个比较,直到找出与给定关键字相同的数为止,它的缺点是效率低下。**时间复杂度o(n)**。 11 | 12 | ## 折半查找 13 | 14 | **折半查找要求线性表是有序表**。搜索过程从数组的中间元素开始,如果中间元素正好是要查找的元素,则搜索过程结束;如果某一特定元素大于或者小于中间元素,则在数组大于或小于中间元素的那一半中查找,而且跟开始一样从中间元素开始比较。如果在某一步骤数组为空,则代表找不到。这种搜索算法每一次比较都使搜索范围缩小一半。**折半搜索每次把搜索区域减少一半,时间复杂度为O(log n)。** 15 | 16 | - **可以借助二叉判定树求得折半查找的平均查找长度**:`log2(n+1)-1`。 17 | - 折半查找在失败时所需比较的关键字个数不超过判定树的深度,n个元素的判定树的深度和n个元素的完全二叉树的深度相同`log2(n)+1`。 18 | 19 | ``` 20 | public int binarySearchStandard(int[] num, int target){ 21 | int start = 0; 22 | int end = num.length - 1; 23 | while(start <= end){ //注意1 24 | int mid = start + ((end - start) >> 1); 25 | if(num[mid] == target) 26 | return mid; 27 | else if(num[mid] > target){ 28 | end = mid - 1; //注意2 29 | } 30 | else{ 31 | start = mid + 1; //注意3 32 | } 33 | } 34 | return -1; 35 | } 36 | ``` 37 | 38 | - 如果是start < end,那么当target等于num[num.length-1]时,会找不到该值。 39 | 40 | - 因为num[mid] > target, 所以如果有num[index] == target, index一定小于mid,能不能写成end = mid呢?举例来说:num = {1, 2, 5, 7, 9}; 如果写成end = mid,当循环到start = 0, end = 0时(即num[start] = 1, num[end] = 1时),mid将永远等于0,此时end也将永远等于0,陷入死循环。也就是说寻找target = -2时,程序将死循环。 41 | 42 | - 因为num[mid] < target, 所以如果有num[index] == target, index一定大于mid,能不能写成start = mid呢?举例来说:num = {1, 2, 5, 7, 9}; 如果写成start = mid,当循环到start = 3, end = 4时(即num[start] = 7, num[end] = 9时),mid将永远等于3,此时start也将永远等于3,陷入死循环。也就是说寻找target = 9时,程序将死循环。 43 | 44 | ## 分块查找 45 | 分块查找又称索引顺序查找,它是一种性能介于顺序查找和折半查找之间的查找方法。**分块查找由于只要求索引表是有序的,对块内节点没有排序要求,因此特别适合于节点动态变化的情况**。 46 | -------------------------------------------------------------------------------- /basic/1-algo/8-questions.md: -------------------------------------------------------------------------------- 1 | # 面试题 2 | 3 | ### 什么是迭代器失效? 4 | 5 | 对于`vector`而言,添加和删除操作可能使容器的部分或者全部迭代器失效。那为什么迭代器会失效呢?`vector`元素在内存中是顺序存储,试想:如果当前容器中已经存在了10个元素,现在又要添加一个元素到容器中,但是内存中紧跟在这10个元素后面没有一个空闲空间,而`vector`的元素必须顺序存储一边索引访问,所以我们不能在内存中随便找个地方存储这个元素。**于是`vector`必须重新分配存储空间,用来存放原来的元素以及新添加的元素:存放在旧存储空间的元素被复制到新的存储空间里,接着插入新的元素,最后撤销旧的存储空间**。这种情况发生,一定会导致`vector`容器的所有迭代器都失效。 6 | 7 | *** 8 | 9 | ### 二叉树如何转换为森林? 10 | 11 | 若结点x是双亲y的左孩子,则把x的右孩子,右孩子的右孩子,…,都与y用连线连起来,最后去掉所有双亲到右孩子的连线。 12 | 13 | ![](images/algo_question_1.jpg) 14 | -------------------------------------------------------------------------------- /basic/1-algo/README.md: -------------------------------------------------------------------------------- 1 | # 数据结构与算法 2 | 3 | -------------------------------------------------------------------------------- /basic/1-algo/images/9d89be415d4f099d1eb4042af706f278.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/basic/1-algo/images/9d89be415d4f099d1eb4042af706f278.png -------------------------------------------------------------------------------- /basic/1-algo/images/algo_question_1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/basic/1-algo/images/algo_question_1.jpg -------------------------------------------------------------------------------- /basic/1-algo/images/b+.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/basic/1-algo/images/b+.png -------------------------------------------------------------------------------- /basic/1-algo/images/b-.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/basic/1-algo/images/b-.png -------------------------------------------------------------------------------- /basic/1-algo/images/e3ccf6537c3a42f6c6f1e8d7e26ba0ed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/basic/1-algo/images/e3ccf6537c3a42f6c6f1e8d7e26ba0ed.png -------------------------------------------------------------------------------- /basic/1-algo/images/hashmap-structure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/basic/1-algo/images/hashmap-structure.png -------------------------------------------------------------------------------- /basic/1-algo/images/prim.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/basic/1-algo/images/prim.jpg -------------------------------------------------------------------------------- /basic/1-algo/images/red_black_tree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/basic/1-algo/images/red_black_tree.png -------------------------------------------------------------------------------- /basic/1-algo/images/sort.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/basic/1-algo/images/sort.png -------------------------------------------------------------------------------- /basic/1-algo/images/tree.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/basic/1-algo/images/tree.jpg -------------------------------------------------------------------------------- /basic/2-op/2-os.md: -------------------------------------------------------------------------------- 1 | # 操作系统基础 2 | 3 | ## 操作系统提供的服务 4 | 5 | 操作系统的五大功能,分别为:`作业管理`、`文件管理`、`存储管理`、`输入输出设备管理`、`进程及处理机管理` 6 | 7 | ## 中断 8 | 9 | 所谓的中断就是在计算机执行程序的过程中,由于出现了某些特殊事情,使得CPU暂停对程序的执行,转而去执行处理这一事件的程序。等这些特殊事情处理完之后再回去执行之前的程序。中断一般分为三类: 10 | 11 | - `内部异常中断`:由计算机硬件异常或故障引起的中断; 12 | - `软中断`:由程序中执行了引起中断的指令而造成的中断(这也是和我们将要说明的系统调用相关的中断); 13 | - `外部中断`:由外部设备请求引起的中断,比如I/O请求。 14 | 15 | >简单来说,对中断的理解就是对一些特殊事情的处理。 16 | 17 | 与中断紧密相连的一个概念就是中断处理程序了。**当中断发生的时候,系统需要去对中断进行处理,对这些中断的处理是由操作系统内核中的特定函数进行的,这些处理中断的特定的函数就是我们所说的中断处理程序了**。 18 | 19 | 另一个与中断紧密相连的概念就是中断的优先级。**中断的优先级说明的是当一个中断正在被处理的时候,处理器能接受的中断的级别。中断的优先级也表明了中断需要被处理的紧急程度。每个中断都有一个对应的优先级,当处理器在处理某一中断的时候,只有比这个中断优先级高的中断可以被处理器接受并且被处理。优先级比这个当前正在被处理的中断优先级要低的中断将会被忽略**。 20 | 21 | 典型的中断优先级如下所示: 22 | 23 | ``` 24 | 机器错误 > 时钟 > 磁盘 > 网络设备 > 终端 > 软件中断 25 | ``` 26 | 27 | 当发生软件中断时,其他所有的中断都可能发生并被处理;但当发生磁盘中断时,就只有时钟中断和机器错误中断能被处理了。 28 | 29 | ## 系统调用 30 | 31 | 在讲系统调用之前,先说下进程的执行在系统上的两个级别:用户级和核心级,也称为`用户态`和`系统态`(`user mode` and `kernel mode`)。 32 | 33 | **程序的执行一般是在用户态下执行的,但当程序需要使用操作系统提供的服务时,比如说打开某一设备、创建文件、读写文件等,就需要向操作系统发出调用服务的请求,这就是系统调用**。 34 | 35 | Linux系统有专门的函数库来提供这些请求操作系统服务的入口,这个函数库中包含了操作系统所提供的对外服务的接口。**当进程发出系统调用之后,它所处的运行状态就会由用户态变成核心态。但这个时候,进程本身其实并没有做什么事情,这个时候是由内核在做相应的操作,去完成进程所提出的这些请求**。 36 | 37 | **系统调用和中断的关系就在于,当进程发出系统调用申请的时候,会产生一个软件中断。产生这个软件中断以后,系统会去对这个软中断进行处理,这个时候进程就处于核心态了**。 38 | 39 | 那么用户态和核心态之间的区别是什么呢? 40 | 41 | - 用户态的进程能存取它们自己的指令和数据,但不能存取内核指令和数据(或其他进程的指令和数据)。然而,核心态下的进程能够存取内核和用户地址 42 | - 某些机器指令是特权指令,在用户态下执行特权指令会引起错误 43 | 44 | 对此要理解的一个是,**在系统中内核并不是作为一个与用户进程平行的估计的进程的集合,内核是为用户进程运行的**。 45 | -------------------------------------------------------------------------------- /basic/2-op/7-interrupt.md: -------------------------------------------------------------------------------- 1 | # 中断 2 | 3 | 中断(英语:Interrupt)是指 **处理器接收到来自硬件或软件的信号,提示发生了某个事件,应该被注意,这种情况就称为中断**。 4 | 5 | 通常,在接收到来自外围硬件(相对于中央处理器和内存)的异步信号,或来自软件的同步信号之后,处理器将会进行相应的 *硬件/软件* 处理。发出这样的信号称为进行中断请求(interrupt request,IRQ)。**硬件中断导致处理器通过一个运行信息切换(context switch)来保存执行状态(以程序计数器和程序状态字等寄存器信息为主);软件中断则通常作为CPU指令集中的一个指令,以可编程的方式直接指示这种运行信息切换,并将处理导向一段中断处理代码**。中断在计算机多任务处理,尤其是即时系统中尤为有用。 6 | 7 | ## 中断分类 8 | 9 | ### 硬件中断 10 | 11 | 由硬件发出或产生的中断称为硬中断,按硬中断事件的来源和实现手段可将中断划分为外中断和内中断: 12 | 13 | - **外中断**:又称为中断或异步中断,是指 **来自处理器以外的中断信号,包括时钟中断、键盘中断、外部设备中断等**。外中断又分为可屏蔽中断和不可屏蔽中断,各个中断具有不同的优先级,表示事件的紧急程度,在处理高一级中断时,往往会部分或全部屏蔽低等级中断。 14 | - **内中断**:又称为异常或同步中断(产生时必须考虑与处理器时钟同步),是指 **来自处理器内部的中断信号,通常是由于程序执行过程中,发现与当前指令关联的、不正常的或错误的事件**。内中断可以细分为: 15 | - 访管中断,由执行系统调用而引起的。 16 | - 硬件故障中断,如电源失效、总线超时等。 17 | - 程序性中断,如非法操作、地址越界、除数为0和浮点溢出等。 18 | 19 | ### 软件中断 20 | 21 | 软件中断:是一条CPU指令,用以自陷一个中断。由于 **软中断指令通常要运行一个切换CPU至内核态(Kernel Mode/Ring 0)的子例程,它常被用作实现系统调用(System call)**。 22 | 23 | 处理器通常含有一个内部中断屏蔽位,并允许通过软件来设定。一旦被设定,所有外部中断都将被系统忽略。这个屏蔽位的访问速度显然快于中断控制器上的中断屏蔽寄存器,因此可提供更快速地中断屏蔽控制。 24 | 25 | 中断尽管可以提高计算机处理性能,但 **过于密集的中断请求/响应反而会影响系统性能。这类情形被称作中断风暴(interrupt storm)**。 26 | -------------------------------------------------------------------------------- /basic/2-op/8-device.md: -------------------------------------------------------------------------------- 1 | # 设备管理 2 | 3 | 外部设备分为两大类: 4 | 5 | - **存储型设备**:以存储大量信息和快速检索为目标,在系统中存储持久性信息。 6 | - **I/O型设备**:如显示器、打印机等。 7 | 8 | ## I/O硬件原理 9 | 10 | ### I/O系统 11 | 12 | 通常把I/O设备及其接口线路、控制部件、通道和管理软件称为I/O系统,把计算机的内存和设备介质之间的信息传送操作称为I/O操作。可按照不同方式对设备进行分类:按I/O操作特性分为输入型设备、输出型设备和存储型设备;按I/O信息交换单位分为字符设备和块设备。 13 | 14 | > 输入、输出型设备通常是字符设备,存储型设备通常是块设备。 15 | 16 | 存储型设备又分为顺序存储设备和直接存取设备。前者严格依赖信息的物理位置进行读写和定位,如磁带。后者的特点是存取任何一个物理块所需要的时间几乎不依赖于此信息所处的位置,如磁盘。 17 | 18 | ### I/O控制方式 19 | 20 | #### 轮询方式 21 | 22 | 轮询方式又称程序直接控制方式,使用查询指令测试设备控制器的忙闲状态位,确定内存和设备是否能交换数据。轮询方式采用三条指令:查询指令,查询设备是否就绪;读写指令,当设备就绪时执行数据交换;转移指令,当设备未就绪时执行转移指令指向查询指令继续查询。可见,在这种方式下CPU和设备只能串行工作。 23 | 24 | #### 中断方式 25 | 26 | 在这种方式下CPU和设备之间传输数据的过程如下: 27 | 28 | 1. 进程发出启动I/O指令,CPU加载控制信息到设备控制器的寄存器,然后进程继续执行不涉及本次I/O数据的任务,或放弃CPU等待设备I/O操作完成。 29 | 30 | 2. 设备控制器检查寄存器的内容,按照I/O指令的要求执行相应I/O操作,一旦传输完成,设备控制器发出I/O中断请求信号。 31 | 32 | 3. CPU收到并响应I/O中断后,转向设备的I/O中断处理程序执行。 33 | 34 | 4. 中断处理程序执行数据读取操作,将I/O缓冲寄存器的内容写入内存,操作结束后退出中断处理程序,返回发生中断前的状态。 35 | 36 | 5. 进程调度程序在适当的时候让得到数据的进程恢复执行。 37 | 38 | 在I/O中断方式中,如果设备控制器的数据缓冲区较小,当缓冲器装满后便会发生中断,那么在数据传输过程中发生中断次数会很多,这样就消耗了大量CPU时间。 39 | 40 | #### DMA方式 41 | 42 | 虽然中断方式提高了CPU利用率,但是在响应中断请求后必须停止现行程序,转入中断处理程序并参与数据传输操作。在`DMA(Direct Memory Access)`方式中,内存和设备之间有一条数据通路成块地传送数据,无须CPU干预,实际数据传输操作由DMA直接完成。为实现DMA,至少需要以下逻辑部件: 43 | 44 | 1. 内存地址寄存器:存放内存中需要交换数据的地址,DMA传送之前由程序送入首地址;DMA传送过程中,每次交换数据都把地址寄存器的内容加1。 45 | 46 | 2. 字计数器:记录传送数据的总字数,每次传送一个字就把字计数器减1。 47 | 48 | 3. 数据缓冲寄存器或数据缓冲区:暂存每次传送的数据。 49 | 50 | 4. 设备地址寄存器:存放I/O信息的地址,如磁盘的柱面号。 51 | 52 | 5. 中断机制和控制逻辑:用于向CPU提出I/O中断请求及CPU发来的I/O命令,管理DMA的传送过程。 53 | 54 | #### 通道方式 55 | 56 | 通道又称I/O处理器,能完成内存和设备之间的信息传送,与CPU并行地执行操作。采用I/O通道设计后,I/O操作过程如下:CPU在执行主程序时遇到I/O请求,启动在指定通道上选址的设备,一旦启动成功,通道开始控制设备进行操作,这时CPU就可以执行其他任务并与通道并行工作,直到I/O操作完成;当通道发出I/O操作结束中断时,处理器才响应并停止当前工作,转向I/O操作结束事件。 57 | -------------------------------------------------------------------------------- /basic/2-op/README.md: -------------------------------------------------------------------------------- 1 | # 操作系统 2 | 3 | -------------------------------------------------------------------------------- /basic/2-op/images/076dcab40e2b43efa5d1aa97d96a85e2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/basic/2-op/images/076dcab40e2b43efa5d1aa97d96a85e2.png -------------------------------------------------------------------------------- /basic/2-op/images/359a774ea7d5d1e6ac08845023993796.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/basic/2-op/images/359a774ea7d5d1e6ac08845023993796.png -------------------------------------------------------------------------------- /basic/2-op/images/3b385bdf805241ee6cd0d4634bd7510a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/basic/2-op/images/3b385bdf805241ee6cd0d4634bd7510a.png -------------------------------------------------------------------------------- /basic/2-op/images/c6d2db53d71a8c76c2c9a546c5811773.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/basic/2-op/images/c6d2db53d71a8c76c2c9a546c5811773.png -------------------------------------------------------------------------------- /basic/2-op/images/kernel_thread.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/basic/2-op/images/kernel_thread.jpg -------------------------------------------------------------------------------- /basic/2-op/images/memory_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/basic/2-op/images/memory_1.png -------------------------------------------------------------------------------- /basic/2-op/images/mix_thread.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/basic/2-op/images/mix_thread.jpg -------------------------------------------------------------------------------- /basic/2-op/images/page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/basic/2-op/images/page.png -------------------------------------------------------------------------------- /basic/2-op/images/process_status.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/basic/2-op/images/process_status.jpg -------------------------------------------------------------------------------- /basic/2-op/images/segment-page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/basic/2-op/images/segment-page.png -------------------------------------------------------------------------------- /basic/2-op/images/segment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/basic/2-op/images/segment.png -------------------------------------------------------------------------------- /basic/2-op/images/user_thread.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/basic/2-op/images/user_thread.jpg -------------------------------------------------------------------------------- /basic/3-net/1-osi.md: -------------------------------------------------------------------------------- 1 | # 网络分层 2 | 3 | ## OSI 4 | 5 | | 层 | 功能 | 6 | | :------------- | :------------- | 7 | | 应用层 |网络进程到应用程序。针对特定应用规定各层协议、时序、表示等,进行封装 。在端系统中用软件来实现,如HTTP等| 8 | | 表示层 |数据表示形式,加密和解密,把机器相关的数据转换成独立于机器的数据。规定数据的格式化表示 ,数据格式的转换等| 9 | | 会话层 |主机间通讯,管理应用程序之间的会话。规定通信时序 ;数据交换的定界、同步,创建检查点等| 10 | | 传输层 |在网络的各个节点之间可靠地分发数据包。所有传输遗留问题;复用;流量;可靠| 11 | | 网络层 |在网络的各个节点之间进行地址分配、路由和(不一定可靠的)分发报文。路由( IP寻址);拥塞控制。| 12 | | 数据链路层 |一个可靠的点对点数据直链。检错与纠错(CRC码);多路访问;寻址| 13 | | 物理层 |一个(不一定可靠的)点对点数据直链。定义机械特性;电气特性;功能特性;规程特性| 14 | -------------------------------------------------------------------------------- /basic/3-net/10-questions.md: -------------------------------------------------------------------------------- 1 | # 面试题 2 | 3 | ### CSMA/CD有什么作用? 4 | 5 | CSMA/CD即带冲突检测的载波监听多路访问技术,应用在 `OSI` 的第二层数据链路层,是为了解决共享介质的传输效率的问题。**其原理简单总结为:先听后发,边发边听,冲突停发,随机延迟后重发**。 6 | 7 | *** 8 | 9 | ### Http会话的过程? 10 | 11 | - 建立tcp连接 12 | - 发出请求文档 13 | - 发出响应文档 14 | - 释放tcp连接 15 | 16 | *** 17 | 18 | ### TCP协议如何实现可靠传输? 19 | 20 | TCP 协议是通过ARQ协议以及等待、确认、重传等机制实现可靠传输。 21 | -------------------------------------------------------------------------------- /basic/3-net/4-ip.md: -------------------------------------------------------------------------------- 1 | # IP 2 | 3 | ## 地址分类 4 | 5 | - A类:**8位网络号**,`0_ _ _ _ _ _ _`,1.0.0.0 ~ 126.0.0.0 6 | - B类:**16位网络号**,`10 _ _ ...`,128.0.0.0 ~ 191.255.255.255 7 | - C类:**24位网络号**,`110_ _ _...`,192.0.0.0 ~ 223.255.255.255 8 | - D类:**多播地址**,`1110_ _ _...` 9 | - E类:**保留地址**,`1111_ _ _ ...` 10 | 11 | ## 私有地址 12 | 13 | - A类:`10.0.0.0 ~ 10.255.255.255`(长度相当于1个A类IP地址) 14 | - B类:`172.16.0.0 ~ 172.31.255.255`(长度相当于16个连续的B类IP地址) 15 | - C类:`192.168.0.0 ~ 192.168.255.255`(长度相当于256个连续的C类IP地址) 16 | 17 | 18 | ## 特殊的IP地址 19 | 20 | - `0.0.0.0`:已经不是一个真正意义上的IP地址。它表示的是这样一个集合:**所有不清楚的主机和目的网络。这里的“不清楚”是指在本机的路由表里没有特定条目指明如何到达**。如果在网络设置中设置了缺省网关,那么系统会自动产生一个目的地址为0.0.0.0的缺省路由.对本机来说,它就是一个“收容所”,所有不认识的“三无”人员,一 律送进去。 21 | 22 | - `255.255.255.255`: 限制广播地址,对本机来说,这个地址指本网段内(同一广播域)的所有主机。**这个地址不能被路由器转发**。 23 | 24 | - `127.0.0.1`:本机地址主要用于测试。这样一个地址,是不能把它发到网络接口的。 25 | -------------------------------------------------------------------------------- /basic/3-net/README.md: -------------------------------------------------------------------------------- 1 | # 计算机网络 2 | -------------------------------------------------------------------------------- /basic/3-net/images/0be933dd6159a4a907245547ceab5cda.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/basic/3-net/images/0be933dd6159a4a907245547ceab5cda.png -------------------------------------------------------------------------------- /basic/3-net/images/44e2b283e89f3fbe81b280df04d2feeb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/basic/3-net/images/44e2b283e89f3fbe81b280df04d2feeb.png -------------------------------------------------------------------------------- /basic/3-net/images/arq.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/basic/3-net/images/arq.png -------------------------------------------------------------------------------- /basic/3-net/images/tcp_finish.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/basic/3-net/images/tcp_finish.jpg -------------------------------------------------------------------------------- /basic/3-net/images/tcp_head.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/basic/3-net/images/tcp_head.png -------------------------------------------------------------------------------- /basic/3-net/images/tcp_slow_begin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/basic/3-net/images/tcp_slow_begin.png -------------------------------------------------------------------------------- /basic/3-net/images/tcp_traffic_control.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/basic/3-net/images/tcp_traffic_control.png -------------------------------------------------------------------------------- /basic/README.md: -------------------------------------------------------------------------------- 1 | # 计算机基础 2 | -------------------------------------------------------------------------------- /basic/cryptology.md: -------------------------------------------------------------------------------- 1 | # 密码学 2 | 3 | ## 对称加密 4 | 5 | 对称加密算法的加密和解密使用的密匙是相同的,也就是说如果通讯两方如果使用对称加密算法来加密通讯数据,那么通讯双方就需要都知道这个密匙,收到通讯数据后用这个密匙来解密数据。 6 | 7 | 这类算法在加密和解密时使用相同的密钥,或是使用两个可以简单地相互推算的密钥。事实上,这组密钥成为在两个或多个成员间的共同秘密,以便维持专属的通信联系。与非对称加密相比,要求双方获取相同的密钥是对称密钥加密的主要缺点之一。常见的对称加密算法有 `DES、3DES、AES、Blowfish、IDEA、RC5、RC6`。 8 | 9 | **对称加密的速度比公钥加密快很多,在很多场合都需要对称加密**。 10 | 11 | ## 非对称加密 12 | 13 | 它需要两个密钥,**一个是公开密钥,另一个是私有密钥;一个用作加密的时候,另一个则用作解密**。使用其中一个密钥把明文加密后所得的密文,只能用相对应的另一个密钥才能解密得到原本的明文;甚至连最初用来加密的密钥也不能用作解密。由于加密和解密需要两个不同的密钥,故被称为非对称加密; 14 | 15 | 虽然两个密钥在数学上相关,但如果知道了其中一个,并不能凭此计算出另外一个;因此其中一个可以公开,称为 **公钥**,任意向外发布;不公开的密钥为 **私钥** ,必须由用户自行严格秘密保管,绝不透过任何途径向任何人提供,也不会透露给要通信的另一方,即使他被信任。 16 | 17 | > 公钥 & 私钥 均可以作为加密密钥 18 | 19 | ## 数字签名 20 | 21 | 数字签名是一种类似写在纸上的签名,但是使用了 **公钥加密领域的技术实现** ,用于鉴别数字信息的方法。在网络上,我们可以使用“数字签名”来进行身份确认。数字签名是一个独一无二的数值,若公钥能通过验证,那我们就能确定对应的公钥的正确性,数字签名兼具这两种双重属性:"可确认性"及"不可否认性(不需要笔迹专家验证)"。 22 | 23 | 数字签名就是将公钥密码反过来使用。签名者将讯息用私钥加密(**这是一种反用,因为通常非对称加密中私钥用于解密**),然后公布公钥;验证者使用公钥将加密讯息解密并比对消息(一般签名对象为消息的散列值)。 24 | 25 | ## 密码散列函数 26 | 27 | 密码散列函数(英语:`Cryptographic hash function`),又译为加密散列函数、密码散列函数、加密散列函数,是散列函数的一种。它被认为是一种 **单向函数**,也就是说极其难以由散列函数输出的结果,回推输入的数据是什么。这种散列函数的输入数据,通常被称为消息( `message` ),而它的输出结果,经常被称为消息摘要( `message digest` )或摘要( `digest` )。 28 | -------------------------------------------------------------------------------- /img/2020Android最新技术详解.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/img/2020Android最新技术详解.png -------------------------------------------------------------------------------- /img/2020面试专题.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/img/2020面试专题.png -------------------------------------------------------------------------------- /img/2020面试专题目录.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/img/2020面试专题目录.png -------------------------------------------------------------------------------- /img/23种设计模式.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/img/23种设计模式.png -------------------------------------------------------------------------------- /img/Kotlin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/img/Kotlin.png -------------------------------------------------------------------------------- /img/Kotlin_副本.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/img/Kotlin_副本.png -------------------------------------------------------------------------------- /img/MS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/img/MS.png -------------------------------------------------------------------------------- /img/PDF.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/img/PDF.png -------------------------------------------------------------------------------- /img/VX.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/img/VX.png -------------------------------------------------------------------------------- /img/flutter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/img/flutter.png -------------------------------------------------------------------------------- /img/flutter大全.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/img/flutter大全.png -------------------------------------------------------------------------------- /img/面试.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/img/面试.png -------------------------------------------------------------------------------- /img/音视频开发1-10视频.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/img/音视频开发1-10视频.png -------------------------------------------------------------------------------- /java/10-serilaser.md: -------------------------------------------------------------------------------- 1 | # 序列化 2 | 3 | ## ProtoBuffer 4 | 5 | `Protocol Buffers` 是一种轻便高效的结构化数据存储格式,可以用于结构化数据串行化,或者说序列化。它很适合做数据存储或 `RPC` 数据交换格式。可用于通讯协议、数据存储等领域的语言无关、平台无关、可扩展的序列化结构数据格式。 6 | 7 | ### Protobuf 的优点 8 | 9 | - **Protobuf 更小、更快、也更简单**。你可以定义自己的数据结构,然后使用代码生成器生成的代码来读写这个数据结构。你甚至可以在无需重新部署程序的情况下更新数据结构。只需使用 `Protobuf` 对数据结构进行一次描述,即可利用各种不同语言或从各种不同数据流中对你的结构化数据轻松读写。 10 | - **“向后”兼容性好**,人们不必破坏已部署的、依靠“老”数据格式的程序就可以对数据结构进行升级。这样您的程序就可以不必担心因为消息结构的改变而造成的大规模的代码重构或者迁移的问题。因为添加新的消息中的 `field` 并不会引起已经发布的程序的任何改变。 11 | - **Protobuf 语义更清晰**,无需类似 XML 解析器的东西(因为 `Protobuf` 编译器会将 `.proto` 文件编译生成对应的数据访问类以对 `Protobuf` 数据进行序列化、反序列化操作)。 12 | - **Protobuf 的编程模式比较友好**,简单易学,同时它拥有良好的文档和示例,对于喜欢简单事物的人们而言,Protobuf 比其他的技术更加有吸引力。 13 | 14 | ### Protobuf 的不足 15 | 16 | 由于文本并不适合用来描述数据结构,所以 `Protobuf` 也不适合用来对基于文本的标记文档(如 HTML)建模。另外,由于 XML 具有某种程度上的自解释性,它可以被人直接读取编辑,在这一点上 `Protobuf` 不行,它以二进制的方式存储,除非你有 `.proto` 定义,否则你没法直接读出 `Protobuf` 的任何内容。 17 | -------------------------------------------------------------------------------- /java/2-operator.md: -------------------------------------------------------------------------------- 1 | # 运算符优先级 2 | 3 | 优先级从上到下依次递减,最上面具有最高的优先级,逗号操作符具有最低的优先级。 4 | 5 | 相同优先级中,按结合顺序计算。**大多数运算是从左至右计算,只有三个优先级是从右至左结合的,它们是单目运算符、条件运算符、赋值运算符**。 6 | 7 | 基本的优先级需要记住: 8 | 9 | - 指针最优,单目运算优于双目运算。如正负号。 10 | - 先乘除(模),后加减。 11 | - 先算术运算,后移位运算,最后位运算。请特别注意:`1 << 3 + 2 & 7`等价于 `(1 << (3 + 2)) & 7`. 12 | - 逻辑运算最后计算。 13 | 14 | 15 | ## 优先级表 16 | 17 | | 运算符 | 结合性 | 18 | | :------------- | :------------- | 19 | |[ ] . ( ) (方法调用)|从左向右 | 20 | |! ~ ++ -- +(一元运算) -(一元运算) |从右向左| 21 | |* / % |从左向右 | 22 | |+ - | 从左向右| 23 | |<< >> >>> |从左向右| 24 | |< <= > >= instanceof| 从左向右| 25 | |== !=| 从左向右| 26 | |&|从左向右| 27 | |^|从左向右| 28 | | | |从左向右| 29 | |&& | 从左向右| 30 | | || | 从左向右| 31 | | ?: | 从右向左| 32 | | = += -= *= /= %= &= |= ^= <<= >>= >>= | 从右向左| 33 | |,| 从左到右| 34 | 35 | > 无符号右移运算符 `>>>`,无符号右移的规则只记住一点:**忽略了符号位扩展,0 补最高位**。无符号右移规则和右移运算是一样的,只是填充时不管左边的数字是正是负都用 0 来填充,无符号右移运算只针对负数计算,因为对于正数来说这种运算没有意义。无符号右移运算符 `>>>` 只是对 32 位和 64 位的值有意义 36 | -------------------------------------------------------------------------------- /java/3-exception.md: -------------------------------------------------------------------------------- 1 | # Java异常 2 | 3 | Java中有Error和Exception,它们都是继承自Throwable类。 4 | 5 | ![](images/error.png) 6 | 7 | ![](images/exception.png) 8 | 9 | ## 二者的不同之处 10 | 11 | Exception: 12 | 13 | - 可以是可被控制(checked) 或不可控制的(unchecked)。 14 | 15 | - 表示一个由程序员导致的错误。 16 | 17 | - 应该在应用程序级被处理。 18 | 19 | Error: 20 | 21 | - 总是不可控制的(unchecked)。 22 | 23 | - 经常用来用于表示系统错误或低层资源的错误。 24 | 25 | - 如何可能的话,应该在系统级被捕捉。 26 | 27 | ## 异常的分类 28 | 29 | - **Checked exception**: 这类异常都是Exception的子类。异常的向上抛出机制进行处理,假如子类可能产生A异常,那么在父类中也必须throws A异常。可能导致的问题:代码效率低,耦合度过高。 30 | 31 | - **Unchecked exception**: **这类异常都是RuntimeException的子类,虽然RuntimeException同样也是Exception的子类,但是它们是非凡的,它们不能通过client code来试图解决**,所以称为Unchecked exception 。 32 | -------------------------------------------------------------------------------- /java/8-annotation.md: -------------------------------------------------------------------------------- 1 | # 注解 2 | 3 | 注解(`Annotation`)是 Java1.5 中引入的一个重大修改之一,为我们在代码中添加信息提供了一种形式化的方法,使我们可以在稍后某个时刻非常方便的使用这些数据。注解在一定程度上是把元数据与源代码结合在一起,而不是保存在外部文档中。注解的含义可以理解为 java 中的元数据。元数据是描述数据的数据。 4 | 5 | 注解是一个继承自`java.lang.annotation.Annotation`的接口 6 | 7 | ## 可见性 8 | 9 | 根据注解在程序不同时期的可见性,可以把注解区分为: 10 | - `source`:注解会在编译期间被丢弃,不会编译到 class 文件 11 | - `class`:注解会被编译到 class 文件中,但是在运行时不能获取 12 | - `runtime`:注解会被编译到 class 文件中,并且能够在运行时通过反射获取 13 | 14 | ## 继承 15 | 16 | | | 有@Inherited | 没有@Inherited | 17 | |:---:|:---:|:---:| 18 | | 子类的类上能否继承到父类的类上的注解? | 否 | 能 | 19 | | 子类实现了父类上的抽象方法 | 否 | 否 | 20 | | 子类继承了父类上的方法 | 能 | 能 | 21 | | 子类覆盖了父类上的方法 | 否 | 否 | 22 | 23 | `@Inherited` 只是可控制对类名上注解是否可以被继承。不能控制方法上的注解是否可以被继承。 24 | 25 | ## 注解的实现机制 26 | 27 | 1. 注解是继承自:`java.lang.annotation.Annotation` 的接口 28 | 29 | ``` 30 | ... 31 | Compiled from "TestAnnotation.java" 32 | public interface TestAnnotation extends java.lang.annotation.Annotation 33 | ... 34 | ``` 35 | 36 | 2. 注解内部的属性是在编译期间确定的 37 | 38 | ``` 39 | ... 40 | SourceFile: "SimpleTest.java" 41 | RuntimeVisibleAnnotations: 42 | 0: #43(#44=s#45) 43 | ... 44 | ``` 45 | 46 | 3. 注解在运行时会生成 `Proxy` 代理类,并使用 `AnnotationInvocationHandler.memberValues` 来进行数据读取 47 | 48 | ``` 49 | ... 50 | default: 51 | //从 Map 中获取数据 52 | Object var6 = this.memberValues.get(var4); 53 | if (var6 == null) { 54 | throw new IncompleteAnnotationException(this.type, var4); 55 | } else if (var6 instanceof ExceptionProxy) { 56 | throw ((ExceptionProxy)var6).generateException(); 57 | } else { 58 | if (var6.getClass().isArray() && Array.getLength(var6) != 0) { 59 | var6 = this.cloneArray(var6); 60 | } 61 | 62 | return var6; 63 | } 64 | } 65 | ... 66 | ``` 67 | 68 | ## 参考链接 69 | 70 | - [java注解是怎么实现的?](https://www.zhihu.com/question/24401191) 71 | -------------------------------------------------------------------------------- /java/README.md: -------------------------------------------------------------------------------- 1 | # Java -------------------------------------------------------------------------------- /java/collection/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/java/collection/README.md -------------------------------------------------------------------------------- /java/collection/images/2-HashMap-03719.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/java/collection/images/2-HashMap-03719.png -------------------------------------------------------------------------------- /java/collection/images/2-HashMap-4d03d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/java/collection/images/2-HashMap-4d03d.png -------------------------------------------------------------------------------- /java/collection/images/2-HashMap-4fb68.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/java/collection/images/2-HashMap-4fb68.png -------------------------------------------------------------------------------- /java/collection/images/2-HashMap-7bdc9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/java/collection/images/2-HashMap-7bdc9.png -------------------------------------------------------------------------------- /java/collection/images/ConcurrentHashMap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/java/collection/images/ConcurrentHashMap.png -------------------------------------------------------------------------------- /java/collection/images/collection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/java/collection/images/collection.png -------------------------------------------------------------------------------- /java/collection/images/map.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/java/collection/images/map.png -------------------------------------------------------------------------------- /java/concurrent/5-threadlocal.md: -------------------------------------------------------------------------------- 1 | # Threadlocal原理 2 | 3 | `ThreadLocal` 为解决多线程程序的并发问题提供了一种新的思路。使用这个工具类可以很简洁地编写出优美的多线程程序。当使用 ThreadLocal 维护变量时,ThreadLocal 为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。 4 | 5 | 每个线程中都保有一个`ThreadLocalMap`的成员变量,`ThreadLocalMap `内部采用`WeakReference`数组保存,数组的key即为`ThreadLocal `内部的Hash值。 6 | 7 | ## 内存泄漏 8 | 9 | `ThreadLocalMap` 使用 `ThreadLocal` 的弱引用作为 key ,如果一个 `ThreadLocal` 没有外部强引用来引用它,那么系统 GC 的时候,这个 `ThreadLocal` 势必会被回收,这样一来,`ThreadLocalMap` 中就会出现 `key` 为 `null` 的 `Entry` ,就没有办法访问这些 `key` 为 `null` 的 `Entry` 的 `value`,如果当前线程再迟迟不结束的话,这些 `key` 为 `null` 的 `Entry` 的 `value` 就会一直存在一条强引用链:`Thread Ref -> Thread -> ThreaLocalMap -> Entry -> value` 永远无法回收,造成内存泄漏。 10 | 11 | ``` 12 | static class Entry extends WeakReference> { 13 | /** The value associated with this ThreadLocal. */ 14 | Object value; 15 | 16 | Entry(ThreadLocal k, Object v) { 17 | super(k); 18 | value = v; 19 | } 20 | } 21 | ``` 22 | 23 | 其实,`ThreadLocalMap` 的设计中已经考虑到这种情况,也加上了一些防护措施:在 `ThreadLocal` 的 `get(),set(),remove()`的时候都会清除线程 `ThreadLocalMap` 里所有 `key` 为 `null` 的 `value` 24 | -------------------------------------------------------------------------------- /java/concurrent/7-CountDownLatch.md: -------------------------------------------------------------------------------- 1 | # CountDownLatch 2 | 3 | `CountDownLatch` 是可以使一个或者多个线程等待其他线程完成某些操作的同步器。`CountDownLatch` 通过一个给定的数字 `count` 进行初始化。调用 `await` 方法的线程会一直阻塞到其他线程调用 `countDown` 将 `count` 变为0,这时所有的线程都将释放,并且后续的 `await` 方法调用都会立即返回。`count` 值不能重置。如果你需要重置 `count` 请考虑使用 `CyclicBarrier`。 4 | 5 | `CountDownLatch` 是一个能力很强的同步工具,可以用在多种途径。`CountDownLatch` 最重要的属性是其不要求 调用 `countDown` 的线程等待到 `count` 为0,只是要求所有 `await` 调用线程等待。 6 | 7 | `CountDownLatch` 内部使用的是 AQS,AQS 里面的 state 是一个整数值,这边用一个 `int count` 参数其实初始化就是设置了这个值,所有调用了 `await` 方法的等待线程会挂起,然后有其他一些线程会做 `state = state - 1` 操作,当 `state` 减到 `0` 的同时,那个将 `state` 减为 `0` 的线程会负责唤醒 所有调用了 `await` 方法的线程。 8 | 9 | ![](images/7-CountDownLatch-29ecd.png) 10 | 11 | - `countDown()` 方法每次调用都会将 `state` 减 1,直到 `state` 的值为 0;而 `await` 是一个阻塞方法,当 `state` 减为 `0` 的时候,`await` 方法才会返回。`await` 可以被多个线程调用,读者这个时候脑子里要有个图:所有调用了 `await` 方法的线程阻塞在 `AQS` 的阻塞队列中,等待条件满足(`state == 0`),将线程从队列中一个个唤醒过来。 12 | - `await()` 方法,它代表线程阻塞,等待 `state` 的值减为 `0`。 13 | -------------------------------------------------------------------------------- /java/concurrent/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/java/concurrent/README.md -------------------------------------------------------------------------------- /java/concurrent/images/4-AQS-cef7a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/java/concurrent/images/4-AQS-cef7a.png -------------------------------------------------------------------------------- /java/concurrent/images/7-CountDownLatch-29ecd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/java/concurrent/images/7-CountDownLatch-29ecd.png -------------------------------------------------------------------------------- /java/concurrent/images/synchronized_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/java/concurrent/images/synchronized_1.png -------------------------------------------------------------------------------- /java/concurrent/images/synchronized_2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/java/concurrent/images/synchronized_2.gif -------------------------------------------------------------------------------- /java/concurrent/images/thread_1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/java/concurrent/images/thread_1.jpg -------------------------------------------------------------------------------- /java/concurrent/images/thread_2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/java/concurrent/images/thread_2.jpg -------------------------------------------------------------------------------- /java/concurrent/images/thread_3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/java/concurrent/images/thread_3.jpg -------------------------------------------------------------------------------- /java/concurrent/images/thread_4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/java/concurrent/images/thread_4.jpg -------------------------------------------------------------------------------- /java/concurrent/images/volatile_1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/java/concurrent/images/volatile_1.jpg -------------------------------------------------------------------------------- /java/concurrent/images/volatile_2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/java/concurrent/images/volatile_2.jpg -------------------------------------------------------------------------------- /java/gc/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/java/gc/README.md -------------------------------------------------------------------------------- /java/gc/images/hotspot-jvm-1.6-garbage-collector.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/java/gc/images/hotspot-jvm-1.6-garbage-collector.jpg -------------------------------------------------------------------------------- /java/gc/images/jvm-gc-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/java/gc/images/jvm-gc-1.jpg -------------------------------------------------------------------------------- /java/images/error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/java/images/error.png -------------------------------------------------------------------------------- /java/images/exception.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/java/images/exception.png -------------------------------------------------------------------------------- /java/images/oop.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/java/images/oop.gif -------------------------------------------------------------------------------- /java/images/touch-class-instance.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/java/images/touch-class-instance.png -------------------------------------------------------------------------------- /java/jvm/3-dispatcher.md: -------------------------------------------------------------------------------- 1 | # Java分派机制 2 | 3 | 在Java中,符合“编译时可知,运行时不可变”这个要求的方法主要是静态方法和私有方法。这两种方法都不能通过继承或别的方法重写,因此它们适合在类加载时进行解析。 4 | 5 | Java虚拟机中有四种方法调用指令: 6 | - `invokestatic`:调用静态方法。 7 | - `invokespecial`:调用实例构造器方法,私有方法和super。 8 | - `invokeinterface`:调用接口方法。 9 | - `invokevirtual`:调用以上指令不能调用的方法(虚方法)。 10 | 11 | 只要能被`invokestatic`和`invokespecial`指令调用的方法,都可以在解析阶段确定唯一的调用版本,符合这个条件的有:静态方法、私有方法、实例构造器、父类方法,他们在类加载的时候就会把符号引用解析为改方法的直接引用。这些方法被称为非虚方法,反之其他方法称为虚方法(final方法除外)。 12 | 13 | >虽然final方法是使用`invokevirtual `指令来调用的,但是由于它无法被覆盖,多态的选择是唯一的,所以是一种非虚方法。 14 | 15 | ## 静态分派 16 | 17 | > 对于类字段的访问也是采用静态分派 18 | 19 | `People man = new Man()` 20 | 21 | **静态分派主要针对重载**,方法调用时如何选择。在上面的代码中,`People`被称为变量的引用类型,`Man`被称为变量的实际类型。**静态类型是在编译时可知的,而动态类型是在运行时可知的**,编译器不能知道一个变量的实际类型是什么。 22 | 23 | **编译器在重载时候通过参数的静态类型而不是实际类型作为判断依据**。并且静态类型在编译时是可知的,所以编译器根据重载的参数的静态类型进行方法选择。 24 | 25 | > 在某些情况下有多个重载,那编译器如何选择呢? 26 | > 编译器会选择"最合适"的函数版本,那么怎么判断"最合适“呢?越接近传入参数的类型,越容易被调用。 27 | 28 | ## 动态分派 29 | 30 | 动态分派主要针对重写,使用`invokevirtual`指令调用。`invokevirtual`指令多态查找过程: 31 | - 找到操作数栈顶的第一个元素所指向的对象的实际类型,记为C。 32 | - 如果在类型C中找到与常量中的描述符合简单名称都相符的方法,则进行访问权限校验,如果通过则返回这个方法的直接引用,查找过程结束;如果权限校验不通过,返回java.lang.IllegalAccessError异常。 33 | - 否则,按照继承关系从下往上一次对C的各个父类进行第2步的搜索和验证过程。 34 | - 如果始终没有找到合适的方法,则抛出 java.lang.AbstractMethodError异常。 35 | 36 | ## 虚拟机动态分派的实现 37 | 38 | 由于动态分派是非常繁琐的动作,而且动态分派的方法版本选择需要考虑运行时在类的方法元数据中搜索合适的目标方法,**因此在虚拟机的实现中基于性能的考虑,在方法区中建立一个虚方法表**(`invokeinterface `有接口方法表),来提高性能。 39 | 40 | ![](images/dispatcher.bmp) 41 | 42 | 虚方法表中存放各个方法的实际入口地址。如果某个方法在子类没有重写,那么子类的虚方法表里的入口和父类入口一致,如果子类重写了这个方法,那么子类方法表中的地址会被替换为子类实现版本的入口地址。 43 | -------------------------------------------------------------------------------- /java/jvm/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/java/jvm/README.md -------------------------------------------------------------------------------- /java/jvm/images/2019-04-12-09-49-38.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/java/jvm/images/2019-04-12-09-49-38.png -------------------------------------------------------------------------------- /java/jvm/images/2019-04-12-10-01-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/java/jvm/images/2019-04-12-10-01-01.png -------------------------------------------------------------------------------- /java/jvm/images/2019-04-12-10-06-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/java/jvm/images/2019-04-12-10-06-01.png -------------------------------------------------------------------------------- /java/jvm/images/2019-04-12-11-21-50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/java/jvm/images/2019-04-12-11-21-50.png -------------------------------------------------------------------------------- /java/jvm/images/class-loader-proxy-partten.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/java/jvm/images/class-loader-proxy-partten.png -------------------------------------------------------------------------------- /java/jvm/images/dispatcher.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/java/jvm/images/dispatcher.bmp -------------------------------------------------------------------------------- /java/jvm/images/java-class-loader.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/java/jvm/images/java-class-loader.png -------------------------------------------------------------------------------- /java/jvm/images/java-default-value.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/java/jvm/images/java-default-value.png -------------------------------------------------------------------------------- /java/jvm/images/jvm-architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/java/jvm/images/jvm-architecture.png -------------------------------------------------------------------------------- /java/jvm/images/jvm-data-arrange.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/java/jvm/images/jvm-data-arrange.png -------------------------------------------------------------------------------- /java/jvm/images/jvm-data-type.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/java/jvm/images/jvm-data-type.png -------------------------------------------------------------------------------- /java/jvm/images/jvm-method-const-area.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/java/jvm/images/jvm-method-const-area.png -------------------------------------------------------------------------------- /java/jvm/images/jvm-thread-data-area.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/java/jvm/images/jvm-thread-data-area.png -------------------------------------------------------------------------------- /leetcode/LRUCache.md: -------------------------------------------------------------------------------- 1 | # [LRU缓存机制](https://leetcode-cn.com/explore/interview/card/bytedance/245/data-structure/1032/) 2 | 3 | **头条重点** 4 | 5 | ## 题目 6 | 7 | 运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制。它应该支持以下操作: 获取数据 get 和 写入数据 put 。 8 | 9 | 获取数据 get(key) - 如果密钥 (key) 存在于缓存中,则获取密钥的值(总是正数),否则返回 -1。 10 | 写入数据 put(key, value) - 如果密钥不存在,则写入其数据值。当缓存容量达到上限时,它应该在写入新数据之前删除最近最少使用的数据值,从而为新的数据值留出空间。 11 | 12 | 进阶: 13 | 14 | 你是否可以在 O(1) 时间复杂度内完成这两种操作? 15 | 16 | ``` 17 | 示例: 18 | 19 | LRUCache cache = new LRUCache( 2 /* 缓存容量 */ ); 20 | 21 | cache.put(1, 1); 22 | cache.put(2, 2); 23 | cache.get(1); // 返回 1 24 | cache.put(3, 3); // 该操作会使得密钥 2 作废 25 | cache.get(2); // 返回 -1 (未找到) 26 | cache.put(4, 4); // 该操作会使得密钥 1 作废 27 | cache.get(1); // 返回 -1 (未找到) 28 | cache.get(3); // 返回 3 29 | cache.get(4); // 返回 4 30 | ``` 31 | 32 | ## 解题思路 33 | 34 | ``` 35 | class LRUCache extends LinkedHashMap{ 36 | 37 | private final int capacity; 38 | 39 | public LRUCache(int capacity) { 40 | super(capacity*, 0.75f, true); 41 | this.capacity = capacity; 42 | } 43 | 44 | public int get(int key) { 45 | Integer integer = super.get(key); 46 | 47 | return integer == null ? -1 : integer; 48 | } 49 | 50 | public void put(int key, int value) { 51 | 52 | super.put(key, value); 53 | } 54 | 55 | @Override 56 | protected boolean removeEldestEntry(Map.Entry eldest) { 57 | return size() > this.capacity; 58 | } 59 | } 60 | ``` 61 | -------------------------------------------------------------------------------- /leetcode/MinStack.md: -------------------------------------------------------------------------------- 1 | # [最小栈](https://leetcode-cn.com/explore/interview/card/bytedance/245/data-structure/1049/) 2 | 3 | **头条重点** 4 | 5 | ## 题目 6 | 7 | 8 | 设计一个支持 push,pop,top 操作,并能在常数时间内检索到最小元素的栈。 9 | 10 | push(x) -- 将元素 x 推入栈中。 11 | pop() -- 删除栈顶的元素。 12 | top() -- 获取栈顶元素。 13 | getMin() -- 检索栈中的最小元素。 14 | 15 | ``` 16 | 示例: 17 | 18 | MinStack minStack = new MinStack(); 19 | minStack.push(-2); 20 | minStack.push(0); 21 | minStack.push(-3); 22 | minStack.getMin(); --> 返回 -3. 23 | minStack.pop(); 24 | minStack.top(); --> 返回 0. 25 | minStack.getMin(); --> 返回 -2. 26 | ``` 27 | 28 | ## 解题思路 29 | 30 | ``` 31 | class MinStack { 32 | 33 | /** initialize your data structure here. */ 34 | public MinStack() { 35 | 36 | } 37 | 38 | private LinkedList stack = new LinkedList<>(); 39 | private Queue minStack = new PriorityQueue<>(); 40 | 41 | 42 | 43 | public void push(int x) { 44 | stack.offerFirst(x); 45 | minStack.offer(x); 46 | } 47 | 48 | public void pop() { 49 | Integer poll = stack.pollFirst(); 50 | if (poll != null) { 51 | minStack.remove(poll); 52 | } 53 | } 54 | 55 | public int top() { 56 | Integer first = stack.peekFirst(); 57 | return first == null ? 0 : first; 58 | } 59 | 60 | public int getMin() { 61 | Integer first = minStack.peek(); 62 | return first == null ? 0 : first; 63 | } 64 | } 65 | ``` 66 | -------------------------------------------------------------------------------- /leetcode/README.md: -------------------------------------------------------------------------------- 1 | # LeetCode 2 | 3 | 包含头条常见的面试题 4 | -------------------------------------------------------------------------------- /leetcode/StringMultiply.md: -------------------------------------------------------------------------------- 1 | # [字符串相乘](https://leetcode-cn.com/explore/interview/card/bytedance/242/string/1015/) 2 | 3 | ## 题目 4 | 5 | 给定两个以字符串形式表示的非负整数 `num1` 和 `num2`,返回 `num1` 和 `num2` 的乘积,它们的乘积也表示为字符串形式。 6 | 7 | ``` 8 | 示例 1: 9 | 10 | 输入: num1 = "2", num2 = "3" 11 | 输出: "6" 12 | ``` 13 | 14 | - num1 和 num2 的长度小于110。 15 | - num1 和 num2 只包含数字 0-9。 16 | - num1 和 num2 均不以零开头,除非是数字 0 本身。 17 | - 不能使用任何标准库的大数类型(比如 BigInteger)或直接将输入转换为整数来处理。 18 | 19 | ## 解题思路 20 | 21 | 1. 对于字符串 `num2` 中的每一位数与字符串 `num1` 相乘所得的结果,不再分开计算最后相加,而是先全部累加,最后再考虑进位的影响。 22 | 23 | 1. 对于最终结果的第`i + j`位数,可以由 `num1` 数组的第 `i` 位数和 `num2` 数组的第 `j` 位数组成。 24 | 25 | ``` 26 | public String multiply(String num1, String num2) { 27 | if (num1.length() == 0 || num2.length() == 0) { 28 | return ZEO; 29 | } 30 | 31 | if (num1.equals(ZEO) || num2.equals(ZEO)) { 32 | return ZEO; 33 | } 34 | 35 | if (num1.equals(ONE)) { 36 | return num2; 37 | } 38 | 39 | if (num2.equals(ONE)) { 40 | return num1; 41 | } 42 | 43 | int[] num = new int[num1.length() + num2.length() - 1]; 44 | Arrays.fill(num, 0); 45 | for (int i = 0; i < num1.length(); i++) { 46 | for (int j = 0; j < num2.length(); j++) { 47 | num[i + j] += (num1.charAt(i) - '0') * (num2.charAt(j) - '0'); 48 | } 49 | } 50 | 51 | StringBuilder res = new StringBuilder(); 52 | int addIn = 0; 53 | for (int i = num.length - 1; i >= 0; i--) { 54 | int t = num[i] + addIn; 55 | addIn = t / 10; 56 | res.append(t % 10); 57 | } 58 | 59 | if (addIn > 0) { 60 | res.append(addIn); 61 | } 62 | return res.reverse().toString(); 63 | } 64 | ``` 65 | -------------------------------------------------------------------------------- /leetcode/addTwoNumbers.md: -------------------------------------------------------------------------------- 1 | # [两数相加](https://leetcode-cn.com/explore/interview/card/bytedance/244/linked-list-and-tree/1022/) 2 | 3 | **头条重点** 4 | 5 | ## 题目 6 | 7 | 给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。 8 | 9 | 如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。 10 | 11 | 您可以假设除了数字 0 之外,这两个数都不会以 0 开头。 12 | 13 | ``` 14 | 示例: 15 | 16 | 输入:(2 -> 4 -> 3) + (5 -> 6 -> 4) 17 | 输出:7 -> 0 -> 8 18 | 原因:342 + 465 = 807 19 | ``` 20 | 21 | ## 解题思路 22 | 23 | ``` 24 | public ListNode addTwoNumbers(ListNode l1, ListNode l2) { 25 | if (l1 == null || l2 == null) { 26 | return null; 27 | } 28 | 29 | StringBuilder builder1 = new StringBuilder(); 30 | while (l1 != null) { 31 | builder1.append(l1.val); 32 | l1 = l1.next; 33 | } 34 | 35 | StringBuilder builder2 = new StringBuilder(); 36 | while (l2 != null) { 37 | builder2.append(l2.val); 38 | l2 = l2.next; 39 | } 40 | 41 | BigDecimal bigDecimal1 = new BigDecimal(builder1.reverse().toString()); 42 | BigDecimal bigDecimal2 = new BigDecimal(builder2.reverse().toString()); 43 | 44 | String resStr = bigDecimal1.add(bigDecimal2).toPlainString(); 45 | 46 | ListNode head = new ListNode(Integer.parseInt(String.valueOf(resStr.charAt(resStr.length() - 1)))); 47 | ListNode cur = head; 48 | for (int i = resStr.length() - 2; i >= 0; i--) { 49 | cur.next = new ListNode(Integer.parseInt(String.valueOf(resStr.charAt(i)))); 50 | cur = cur.next; 51 | } 52 | 53 | return head; 54 | } 55 | ``` 56 | -------------------------------------------------------------------------------- /leetcode/checkInclusion.md: -------------------------------------------------------------------------------- 1 | # [字符串的排列](https://leetcode-cn.com/explore/interview/card/bytedance/242/string/1016/) 2 | 3 | ## 题目 4 | 5 | 给定两个字符串 s1 和 s2,写一个函数来判断 s2 是否包含 s1 的排列。 6 | 7 | 换句话说,第一个字符串的排列之一是第二个字符串的子串。 8 | 9 | 10 | ``` 11 | 示例1: 12 | 13 | 输入: s1 = "ab" s2 = "eidbaooo" 14 | 输出: True 15 | 解释: s2 包含 s1 的排列之一 ("ba"). 16 | ``` 17 | 18 | ## 解题思路 19 | 20 | 1. 这道题,我们用到的算法是 **滑动窗口** 21 | 2. 首先字符串s1的排列的可能性应该是它的长度的阶乘,因为字符串长度可能为10000,所以找出所有排列情况是不太可能。 22 | 3. 我们可以转换思路,**不要关注排列的形式,而是关注排列中元素的数量关系** 23 | 4. 比如 `aab`,那么,转换为数量关系就是`{a:2,b:1}`,因为 S1 长度为 3,所以我们的窗口长度也为3 24 | 5. 如果我们在 S2 的找到了这样一个窗口符合出现 `a` 的次数是两个, `b` 是一个,那么 S2 就是包含 S1 的排列的 25 | 26 | ``` 27 | public boolean checkInclusion(String s1, String s2) { 28 | int len1 = s1.length(); 29 | int len2 = s2.length(); 30 | int[] c1 = new int[26]; 31 | int[] c2 = new int[26]; 32 | 33 | for (char c : s1.toCharArray()) { 34 | c1[c - 'a']++; 35 | } 36 | 37 | for (int i = 0; i < len2; i++) { 38 | if (i >= len1) 39 | --c2[s2.charAt(i - len1) - 'a'];//先把坐标查过的减掉 40 | c2[s2.charAt(i) - 'a']++; 41 | if (Arrays.equals(c1, c2)) 42 | return true; 43 | } 44 | 45 | return false; 46 | } 47 | ``` 48 | -------------------------------------------------------------------------------- /leetcode/detectCycle.md: -------------------------------------------------------------------------------- 1 | # [环形链表 II](https://leetcode-cn.com/explore/interview/card/bytedance/244/linked-list-and-tree/1023/) 2 | 3 | ## 题目 4 | 5 | 给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。 6 | 7 | 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。 8 | 9 | 10 | ## 解题思路 11 | 12 | 1. 首先通过快慢指针确定链表是否有环 13 | 2. 再使用一个指针从头节点与快慢指针相遇节点同步长前进,最终找到环的入口 14 | 15 | ``` 16 | public ListNode detectCycle(ListNode head) { 17 | ListNode fast = head, slow = head; 18 | 19 | ListNode meetNode = null; 20 | while (fast != null && fast.next != null) { 21 | fast = fast.next.next; 22 | slow = slow.next; 23 | 24 | if (fast == slow) { 25 | meetNode = fast; 26 | break; 27 | } 28 | } 29 | 30 | if (meetNode == null) { 31 | return meetNode; 32 | } 33 | 34 | while (head != meetNode) { 35 | head = head.next; 36 | if (head == meetNode) { 37 | break; 38 | } 39 | 40 | meetNode = meetNode.next; 41 | } 42 | 43 | return meetNode; 44 | } 45 | ``` 46 | -------------------------------------------------------------------------------- /leetcode/findCircleNum.md: -------------------------------------------------------------------------------- 1 | # [朋友圈](https://leetcode-cn.com/explore/interview/card/bytedance/243/array-and-sorting/1036/) 2 | 3 | **头条重点** 4 | 5 | ## 题目 6 | 7 | 班上有 N 名学生。其中有些人是朋友,有些则不是。他们的友谊具有是传递性。如果已知 A 是 B 的朋友,B 是 C 的朋友,那么我们可以认为 A 也是 C 的朋友。所谓的朋友圈,是指所有朋友的集合。 8 | 9 | 给定一个 `N * N` 的矩阵 M,表示班级中学生之间的朋友关系。如果`M[i][j] = 1`,表示已知第 i 个和 j 个学生互为朋友关系,否则为不知道。你必须输出所有学生中的已知的朋友圈总数。 10 | 11 | ``` 12 | 示例 1: 13 | 14 | 输入: 15 | [[1,1,0], 16 | [1,1,0], 17 | [0,0,1]] 18 | 输出: 2 19 | 说明:已知学生0和学生1互为朋友,他们在一个朋友圈。 20 | 第2个学生自己在一个朋友圈。所以返回2。 21 | ``` 22 | 23 | ``` 24 | 示例 2: 25 | 26 | 输入: 27 | [[1,1,0], 28 | [1,1,1], 29 | [0,1,1]] 30 | 输出: 1 31 | 说明:已知学生0和学生1互为朋友,学生1和学生2互为朋友,所以学生0和学生2也是朋友,所以他们三个在一个朋友圈,返回1。 32 | ``` 33 | 34 | 注意: 35 | 36 | - N 在[1,200]的范围内。 37 | - 对于所有学生,有`M[i][i] = 1`。 38 | - 如果有`M[i][j] = 1`,则有`M[j][i] = 1`。 39 | 40 | ## 解题思路 41 | 42 | 1. 逐个遍历所有学生,将他所有朋友标记 43 | 44 | ``` 45 | public int findCircleNum(int[][] M) { 46 | if (M.length == 0) { 47 | return 0; 48 | } 49 | 50 | int[] marks = new int[M.length]; 51 | 52 | 53 | int total = 0; 54 | for (int i = 0; i < M.length; i++) { 55 | if (marks[i] != 1) { 56 | total++; 57 | 58 | dfs(M, marks, i); 59 | } 60 | } 61 | return total; 62 | } 63 | 64 | private void dfs(int[][] M, int[] marks, int i) { 65 | marks[i] = 1; 66 | 67 | for (int j = 0; j < M[i].length; j++) { 68 | if (M[i][j] == 1 && marks[j] != 1) { 69 | dfs(M, marks, j); 70 | } 71 | } 72 | } 73 | ``` 74 | -------------------------------------------------------------------------------- /leetcode/findKthLargest.md: -------------------------------------------------------------------------------- 1 | # [数组中的第K个最大元素](https://leetcode-cn.com/explore/interview/card/bytedance/243/array-and-sorting/1018/) 2 | 3 | ## 题目 4 | 5 | 在未排序的数组中找到第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。 6 | 7 | ``` 8 | 示例 1: 9 | 10 | 输入: [3,2,1,5,6,4] 和 k = 2 11 | 输出: 5 12 | 示例 2: 13 | 14 | 输入: [3,2,3,1,2,4,5,5,6] 和 k = 4 15 | 输出: 4 16 | ``` 17 | 18 | ## 解题思路 19 | 20 | 1. 利用快排的思想,当排序到 `k` 后,停止排序,输出结果 21 | 22 | ``` 23 | public static int findKthLargest(int[] nums, int k) { 24 | fastSort(nums, 0, nums.length - 1); 25 | return nums[nums.length - k]; 26 | } 27 | 28 | public static void fastSort(int[] nums, int start, int end) { 29 | if (nums.length <= 1) { 30 | return; 31 | } 32 | 33 | if (start > end) { 34 | return; 35 | } 36 | 37 | if (end < 0 || start < 0 || end > nums.length - 1 || start > nums.length - 1) { 38 | return; 39 | } 40 | 41 | int left = start, right = end; 42 | int keyIndex = (left + right) / 2; 43 | 44 | while (left < right) { 45 | while (right > keyIndex && nums[right] > nums[keyIndex]) { 46 | right--; 47 | } 48 | 49 | if (right > keyIndex) { 50 | swap(nums, keyIndex, right); 51 | keyIndex = right; 52 | } 53 | 54 | while (left < keyIndex && nums[left] < nums[keyIndex]) { 55 | left++; 56 | } 57 | 58 | if (left < keyIndex) { 59 | swap(nums, left, keyIndex); 60 | keyIndex = left; 61 | } 62 | left++; 63 | } 64 | 65 | fastSort(nums, keyIndex + 1, end); 66 | fastSort(nums, start, keyIndex - 1); 67 | 68 | } 69 | ``` 70 | -------------------------------------------------------------------------------- /leetcode/findLengthOfLCIS.md: -------------------------------------------------------------------------------- 1 | # [最长连续递增序列](https://leetcode-cn.com/explore/interview/card/bytedance/243/array-and-sorting/1035/) 2 | 3 | ## 题目 4 | 5 | 给定一个未经排序的整数数组,找到最长且连续的的递增序列。 6 | 7 | ``` 8 | 示例 1: 9 | 10 | 输入: [1,3,5,4,7] 11 | 输出: 3 12 | 解释: 最长连续递增序列是 [1,3,5], 长度为3。 13 | 尽管 [1,3,5,7] 也是升序的子序列, 但它不是连续的,因为5和7在原数组里被4隔开。 14 | 示例 2: 15 | 16 | 输入: [2,2,2,2,2] 17 | 输出: 1 18 | 解释: 最长连续递增序列是 [2], 长度为1。 19 | ``` 20 | 21 | ## 解题思路 22 | 23 | 1. 用两个变量记录序列开始和结束的下标 24 | 2. 从左到右遍历,如果下一个节点小当前节点则移动 `start`,否则移动`end`,并更新 `max` 25 | 26 | ``` 27 | public static int findLengthOfLCIS(int[] nums) { 28 | if (nums.length == 0) { 29 | return 0; 30 | } 31 | 32 | if (nums.length == 1) { 33 | return 1; 34 | } 35 | 36 | int start = 0, end = 0; 37 | int max = 1; 38 | 39 | for (int i = 1; i < nums.length; i++) { 40 | if (nums[i] > nums[i - 1]) { 41 | end = i; 42 | max = Math.max(max, end - start + 1); 43 | } else { 44 | start = i; 45 | } 46 | } 47 | 48 | return max; 49 | } 50 | ``` 51 | -------------------------------------------------------------------------------- /leetcode/getIntersectionNode.md: -------------------------------------------------------------------------------- 1 | # [相交链表](https://leetcode-cn.com/explore/interview/card/bytedance/244/linked-list-and-tree/1024/) 2 | 3 | ## 题目 4 | 5 | 编写一个程序,找到两个单链表相交的起始节点。 6 | 7 | ## 解题思路 8 | 9 | 1. 首先将两个链表中长的一个向前遍历,直到两个链表长度一致 10 | 2. 两个链表同时向前遍历,便可找到交点 11 | 12 | ``` 13 | public ListNode getIntersectionNode(ListNode headA, ListNode headB) { 14 | if (headA == null || headB == null) { 15 | return null; 16 | } 17 | 18 | if (headA == headB) { 19 | return headA; 20 | } 21 | 22 | int lenA = 1; 23 | int lenB = 1; 24 | ListNode temp = headA; 25 | while (temp.next != null) { 26 | temp = temp.next; 27 | lenA++; 28 | } 29 | 30 | ListNode tailA = temp; 31 | 32 | temp = headB; 33 | while (temp.next != null) { 34 | temp = temp.next; 35 | lenB++; 36 | } 37 | 38 | ListNode tailB = temp; 39 | if (tailB != tailA) { 40 | return null; 41 | } 42 | 43 | if (lenA > lenB) { 44 | for (int i = 0; i < lenA - lenB && headA != null; i++) { 45 | headA = headA.next; 46 | } 47 | 48 | } else if (lenA < lenB) { 49 | for (int i = 0; i < lenB - lenA && headB != null; i++) { 50 | headB = headB.next; 51 | } 52 | } 53 | 54 | while (!headA.equals(headB)) { 55 | headA = headA.next; 56 | headB = headB.next; 57 | } 58 | 59 | return headA; 60 | } 61 | ``` 62 | -------------------------------------------------------------------------------- /leetcode/images/5981c540e595049ee84429c3f4a7face.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/leetcode/images/5981c540e595049ee84429c3f4a7face.png -------------------------------------------------------------------------------- /leetcode/lengthOfLongestSubstring.md: -------------------------------------------------------------------------------- 1 | # [无重复字符的最长子串](https://leetcode-cn.com/explore/interview/card/bytedance/242/string/1012/) 2 | 3 | **头条重点** 4 | 5 | ## 题目 6 | 7 | 给定一个字符串,请你找出其中不含有重复字符的 **最长子串** 的长度。 8 | 9 | ``` 10 | 输入: "abcabcbb" 11 | 输出: 3 12 | 解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。 13 | ``` 14 | 15 | 16 | ## 解题思路 17 | 18 | 1. 用 Map 记录字符所在位置,当遇到重复字符时,移动 `start` 指针 19 | 2. 替换 Map 中下标,并计算子串长度 20 | 21 | ``` 22 | public int lengthOfLongestSubstring(String str) { 23 | if (str == null || str.length() == 0) return 0; 24 | 25 | HashMap temp = new HashMap<>(); 26 | char[] chars = str.toCharArray(); 27 | 28 | int res = 0, start = 0; 29 | for (int i = 0; i < chars.length; i++) { 30 | if (temp.containsKey(chars[i])) { 31 | start = Math.max(temp.put(chars[i], i) + 1, start); 32 | } 33 | 34 | temp.put(chars[i], i); 35 | res = Math.max(res, i - start + 1); 36 | 37 | } 38 | 39 | return res; 40 | } 41 | ``` 42 | -------------------------------------------------------------------------------- /leetcode/longestCommonPrefix.md: -------------------------------------------------------------------------------- 1 | # [最长公共前缀](https://leetcode-cn.com/explore/interview/card/bytedance/242/string/1014/) 2 | 3 | ## 题目 4 | 5 | 编写一个函数来查找字符串数组中的最长公共前缀。 6 | 7 | 如果不存在公共前缀,返回空字符串 ""。 8 | 9 | ``` 10 | 示例 1: 11 | 输入: ["flower","flow","flight"] 12 | 输出: "fl" 13 | ``` 14 | 15 | ## 解题思路 16 | 17 | 1. 找到最短字符串 18 | 2. 多个字符串逐个字符比较 19 | 20 | ``` 21 | public String longestCommonPrefix(String[] strs) { 22 | if (strs.length == 0) { 23 | return ""; 24 | } 25 | 26 | int minLen = strs[0].length(); 27 | for (String str : strs) { 28 | minLen = Math.min(minLen, str.length()); 29 | } 30 | 31 | char[][] data = new char[strs.length][minLen]; 32 | for (int i = 0; i < strs.length; i++) { 33 | char[] chars = strs[i].toCharArray(); 34 | System.arraycopy(chars, 0, data[i], 0, minLen); 35 | } 36 | 37 | StringBuilder res = new StringBuilder(); 38 | for (int i = 0; i < minLen; i++) { 39 | for (int j = 1; j < data.length; j++) { 40 | if (data[j - 1][i] != data[j][i]) { 41 | return res.toString(); 42 | } 43 | } 44 | res.append(data[0][i]); 45 | } 46 | return res.toString(); 47 | } 48 | ``` 49 | -------------------------------------------------------------------------------- /leetcode/longestConsecutive.md: -------------------------------------------------------------------------------- 1 | # [最长连续序列](https://leetcode-cn.com/explore/interview/card/bytedance/243/array-and-sorting/1019/) 2 | 3 | 4 | ## 题目 5 | 6 | 给定一个未排序的整数数组,找出最长连续序列的长度。 7 | 8 | 要求算法的时间复杂度为 O(n)。 9 | 10 | ``` 11 | 示例: 12 | 13 | 输入: [100, 4, 200, 1, 3, 2] 14 | 输出: 4 15 | 解释: 最长连续序列是 [1, 2, 3, 4]。它的长度为 4。 16 | ``` 17 | 18 | ## 解题思路 19 | 20 | 1. 用 `Set` 保存所有数字 21 | 2. 遍历数组,查找当前数字之前、之后的数,并计算个数 22 | 23 | ``` 24 | public static int longestConsecutive(int[] nums) { 25 | if (nums.length <= 1) { 26 | return nums.length; 27 | } 28 | 29 | Set set = new HashSet<>(); 30 | 31 | for (int num : nums) { 32 | set.add(num); 33 | } 34 | 35 | int pre, after, max = 0; 36 | for (int num : nums) { 37 | int temp = 1; 38 | set.remove(num); 39 | 40 | pre = num; 41 | after = num; 42 | 43 | while (set.contains(--pre)) { 44 | temp++; 45 | set.remove(pre); 46 | } 47 | 48 | while (set.contains(++after)) { 49 | temp++; 50 | set.remove(after); 51 | } 52 | 53 | max = Math.max(max, temp); 54 | if (max > nums.length / 2) { 55 | return max; 56 | } 57 | } 58 | 59 | return max; 60 | } 61 | ``` 62 | -------------------------------------------------------------------------------- /leetcode/lowestCommonAncestor.md: -------------------------------------------------------------------------------- 1 | # [二叉树的最近公共祖先](https://leetcode-cn.com/explore/interview/card/bytedance/244/linked-list-and-tree/1026/) 2 | 3 | ## 题目 4 | 5 | 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。 6 | 7 | 百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。” 8 | 9 | ``` 10 | 示例 1: 11 | 12 | 输入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1 13 | 输出: 3 14 | 解释: 节点 5 和节点 1 的最近公共祖先是节点 3。 15 | ``` 16 | 17 | ## 解题思路 18 | 19 | 1. 通过 DFS 找到节点的路径 20 | 2. 从头开始遍历两个节点的路径,找到最后一个相等的节点 21 | 22 | ``` 23 | public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { 24 | LinkedList pathP = new LinkedList<>(); 25 | LinkedList pathQ = new LinkedList<>(); 26 | 27 | findNodePath(pathP, root, p); 28 | findNodePath(pathQ, root, q); 29 | 30 | TreeNode last = null; 31 | while (!pathP.isEmpty() && !pathQ.isEmpty()) { 32 | TreeNode pi = pathP.pollFirst(); 33 | TreeNode qi = pathQ.pollFirst(); 34 | 35 | if (qi==pi) { 36 | last = pi; 37 | }else break; 38 | 39 | } 40 | 41 | return last; 42 | } 43 | 44 | private void findNodePath(LinkedList path, TreeNode root, TreeNode target) { 45 | if (root == null) { 46 | return; 47 | } 48 | 49 | if (!path.isEmpty() && path.getLast().val == target.val) { 50 | return; 51 | } 52 | 53 | path.addLast(root); 54 | 55 | findNodePath(path, root.left, target); 56 | if (!path.isEmpty() && path.getLast().val == target.val) { 57 | return; 58 | } 59 | 60 | findNodePath(path, root.right, target); 61 | 62 | if (!path.isEmpty() && path.getLast().val != target.val) { 63 | path.removeLast(); 64 | } 65 | } 66 | ``` 67 | -------------------------------------------------------------------------------- /leetcode/maxProfit.md: -------------------------------------------------------------------------------- 1 | # [买卖股票的最佳时机](https://leetcode-cn.com/explore/interview/card/bytedance/246/dynamic-programming-or-greedy/1042/) 2 | 3 | **头条重点** 4 | 5 | ## 题目 6 | 7 | 给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。如果你最多只允许完成一笔交易(即买入和卖出一支股票),设计一个算法来计算你所能获取的最大利润。 8 | 9 | 注意你不能在买入股票前卖出股票。 10 | 11 | ``` 12 | 示例 1: 13 | 14 | 输入: [7,1,5,3,6,4] 15 | 输出: 5 16 | 解释: 在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。 17 | 注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格。 18 | 示例 2: 19 | 20 | 输入: [7,6,4,3,1] 21 | 输出: 0 22 | 解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。 23 | ``` 24 | 25 | ## 解题思路 26 | 27 | 1. 要先买入才能卖出,先找最低价格点 28 | 2. 再找最低价格之后的最高价格,用 `res` 表示最大利润 29 | 30 | ``` 31 | public int maxProfit(int[] prices) { 32 | if (prices.length <= 1) { 33 | return 0; 34 | } 35 | 36 | int res = 0; 37 | int minBuy = prices[0]; 38 | for (int price : prices) { 39 | res = Math.max(res, price - minBuy); 40 | minBuy = Math.min(minBuy, price); 41 | } 42 | 43 | return res; 44 | } 45 | ``` 46 | -------------------------------------------------------------------------------- /leetcode/maxProfit2.md: -------------------------------------------------------------------------------- 1 | # [买卖股票的最佳时机 II](https://leetcode-cn.com/explore/interview/card/bytedance/246/dynamic-programming-or-greedy/1043/) 2 | 3 | **头条重点** 4 | 5 | ## 题目 6 | 7 | 给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。 8 | 9 | 注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。 10 | 11 | ``` 12 | 示例 1: 13 | 14 | 输入: [7,1,5,3,6,4] 15 | 输出: 7 16 | 解释: 在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。 17 | 随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6-3 = 3 。 18 | 示例 2: 19 | 20 | 输入: [1,2,3,4,5] 21 | 输出: 4 22 | 解释: 在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。 23 | 注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。 24 | 因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。 25 | 示例 3: 26 | 27 | 输入: [7,6,4,3,1] 28 | 输出: 0 29 | 解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。 30 | ``` 31 | 32 | ## 解题思路 33 | 34 | 1. 贪心算法,尽可能的多进行交易 35 | 36 | ``` 37 | public int maxProfit(int[] prices) { 38 | if (prices.length <= 1) { 39 | return 0; 40 | } 41 | 42 | int res = 0; 43 | for (int i = 1; i < prices.length; i++) { 44 | int profit = prices[i] - prices[i - 1]; 45 | if (profit > 0) { 46 | res += profit; 47 | } 48 | } 49 | return res; 50 | } 51 | ``` 52 | -------------------------------------------------------------------------------- /leetcode/maxSubArray.md: -------------------------------------------------------------------------------- 1 | # [最大子序和](https://leetcode-cn.com/explore/interview/card/bytedance/246/dynamic-programming-or-greedy/1029/) 2 | 3 | **头条重点** 4 | 5 | ## 题目 6 | 7 | 给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。 8 | 9 | ``` 10 | 示例: 11 | 12 | 输入: [-2,1,-3,4,-1,2,1,-5,4], 13 | 输出: 6 14 | 解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。 15 | 进阶: 16 | ``` 17 | 18 | 如果你已经实现复杂度为 O(n) 的解法,尝试使用更为精妙的分治法求解。 19 | 20 | ## 解题思路 21 | 22 | 1. 动态规划:$$f(i)=\begin{cases}num[i]&f(i-1)+num[i]num[i]\end{cases}$$ 23 | 24 | 2. 用`result[i]`保存以数字`nums[i]`结尾的最大子序和,然后不断更新`result`数组的最大值即可。总的时间复杂度O(n) 25 | 26 | ``` 27 | public int maxSubArray(int[] nums) { 28 | if (nums.length == 0) { 29 | return 0; 30 | } 31 | 32 | if (nums.length == 1) { 33 | return nums[0]; 34 | } 35 | 36 | int[] res = new int[nums.length]; 37 | res[0] = nums[0]; 38 | 39 | int max = res[0]; 40 | for (int i = 1; i < nums.length; i++) { 41 | int curMax = nums[i] + res[i - 1]; 42 | if (curMax > nums[i]) { 43 | res[i] = curMax; 44 | } else { 45 | res[i] = nums[i]; 46 | } 47 | max = Math.max(max, res[i]); 48 | } 49 | 50 | 51 | return max; 52 | } 53 | ``` 54 | -------------------------------------------------------------------------------- /leetcode/mergeKLists.md: -------------------------------------------------------------------------------- 1 | # [合并K个排序链表](https://leetcode-cn.com/explore/interview/card/bytedance/244/linked-list-and-tree/1025/) 2 | 3 | **头条重点** 4 | 5 | ## 题目 6 | 7 | 合并 k 个排序链表,返回合并后的排序链表。请分析和描述算法的复杂度。 8 | 9 | ``` 10 | 示例: 11 | 12 | 输入: 13 | [ 14 | 1->4->5, 15 | 1->3->4, 16 | 2->6 17 | ] 18 | 输出: 1->1->2->3->4->4->5->6 19 | ``` 20 | 21 | ## 解题思路 22 | 23 | 1. 通过小根堆,将所有元素放入小根堆 24 | 2. 从小根堆依次取出数据 25 | 26 | ``` 27 | public ListNode mergeKLists(ListNode[] lists) { 28 | if (lists == null) { 29 | return null; 30 | } 31 | 32 | Queue set = new PriorityQueue<>(Comparator.comparingInt(o -> o.val)); 33 | 34 | for (ListNode node : lists) { 35 | while (node != null) { 36 | set.add(node); 37 | node = node.next; 38 | } 39 | } 40 | 41 | ListNode head = new ListNode(-1); 42 | ListNode res = head; 43 | ListNode cur; 44 | while ((cur = set.poll()) != null) { 45 | head.next = cur; 46 | head = head.next; 47 | } 48 | 49 | head.next = null; 50 | return res.next; 51 | } 52 | ``` 53 | -------------------------------------------------------------------------------- /leetcode/mergeRagen.md: -------------------------------------------------------------------------------- 1 | # [合并区间](https://leetcode-cn.com/explore/interview/card/bytedance/243/array-and-sorting/1046/) 2 | 3 | ## 题目 4 | 5 | 给出一个区间的集合,请合并所有重叠的区间。 6 | 7 | ``` 8 | 示例 1: 9 | 10 | 输入: [[1,3],[2,6],[8,10],[15,18]] 11 | 输出: [[1,6],[8,10],[15,18]] 12 | 解释: 区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6]. 13 | 示例 2: 14 | 15 | 输入: [[1,4],[4,5]] 16 | 输出: [[1,5]] 17 | 解释: 区间 [1,4] 和 [4,5] 可被视为重叠区间。 18 | ``` 19 | 20 | ## 解题思路 21 | 22 | 1. 将区间按起始地址排序 23 | 2. 遍历所有区间,如果 `Last` 与当前区间没有重合,则将当前区间加入结果集合。 24 | 3. 如果重合,并且 `last.end < t.end`,修改 `Last` 的边界 25 | 26 | ``` 27 | public List merge(List intervals) { 28 | if (intervals.size() <= 1) { 29 | return intervals; 30 | } 31 | 32 | intervals.sort(Comparator.comparingInt(o -> o.start)); 33 | 34 | List res = new ArrayList<>(); 35 | res.add(intervals.get(0)); 36 | 37 | for (int i = 1; i < intervals.size(); i++) { 38 | Interval t = intervals.get(i); 39 | Interval last = res.get(res.size() - 1); 40 | if (last.end >= t.start) { 41 | if (last.end < t.end) last.end = t.end; 42 | } else { 43 | res.add(t); 44 | } 45 | } 46 | 47 | return res; 48 | } 49 | ``` 50 | -------------------------------------------------------------------------------- /leetcode/mergeTwoLists.md: -------------------------------------------------------------------------------- 1 | # [合并两个有序链表](https://leetcode-cn.com/explore/interview/card/bytedance/244/linked-list-and-tree/1048/) 2 | 3 | ## 题目 4 | 5 | 将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 6 | 7 | ``` 8 | 示例: 9 | 10 | 输入:1->2->4, 1->3->4 11 | 输出:1->1->2->3->4->4 12 | ``` 13 | 14 | ## 解题思路 15 | 16 | 17 | ``` 18 | public ListNode mergeTwoLists(ListNode l1, ListNode l2) { 19 | if (l1 == null && l2 == null) { 20 | return null; 21 | } 22 | 23 | if (l1 == null) { 24 | return l2; 25 | } 26 | 27 | if (l2 == null) { 28 | return l1; 29 | } 30 | 31 | ListNode head; 32 | 33 | if (l1.val > l2.val) { 34 | head = l2; 35 | l2 = l2.next; 36 | } else { 37 | head = l1; 38 | l1 = l1.next; 39 | } 40 | 41 | ListNode res = head; 42 | while (true) { 43 | ListNode cur; 44 | if (l1 == null && l2 == null) { 45 | break; 46 | } 47 | 48 | if (l1 == null) { 49 | cur = l2; 50 | l2 = l2.next; 51 | } else if (l2 == null) { 52 | cur = l1; 53 | l1 = l1.next; 54 | } else if (l1.val > l2.val) { 55 | cur = l2; 56 | l2 = l2.next; 57 | } else { 58 | cur = l1; 59 | l1 = l1.next; 60 | } 61 | 62 | head.next = cur; 63 | head = head.next; 64 | } 65 | 66 | return res; 67 | } 68 | ``` 69 | -------------------------------------------------------------------------------- /leetcode/mySqrt.md: -------------------------------------------------------------------------------- 1 | # [x 的平方根](https://leetcode-cn.com/explore/interview/card/bytedance/247/bonus/1045/) 2 | 3 | **头条重点** 4 | 5 | ## 题目 6 | 7 | 实现 int sqrt(int x) 函数。 8 | 9 | 计算并返回 x 的平方根,其中 x 是非负整数。 10 | 11 | 由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去。 12 | 13 | ``` 14 | 示例 1: 15 | 16 | 输入: 4 17 | 输出: 2 18 | 示例 2: 19 | 20 | 输入: 8 21 | 输出: 2 22 | 说明: 8 的平方根是 2.82842...,由于返回类型是整数,小数部分将被舍去。 23 | ``` 24 | 25 | ## 解题思路 26 | 27 | 1. 牛顿迭代法:$$a_{i}=(x/a_{i-1}+a_{i-1})/2$$ 28 | 29 | ``` 30 | public int mySqrt(int x) { 31 | double a = 1, diff = 0; 32 | 33 | do { 34 | a = (x / a + a) / 2.0; 35 | diff = Math.abs(a * a - x); 36 | } while (diff > 0.1); 37 | 38 | return (int) a; 39 | } 40 | ``` 41 | -------------------------------------------------------------------------------- /leetcode/restoreIpAddresses.md: -------------------------------------------------------------------------------- 1 | # [复原IP地址](https://leetcode-cn.com/explore/interview/card/bytedance/242/string/1044/) 2 | 3 | **头条重点** 4 | 5 | ## 题目 6 | 7 | 给定一个只包含数字的字符串,复原它并返回所有可能的 IP 地址格式。 8 | 9 | ``` 10 | 示例: 11 | 12 | 输入: "25525511135" 13 | 输出: ["255.255.11.135", "255.255.111.35"] 14 | ``` 15 | 16 | ## 解题思路 17 | 18 | 1. 利用回溯法,遍历所有可能的 IP 19 | 20 | ``` 21 | public static List restoreIpAddresses(String s) { 22 | if (s.length() > 12 || s.length() < 4) { 23 | return Collections.emptyList(); 24 | } 25 | 26 | List res = new ArrayList<>(); 27 | ArrayList ip = new ArrayList<>(); 28 | for (int i = 0; i < 4; i++) { 29 | ip.add(""); 30 | } 31 | p(res, s.toCharArray(), 0, ip, 0); 32 | 33 | return res; 34 | } 35 | 36 | private static void p(List res, char[] chars, int startIndex, List ip, int segmentIndex) { 37 | StringBuilder builder = new StringBuilder(); 38 | for (int i = startIndex; i < chars.length; i++) { 39 | builder.append(chars[i]); 40 | String ipStr = builder.toString(); 41 | int parseInt = Integer.parseInt(ipStr); 42 | if (parseInt > 255) { 43 | return; 44 | } 45 | if (ipStr.length() > 1 && ipStr.startsWith("0")) { 46 | return; 47 | } 48 | 49 | ip.set(segmentIndex, ipStr); 50 | if (segmentIndex == 3 && i == chars.length - 1) { 51 | res.add(String.join(".", ip)); 52 | } 53 | 54 | if (segmentIndex < 3) { 55 | p(res, chars, i + 1, ip, segmentIndex + 1); 56 | } 57 | } 58 | ``` 59 | -------------------------------------------------------------------------------- /leetcode/reverseList.md: -------------------------------------------------------------------------------- 1 | # [反转链表](https://leetcode-cn.com/explore/interview/card/bytedance/244/linked-list-and-tree/1038/) 2 | 3 | **头条重点** 4 | 5 | ## 题目 6 | 7 | 反转一个单链表。 8 | 9 | ``` 10 | 示例: 11 | 12 | 输入: 1->2->3->4->5->NULL 13 | 输出: 5->4->3->2->1->NULL 14 | ``` 15 | 16 | ## 解题思路 17 | 18 | 1. 三个指针进行反转 19 | 20 | ``` 21 | public ListNode reverseList(ListNode head) { 22 | if (head == null) { 23 | return head; 24 | } 25 | 26 | if (head.next == null) { 27 | return head; 28 | } 29 | 30 | ListNode pre = head; 31 | ListNode cur = head.next; 32 | 33 | while (cur != null) { 34 | ListNode next = cur.next; 35 | cur.next = pre; 36 | 37 | pre = cur; 38 | cur = next; 39 | } 40 | 41 | head.next = null; 42 | 43 | return pre; 44 | } 45 | ``` 46 | -------------------------------------------------------------------------------- /leetcode/reverseWords.md: -------------------------------------------------------------------------------- 1 | # [翻转字符串里的单词](https://leetcode-cn.com/explore/interview/card/bytedance/242/string/1011/) 2 | 3 | ## 题目 4 | 5 | 给定一个字符串,逐个翻转字符串中的每个单词。 6 | 7 | ``` 8 | 示例 1: 9 | 10 | 输入: "the sky is blue" 11 | 输出: "blue is sky the" 12 | ``` 13 | 14 | 说明: 15 | 16 | - 无空格字符构成一个单词。 17 | - 输入字符串可以在前面或者后面包含多余的空格,但是反转后的字符不能包括。 18 | - 如果两个单词间有多余的空格,将反转后单词间的空格减少到只含一个。 19 | 20 | ## 解题思路 21 | 22 | 1. 按空格拆分字符串为字符串数组 `t` 23 | 2. 逆序遍历字符串数组 `t`,并组成新的字符串 24 | 25 | ``` 26 | public String reverseWords(String s) { 27 | String trimed = s.trim(); 28 | 29 | String[] split = trimed.split(" "); 30 | 31 | StringBuilder builder = new StringBuilder(); 32 | for (int i = split.length - 1; i >= 0; i--) { 33 | String t = split[i]; 34 | if (t.trim().isEmpty()) { 35 | continue; 36 | } 37 | 38 | builder.append(t).append(" "); 39 | } 40 | 41 | return builder.toString().trim(); 42 | } 43 | ``` 44 | -------------------------------------------------------------------------------- /leetcode/salary.md: -------------------------------------------------------------------------------- 1 | # [第二高的薪水](https://leetcode-cn.com/explore/interview/card/bytedance/247/bonus/1039/) 2 | 3 | **头条重点** 4 | 5 | ## 题目 6 | 7 | 编写一个 SQL 查询,获取 Employee 表中第二高的薪水(Salary) 。 8 | 9 | ``` 10 | +----+--------+ 11 | | Id | Salary | 12 | +----+--------+ 13 | | 1 | 100 | 14 | | 2 | 200 | 15 | | 3 | 300 | 16 | +----+--------+ 17 | ``` 18 | 19 | 例如上述 Employee 表,SQL查询应该返回 200 作为第二高的薪水。如果不存在第二高的薪水,那么查询应返回 null。 20 | 21 | ``` 22 | +---------------------+ 23 | | SecondHighestSalary | 24 | +---------------------+ 25 | | 200 | 26 | +---------------------+ 27 | ``` 28 | 29 | ## 解题思路 30 | 31 | 1. 子查询 32 | 33 | ``` 34 | select IFNULL((select Distinct Salary from Employee order by Salary DESC limit 1,1),null) 35 | as SecondHighestSalary 36 | ``` 37 | -------------------------------------------------------------------------------- /leetcode/searchRote.md: -------------------------------------------------------------------------------- 1 | # [搜索旋转排序数组](https://leetcode-cn.com/explore/interview/card/bytedance/243/array-and-sorting/1017/) 2 | 3 | **头条重点** 4 | 5 | ## 题目 6 | 7 | 假设按照升序排序的数组在预先未知的某个点上进行了旋转。( 例如,数组 `[0,1,2,4,5,6,7]` 可能变为 `[4,5,6,7,0,1,2]` )。 8 | 9 | 搜索一个给定的目标值,如果数组中存在这个目标值,则返回它的索引,否则返回 -1 。 10 | 11 | 你可以假设数组中不存在重复的元素。 12 | 13 | 你的算法时间复杂度必须是 O(log n) 级别。 14 | 15 | ``` 16 | 示例 1: 17 | 18 | 输入: nums = [4,5,6,7,0,1,2], target = 0 19 | 输出: 4 20 | 示例 2: 21 | 22 | 输入: nums = [4,5,6,7,0,1,2], target = 3 23 | 输出: -1 24 | ``` 25 | 26 | ## 解题思路 27 | 28 | 1. 旋转数组是分为两段有序,主要得注意 `mid` 落在哪个段上 29 | 30 | ``` 31 | public static int search(int[] nums, int target) { 32 | int start = 0, end = nums.length - 1; 33 | 34 | while (start <= end) { 35 | int mid = (start + end) / 2; 36 | if (nums[mid]==target) return mid; 37 | 38 | if (nums[mid] >= nums[start]) { 39 | if (target < nums[mid] && target >= nums[start]) { 40 | end = mid - 1; 41 | } else { 42 | start = mid + 1; 43 | } 44 | 45 | } 46 | 47 | if (nums[mid] <= nums[end]) { 48 | if (target > nums[mid] && target <= nums[end]) { 49 | start = mid + 1; 50 | } else { 51 | end = mid - 1; 52 | } 53 | } 54 | } 55 | 56 | return -1; 57 | } 58 | ``` 59 | -------------------------------------------------------------------------------- /leetcode/simplifyPath.md: -------------------------------------------------------------------------------- 1 | # [简化路径](https://leetcode-cn.com/explore/interview/card/bytedance/242/string/1013/) 2 | 3 | **头条重点** 4 | 5 | ## 题目 6 | 7 | 以 Unix 风格给出一个文件的绝对路径,你需要简化它。或者换句话说,将其转换为规范路径。 8 | 9 | 在 Unix 风格的文件系统中,一个点(.)表示当前目录本身;此外,两个点 (..) 表示将目录切换到上一级(指向父目录);两者都可以是复杂相对路径的组成部分。 10 | 11 | 请注意,返回的规范路径必须始终以斜杠 / 开头,并且两个目录名之间必须只有一个斜杠 /。最后一个目录名(如果存在)不能以 / 结尾。此外,规范路径必须是表示绝对路径的最短字符串。 12 | 13 | ``` 14 | 示例 1: 15 | 16 | 输入:"/home/" 17 | 输出:"/home" 18 | 解释:注意,最后一个目录名后面没有斜杠。 19 | 20 | 示例 2: 21 | 22 | 输入:"/../" 23 | 输出:"/" 24 | 解释:从根目录向上一级是不可行的,因为根是你可以到达的最高级。 25 | 示例 3: 26 | 27 | 输入:"/home//foo/" 28 | 输出:"/home/foo" 29 | 解释:在规范路径中,多个连续斜杠需要用一个斜杠替换。 30 | 示例 4: 31 | 32 | 输入:"/a/./b/../../c/" 33 | 输出:"/c" 34 | 示例 5: 35 | 36 | 输入:"/a/../../b/../c//.//" 37 | 输出:"/c" 38 | 示例 6: 39 | 40 | 输入:"/a//b////c/d//././/.." 41 | 输出:"/a/b/c" 42 | ``` 43 | 44 | ## 解题思路 45 | 46 | 1. 利用栈的特性,将有效路径名压入 47 | 2. 当遇到 `..` 时 `pop` 栈 48 | 3. 最后按顺序 `pop` 组成最终路径 49 | 50 | ``` 51 | public static String simplifyPath(String path) { 52 | ArrayDeque stack = new ArrayDeque<>(); 53 | String[] split = path.split("/"); 54 | for (String s : split) { 55 | if (s.isEmpty()) { 56 | continue; 57 | } 58 | 59 | switch (s) { 60 | case "..": 61 | stack.pollLast(); 62 | break; 63 | case ".": 64 | break; 65 | default: 66 | stack.offerLast(s); 67 | } 68 | } 69 | 70 | StringBuilder builder = new StringBuilder("/"); 71 | for (String s : stack) { 72 | builder.append(s); 73 | builder.append("/"); 74 | } 75 | 76 | if (builder.length() > 1) { 77 | builder.deleteCharAt(builder.length() - 1); 78 | } 79 | return builder.toString(); 80 | } 81 | ``` 82 | -------------------------------------------------------------------------------- /leetcode/trap.md: -------------------------------------------------------------------------------- 1 | # [接雨水](https://leetcode-cn.com/explore/interview/card/bytedance/243/array-and-sorting/1047/) 2 | 3 | **头条重点** 4 | 5 | ## 题目 6 | 7 | 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。 8 | 9 | ![image](images/5981c540e595049ee84429c3f4a7face.png) 10 | 11 | 上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。 感谢 Marcos 贡献此图。 12 | 13 | ``` 14 | 示例: 15 | 16 | 输入: [0,1,0,2,1,0,1,3,2,1,2,1] 17 | 输出: 6 18 | ``` 19 | 20 | ## 解题思路 21 | 22 | 1. 首先找到最高点,然后从首尾向中间遍历,找到局部高点,然后就可以计算总量 23 | 24 | ``` 25 | public int trap(int[] height) { 26 | if (height.length <= 2) { 27 | return 0; 28 | } 29 | 30 | int max = 0, maxIndex = 0; 31 | for (int i = 0; i < height.length; i++) { 32 | if (height[i] > max) { 33 | max = height[i]; 34 | maxIndex = i; 35 | } 36 | } 37 | 38 | int total = 0; 39 | int topIndex = 0;//局部最高点 40 | for (int i = 0; i < maxIndex; i++) { 41 | if (height[topIndex] < height[i]) { 42 | topIndex = i; 43 | } else { 44 | total += height[topIndex] - height[i]; 45 | } 46 | } 47 | 48 | topIndex = height.length - 1; 49 | for (int i = height.length - 1; i > maxIndex; i--) { 50 | if (height[topIndex] < height[i]) { 51 | topIndex = i; 52 | } else { 53 | total += height[topIndex] - height[i]; 54 | } 55 | } 56 | 57 | 58 | return total; 59 | } 60 | ``` 61 | -------------------------------------------------------------------------------- /leetcode/zigzagLevelOrder.md: -------------------------------------------------------------------------------- 1 | # [二叉树的锯齿形层次遍历](https://leetcode-cn.com/explore/interview/card/bytedance/244/linked-list-and-tree/1027/) 2 | 3 | ## 题目 4 | 5 | 给定一个二叉树,返回其节点值的锯齿形层次遍历。(即先从左往右,再从右往左进行下一层遍历,以此类推,层与层之间交替进行)。 6 | 7 | ``` 8 | 例如: 9 | 给定二叉树 [3,9,20,null,null,15,7], 10 | 11 | 3 12 | / \ 13 | 9 20 14 | / \ 15 | 15 7 16 | 返回锯齿形层次遍历如下: 17 | 18 | [ 19 | [3], 20 | [20,9], 21 | [15,7] 22 | ] 23 | ``` 24 | 25 | ## 解题思路 26 | 27 | 1. 通过遍历每层的节点 28 | 2. 根据层数不同,用不同方式进行输出 29 | 30 | ``` 31 | public List> zigzagLevelOrder(TreeNode root) { 32 | List> temp = new ArrayList<>(); 33 | all(temp, root, 0); 34 | 35 | List> res = new ArrayList<>(); 36 | for (int i = 0; i < temp.size(); i++) { 37 | if (i % 2 == 1) { 38 | res.add(temp.get(i)); 39 | } else { 40 | Collections.reverse(temp.get(i)); 41 | res.add(temp.get(i)); 42 | } 43 | 44 | } 45 | return res; 46 | } 47 | 48 | private void all(List> res, TreeNode root, int level) { 49 | if (root == null) { 50 | return; 51 | } 52 | 53 | for (int i = 0; i < level - res.size() + 1; i++) { 54 | res.add(new LinkedList<>()); 55 | } 56 | 57 | res.get(level).add(root.val); 58 | 59 | all(res, root.right, level + 1); 60 | all(res, root.left, level + 1); 61 | } 62 | ``` 63 | -------------------------------------------------------------------------------- /offer/Add.md: -------------------------------------------------------------------------------- 1 | # 不用加减乘除做加法 2 | 3 | ## 题目 4 | 5 | [牛客网](https://www.nowcoder.com/practice/59ac416b4b944300b617d4f7f111b215?tpId=13&tqId=11201&tPage=3&rp=2&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking) 6 | 7 | 写一个函数,求两个整数之和,要求在函数体内不得使用`+、-、*、/`四则运算符号。 8 | 9 | ## 解题思路 10 | 11 | 1. 将加法分解成两步 12 | 2. 两个数不计算进位相加得到 `sum`,计算进位 `carry` 13 | 3. 再将进位加上:`sum = sum + carry` 14 | 4. 直到没有进位为止 15 | 16 | ``` 17 | public int Add(int num1, int num2) { 18 | int sum, carry; 19 | do { 20 | sum = num1 ^ num2; 21 | carry = (num1 & num2) << 1; 22 | 23 | num1 = sum; 24 | num2 = carry; 25 | } while (num2 != 0); 26 | 27 | return sum; 28 | } 29 | ``` 30 | -------------------------------------------------------------------------------- /offer/BST-Link-Convert.md: -------------------------------------------------------------------------------- 1 | # 二叉搜索树与双向链表 2 | 3 | ## 题目 4 | 5 | [牛客网](https://www.nowcoder.com/practice/947f6eb80d944a84850b0538bf0ec3a5?tpId=13&tqId=11179&rp=1&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking&tPage=2) 6 | 7 | 输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。 8 | 9 | 10 | ## 解题思路 11 | 12 | 1. 由于 BST 的特性,采用中序遍历正好符合排序 13 | 2. 要考虑 root 节点要与 左节点的最大值连接,与右节点的最小值连接 14 | 3. 增加一个已排序链表的指针,指向最后一个已排序节点 15 | 16 | ``` 17 | public TreeNode Convert(TreeNode pRootOfTree) { 18 | if (pRootOfTree == null) { 19 | return null; 20 | } 21 | 22 | TreeNode[] nodeList = {new TreeNode(-1)}; 23 | 24 | ConvertToLink(pRootOfTree, nodeList); 25 | 26 | TreeNode cursor = pRootOfTree; 27 | while (cursor.left != null) { 28 | cursor = cursor.left; 29 | } 30 | 31 | cursor.right.left = null; 32 | return cursor.right; 33 | } 34 | 35 | private void ConvertToLink(TreeNode root, TreeNode[] nodeList) { 36 | if (root == null) { 37 | return; 38 | } 39 | 40 | ConvertToLink(root.left, nodeList); 41 | 42 | root.left = nodeList[0]; 43 | nodeList[0].right = root; 44 | nodeList[0] = root; 45 | 46 | ConvertToLink(root.right, nodeList); 47 | } 48 | ``` 49 | -------------------------------------------------------------------------------- /offer/BSTKthNode.md: -------------------------------------------------------------------------------- 1 | # 二叉搜索树的第k个结点 2 | 3 | ## 题目 4 | 5 | 6 | 给定一棵二叉搜索树,请找出其中的第 k 小的结点。例如,`5,3,7,2,4,6,8` 中,按结点数值大小顺序第三小结点的值为4。 7 | 8 | [牛客网](https://www.nowcoder.com/practice/ef068f602dde4d28aab2b210e859150a?tpId=13&tqId=11215&tPage=4&rp=2&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking) 9 | 10 | 11 | ## 解题思路 12 | 13 | 1. BST 中序遍历的结果就是排序后的结果 14 | 15 | ``` 16 | public TreeNode KthNode(TreeNode pRoot, int k) { 17 | TreeNode[] nodes = new TreeNode[1]; 18 | 19 | int[] ints = {0}; 20 | 21 | KthNode(pRoot, k, nodes, ints); 22 | 23 | return nodes[0]; 24 | } 25 | 26 | private void KthNode(TreeNode root, int k, TreeNode[] res, int[] cursor) { 27 | if (root == null) return; 28 | 29 | if (res[0] != null) return; 30 | 31 | KthNode(root.left, k, res, cursor); 32 | cursor[0]++; 33 | 34 | if (cursor[0] == k) { 35 | res[0] = root; 36 | return; 37 | } 38 | 39 | KthNode(root.right, k, res, cursor); 40 | } 41 | ``` 42 | -------------------------------------------------------------------------------- /offer/CloneLink.md: -------------------------------------------------------------------------------- 1 | # 复杂链表的复制 2 | 3 | ## 题目 4 | 5 | [牛客网](https://www.nowcoder.com/practice/f836b2c43afc4b35ad6adc41ec941dba?tpId=13&tqId=11178&rp=1&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking&tPage=2) 6 | 7 | 输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为复制后复杂链表的 head 。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空) 8 | 9 | 10 | ## 解题思路 11 | 12 | 13 | 1. 复制每个节点,如:复制节点 A 得到 A1 ,将 A1 插入节点 A 后面 14 | 2. 遍历链表,并将 `A1->random = A->random->next`; 15 | 3. 将链表拆分成原链表和复制后的链表 16 | 17 | ``` 18 | public RandomListNode Clone(RandomListNode pHead) { 19 | if (pHead == null) { 20 | return null; 21 | } 22 | 23 | RandomListNode cursor = pHead; 24 | while (cursor != null) { 25 | RandomListNode copyNode = new RandomListNode(cursor.label); 26 | 27 | RandomListNode nextNode = cursor.next; 28 | cursor.next = copyNode; 29 | copyNode.next = nextNode; 30 | 31 | cursor = nextNode; 32 | } 33 | 34 | cursor = pHead; 35 | while (cursor != null) { 36 | RandomListNode copyNode = cursor.next; 37 | 38 | if (cursor.random == null) { 39 | cursor = copyNode.next; 40 | continue; 41 | } 42 | 43 | copyNode.random = cursor.random.next; 44 | 45 | cursor = copyNode.next; 46 | } 47 | 48 | RandomListNode copyHead = pHead.next; 49 | cursor = pHead; 50 | while (cursor.next != null) { 51 | RandomListNode copyNode = cursor.next; 52 | cursor.next = copyNode.next; 53 | cursor = copyNode; 54 | } 55 | 56 | return copyHead; 57 | } 58 | ``` 59 | -------------------------------------------------------------------------------- /offer/CountOfSortedArray.md: -------------------------------------------------------------------------------- 1 | # 在排序数组中查找数字 2 | 3 | ## 题目 4 | 5 | 统计一个数字在排序数组中出现的次数。 6 | 7 | ## 解题思路 8 | 9 | 1. 通过二分查找分别找到 n 的第一个位置和最后一个位置 10 | 2. 再进行计算就可以得出结果 11 | 12 | ``` 13 | public int countOfSortedArray2(int[] nums, int n) { 14 | if (nums == null || nums.length == 0) return 0; 15 | 16 | int firstN = getFirstN(nums, n); 17 | int lastN = getLastN(nums, n); 18 | 19 | return lastN - firstN + 1; 20 | } 21 | 22 | private int getFirstN(int[] nums, int n) { 23 | int s = 0, e = nums.length - 1; 24 | 25 | int mid = -1; 26 | while (s <= e) { 27 | mid = (s + e) / 2; 28 | 29 | if (mid > 0 && nums[mid - 1] == n) { 30 | e = mid - 1; 31 | continue; 32 | } 33 | 34 | if (nums[mid] > n) { 35 | e = mid - 1; 36 | continue; 37 | } 38 | 39 | if (nums[mid] < n) { 40 | s = mid + 1; 41 | continue; 42 | } 43 | 44 | break; 45 | } 46 | 47 | return mid; 48 | } 49 | 50 | private int getLastN(int[] nums, int n) { 51 | int s = 0, e = nums.length - 1; 52 | 53 | int mid = -1; 54 | while (s <= e) { 55 | mid = (s + e) / 2; 56 | 57 | if (mid < nums.length - 1 && nums[mid + 1] == n) { 58 | s = mid + 1; 59 | continue; 60 | } 61 | 62 | if (nums[mid] > n) { 63 | e = mid - 1; 64 | continue; 65 | } 66 | 67 | if (nums[mid] < n) { 68 | s = mid + 1; 69 | continue; 70 | } 71 | 72 | break; 73 | } 74 | 75 | return mid; 76 | } 77 | ``` 78 | -------------------------------------------------------------------------------- /offer/CutRope.md: -------------------------------------------------------------------------------- 1 | # 剪绳子 2 | 3 | ## 题目 4 | 5 | 给定一根长度为n的绳子,请把绳子剪成m段(m、n都是整数,n>1并且m>1),每段绳子的长度记为`k[0],k[1],…,k[m]`。请问`k[0]* k[1] * … *k[m]`可能的最大乘积是多少? 6 | 7 | ## 解题思路 8 | 9 | 1. 尽可能剪长度为 3 的绳子 10 | 2. 当长度剩下的为 4 时,不能再减去 3,而是 2*2 11 | 12 | ``` 13 | public int cutRope(int n) { 14 | if (n < 2) return 0; 15 | 16 | if (n == 2) return 1; 17 | 18 | if (n == 3) return 2; 19 | 20 | int timesOf3 = n / 3; 21 | 22 | if (n - timesOf3 * 3 == 1) { 23 | timesOf3 = 1; 24 | } 25 | 26 | int timesOf2 = (n - (timesOf3 * 3)) / 2; 27 | 28 | return (int) (Math.pow(3, timesOf3) * Math.pow((2), timesOf2)); 29 | } 30 | ``` 31 | -------------------------------------------------------------------------------- /offer/Duplicate.md: -------------------------------------------------------------------------------- 1 | # 数组中重复的数字 2 | 3 | ## 题目 4 | 5 | 在一个长度为n的数组里的所有数字都在0到 n-1 的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 例如,如果输入长度为7的数组`{2,3,1,0,2,5,3}`,那么对应的输出是第一个重复的数字2。 6 | 7 | ## 解题思路 8 | 9 | ### 解法一 10 | 11 | 1. 由于数组内数字在 `0 ~ n-1` 的范围内,可以将数组按 **数字做下标** 进行重排序 12 | 2. 将 `n` 放置到 `num[n]` 上,交换之前再判定在 `num[n]` 上是否为相同数字 13 | 14 | ``` 15 | public boolean duplicate(int numbers[], int length, int[] duplication) { 16 | if (numbers == null || numbers.length == 0) return false; 17 | 18 | for (int i = 0; i < numbers.length; i++) { 19 | 20 | while (numbers[i] != i) { 21 | int number = numbers[i]; 22 | int wrongNum = numbers[number]; 23 | if (number == wrongNum) { 24 | duplication[0] = number; 25 | return true; 26 | } 27 | 28 | swap(numbers, i, number); 29 | } 30 | 31 | } 32 | 33 | 34 | return false; 35 | } 36 | 37 | private static void swap(int[] nums, int i, int j) { 38 | int temp = nums[i]; 39 | nums[i] = nums[j]; 40 | nums[j] = temp; 41 | } 42 | ``` 43 | 44 | ### 解法二 45 | 46 | 1. 把数字 `1 ~ n` 划分为 `1 ~ m`、`m+1 ~ n`,统计两个子数组中每个数字在 `1~n` 出现的次数 47 | 2. 如果出现的次数大于 `m`,那么重复数字一定在 `1 ~ m` 中 48 | 3. 继续这样进行划分,可以找到重复数组 49 | -------------------------------------------------------------------------------- /offer/EntryNodeOfLoop.md: -------------------------------------------------------------------------------- 1 | # 链表中环的入口结点 2 | 3 | ## 题目 4 | 5 | 给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null。 6 | 7 | 8 | ## 解题思路 9 | 10 | 1. 首先通过 **快慢指针**(快:每次走两步;慢:每次走一步)确定是否有环 11 | 2. 当有环时,再从头节点出发,与快指针按 **相同速度** 向前移动,当 `cursor = fast` 则找到环入口 12 | 13 | ``` 14 | public ListNode EntryNodeOfLoop(ListNode pHead) { 15 | if (pHead == null || pHead.next == null) return null; 16 | 17 | ListNode fast = pHead, slow = pHead; 18 | 19 | while (fast.next != null) { 20 | slow = slow.next; 21 | fast = fast.next.next; 22 | 23 | if (fast == slow) break; 24 | } 25 | 26 | if (fast != slow) return null; 27 | 28 | ListNode cursor = pHead; 29 | while (cursor != fast) { 30 | cursor = cursor.next; 31 | fast = fast.next; 32 | } 33 | 34 | return cursor; 35 | } 36 | ``` 37 | -------------------------------------------------------------------------------- /offer/FindContinuousSequence.md: -------------------------------------------------------------------------------- 1 | # 和为S的连续正数序列 2 | 3 | ## 题目 4 | 5 | [牛客网](https://www.nowcoder.com/practice/c451a3fd84b64cb19485dad758a55ebe?tpId=13&tqId=11194&tPage=2&rp=2&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking) 6 | 7 | 输出所有和为S的连续正数序列。序列内按照从小至大的顺序,序列间按照开始数字从小到大的顺序 8 | 9 | ## 解题思路 10 | 11 | 1. 与上一个题目类似,需要确定的是序列的最大值,不超过 `sum` 12 | 2. 使用窗口模式,两个指针定义一个窗口,和为 `t` 13 | 14 | ``` 15 | public ArrayList> FindContinuousSequence(int sum) { 16 | ArrayList> res = new ArrayList<>(); 17 | if (sum == 1) { 18 | return res; 19 | } 20 | 21 | int start = 1, end = 2; 22 | int t = start + end; 23 | 24 | while (start < end) { 25 | if (t == sum) { 26 | ArrayList ints = new ArrayList<>(); 27 | for (int i = start; i <= end; i++) { 28 | ints.add(i); 29 | } 30 | res.add(ints); 31 | t -= start; 32 | start++; 33 | } else if (t > sum) { 34 | t -= start; 35 | start++; 36 | } else { 37 | if (end >= sum) break; 38 | 39 | end++; 40 | t += end; 41 | } 42 | } 43 | 44 | return res; 45 | } 46 | ``` 47 | -------------------------------------------------------------------------------- /offer/FindGreatestSumOfSubArray.md: -------------------------------------------------------------------------------- 1 | # 连续子数组的最大和 2 | 3 | ## 题目 4 | 5 | [牛客网](https://www.nowcoder.com/practice/459bd355da1549fa8a49e350bf3df484?tpId=13&tqId=11183&rp=1&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking&tPage=2) 6 | 7 | 例如:`{6,-3,-2,7,-15,1,2,2}`,连续子向量的最大和为8(从第0个开始,到第3个为止)。给一个数组,返回它的最大连续子序列的和,你会不会被他忽悠住?(子向量的长度至少是1) 8 | 9 | ## 解题思路 10 | 11 | 通过动态规划计算最大和,$$f(i)$$ 定义为以第 $$i$$ 个数字结尾的子数组的最大和,那么 $$max(f(i))$$ 就有以下公式: 12 | 13 | $$ 14 | max(f(i))=\begin{cases} 15 | num[i] & i=0 or f(i)<0\\ 16 | num[i]+f(i) & i\ne0 and f(i)>0 17 | \end{cases} 18 | $$ 19 | 20 | ``` 21 | public int FindGreatestSumOfSubArray(int[] array) { 22 | if (array == null || array.length == 0) { 23 | return 0; 24 | } 25 | 26 | int max = array[0]; 27 | int sum = 0; 28 | for (int a : array) { 29 | if (sum + a > a) { 30 | sum += a; 31 | } else { 32 | sum = a; 33 | } 34 | 35 | if (sum > max) { 36 | max = sum; 37 | } 38 | } 39 | 40 | return max; 41 | } 42 | ``` 43 | -------------------------------------------------------------------------------- /offer/FindKthToTail.md: -------------------------------------------------------------------------------- 1 | # 链表中倒数第k个结点 2 | 3 | ## 题目 4 | 5 | [牛客网](https://www.nowcoder.com/practice/529d3ae5a407492994ad2a246518148a?tpId=13&tqId=11167&rp=1&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking&tPage=1) 6 | 7 | 输入一个链表,输出该链表中倒数第k个结点。 8 | 9 | ## 解题思路 10 | 11 | 1. 两个指针,快指针先走 k 步,然后慢指针在向前移动,当快指针遍历结束,慢指针指向倒数第 k 个节点 12 | 2. 需要考虑倒数 k 个节点不存在的情况 13 | 14 | ``` 15 | public ListNode FindKthToTail(ListNode head, int k) { 16 | if (head == null) { 17 | return null; 18 | } 19 | 20 | ListNode cursor = head; 21 | ListNode cursorK = head; 22 | 23 | int i = 0; 24 | 25 | while (cursorK != null) { 26 | cursorK = cursorK.next; 27 | 28 | if (i >= k) { 29 | cursor = cursor.next; 30 | } 31 | 32 | i++; 33 | } 34 | 35 | if (i < k) { 36 | return null; 37 | } 38 | 39 | return cursor; 40 | } 41 | ``` 42 | -------------------------------------------------------------------------------- /offer/FindNumbersWithSum.md: -------------------------------------------------------------------------------- 1 | # 和为S的两个数字 2 | 3 | ## 题目 4 | 5 | [牛客网](https://www.nowcoder.com/practice/390da4f7a00f44bea7c2f3d19491311b?tpId=13&tqId=11195&tPage=3&rp=2&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking) 6 | 7 | 输入一个递增排序的数组和一个数字S,在数组中查找两个数,使得他们的和正好是S,如果有多对数字的和等于S,输出两个数的乘积最小的。 8 | 9 | > 对应每个测试案例,输出两个数,小的先输出。 10 | 11 | ## 解题思路 12 | 13 | 1. 利用二分查找的思想,由于是排序数组,通过两个指针来进行遍历 14 | 15 | ``` 16 | public ArrayList FindNumbersWithSum(int[] array, int sum) { 17 | ArrayList res = new ArrayList<>(); 18 | 19 | if (array == null || array.length == 1) { 20 | return res; 21 | } 22 | 23 | int start = 0, end = array.length - 1; 24 | int minMulti = Integer.MAX_VALUE; 25 | int a = -1, b = -1; 26 | 27 | while (start < end) { 28 | int t = array[start] + array[end]; 29 | if (t == sum) { 30 | int multi = array[start] * array[end]; 31 | if (multi < minMulti) { 32 | a = array[start]; 33 | b = array[end]; 34 | minMulti = multi; 35 | } 36 | start++; 37 | end--; 38 | } else if (t > sum) end--; 39 | else start++; 40 | } 41 | 42 | if (a == -1 || b == -1) { 43 | return res; 44 | } 45 | 46 | res.add(a); 47 | res.add(b); 48 | 49 | return res; 50 | } 51 | ``` 52 | -------------------------------------------------------------------------------- /offer/FindNumsAppearOnce.md: -------------------------------------------------------------------------------- 1 | # 数组中只出现一次的数字 2 | 3 | ## 题目 4 | 5 | [牛客网](https://www.nowcoder.com/practice/e02fdb54d7524710a7d664d082bb7811?tpId=13&tqId=11193&tPage=2&rp=2&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking) 6 | 7 | 一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。 8 | 9 | ## 解题思路 10 | 11 | 1. 两个相等的数字进行异或的结果为0 12 | 2. 在这个特殊的数组中,重复出现的数字只能为2次,那么如果将所有数字异或 就等价与将两个不同的数字进行异或 13 | 3. 异或的结果肯定有一位为1,那么这两个不同的数字,在这一位上不同。 14 | 4. 找到第一个为1的位,并将第一位为1的位是否为1作为分组条件,相同的数字一定在同一个分组里,整个数组分组异或 15 | 5. 得到两个结果,即为两个不同的数 16 | 17 | ``` 18 | /** 19 | * num1,num2分别为长度为1的数组。传出参数。将num1[0],num2[0]设置为返回结果 20 | * @param array 21 | * @param num1 22 | * @param num2 23 | */ 24 | public void FindNumsAppearOnce(int[] array, int num1[], int num2[]) { 25 | if (array == null || array.length < 3) { 26 | return; 27 | } 28 | 29 | int result = array[0]; 30 | 31 | for (int i = 1; i < array.length; i++) { 32 | result ^= array[i]; 33 | } 34 | 35 | //找到第一个为1的位 36 | int indexOfFirstBit1 = 0; 37 | int temp = result; 38 | while (temp != 0) { 39 | indexOfFirstBit1++; 40 | temp >>>= 1; 41 | } 42 | 43 | int mask = 1; 44 | for (int i = 1; i < indexOfFirstBit1; i++) { 45 | mask <<= 1; 46 | } 47 | 48 | //将第一位为1的位是否为1作为分组条件,分组异或 49 | int n1 = -1, n2 = -1; 50 | for (int i : array) { 51 | if ((i & mask) == mask) { 52 | if (n1 == -1) n1 = i; 53 | else n1 ^= i; 54 | } else { 55 | if (n2 == -1) n2 = i; 56 | else n2 ^= i; 57 | } 58 | } 59 | 60 | num1[0] = n1; 61 | num2[0] = n2; 62 | } 63 | ``` 64 | -------------------------------------------------------------------------------- /offer/FindPath.md: -------------------------------------------------------------------------------- 1 | # 二叉树中和为某一值的路径 2 | 3 | ## 题目 4 | 5 | [二叉树中和为某一值的路径](https://www.nowcoder.com/practice/b736e784e3e34731af99065031301bca?tpId=13&tqId=11177&rp=1&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking&tPage=2) 6 | 7 | 输入一颗二叉树的跟节点和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。(注意: 在返回值的 list 中,数组长度大的数组靠前) 8 | 9 | ## 解题思路 10 | 11 | 1. 将走过的路径记录下来,当走过路径总和 = target 并且当前节点是叶子节点时,该路径符合要求 12 | 2. 通过递归遍历所有可能的路径 13 | 14 | ``` 15 | public ArrayList> FindPath(TreeNode root, int target) { 16 | ArrayList> res = new ArrayList<>(); 17 | 18 | FindPath(res, new LinkedList<>(), root, 0, target); 19 | 20 | res.sort(Comparator.comparingInt(list -> -list.size())); 21 | 22 | return res; 23 | } 24 | 25 | 26 | private void FindPath(ArrayList> res, 27 | LinkedList path, 28 | TreeNode node, 29 | int pathSum, 30 | int target) { 31 | if (node == null) { 32 | return; 33 | } 34 | 35 | if (pathSum > target) { 36 | return; 37 | } 38 | 39 | if (pathSum + node.val == target && node.right == null && node.left == null) { 40 | ArrayList resPath = new ArrayList<>(path); 41 | resPath.add(node.val); 42 | res.add(resPath); 43 | return; 44 | } 45 | 46 | path.addLast(node.val); 47 | 48 | if (node.left != null) { 49 | FindPath(res, path, node.left, pathSum + node.val, target); 50 | } 51 | 52 | if (node.right != null) { 53 | FindPath(res, path, node.right, pathSum + node.val, target); 54 | } 55 | 56 | path.removeLast(); 57 | } 58 | ``` 59 | -------------------------------------------------------------------------------- /offer/FirstNotRepeatingChar.md: -------------------------------------------------------------------------------- 1 | # 第一个只出现一次的字符 2 | 3 | ## 题目 4 | 5 | [牛客网](https://www.nowcoder.com/practice/1c82e8cf713b4bbeb2a5b31cf5b0417c?tpId=13&tqId=11187&tPage=2&rp=2&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking) 6 | 7 | 在一个字符串(`0<=字符串长度<=10000`,全部由字母组成)中找到第一个只出现一次的字符,并返回它的位置, 如果没有则返回 -1(需要区分大小写). 8 | 9 | ## 解题思路 10 | 11 | 1. 通过 `LinkedHashMap` 记录数组顺序,然后计算字符出现的次数 12 | 2. 遍历找到第一个只出现 1次 的字符 13 | 14 | ``` 15 | public int FirstNotRepeatingChar(String str) { 16 | LinkedHashMap data = new LinkedHashMap<>(); 17 | char[] chars = str.toCharArray(); 18 | for (char c : chars) { 19 | Integer count = data.getOrDefault(c, 0); 20 | data.put(c, count + 1); 21 | } 22 | 23 | Character res = null; 24 | for (Character c : data.keySet()) { 25 | if (data.get(c) == 1) { 26 | res = c; 27 | break; 28 | } 29 | } 30 | 31 | if (res == null) { 32 | return -1; 33 | } 34 | 35 | for (int i = 0; i < chars.length; i++) { 36 | if (chars[i] == res) { 37 | return i; 38 | } 39 | } 40 | 41 | return -1; 42 | } 43 | ``` 44 | -------------------------------------------------------------------------------- /offer/GetLeastNumbersSolution.md: -------------------------------------------------------------------------------- 1 | # 最小的K个数 2 | 3 | ## 题目 4 | 5 | [牛客网](https://www.nowcoder.com/practice/6a296eb82cf844ca8539b57c23e6e9bf?tpId=13&tqId=11182&rp=1&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking&tPage=2) 6 | 7 | 输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,。 8 | 9 | ## 解题思路 10 | 11 | 1. 利用堆排序原理,计算出最小的 k 个数 12 | 13 | ``` 14 | public ArrayList GetLeastNumbers_Solution(int[] input, int k) { 15 | ArrayList res = new ArrayList<>(); 16 | if (k > input.length || k == 0) { 17 | return res; 18 | } 19 | 20 | for (int i = input.length - 1; i >= 0; i--) { 21 | minHeap(input, 0, i); 22 | 23 | swap(input, 0, i); 24 | 25 | res.add(input[i]); 26 | if (res.size() == k) break; 27 | } 28 | return res; 29 | } 30 | 31 | private void minHeap(int[] heap, int start, int end) { 32 | if (start == end) { 33 | return; 34 | } 35 | 36 | int childLeft = start * 2 + 1; 37 | int childRight = childLeft + 1; 38 | 39 | if (childLeft <= end) { 40 | minHeap(heap, childLeft, end); 41 | 42 | if (heap[childLeft] < heap[start]) { 43 | swap(heap, start, childLeft); 44 | } 45 | } 46 | 47 | if (childRight <= end) { 48 | minHeap(heap, childRight, end); 49 | 50 | if (heap[childRight] < heap[start]) { 51 | swap(heap, start, childRight); 52 | } 53 | } 54 | } 55 | 56 | private void swap(int[] nums, int a, int b) { 57 | int t = nums[a]; 58 | nums[a] = nums[b]; 59 | nums[b] = t; 60 | } 61 | ``` 62 | -------------------------------------------------------------------------------- /offer/GetNext.md: -------------------------------------------------------------------------------- 1 | # 二叉树的下一个结点 2 | 3 | ## 题目 4 | 5 | 给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。 6 | 7 | ## 解题思路 8 | 9 | 考虑以下二叉树: 10 | 11 | ![image](images/07ce2975ccdf288110e897a00f76f43f.png) 12 | 13 | 其中序遍历的结果是:`d,b,h,e,i,a,f,c,g` 14 | 15 | 1. 当前节点有右子树:右子树的最左节点 -- b 节点 16 | 2. 当前节点无右子树并且为父节点的左子树:父节点 -- d 节点 17 | 3. 当前节点无右子树并且为父节点的右子树:第一个祖先节点为左节点的节点 -- i 节点 18 | 19 | ``` 20 | public TreeLinkNode GetNext(TreeLinkNode pNode) { 21 | if (pNode == null) return null; 22 | 23 | TreeLinkNode parent = pNode.next; 24 | if (pNode.right == null) { 25 | if (parent == null) { 26 | return null; 27 | } 28 | 29 | //右节点 30 | if (parent.right == pNode) { 31 | TreeLinkNode cursor = parent; 32 | while (true) { 33 | TreeLinkNode p = cursor.next; 34 | if (p == null) return null; 35 | 36 | if (cursor == p.left) return p; 37 | 38 | cursor = p; 39 | } 40 | 41 | 42 | } else { 43 | return parent; 44 | } 45 | 46 | } else { 47 | TreeLinkNode cursor = pNode.right; 48 | while (cursor.left != null) { 49 | cursor = cursor.left; 50 | } 51 | 52 | return cursor; 53 | } 54 | 55 | } 56 | ``` 57 | -------------------------------------------------------------------------------- /offer/GetNumberOfK.md: -------------------------------------------------------------------------------- 1 | # 数字在排序数组中出现的次数 2 | 3 | ## 题目 4 | 5 | [牛客网](https://www.nowcoder.com/practice/70610bf967994b22bb1c26f9ae901fa2?tpId=13&tqId=11190&tPage=2&rp=2&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking) 6 | 7 | 统计一个数字在排序数组中出现的次数。 8 | 9 | ## 解题思路 10 | 11 | 1. 利用二分查找,找到任意一个 `k` 12 | 2. 由于 `k` 有多个,并且当前找到的 `k` 可能在任意位置。所以,在当前 `k` 的前后进行遍历查找 13 | 14 | ``` 15 | public int GetNumberOfK(int[] array, int k) { 16 | if (array == null || array.length == 0) { 17 | return 0; 18 | } 19 | 20 | //二分查找 21 | int start = 0, end = array.length - 1; 22 | int t = -1; 23 | while (start < end) { 24 | int mid = (start + end) / 2; 25 | if (array[mid] == k) { 26 | t = mid; 27 | break; 28 | } else if (array[mid] > k) { 29 | end = mid - 1; 30 | } else { 31 | start = mid + 1; 32 | } 33 | } 34 | 35 | if (array[start] == k) { 36 | t = start; 37 | } 38 | 39 | if (t == -1) { 40 | return 0; 41 | } 42 | 43 | //左侧 44 | int sum = 0; 45 | int a = t; 46 | while (a >= 0 && array[a] == k) { 47 | sum++; 48 | a--; 49 | } 50 | 51 | //右侧 52 | a = t + 1; 53 | while (a < array.length && array[a] == k) { 54 | sum++; 55 | a++; 56 | } 57 | 58 | return sum; 59 | } 60 | ``` 61 | -------------------------------------------------------------------------------- /offer/GetUglyNumber.md: -------------------------------------------------------------------------------- 1 | # 丑数 2 | 3 | [牛客网](https://www.nowcoder.com/practice/1c82e8cf713b4bbeb2a5b31cf5b0417c?tpId=13&tqId=11187&tPage=2&rp=2&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking) 4 | 5 | 把只包含质因子2、3和5的数称作丑数(Ugly Number)。例如6、8都是丑数,但14不是,因为它包含质因子7。 习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第N个丑数。 6 | 7 | ## 解题思路 8 | 9 | 1. 通过保存已有丑数的方式,用空间换时间 10 | 1. 对于已有丑数 $$M$$ ,那么下一个丑数 $$M=\min(M_{2}\times2,M_{3}\times3,M_{5}\times5)$$ 11 | 2. $$M_{max}$$ 是目前最大的丑数,那么 $$M_{2}$$ 是已有丑数中 $$M_{2}\times2$$ 第一个大于 $$M_{max}$$ 的丑数 12 | 13 | ``` 14 | public int GetUglyNumber_Solution(int index) { 15 | if (index == 0) { 16 | return 0; 17 | } 18 | 19 | if (index == 1) { 20 | return 1; 21 | } 22 | 23 | ArrayList list = new ArrayList<>(index); 24 | list.add(1); 25 | 26 | int preIndex2 = 0; 27 | int preIndex3 = 0; 28 | int preIndex5 = 0; 29 | for (int i = 0; i < index; i++) { 30 | int next2 = list.get(preIndex2) * 2; 31 | int next3 = list.get(preIndex3) * 3; 32 | int next5 = list.get(preIndex5) * 5; 33 | 34 | int nextV = Math.min(Math.min(next2, next3), next5); 35 | list.add(nextV); 36 | 37 | while (preIndex2 < list.size() - 1 && list.get(preIndex2) * 2 <= nextV) preIndex2++; 38 | while (preIndex3 < list.size() - 1 && list.get(preIndex3) * 3 <= nextV) preIndex3++; 39 | while (preIndex5 < list.size() - 1 && list.get(preIndex5) * 5 <= nextV) preIndex5++; 40 | } 41 | 42 | return list.get(index - 1); 43 | } 44 | ``` 45 | -------------------------------------------------------------------------------- /offer/HasSubtree.md: -------------------------------------------------------------------------------- 1 | # 树的子结构 2 | 3 | ## 题目 4 | 5 | [牛客网](https://www.nowcoder.com/practice/6e196c44c7004d15b1610b9afca8bd88?tpId=13&tqId=11170&rp=1&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking&tPage=1) 6 | 7 | 输入两棵二叉树A,B,判断B是不是A的子结构。(ps:我们约定空树不是任意一个树的子结构) 8 | 9 | ## 解题思路 10 | 11 | 1. 遍历查找相等根节点 12 | 2. 通过递归查找当前根节点下是否包含子树 root2 13 | 14 | ``` 15 | public boolean HasSubtree(TreeNode root1, TreeNode root2) { 16 | if (root2 == null) { 17 | return false; 18 | } 19 | 20 | LinkedList pipeline = new LinkedList<>(); 21 | pipeline.addLast(root1); 22 | 23 | while (!pipeline.isEmpty()) { 24 | TreeNode node = pipeline.pop(); 25 | if (node == null) { 26 | continue; 27 | } 28 | 29 | pipeline.addLast(node.left); 30 | pipeline.addLast(node.right); 31 | 32 | if (node.val == root2.val && isSub(node, root2)) { 33 | return true; 34 | } 35 | } 36 | 37 | return false; 38 | } 39 | 40 | private boolean isSub(TreeNode root1, TreeNode root2) { 41 | if (root1 == null && root2 == null) { 42 | return true; 43 | } 44 | 45 | if (root1 == null) { 46 | return false; 47 | } 48 | 49 | if (root2 == null) { 50 | return true; 51 | } 52 | 53 | if (root1.val == root2.val) { 54 | return isSub(root1.left, root2.left) && isSub(root1.right, root2.right); 55 | } else { 56 | return false; 57 | } 58 | 59 | } 60 | ``` 61 | -------------------------------------------------------------------------------- /offer/InversePairs.md: -------------------------------------------------------------------------------- 1 | # 数组中的逆序对 2 | 3 | ## 题目 4 | 5 | [牛客网](https://www.nowcoder.com/practice/96bd6684e04a44eb80e6a68efc0ec6c5?tpId=13&tqId=11188&tPage=2&rp=2&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking) 6 | 7 | 在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。并将`P`对`1000000007`取模的结果输出。 即输出`P%1000000007` 8 | 9 | 输入描述: 题目保证输入的数组中没有的相同的数字 10 | 11 | 数据范围: 12 | 13 | ``` 14 | 对于%50的数据,size<=10^4 15 | 16 | 对于%75的数据,size<=10^5 17 | 18 | 对于%100的数据,size<=2*10^5 19 | ``` 20 | 21 | ## 解题思路 22 | 23 | 1. 使用归并排序的方式,划分子数组 24 | 2. 两个子数组进行对比,有两个分别指向两个数组末尾的指针 `f,s`,数组分割下标为 `mid`,如果 `array[f] > array[s]`那么,就有`s - mid`个 `array[f]` 的逆序 25 | 3. 依此类推,最终将数组排序,并且获得结果 26 | 27 | ``` 28 | public int InversePairs(int[] array) { 29 | long[] sum = {0}; 30 | if (array == null || array.length == 0) { 31 | return (int) sum[0]; 32 | } 33 | 34 | int[] temp = new int[array.length]; 35 | mergeSort(array, 0, array.length - 1, temp, sum); 36 | return (int) (sum[0] % 1000000007); 37 | } 38 | 39 | 40 | private void mergeSort(int[] array, int start, int end, int[] temp, long[] sum) { 41 | if (start == end) { 42 | return; 43 | } 44 | 45 | int mid = (start + end) / 2; 46 | 47 | mergeSort(array, start, mid, temp, sum); 48 | mergeSort(array, mid + 1, end, temp, sum); 49 | 50 | int f = mid, s = end; 51 | int t = end; 52 | while (f >= start && s >= mid + 1) { 53 | if (array[f] > array[s]) { 54 | temp[t--] = array[f--]; 55 | sum[0] += s - mid; 56 | } else { 57 | temp[t--] = array[s--]; 58 | } 59 | } 60 | 61 | while (f >= start) { 62 | temp[t--] = array[f--]; 63 | } 64 | 65 | while (s >= mid + 1) { 66 | temp[t--] = array[s--]; 67 | } 68 | 69 | for (int i = end, j = end; i >= start; ) { 70 | array[j--] = temp[i--]; 71 | } 72 | } 73 | ``` 74 | -------------------------------------------------------------------------------- /offer/IsNumeric.md: -------------------------------------------------------------------------------- 1 | # 表示数值的字符串 2 | 3 | ## 题目 4 | 5 | 请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。例如,字符串"+100","5e2","-123","3.1416"和"-1E-16"都表示数值。 但是"12e","1a3.14","1.2.3","+-5"和"12e+4.3"都不是。 6 | 7 | 8 | ## 解题思路 9 | 10 | 1. 数字符合 `A[.[B]][e|EC]` 和 `.B[e|EC]` 的表达式,其中 `A` 表示整数部分,`B` 表示小数部分,`C` 表示指数部分 11 | 2. `A` 可以有正负,但是 `B` 没有 12 | 3. `e|E` 之前、之后都必须有数字 13 | 14 | ``` 15 | public boolean isNumeric(char[] str) { 16 | if (str == null || str.length == 0) return false; 17 | 18 | int index = scanInteger(str, 0); 19 | 20 | boolean numeric = index != 0; 21 | 22 | //小数 23 | if (index < str.length && str[index] == '.') { 24 | index++; 25 | int pre = index; 26 | index = scanUnsignedInteger(str, index); 27 | 28 | //1. 小数可以没有整数部分 29 | //2. 小数后可以没有数字 30 | //3. 小数后可以有数字 31 | numeric |= index != pre; 32 | } 33 | 34 | //指数 35 | if (index < str.length && (str[index] == 'e' || str[index] == 'E')) { 36 | index++; 37 | int pre = index; 38 | index = scanInteger(str, index); 39 | 40 | //1. e或者E之前必须有数字 41 | //2. e或者E之后必须有数字 42 | numeric &= index != pre; 43 | } 44 | 45 | return numeric && index == str.length; 46 | } 47 | 48 | private int scanInteger(char[] str, int s) { 49 | if (s < str.length && (str[s] == '+' || str[s] == '-')) 50 | s++; 51 | 52 | return scanUnsignedInteger(str, s); 53 | } 54 | 55 | 56 | private int scanUnsignedInteger(char[] str, int s) { 57 | while (s < str.length && str[s] >= '0' && str[s] <= '9') { 58 | s++; 59 | } 60 | 61 | return s; 62 | } 63 | ``` 64 | -------------------------------------------------------------------------------- /offer/IsPopOrder.md: -------------------------------------------------------------------------------- 1 | # 栈的压入、弹出序列 2 | 3 | ## 题目 4 | 5 | [牛客网](https://www.nowcoder.com/practice/d77d11405cc7470d82554cb392585106?tpId=13&tqId=11174&rp=1&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking&tPage=1) 6 | 7 | 输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。(注意:这两个序列的长度是相等的) 8 | 9 | ## 解题思路 10 | 11 | 1. 通过 Stack 进行模拟 push,当 pop 的节点等于 Stack 的 top 节点时,pop Stack 12 | 2. 最后如果 Stack 剩余数据,则判定为 false 13 | 14 | ``` 15 | public boolean IsPopOrder(int[] pushA, int[] popA) { 16 | if (pushA.length != popA.length) { 17 | return false; 18 | } 19 | 20 | if (pushA.length == 0) { 21 | return false; 22 | } 23 | 24 | LinkedList stack = new LinkedList<>(); 25 | 26 | int j = 0; 27 | for (int value : pushA) { 28 | stack.addLast(value); 29 | 30 | while (stack.peekLast() != null && popA[j] == stack.getLast()) { 31 | j++; 32 | stack.removeLast(); 33 | } 34 | } 35 | 36 | return stack.isEmpty(); 37 | } 38 | ``` 39 | -------------------------------------------------------------------------------- /offer/IsSymmetrical.md: -------------------------------------------------------------------------------- 1 | # 对称的二叉树 2 | 3 | ## 题目 4 | 5 | 请实现一个函数,用来判断一颗二叉树是不是对称的。注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的。 6 | 7 | ## 解题思路 8 | 9 | 1. 定义一个对称的前序遍历,即`root -> right -> left` 与普通的前序遍历进行对比 10 | 2. 相同则认为树是对称的 11 | 12 | ``` 13 | boolean isSymmetrical(TreeNode pRoot) { 14 | LinkedList scanner = new LinkedList<>(); 15 | LinkedList symmetricalScanner = new LinkedList<>(); 16 | 17 | preScanner(scanner, pRoot); 18 | symmetricalPreScanner(symmetricalScanner, pRoot); 19 | 20 | return scanner.equals(symmetricalScanner); 21 | } 22 | 23 | /** 24 | * 普通的前序遍历 25 | * @param res 26 | * @param root 27 | */ 28 | private void preScanner(LinkedList res, TreeNode root) { 29 | if (root == null) { 30 | res.addLast(null); 31 | return; 32 | } 33 | 34 | res.addLast(root.val); 35 | 36 | preScanner(res, root.left); 37 | preScanner(res, root.right); 38 | } 39 | 40 | /** 41 | * 先右再左的前序遍历 42 | * @param res 43 | * @param root 44 | */ 45 | private void symmetricalPreScanner(LinkedList res, TreeNode root) { 46 | if (root == null) { 47 | res.addLast(null); 48 | return; 49 | } 50 | 51 | res.addLast(root.val); 52 | 53 | symmetricalPreScanner(res, root.right); 54 | symmetricalPreScanner(res, root.left); 55 | } 56 | 57 | ``` 58 | -------------------------------------------------------------------------------- /offer/LastRemaining.md: -------------------------------------------------------------------------------- 1 | # 圆圈中最后剩下的数 2 | 3 | ## 题目 4 | 5 | [牛客网](https://www.nowcoder.com/practice/f78a359491e64a50bce2d89cff857eb6?tpId=13&tqId=11199&tPage=3&rp=2&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking) 6 | 7 | 每年六一儿童节,牛客都会准备一些小礼物去看望孤儿院的小朋友,今年亦是如此。HF 作为牛客的资深元老,自然也准备了一些小游戏。其中,有个游戏是这样的:首先,让小朋友们围成一个大圈。然后,他随机指定一个数m,让编号为0的小朋友开始报数。每次喊到m-1的那个小朋友要出列唱首歌,然后可以在礼品箱中任意的挑选礼物,并且不再回到圈中,从他的下一个小朋友开始,继续0...m-1报数....这样下去....直到剩下最后一个小朋友,可以不用表演,并且拿到牛客名贵的“名侦探柯南”典藏版。请你试着想下,哪个小朋友会得到这份礼品呢?(注:小朋友的编号是从 `0` 到 `n-1` ) 8 | 9 | ## 解题思路 10 | 11 | ### 模拟 12 | 13 | 最简单直接的解法,但是时间效率不够 14 | 15 | ``` 16 | public int LastRemaining_Solution(int n, int m) { 17 | if (n == 1) return 1; 18 | 19 | LinkedList data = new LinkedList<>(); 20 | for (int i = 0; i < n; i++) { 21 | data.addLast(i); 22 | } 23 | 24 | while (data.size() != 1) { 25 | for (int i = 0; i < m; i++) { 26 | Integer first = data.pollFirst(); 27 | 28 | if (i != m - 1) { 29 | data.addLast(first); 30 | } 31 | } 32 | } 33 | 34 | 35 | return data.pollFirst(); 36 | } 37 | ``` 38 | 39 | ### 通过数学推导的解法 40 | 41 | 时间效率和空间效率都很高,但是。。。没看懂 42 | 43 | $$ 44 | f(n,m)= 45 | \begin{cases} 46 | 0&n=1 \\ 47 | [f(n-1,m)+m]\%n & n>1 48 | \end{cases} 49 | $$ 50 | 51 | ``` 52 | public int LastRemaining_Solution(int n, int m) { 53 | if (n == 0) return -1; 54 | 55 | if (n == 1) return 0; 56 | 57 | int last = 0; 58 | for (int i = 2; i <= n; i++) { 59 | last = (last + m) % i; 60 | } 61 | 62 | return last; 63 | } 64 | ``` 65 | -------------------------------------------------------------------------------- /offer/LeftRotateString.md: -------------------------------------------------------------------------------- 1 | # 左旋转字符串 2 | 3 | ## 题目 4 | 5 | [牛客网](https://www.nowcoder.com/practice/12d959b108cb42b1ab72cef4d36af5ec?tpId=13&tqId=11196&tPage=3&rp=2&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking) 6 | 7 | 汇编语言中有一种移位指令叫做循环左移(ROL),现在有个简单的任务,就是用字符串模拟这个指令的运算结果。对于一个给定的字符序列S,请你把其循环左移K位后的序列输出。例如,字符序列`S=”abcXYZdef”`,要求输出循环左移3位后的结果,即`“XYZdefabc”`。是不是很简单?OK,搞定它! 8 | 9 | ## 解题思路 10 | 11 | 1. 对于 `abcXYZdef` 左移 3位,可以将字符串分为两个部分:`abc` & `XYZdef` 12 | 2. 分别将两个部分进行反转得到:`cba` & `fedZYX` 13 | 3. 将两部分和在一起再进行反转:`XYZdefabc` 14 | 15 | ``` 16 | public String LeftRotateString(String str, int n) { 17 | if (str == null || str.trim().equals("")) return str; 18 | 19 | String res = revert(str, 0, n - 1); 20 | res = revert(res, n, str.length() - 1); 21 | res = revert(res, 0, str.length() - 1); 22 | 23 | return res; 24 | } 25 | 26 | private String revert(String str, int start, int end) { 27 | char[] chars = str.toCharArray(); 28 | 29 | while (start < end) { 30 | char t = chars[start]; 31 | chars[start] = chars[end]; 32 | chars[end] = t; 33 | 34 | start++; 35 | end--; 36 | } 37 | 38 | return new String(chars); 39 | } 40 | ``` 41 | -------------------------------------------------------------------------------- /offer/LongestNoRepeatSubString.md: -------------------------------------------------------------------------------- 1 | # 最长不含重复字符的子字符串 2 | 3 | ## 题目 4 | 5 | [LeetCode](https://leetcode-cn.com/explore/interview/card/bytedance/242/string/1012/) 6 | 7 | 给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。 8 | 9 | ``` 10 | 输入: "abcabcbb" 11 | 输出: 3 12 | 解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。 13 | ``` 14 | 15 | ## 解题思路 16 | 17 | 1. 用 Map 记录字符所在位置,当遇到重复字符时,移动 `start` 指针 18 | 2. 替换 Map 中下标,并计算子串长度 19 | 20 | ``` 21 | public int longestNoRepeatSubString(String str) { 22 | if (str == null || str.length() == 0) return 0; 23 | 24 | HashMap temp = new HashMap<>(); 25 | char[] chars = str.toCharArray(); 26 | 27 | int res = 0, start = 0; 28 | for (int i = 0; i < chars.length; i++) { 29 | if (temp.containsKey(chars[i])) { 30 | start = Math.max(temp.put(chars[i], i) + 1, start); 31 | } 32 | 33 | temp.put(chars[i], i); 34 | res = Math.max(res, i - start + 1); 35 | } 36 | 37 | return res; 38 | } 39 | ``` 40 | -------------------------------------------------------------------------------- /offer/MaxGift.md: -------------------------------------------------------------------------------- 1 | # 礼物的最大值 2 | 3 | ## 题目 4 | 5 | 在一个 `m*n` 的棋盘中的每一个格都放一个礼物,每个礼物都有一定的价值(价值大于0).你可以从棋盘的左上角开始拿各种里的礼物,并每次向左或者向下移动一格,直到到达棋盘的右下角。给定一个棋盘及上面个的礼物,请计算你最多能拿走多少价值的礼物? 6 | 7 | 比如说现在有一个如下的棋盘: 8 | 9 | ![image](images/d59a892b85e600aecc22e2eca74d517f.png) 10 | 11 | 在这个棋盘中,按照`1,12,5,7,7,16,5`的顺序可以拿到总价值最大的礼物。 12 | 13 | ## 解题思路 14 | 15 | 1. 动态规划,定义 $$f(x,y)$$ 表示`x,y`点上能获取的最大数 16 | 2. 状态转移方程:$$f(x,y)=\max(f(x-1,y),f(x,y-1))+g(x,y)$$ 17 | 3. 可以考虑使用一维数组进行记录 18 | 19 | ``` 20 | public int maxGift(int[][] matrix) { 21 | for (int i = 0; i < matrix.length; i++) { 22 | for (int j = 0; j < matrix[i].length; j++) { 23 | int a = i > 0 ? matrix[i - 1][j] : 0; 24 | int b = j > 0 ? matrix[i][j - 1] : 0; 25 | 26 | matrix[i][j] += Math.max(a, b); 27 | } 28 | } 29 | 30 | System.out.println(Arrays.deepToString(matrix)); 31 | 32 | return matrix[matrix.length - 1][matrix[0].length - 1]; 33 | } 34 | ``` 35 | -------------------------------------------------------------------------------- /offer/MaxInWindows.md: -------------------------------------------------------------------------------- 1 | # 滑动窗口的最大值 2 | 3 | ## 题目 4 | 5 | [牛客网](https://www.nowcoder.com/practice/1624bc35a45c42c0bc17d17fa0cba788?tpId=13&tqId=11217&tPage=4&rp=2&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking) 6 | 7 | 给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。例如,如果输入数组`{2,3,4,2,6,2,5,1}`及滑动窗口的大小3,那么一共存在6个滑动窗口,他们的最大值分别为`{4,4,6,6,6,5}`; 针对数组{2,3,4,2,6,2,5,1}的滑动窗口有以下6个: `{[2,3,4],2,6,2,5,1}, {2,[3,4,2],6,2,5,1}, {2,3,[4,2,6],2,5,1}, {2,3,4,[2,6,2],5,1}, {2,3,4,2,[6,2,5],1}, {2,3,4,2,6,[2,5,1]}`。 8 | 9 | ## 解题思路 10 | 11 | 1. 使用一个队列来保存最大值和次大的值 12 | 13 | ``` 14 | public ArrayList maxInWindows(int[] num, int size) { 15 | ArrayList res = new ArrayList<>(); 16 | 17 | if (size == 0) return res; 18 | 19 | LinkedList queue = new LinkedList<>(); 20 | 21 | for (int i = 0; i < num.length; i++) { 22 | while (queue.peekFirst() != null && i - queue.peekFirst() >= size) { 23 | queue.removeFirst(); 24 | } 25 | 26 | while (queue.peekLast() != null && i - queue.peekLast() >= size) { 27 | queue.removeLast(); 28 | } 29 | 30 | if (queue.isEmpty()) { 31 | queue.addFirst(i); 32 | } else { 33 | if (num[i] > num[queue.peekFirst()]) { 34 | queue.clear(); 35 | queue.addFirst(i); 36 | } else { 37 | while (num[i] > num[queue.peekLast()]) { 38 | queue.removeLast(); 39 | } 40 | queue.addLast(i); 41 | } 42 | } 43 | 44 | if (i >= size - 1) res.add(num[queue.peekFirst()]); 45 | } 46 | 47 | return res; 48 | } 49 | ``` 50 | -------------------------------------------------------------------------------- /offer/MaxProfit.md: -------------------------------------------------------------------------------- 1 | # 股票的最大利润 2 | 3 | ## 题目 4 | 5 | 一只股票在某些时间节点的价格为`{9,11,8,5,7,12,16,14}`。如果我们能在价格为 5 的时候买入并在价格为 16 时卖出,则能获得最大的利润为 11. 6 | 7 | 8 | ## 解题思路 9 | 10 | 1. 要先买入才能卖出,先找最低价格点 11 | 2. 再找最低价格之后的最高价格,用 `maxProfit` 表示最大利润 12 | 13 | ``` 14 | public int maxProfit(int[] nums) { 15 | if (nums == null || nums.length == 0) return 0; 16 | 17 | int min = Integer.MAX_VALUE; 18 | int maxProfit = 0; 19 | for (int i = 0; i < nums.length; i++) { 20 | min = Math.min(min, nums[i]); 21 | 22 | maxProfit = Math.max(maxProfit, nums[i] - min); 23 | } 24 | 25 | return maxProfit; 26 | } 27 | ``` 28 | -------------------------------------------------------------------------------- /offer/MinStack.md: -------------------------------------------------------------------------------- 1 | # 包含min函数的栈 2 | 3 | ## 题目 4 | 5 | [牛客网](https://www.nowcoder.com/practice/4c776177d2c04c2494f2555c9fcc1e49?tpId=13&tqId=11173&rp=1&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking&tPage=1) 6 | 7 | 定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的 min 函数(时间复杂度应为O(1))。 8 | 9 | ## 解题思路 10 | 11 | 1. 通过增加最小栈来记录当前最小节点 12 | 13 | ``` 14 | private LinkedList stack = new LinkedList<>(); 15 | private LinkedList min = new LinkedList<>(); 16 | 17 | public void push(int node) { 18 | stack.addLast(node); 19 | 20 | if (min.isEmpty()) { 21 | min.addLast(node); 22 | return; 23 | } 24 | 25 | if (node < min.peekLast()) { 26 | min.addLast(node); 27 | } else { 28 | min.addLast(min.peekLast()); 29 | } 30 | } 31 | 32 | public void pop() { 33 | if (stack.isEmpty()) { 34 | return; 35 | } 36 | stack.removeLast(); 37 | min.removeLast(); 38 | } 39 | 40 | public int top() { 41 | if (stack.peekLast() == null) { 42 | return 0; 43 | } 44 | return stack.peekLast(); 45 | } 46 | 47 | public int min() { 48 | if (min.peekLast() == null) { 49 | return 0; 50 | } 51 | return min.peekLast(); 52 | } 53 | ``` 54 | -------------------------------------------------------------------------------- /offer/MovingCount.md: -------------------------------------------------------------------------------- 1 | # 机器人的运动范围 2 | 3 | ## 题目 4 | 5 | 地上有一个m行和n列的方格。一个机器人从坐标 `0,0` 的格子开始移动,每一次只能向左,右,上,下四个方向移动一格,但是不能进入行坐标和列坐标的数位之和大于k的格子。 例如,当k为 `18` 时,机器人能够进入方格`(35,37)`,因为`3+5+3+7 = 18`。但是,它不能进入方格`(35,38)`,因为`3+5+3+8 = 19`。请问该机器人能够达到多少个格子? 6 | 7 | ## 解题思路 8 | 9 | 10 | ``` 11 | 12 | ``` 13 | -------------------------------------------------------------------------------- /offer/NOfNumberSerialize.md: -------------------------------------------------------------------------------- 1 | # 数字序列中的某一位的数字 2 | 3 | ## 题目 4 | 5 | 数字以`0123456789101112131415…`的格式序列化到一个字符序列中。在这个序列中,第5位(从0开始计数,即从第0位开始)是5,第13位是1,第19位是4,等等。请写一个函数,求任意第n位对应的数字。 6 | 7 | ## 解题思路 8 | 9 | 1. 可以将 n 进行拆分,1位数一共10个数字、10位,2位数一共90个数字、180位,依此类推 10 | 2. 当确定 n 所在位数范围时,对位数取商,计算出 n 位对应的数字 a,再取余,计算出结果位于 a 的第几位 11 | 12 | ``` 13 | public int nOfNumberSerialize(int n) { 14 | int i = 1; 15 | int count = 0; 16 | int nLeft = n; 17 | 18 | while (true) { 19 | nLeft -= count; 20 | count = countOfIntegers(i) * i; 21 | 22 | if (nLeft < count) { 23 | break; 24 | } 25 | 26 | i++; 27 | } 28 | 29 | int a = nLeft / i; 30 | String s = String.valueOf(a); 31 | 32 | return s.charAt(nLeft % i) - '0'; 33 | } 34 | 35 | private int countOfIntegers(int n) { 36 | int sum = 0; 37 | 38 | if (n == 1) { 39 | sum = 10; 40 | } else { 41 | sum = (int) (9 * Math.pow(10, n - 1)); 42 | } 43 | 44 | return sum; 45 | } 46 | ``` 47 | -------------------------------------------------------------------------------- /offer/NumberOfOneBetweenOneAndN.md: -------------------------------------------------------------------------------- 1 | # 整数中1出现的次数(从1到n整数中1出现的次数) 2 | 3 | ## 题目 4 | 5 | [牛客网](https://www.nowcoder.com/practice/bd7f978302044eee894445e244c7eee6?tpId=13&tqId=11184&rp=1&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking&tPage=2) 6 | 7 | 求出`1~13`的整数中 1 出现的次数,并算出 `100~1300` 的整数中1出现的次数?为此他特别数了一下 `1~13` 中包含1的数字有 `1、10、11、12、13` 因此共出现 6 次,但是对于后面问题他就没辙了。ACMer 希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中1出现的次数(从1 到 n 中1出现的次数)。 8 | 9 | ## 解题思路 10 | 11 | 1. 假定 $$n=21345$$ 将数字分为首位和非首位两个部分 12 | 2. 对于首位为 1 的情况,如果首位 $$>1$$ 那么$$sum=sum+10^{len(n)-1}$$,如果首位 $$=1$$ 那么 $$sum=sum+1$$ 13 | 3. 对于非首位 1,指定其中一位为 1,根据排列组合有 $$10^{len(n)-2}\times(len(n)-1)$$ 个。那么非首位 1 总共有 $$2\times10^{len(n)-2}\times(len(n)-1)$$ 14 | 15 | ``` 16 | public int NumberOf1Between1AndN_Solution(int n) { 17 | int[] res = {0}; 18 | NumberOf1Between1AndN(res, n); 19 | 20 | return res[0]; 21 | } 22 | 23 | private void NumberOf1Between1AndN(int[] res, int n) { 24 | //假设 num=21345 25 | String num = String.valueOf(n); 26 | int firstNum = num.charAt(0) - '0'; 27 | 28 | if (num.length() == 1) { 29 | if (firstNum > 0) res[0]++; 30 | return; 31 | } 32 | 33 | String nextNum = num.substring(1); 34 | int nextN = Integer.valueOf(nextNum); 35 | 36 | //数字 10000 ~ 19999 的第一位中的个数 37 | if (firstNum > 1) { 38 | res[0] += Math.pow(10, num.length() - 1); 39 | } else if (firstNum == 1) { 40 | res[0] += nextN + 1; 41 | } 42 | 43 | //1346 ~ 21345 除第一位之外的数的个数 44 | res[0] += firstNum * (num.length() - 1) * Math.pow(10, num.length() - 2); 45 | 46 | NumberOf1Between1AndN(res, nextN); 47 | } 48 | ``` 49 | -------------------------------------------------------------------------------- /offer/O1DeleteNode.md: -------------------------------------------------------------------------------- 1 | # 在O(1)的时间复杂度下删除节点 2 | 3 | ## 题目 4 | 5 | 给定单向链表的头指针以及待删除的指针,定义一个函数在 O(1) 的时间复杂度下删除 6 | 7 | ## 解题思路 8 | 9 | 1. 待删除节点非尾节点,将后一个节点的值复制到当前节点,然后删除后一个节点 10 | 2. 待删除节点为尾节点,从头节点开始,找到待删除节点的前一个节点进行删除 11 | 12 | ``` 13 | public void O1DeleteNode(ListNode head, ListNode needDelete) { 14 | 15 | if (needDelete.next != null) { 16 | ListNode next = needDelete.next.next; 17 | needDelete.val = needDelete.next.val; 18 | needDelete.next = next; 19 | 20 | } else { 21 | ListNode cursor = head; 22 | 23 | while (cursor != null) { 24 | if (cursor.next == needDelete) break; 25 | 26 | cursor = cursor.next; 27 | } 28 | 29 | if (cursor == null) return; 30 | 31 | cursor.next = needDelete.next; 32 | } 33 | 34 | } 35 | ``` 36 | -------------------------------------------------------------------------------- /offer/PatternMatch.md: -------------------------------------------------------------------------------- 1 | # 正则表达式匹配 2 | 3 | 请实现一个函数用来匹配包括`'.'`和`'*'`的正则表达式。模式中的字符`'.'`表示任意一个字符,而`'*'`表示它前面的字符可以出现任意次(包含0次)。 在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串`"aaa"`与模式`"a.a"`和`"ab*ac*a"`匹配,但是与`"aa.a"`和`"ab*a"`均不匹配 4 | 5 | 6 | ## 解题思路 7 | 8 | 1. 对于 `*` 有三种匹配模式:匹配0次,1次以及多次 9 | 2. 对于 `.` 只有一种匹配模式 10 | 11 | ``` 12 | public boolean match(char[] str, char[] pattern) { 13 | if (str.length == 0 && new String(pattern).replaceAll(".\\*", "").length() == 0) { 14 | return true; 15 | } 16 | 17 | return match(str, 0, pattern, 0); 18 | } 19 | 20 | private boolean match(char[] str, int i, char[] pattern, int j) { 21 | if (i == str.length && j == pattern.length) { 22 | return true; 23 | } 24 | 25 | if (j >= pattern.length) return false; 26 | 27 | if (j + 1 < pattern.length && pattern[j + 1] == '*') { 28 | if ((i < str.length && pattern[j] == str[i]) || (pattern[j] == '.' && i != str.length)) { 29 | return match(str, i + 1, pattern, j + 2) 30 | || match(str, i + 1, pattern, j) 31 | || match(str, i, pattern, j + 2); 32 | } else { 33 | return match(str, i, pattern, j + 2); 34 | } 35 | } 36 | 37 | if ((i < str.length && pattern[j] == str[i]) 38 | || (pattern[j] == '.' && i != str.length)) { 39 | return match(str, i + 1, pattern, j + 1); 40 | } 41 | 42 | return false; 43 | } 44 | ``` 45 | -------------------------------------------------------------------------------- /offer/Permutation.md: -------------------------------------------------------------------------------- 1 | # 字符串的排列 2 | 3 | ## 题目 4 | 5 | [牛客网](https://www.nowcoder.com/practice/fe6b651b66ae47d7acce78ffdd9a96c7?tpId=13&tqId=11180&rp=1&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking&tPage=2) 6 | 7 | 8 | 输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。 9 | 10 | 输入描述:输入一个字符串,长度不超过9(可能有字符重复),字符只包括大小写字母。 11 | 12 | ## 解题思路 13 | 14 | 1. 将字符串划分为两个部分,第一个字符以及后面的其他字符 15 | 2. 将第一个字符和后面所有字符进行交换 16 | 17 | 对于 `abc` 这个字符串,计算出的排列顺序为: 18 | 19 | ``` 20 | abc 21 | acb 22 | bac 23 | bca 24 | cba 25 | cab 26 | ``` 27 | 28 | 代码: 29 | 30 | ``` 31 | public ArrayList Permutation(String str) { 32 | Set res = new HashSet<>(); 33 | 34 | if (str == null || str.length() == 0) { 35 | return new ArrayList<>(); 36 | } 37 | 38 | Permutation(res, str.toCharArray(), 0); 39 | 40 | ArrayList list = new ArrayList<>(res); 41 | 42 | list.sort(String::compareTo); 43 | return list; 44 | } 45 | 46 | private void Permutation(Set res, char[] chars, int start) { 47 | if (start == chars.length) { 48 | res.add(new String(chars)); 49 | return; 50 | } 51 | 52 | for (int i = start; i < chars.length; i++) { 53 | swap(chars, start, i); 54 | 55 | Permutation(res, chars, start + 1); 56 | 57 | swap(chars, start, i); 58 | } 59 | } 60 | 61 | private void swap(char[] chars, int i, int j) { 62 | char temp = chars[i]; 63 | chars[i] = chars[j]; 64 | chars[j] = temp; 65 | } 66 | ``` 67 | -------------------------------------------------------------------------------- /offer/PrintFromTopToBottom.md: -------------------------------------------------------------------------------- 1 | # 从上往下打印二叉树 2 | 3 | ## 题目 4 | 5 | [牛客网](https://www.nowcoder.com/practice/7fe2212963db4790b57431d9ed259701?tpId=13&tqId=11175&rp=1&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking&tPage=1) 6 | 7 | 从上往下打印出二叉树的每个节点,同层节点从左至右打印。 8 | 9 | 10 | ## 解题思路 11 | 12 | 1. 层次遍历,通过队列进行辅助遍历 13 | 14 | ``` 15 | public ArrayList PrintFromTopToBottom(TreeNode root) { 16 | ArrayList res = new ArrayList<>(); 17 | LinkedList nodeQueue = new LinkedList<>(); 18 | 19 | if (root == null) { 20 | return res; 21 | } 22 | 23 | nodeQueue.addLast(root); 24 | 25 | while (!nodeQueue.isEmpty()) { 26 | TreeNode node = nodeQueue.pollFirst(); 27 | if (node == null) { 28 | continue; 29 | } 30 | 31 | nodeQueue.addLast(node.left); 32 | nodeQueue.addLast(node.right); 33 | 34 | res.add(node.val); 35 | } 36 | 37 | return res; 38 | } 39 | ``` 40 | -------------------------------------------------------------------------------- /offer/PrintMinNumber.md: -------------------------------------------------------------------------------- 1 | # 把数组排成最小的数 2 | 3 | ## 题目 4 | 5 | [把数组排成最小的数](https://www.nowcoder.com/practice/8fecd3f8ba334add803bf2a06af1b993?tpId=13&tqId=11185&rp=1&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking&tPage=2) 6 | 7 | 输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。例如输入数组`{3,32,321}`,则打印出这三个数字能排成的最小数字为`321323`。 8 | 9 | ## 解题思路 10 | 11 | 1. 最直接的办法就是,找到数组中数字的所有排列组合,找到最小的 12 | 2. 对于 $$m, n$$,可以组成 $$mn , nm$$ 这两个数,如果 $$mn < nm$$ 那么,$$m$$ 应该在 $$n$$ 之前 13 | 3. 对于一组数,可以通过上述规则进行排序,依次打印出来就是最小的数 14 | 4. 由于组合之后的数可能超出 int 的表示范围,注意使用字符串来处理大数问题 15 | 16 | ``` 17 | public String PrintMinNumber(int[] numbers) { 18 | List nums = new ArrayList<>(); 19 | for (int number : numbers) { 20 | nums.add(String.valueOf(number)); 21 | } 22 | 23 | nums.sort(Comparator.comparing(s -> s, (o1, o2) -> (o1 + o2).compareTo(o2 + o1))); 24 | 25 | StringJoiner joiner = new StringJoiner(""); 26 | nums.forEach(joiner::add); 27 | 28 | return joiner.toString(); 29 | } 30 | ``` 31 | -------------------------------------------------------------------------------- /offer/README.md: -------------------------------------------------------------------------------- 1 | # 剑指Offer 2 | 3 | 包含 剑指Offer 一直 60 道算法题目 4 | 5 | ## 常用技巧 6 | 7 | 1. 异或运算 8 | 2. 删除链表节点时,可通过复制下一个节点的方式减少遍历 9 | 3. 保存计算结果来减少重复计算,优化时间效率 10 | 4. 分治的思想 11 | 5. 滑动窗口 12 | 6. 数学建模 13 | -------------------------------------------------------------------------------- /offer/ReverseSentence.md: -------------------------------------------------------------------------------- 1 | # 翻转单词顺序列 2 | 3 | ## 题目 4 | 5 | [牛客网](https://www.nowcoder.com/practice/3194a4f4cf814f63919d0790578d51f3?tpId=13&tqId=11197&tPage=3&rp=2&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking) 6 | 7 | 牛客最近来了一个新员工 `Fish` ,每天早晨总是会拿着一本英文杂志,写些句子在本子上。同事Cat对Fish写的内容颇感兴趣,有一天他向Fish借来翻看,但却读不懂它的意思。例如,“student. a am I”。后来才意识到,这家伙原来把句子单词的顺序翻转了,正确的句子应该是“I am a student.”。Cat对一一的翻转这些单词顺序可不在行,你能帮助他么? 8 | 9 | ## 解题思路 10 | 11 | 12 | 13 | ``` 14 | public String ReverseSentence(String str) { 15 | if(str == null || str.trim().equals("")) return str; 16 | 17 | String[] split = str.split(" "); 18 | 19 | StringBuilder builder = new StringBuilder(); 20 | for (int i = split.length - 1; i >= 0; i--) { 21 | builder.append(split[i]); 22 | 23 | if (i != 0) builder.append(" "); 24 | } 25 | 26 | return builder.toString(); 27 | } 28 | ``` 29 | -------------------------------------------------------------------------------- /offer/SerializeTree.md: -------------------------------------------------------------------------------- 1 | # 序列化二叉树 2 | 3 | ## 题目 4 | 5 | 请实现两个函数,分别用来序列化和反序列化二叉树 6 | 7 | ## 解题思路 8 | 9 | 1. 通过前序遍历,进行序列化和反序列化 10 | 2. 对于空节点用 `$` 来代替 11 | 12 | ``` 13 | String Serialize(TreeNode root) { 14 | if (root==null) return ""; 15 | 16 | LinkedList res = new LinkedList<>(); 17 | 18 | serialize(res, root); 19 | 20 | StringBuilder builder = new StringBuilder(); 21 | res.forEach(v-> builder.append(v).append(",")); 22 | 23 | return builder.toString(); 24 | } 25 | 26 | 27 | private void serialize(LinkedList res, TreeNode root) { 28 | if (root == null) { 29 | res.addLast("$"); 30 | return; 31 | } 32 | 33 | res.addLast(String.valueOf(root.val)); 34 | serialize(res, root.left); 35 | serialize(res, root.right); 36 | } 37 | 38 | TreeNode Deserialize(String str) { 39 | if (str == null || str.length() == 0) return null; 40 | 41 | return deserialize(str.split(","), new int[]{0}); 42 | } 43 | 44 | 45 | private TreeNode deserialize(String[] str, int[] index) { 46 | if (index[0] >= str.length) return null; 47 | 48 | String c = str[index[0]++]; 49 | if (c.equals("$")) return null; 50 | 51 | TreeNode node = new TreeNode(Integer.valueOf(c)); 52 | node.left = deserialize(str, index); 53 | node.right = deserialize(str, index); 54 | 55 | return node; 56 | } 57 | ``` 58 | -------------------------------------------------------------------------------- /offer/Singleton.md: -------------------------------------------------------------------------------- 1 | # 单例 2 | 3 | ## 题目 4 | 5 | 设计一个类,我们只能生成该类的一个实例 6 | 7 | ## 解题思路 8 | 9 | - 线程安全 10 | - 延迟加载 11 | - 序列化与反序列化安全 12 | 13 | ``` 14 | /** 15 | * 需要额外的工作(Serializable、transient、readResolve())来实现序列化,否则每次反序列化一个序列化的对象实例时都会创建一个新的实例。 16 | *

17 | * 可能会有人使用反射强行调用我们的私有构造器(如果要避免这种情况,可以修改构造器,让它在创建第二个实例的时候抛异常)。 18 | * 19 | * @author haoyang.shi 20 | */ 21 | public class Singleton { 22 | 23 | private Singleton() { 24 | } 25 | 26 | public static Singleton getInstance() { 27 | return Holder.instance; 28 | } 29 | 30 | private static final class Holder { 31 | private static Singleton instance = new Singleton(); 32 | } 33 | } 34 | 35 | /** 36 | * 使用枚举除了线程安全和防止反射强行调用构造器之外,还提供了自动序列化机制,防止反序列化的时候创建新的对象。 37 | *

38 | * 因此,Effective Java推荐尽可能地使用枚举来实现单例。 39 | */ 40 | enum SingletonEnum { 41 | INSTANCE; 42 | 43 | private String name; 44 | 45 | public String getName() { 46 | return name; 47 | } 48 | 49 | public void setName(String name) { 50 | this.name = name; 51 | } 52 | } 53 | ``` 54 | -------------------------------------------------------------------------------- /offer/StreamMid.md: -------------------------------------------------------------------------------- 1 | # 数据流中的中位数 2 | 3 | ## 题目 4 | 5 | [牛客网](https://www.nowcoder.com/practice/9be0172896bd43948f8a32fb954e1be1?tpId=13&tqId=11216&tPage=4&rp=2&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking) 6 | 7 | 如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。我们使用 `Insert()` 方法读取数据流,使用 `GetMedian()` 方法获取当前读取数据的中位数。 8 | 9 | 10 | ## 解题思路 11 | 12 | 1. 同两个堆来表示中位数的左右两部分,左边是大根堆,右边是小根堆 13 | 2. 在插入元素时,两边元素个数最多只能相差1,并且要保证左边的元素均小于右边的元素 14 | 3. 当插入大堆的元素大于部分小堆元素时,需要将大堆的 top 元素移动到小堆,反之亦然 15 | 16 | ``` 17 | private PriorityQueue maxHeap = new PriorityQueue<>((o1, o2) -> -o1.compareTo(o2)); 18 | 19 | private PriorityQueue minHeap = new PriorityQueue<>(); 20 | 21 | private int size = 0; 22 | 23 | 24 | public void Insert(Integer num) { 25 | if (size % 2 == 0) { 26 | maxHeap.add(num); 27 | 28 | if (minHeap.isEmpty() || num > minHeap.peek()) { 29 | minHeap.add(maxHeap.poll()); 30 | } 31 | 32 | } else { 33 | minHeap.add(num); 34 | 35 | if (maxHeap.isEmpty() || num < maxHeap.peek()) { 36 | maxHeap.add(minHeap.poll()); 37 | } 38 | } 39 | 40 | size++; 41 | } 42 | 43 | public Double GetMedian() { 44 | if (maxHeap.isEmpty() && minHeap.isEmpty()) return 0.0; 45 | if (maxHeap.isEmpty()) return minHeap.peek() * 1.0; 46 | if (minHeap.isEmpty()) return maxHeap.peek() * 1.0; 47 | 48 | if (maxHeap.size() == minHeap.size()) { 49 | return (maxHeap.peek() + minHeap.peek()) / 2.0; 50 | } 51 | 52 | return maxHeap.size() > minHeap.size() ? maxHeap.peek() * 1.0 : minHeap.peek() * 1.0; 53 | } 54 | ``` 55 | -------------------------------------------------------------------------------- /offer/SumOfNDice.md: -------------------------------------------------------------------------------- 1 | # n个骰子的点数 2 | 3 | ## 题目 4 | 5 | 把 n 个骰子扔在地上,所有骰子朝上一面的和为 s,输入 n,打印 s 所有可能值的概率 6 | 7 | ## 解题思路 8 | 9 | 1. 首先考虑一个骰子的情况,那么有 1~6 出现的次数均为 1 10 | 2. 再增加一个骰子时,由于各个点数出现的概率一致。用 $$f(n,s)=f(n-1,s-1)+f(n-1,s-2)+f(n-1,s-3)+f(n-1,s-4)+f(n-1,s-5)+f(n-1,s-6)$$ 11 | 3. 使用两个数组循环求解 12 | 13 | ``` 14 | public void SumOfNDice(int n) { 15 | if (n < 1) { 16 | return; 17 | } 18 | 19 | int[][] nums = new int[2][n * 6 + 1]; 20 | 21 | int flag = 0; 22 | 23 | //初始化第一个骰子各总和出现的次数 24 | int maxLen = nums[0].length; 25 | for (int i = 1; i < maxLen; i++) { 26 | nums[flag][i] = 1; 27 | } 28 | 29 | for (int i = 2; i <= n; i++) { 30 | int newFlag = flag ^ 0x01; 31 | Arrays.fill(nums[newFlag], 0); 32 | 33 | for (int j = i; j < maxLen; j++) { 34 | int sum = 0; 35 | 36 | for (int k = 1; k <= 6 && (j - k >= 0); k++) { 37 | sum += nums[flag][j - k]; 38 | } 39 | 40 | nums[newFlag][j] = sum; 41 | } 42 | flag = newFlag; 43 | } 44 | 45 | //debug out 46 | System.out.println(Arrays.toString(nums[flag])); 47 | 48 | int sum = 0; 49 | for (int i : nums[flag]) { 50 | sum += i; 51 | } 52 | 53 | for (int i = 0; i < nums[flag].length; i++) { 54 | System.out.println(i + ":" + nums[flag][i] * 1.0 / sum); 55 | } 56 | } 57 | ``` 58 | -------------------------------------------------------------------------------- /offer/TranslateNumToStr.md: -------------------------------------------------------------------------------- 1 | # 把数字翻译成字符串 2 | 3 | ## 题目 4 | 5 | 给定一个数字,按照如下规则翻译成字符串:0 翻译成“a”,`1` 翻译成`“b”`… `25`翻译成`“z”`。一个数字有多种翻译可能,例如`12258`一共有`5`种,分别是`bccfi`,`bwfi`,`bczi`,`mcfi`,`mzi`。实现一个函数,用来计算一个数字有多少种不同的翻译方法。 6 | 7 | ## 解题思路 8 | 9 | 1. 定义 $$f(i)$$ 表示第 `i` 位有多少种翻译的方法,动态规划方程:$$f(i)=f(i+1)+g(i,i+1) \times f(i+2)$$ 10 | 2. 其中 $$g(i,i+1)$$ 表示 `i,i+1` 是否能组成 `10 ~ 25` 11 | 12 | ``` 13 | public int translateNumToStr(int num) { 14 | char[] str = String.valueOf(num).toCharArray(); 15 | int[] res = new int[str.length]; 16 | 17 | for (int i = str.length - 1; i >= 0; i--) { 18 | if (i + 1 >= str.length) { 19 | res[i] = 1; 20 | continue; 21 | } 22 | 23 | res[i] = res[i + 1]; 24 | 25 | if (i + 2 < str.length && str[i] <= '2' && str[i] >= '1' && str[i + 1] <= '5') { 26 | res[i] += res[i + 2]; 27 | } 28 | } 29 | return res[0]; 30 | } 31 | ``` 32 | -------------------------------------------------------------------------------- /offer/TreeDepth.md: -------------------------------------------------------------------------------- 1 | # 二叉树的深度 2 | 3 | ## 题目 4 | 5 | [牛客网](https://www.nowcoder.com/practice/435fb86331474282a3499955f0a41e8b?tpId=13&tqId=11191&tPage=2&rp=2&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking) 6 | 7 | 输入一棵二叉树,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。 8 | 9 | ## 解题思路 10 | 11 | 1. 深度优先遍历 12 | 13 | ``` 14 | public int TreeDepth(TreeNode root) { 15 | int[] max = {0}; 16 | depth(root, max, 1); 17 | return max[0]; 18 | } 19 | 20 | private void depth(TreeNode root, int[] max, int curDepth) { 21 | if (root == null) return; 22 | 23 | if (curDepth > max[0]) max[0] = curDepth; 24 | 25 | depth(root.left, max, curDepth + 1); 26 | depth(root.right, max, curDepth + 1); 27 | } 28 | ``` 29 | -------------------------------------------------------------------------------- /offer/VerifySquenceOfBST.md: -------------------------------------------------------------------------------- 1 | # 二叉搜索树的后序遍历序列 2 | 3 | ## 题目 4 | 5 | [牛客网](https://www.nowcoder.com/practice/a861533d45854474ac791d90e447bafd?tpId=13&tqId=11176&rp=1&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking&tPage=1) 6 | 7 | 输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出 Yes ,否则输出 No 。假设输入的数组的任意两个数字都互不相同。 8 | 9 | ## 解题思路 10 | 11 | 1. 后序遍历中,最后一个节点为 root 节点 12 | 2. 由于 BST 的左子树都小于 root,右子树都大于 root,那么可以判定该节点是否为 BST 13 | 3. 依次类推,通过递归方式,再判定左右子树 14 | 15 | ``` 16 | public boolean VerifySquenceOfBST(int[] sequence) { 17 | if (sequence.length == 0) { 18 | return false; 19 | } 20 | 21 | if (sequence.length == 1) { 22 | return true; 23 | } 24 | 25 | return isBST(sequence, 0, sequence.length - 1); 26 | } 27 | 28 | private boolean isBST(int[] sequence, int start, int end) { 29 | if (start < 0 || end < 0 || start >= end) { 30 | return true; 31 | } 32 | 33 | int rootV = sequence[end]; 34 | int rightIndex = -1, rightV = Integer.MIN_VALUE; 35 | for (int i = start; i < end; i++) { 36 | if (rightV == Integer.MIN_VALUE && sequence[i] > rootV) { 37 | rightV = sequence[i]; 38 | rightIndex = i; 39 | continue; 40 | } 41 | 42 | if (rightV != Integer.MIN_VALUE && sequence[i] < rootV) { 43 | return false; 44 | } 45 | } 46 | 47 | return isBST(sequence, start, rightIndex - 1) && isBST(sequence, rightIndex, end - 1); 48 | } 49 | ``` 50 | -------------------------------------------------------------------------------- /offer/fibonacci.md: -------------------------------------------------------------------------------- 1 | # 斐波纳切数列 2 | 3 | ## 题目 4 | 5 | [牛客网](https://www.nowcoder.com/practice/c6c7742f5ba7442aada113136ddea0c3?tpId=13&tqId=11160&tPage=1&rp=1&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking) 6 | 7 | 大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项(从0开始,第0项为0)。`n<=39` 8 | 9 | 10 | ## 解题思路 11 | 12 | 1. 递归计算很慢,是最简单的算法 13 | 14 | ``` 15 | public int Fibonacci(int n) { 16 | if (n == 0) { 17 | return 0; 18 | } 19 | 20 | if (n == 1) { 21 | return 1; 22 | } 23 | 24 | int l = 1, ll = 0; 25 | 26 | for (int i = 2; i <= n; i++) { 27 | int t = ll + l; 28 | ll = l; 29 | l = t; 30 | } 31 | 32 | return l; 33 | } 34 | ``` 35 | -------------------------------------------------------------------------------- /offer/find-minimum-in-rotated-sorted-array.md: -------------------------------------------------------------------------------- 1 | # 旋转数组的最小数字 2 | 3 | ## 题目 4 | 5 | [牛客网](https://www.nowcoder.com/practice/9f3231a991af4f55b95579b44b7a01ba?tpId=13&tqId=11159&tPage=1&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking) 6 | 7 | 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。 输入一个非减排序的数组的一个旋转,输出旋转数组的最小元素。 例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。 NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。 8 | 9 | 10 | ## 解题思路 11 | 12 | 1. 旋转之后的数组存在两个上升序列,最小元素在两个上升序列的中间 13 | 2. 用两个指针在两个序列中找到最大和最小的值,这样 end 指向的数则为最小 14 | 15 | ``` 16 | public int minNumberInRotateArray(int[] array) { 17 | if (array.length == 0) { 18 | return 0; 19 | } 20 | 21 | int start = 0, end = array.length - 1; 22 | 23 | while (end - start != 1) { 24 | int mid = (start + end) / 2; 25 | if (array[mid] >= array[start]) { 26 | start = mid; 27 | } 28 | 29 | if (array[mid] <= array[end]) { 30 | end = mid; 31 | } 32 | } 33 | 34 | return array[end]; 35 | } 36 | ``` 37 | -------------------------------------------------------------------------------- /offer/images/07ce2975ccdf288110e897a00f76f43f.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/offer/images/07ce2975ccdf288110e897a00f76f43f.png -------------------------------------------------------------------------------- /offer/images/d59a892b85e600aecc22e2eca74d517f.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/offer/images/d59a892b85e600aecc22e2eca74d517f.png -------------------------------------------------------------------------------- /offer/isContinuous.md: -------------------------------------------------------------------------------- 1 | # 扑克牌顺子 2 | 3 | 4 | ## 题目 5 | 6 | [牛客网](https://www.nowcoder.com/practice/762836f4d43d43ca9deb273b3de8e1f4?tpId=13&tqId=11198&tPage=3&rp=2&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking) 7 | 8 | LL今天心情特别好,因为他去买了一副扑克牌,发现里面居然有 2 个大王, 2 个小王(一副牌原本是 `54` 张)...他随机从中抽出了 5 张牌,想测测自己的手气,看看能不能抽到顺子,如果抽到的话,他决定去买体育彩票,嘿嘿!!“`红心A,黑桃3,小王,大王,方片5`”,“Oh My God!”不是顺子.....LL不高兴了,他想了想,决定大\小 王可以看成任何数字,并且`A看作1,J为11,Q为12,K为13`。上面的5张牌就可以变成“`1,2,3,4,5`”(大小王分别看作2和4),“So Lucky!”。LL决定去买体育彩票啦。 现在,要求你使用这幅牌模拟上面的过程,然后告诉我们 LL 的运气如何, 如果牌能组成顺子就输出 true,否则就输出 false。为了方便起见,你可以认为大小王是0。 9 | 10 | ## 解题思路 11 | 12 | 1. 对数组进行排序 13 | 2. 计算非0元素之间的间隔总和 14 | 3. 如果有相同元素则直接认为失败 15 | 4. 如果间隔大于0,那么间隔的总个数等于0的总个数,即为成功 16 | 17 | ``` 18 | public boolean isContinuous(int[] numbers) { 19 | if (numbers == null || numbers.length < 5) return false; 20 | 21 | Arrays.sort(numbers); 22 | 23 | int count = 0; 24 | int zeroCount = 0; 25 | int pre = -1; 26 | for (int number : numbers) { 27 | if (number == 0) { 28 | zeroCount++; 29 | continue; 30 | } 31 | 32 | if (pre == -1) pre = number; 33 | else { 34 | int t = number - pre - 1; 35 | if (t > 0) { 36 | count += t; 37 | } else if (t < 0) return false; 38 | 39 | pre = number; 40 | } 41 | } 42 | 43 | if (count == 0) return true; 44 | else return count == zeroCount; 45 | } 46 | ``` 47 | -------------------------------------------------------------------------------- /offer/merge-sort-link.md: -------------------------------------------------------------------------------- 1 | # 合并两个排序的链表 2 | 3 | ## 题目 4 | 5 | [牛客网](https://www.nowcoder.com/practice/d8b6b4358f774294a89de2a6ac4d9337?tpId=13&tqId=11169&rp=1&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking&tPage=1) 6 | 7 | 输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。 8 | 9 | ## 解题思路 10 | 11 | 1. 双指针指向两个链表 12 | 2. 循环选取最小值,加入结果集 13 | 14 | ``` 15 | public ListNode Merge(ListNode list1, ListNode list2) { 16 | ListNode head = new ListNode(-1); 17 | ListNode cursor = head; 18 | 19 | while (list1 != null || list2 != null) { 20 | if (list1 == null) { 21 | while (list2 != null) { 22 | cursor.next = list2; 23 | cursor = cursor.next; 24 | list2 = list2.next; 25 | } 26 | 27 | continue; 28 | } 29 | 30 | if (list2 == null) { 31 | while (list1 != null) { 32 | cursor.next = list1; 33 | cursor = cursor.next; 34 | list1 = list1.next; 35 | } 36 | 37 | continue; 38 | } 39 | 40 | if (list1.val < list2.val) { 41 | cursor.next = list1; 42 | cursor = cursor.next; 43 | 44 | list1 = list1.next; 45 | } else { 46 | cursor.next = list2; 47 | cursor = cursor.next; 48 | 49 | list2 = list2.next; 50 | } 51 | } 52 | 53 | return head.next; 54 | } 55 | ``` 56 | -------------------------------------------------------------------------------- /offer/mirror-tree.md: -------------------------------------------------------------------------------- 1 | # 镜像二叉树 2 | 3 | ## 题目 4 | 5 | [镜像二叉树](https://www.nowcoder.com/practice/564f4c26aa584921bc75623e48ca3011?tpId=13&tqId=11171&rp=1&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking&tPage=1) 6 | 7 | 操作给定的二叉树,将其变换为源二叉树的镜像。 8 | 9 | 输入描述: 10 | 11 | ``` 12 | 二叉树的镜像定义:源二叉树 13 | 8 14 | / \ 15 | 6 10 16 | / \ / \ 17 | 5 7 9 11 18 | 镜像二叉树 19 | 8 20 | / \ 21 | 10 6 22 | / \ / \ 23 | 11 9 7 5 24 | ``` 25 | 26 | ## 解题思路 27 | 28 | 1. 从上到下进行左右节点交换 29 | 30 | ``` 31 | public void Mirror(TreeNode root) { 32 | if (root == null) return; 33 | 34 | TreeNode temp = root.left; 35 | root.left = root.right; 36 | root.right = temp; 37 | 38 | Mirror(root.left); 39 | Mirror(root.right); 40 | } 41 | ``` 42 | -------------------------------------------------------------------------------- /offer/number-of-one.md: -------------------------------------------------------------------------------- 1 | # 二进制中1的个数 2 | 3 | ## 题目 4 | 5 | [](https://www.nowcoder.com/practice/8ee967e43c2c4ec193b040ea7fbb10b8?tpId=13&tqId=11164&rp=1&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking&tPage=1) 6 | 7 | 输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。 8 | 9 | ## 解题思路 10 | 11 | 1. 负数是补码表示 12 | 2. `>>>` 为无符号右移,`>>`为有符号右移,当 n 为负数是会增加多余的`1` 13 | 14 | ``` 15 | public int NumberOf1(int n) { 16 | int mask = 0x01; 17 | 18 | int res = 0; 19 | int t = n; 20 | while (t != 0) { 21 | if ((t & mask) == 1) { 22 | res++; 23 | } 24 | t = t >>> 1; 25 | } 26 | 27 | return res; 28 | } 29 | ``` 30 | -------------------------------------------------------------------------------- /offer/power.md: -------------------------------------------------------------------------------- 1 | ## 题目 2 | 3 | [牛客网](https://www.nowcoder.com/practice/1a834e5e3e1a4b7ba251417554e07c00?tpId=13&tqId=11165&tPage=1&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking) 4 | 5 | 给定一个 `double` 类型的浮点数 `base` 和 `int` 类型的整数 `exponent` 。求 `base` 的 `exponent` 次方。 6 | 7 | ## 解题思路 8 | 9 | 1. 当 `n` 为偶数时,$$a^n = a^{n/2} * a^{n/2}$$ 10 | 2. 当 `n` 为奇数时,$$a^n = a^{n/2} * a^{n/2} * a$$ 11 | 3. 可以利用类似斐波纳切的方式,利用递归来进行求解 12 | 13 | ``` 14 | public double Power(double base, int exponent) { 15 | if (base == 0) { 16 | return 0; 17 | } 18 | 19 | if (base == 1) { 20 | return 1; 21 | } 22 | 23 | int t_exponent = Math.abs(exponent); 24 | 25 | double t = PositivePower(base, t_exponent); 26 | 27 | return exponent > 0 ? t : 1 / t; 28 | } 29 | 30 | private double PositivePower(double base, int exponent) { 31 | if (exponent == 0) { 32 | return 1; 33 | } 34 | 35 | if (exponent == 1) { 36 | return base; 37 | } 38 | 39 | double t = PositivePower(base, exponent >> 1); 40 | t *= t; 41 | if ((exponent & 0x01) == 1) { 42 | t *= base; 43 | } 44 | 45 | return t; 46 | } 47 | ``` 48 | -------------------------------------------------------------------------------- /offer/print-link-from-tail.md: -------------------------------------------------------------------------------- 1 | # 从尾到头打印链表 2 | 3 | ## 题目 4 | 5 | [牛客网](https://www.nowcoder.com/practice/d0267f7f55b3412ba93bd35cfa8e8035?tpId=13&tqId=11156&tPage=1&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking) 6 | 7 | 输入一个链表,按链表值从尾到头的顺序返回一个ArrayList。 8 | 9 | ## 解题思路 10 | 11 | 1. 栈 12 | 13 | ``` 14 | public ArrayList printListFromTailToHead(ListNode listNode) { 15 | LinkedList stack = new LinkedList<>(); 16 | 17 | while (listNode != null) { 18 | stack.addLast(listNode.val); 19 | listNode = listNode.next; 20 | } 21 | 22 | ArrayList res = new ArrayList<>(); 23 | 24 | while (!stack.isEmpty()) { 25 | res.add(stack.pollLast()); 26 | } 27 | 28 | return res; 29 | } 30 | ``` 31 | 32 | 2. 递归:当链表过长时,会导致栈溢出 33 | 34 | ``` 35 | public ArrayList printListFromTailToHead(ListNode listNode) { 36 | ArrayList res = new ArrayList<>(); 37 | 38 | print(res,listNode); 39 | 40 | return res; 41 | } 42 | 43 | private void print(ArrayList res, ListNode listNode) { 44 | if (listNode == null) return; 45 | 46 | print(res, listNode.next); 47 | 48 | res.add(listNode.val); 49 | } 50 | ``` 51 | -------------------------------------------------------------------------------- /offer/printn.md: -------------------------------------------------------------------------------- 1 | # 打印最大的 n 位数 2 | 3 | 输入n,打印出 1 到最大的 n 位十进制数。比如输入3,则打印出1、2、3 直到最大的 3 位数 999。 4 | 5 | ## 解题思路 6 | 7 | 1. n 可能很大,导致输出的数字超过 int 或者 long 8 | 9 | ``` 10 | public void PrintN(int n) { 11 | if (n <= 0) { 12 | return; 13 | } 14 | 15 | String res = "0"; 16 | 17 | while (true) { 18 | boolean all9 = true; 19 | 20 | res = Plus(res, 1); 21 | System.out.println(res); 22 | 23 | for (int i = 0; i < res.length(); i++) { 24 | if (res.charAt(i) != '9') { 25 | all9 = false; 26 | break; 27 | } 28 | } 29 | 30 | if (all9 && res.length() == n) { 31 | break; 32 | } 33 | } 34 | } 35 | 36 | private String Plus(String t, int i) { 37 | char[] chars = t.toCharArray(); 38 | StringBuilder res = new StringBuilder(); 39 | chars[chars.length - 1] += i; 40 | 41 | boolean flag = false; 42 | for (int j = chars.length - 1; j >= 0; j--) { 43 | int a = chars[j]; 44 | if (flag) { 45 | a++; 46 | flag = false; 47 | } 48 | 49 | if (a > '9') { 50 | flag = true; 51 | a = a - '9' + '0' - 1; 52 | } 53 | 54 | res.append((char) a); 55 | } 56 | if (flag) { 57 | res.append('1'); 58 | } 59 | 60 | return res.reverse().toString(); 61 | } 62 | ``` 63 | -------------------------------------------------------------------------------- /offer/reConstructBinaryTree.md: -------------------------------------------------------------------------------- 1 | # 重建二叉树 2 | 3 | [](https://www.nowcoder.com/practice/8a19cbe657394eeaac2f6ea9b0f6fcf6?tpId=13&tqId=11157&tPage=1&rp=1&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking) 4 | 5 | 输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列`{1,2,4,7,3,5,6,8}`和中序遍历序列`{4,7,2,1,5,3,8,6}`,则重建二叉树并返回。 6 | 7 | ## 解题思路 8 | 9 | 1. 通过前序遍历找到 root 节点 10 | 2. 那么在 中序遍历中 root 节点的左侧则是左子树,右侧是右子树 11 | 3. 依次类推,递归生成节点的左子树和右子树 12 | 4. 构建过程由下往上 13 | 14 | ``` 15 | public TreeNode reConstructBinaryTree(int[] pre, int[] in) { 16 | Map preIndex = new HashMap<>(); 17 | for (int i = 0; i < pre.length; i++) { 18 | preIndex.put(pre[i], i); 19 | } 20 | 21 | return buildTree(preIndex, in, 0, in.length - 1); 22 | } 23 | 24 | private TreeNode buildTree(Map preIndex, int[] in, int start, int end) { 25 | if (start == end) { 26 | return new TreeNode(in[start]); 27 | } 28 | int indexOfRoot = start; 29 | for (int i = start; i <= end; i++) { 30 | if (preIndex.get(in[i]) < preIndex.get(in[indexOfRoot])) { 31 | indexOfRoot = i; 32 | } 33 | } 34 | TreeNode root = new TreeNode(in[indexOfRoot]); 35 | if (start <= indexOfRoot - 1) root.left = buildTree(preIndex, in, start, indexOfRoot - 1); 36 | if (indexOfRoot + 1 <= end) root.right = buildTree(preIndex, in, indexOfRoot + 1, end); 37 | return root; 38 | } 39 | ``` 40 | -------------------------------------------------------------------------------- /offer/reOrderArray.md: -------------------------------------------------------------------------------- 1 | # 调整数组顺序使奇数位于偶数前面 2 | 3 | ## 题目 4 | 5 | [牛客网](https://www.nowcoder.com/practice/beb5aa231adc45b2a5dcc5b62c93f593?tpId=13&tqId=11166&tPage=1&rp=2&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking 6 | ) 7 | 8 | 输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。 9 | 10 | 11 | ## 解题思路 12 | 13 | 1. 需要保证排序的稳定性 14 | 2. 采用冒泡算法进行排序 15 | 16 | ``` 17 | public void reOrderArray(int[] array) { 18 | if (array.length <= 1) { 19 | return; 20 | } 21 | 22 | for (int i = array.length - 1; i >= 0; i--) { 23 | for (int j = i; j < array.length - 1; j++) { 24 | if (array[j] % 2 == 0 && array[j + 1] % 2 == 1) swap(array, j, j + 1); 25 | } 26 | } 27 | } 28 | 29 | private void swap(int[] array, int a, int b) { 30 | int t = array[a]; 31 | array[a] = array[b]; 32 | array[b] = t; 33 | } 34 | ``` 35 | -------------------------------------------------------------------------------- /offer/replay-space.md: -------------------------------------------------------------------------------- 1 | # 替换空格 2 | 3 | ## 题目 4 | 5 | [牛客网](https://www.nowcoder.com/questionTerminal/4060ac7e3e404ad1a894ef3e17650423) 6 | 7 | 请实现一个函数,将一个字符串中的每个空格替换成`“%20”`。例如,当字符串为`We Are Happy.`则经过替换之后的字符串为 `We%20Are%20Happy`。 8 | 9 | ## 解题思路 10 | 11 | 1. 通过字符串中空格的个数,计算新字符串长度 12 | 2. 两个指针进行字符串拷贝,当遇到`‘ ’`时替换为 `%20` 13 | 14 | ``` 15 | public String replaceSpace(StringBuffer str) { 16 | char[] chars = str.toString().toCharArray(); 17 | StringBuilder res = new StringBuilder(); 18 | for (char c : chars) { 19 | if (c == ' ') res.append("%20"); 20 | else res.append(c); 21 | } 22 | return res.toString(); 23 | } 24 | ``` 25 | -------------------------------------------------------------------------------- /offer/revert-link.md: -------------------------------------------------------------------------------- 1 | # 反转链表 2 | 3 | ## 题目 4 | 5 | [牛客网](https://www.nowcoder.com/practice/75e878df47f24fdc9dc3e400ec6058ca?tpId=13&tqId=11168&rp=1&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking&tPage=1) 6 | 7 | 输入一个链表,反转链表后,输出新链表的表头。 8 | 9 | ## 解题思路 10 | 11 | 1. 三个指针 12 | 13 | ``` 14 | public ListNode ReverseList(ListNode head) { 15 | if (head == null || head.next == null) { 16 | return head; 17 | } 18 | 19 | ListNode pre = head, cur = head.next, next; 20 | pre.next = null; 21 | 22 | while (cur != null) { 23 | next = cur.next; 24 | cur.next = pre; 25 | 26 | pre = cur; 27 | cur = next; 28 | } 29 | 30 | return pre; 31 | } 32 | ``` 33 | -------------------------------------------------------------------------------- /offer/search-a-2d-matrix.md: -------------------------------------------------------------------------------- 1 | # 搜索二维矩阵 2 | 3 | ## 题目 4 | 5 | [Leetcode](https://leetcode-cn.com/problems/search-a-2d-matrix-ii/) 6 | 7 | 编写一个高效的算法来搜索 m x n 矩阵 matrix 中的一个目标值 target。该矩阵具有以下特性: 8 | 9 | - 每行的元素从左到右升序排列。 10 | - 每列的元素从上到下升序排列。 11 | 12 | 示例: 13 | 14 | 现有矩阵 matrix 如下: 15 | 16 | ``` 17 | [ 18 | [1, 4, 7, 11, 15], 19 | [2, 5, 8, 12, 19], 20 | [3, 6, 9, 16, 22], 21 | [10, 13, 14, 17, 24], 22 | [18, 21, 23, 26, 30] 23 | ] 24 | ``` 25 | 26 | - 给定 target = 5,返回 true。 27 | - 给定 target = 20,返回 false。 28 | 29 | ## 解题思路 30 | 31 | 二维数组是有规律的:**右上角的数字是一列中最小的、一行中最大的**,通过这个数字和 target 进行对比,可以将一行或者一列作为候选区域排出,那么 target 可能存在的范围缩小,最终得出结果。 32 | 33 | ``` 34 | public boolean searchMatrix(int[][] matrix, int target) { 35 | if (matrix.length == 0) { 36 | return false; 37 | } 38 | 39 | for (int i = 0, j = matrix[0].length - 1; i < matrix.length && j >= 0; ) { 40 | if (matrix[i][j] > target) { 41 | j--; 42 | } else if (matrix[i][j] < target) { 43 | i++; 44 | } else { 45 | return true; 46 | } 47 | } 48 | 49 | return false; 50 | } 51 | ``` 52 | -------------------------------------------------------------------------------- /offer/sum.md: -------------------------------------------------------------------------------- 1 | # 求1+2+3+...+n 2 | 3 | ## 题目 4 | 5 | [牛客网](https://www.nowcoder.com/practice/7a0da8fc483247ff8800059e12d7caf1?tpId=13&tqId=11200&tPage=3&rp=2&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking) 6 | 7 | 求1+2+3+...+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。 8 | 9 | ## 解题思路 10 | 11 | 1. 利用递归代替循环 12 | 13 | ``` 14 | public int Sum_Solution(int n) { 15 | int ans = n; 16 | boolean t = ((ans != 0) && ((ans += Sum_Solution(n - 1)) != 0)); 17 | return ans; 18 | } 19 | ``` 20 | -------------------------------------------------------------------------------- /offer/two-stack-fifo.md: -------------------------------------------------------------------------------- 1 | # 用两个栈实现一个队列 2 | 3 | ## 题目 4 | 5 | [牛客网](https://www.nowcoder.com/practice/54275ddae22f475981afa2244dd448c6?tpId=13&tqId=11158&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking) 6 | 7 | 用两个栈来实现一个队列,完成队列的 Push 和 Pop 操作。 队列中的元素为int类型。 8 | 9 | 10 | ## 解题思路 11 | 12 | 1. 用 stack1 作为 push 队列,将元素 push 到 stack1 13 | 2. 用 stack2 作为 pop 队列,当 stack2 为空时则将 stack1 的数据 push 到 stack2,否则直接 pop stack2 14 | 15 | 相当于将两个 stack 拼接:-> stack1 <::> stack2 -> 16 | 17 | ``` 18 | Stack pushStack = new Stack<>(); 19 | Stack popStack = new Stack<>(); 20 | 21 | public void push(int node) { 22 | pushStack.push(node); 23 | } 24 | 25 | public int pop() { 26 | if (popStack.isEmpty()) { 27 | while (!pushStack.isEmpty()) { 28 | popStack.push(pushStack.pop()); 29 | } 30 | } 31 | if (popStack.isEmpty()) return -1; 32 | else return popStack.pop(); 33 | } 34 | ``` 35 | -------------------------------------------------------------------------------- /study/java/art/ART虚拟机:ART虚拟机概述.md: -------------------------------------------------------------------------------- 1 | # ART虚拟机:OAT文件的加载流程 2 | 3 | 作者:[涂程]() 4 | 5 | 校对:[David]() 6 | 7 | 文章状态:编辑中 8 | 9 | **关于项目** 10 | 11 | > [AndroidInterView]()项目旨在通过提供一系列最新的Android高级面试题,最顶尖的行业干货。降低面试Android岗位的门槛,让更多的Android工程师理解Android系统,掌握Android系统。 12 | 13 | **文章目录** 14 | 15 | 16 | 17 | 文章正文 18 | 19 | 20 | 21 | > 本篇文章到这里就结束了,欢迎关注我们的AndroidInterView微信公众平台,AndroidInterView致力于分享Android系统源码的设计与实现相关文章,也欢迎开源爱好者参与到AndroidInterView项目中来。 22 | 23 | 24 | 25 | ##### 后续持续更新中,添加QQ群:4112676, 备注github 26 | 27 | ##### 加微信号,获取Android 2019年面试视频。发送"面试 "即可领取 另附企业内推,架构设计资料,相关视频资料 28 | 29 | 微信号 30 | 31 | [![image](E:/CSDN%E5%AD%A6%E9%99%A2/Github%E7%BB%84%E7%BB%87%E5%8F%B7/img/img.jpg)]( -------------------------------------------------------------------------------- /study/java/art/ART虚拟机:OAT文件的加载流程.md: -------------------------------------------------------------------------------- 1 | # ART虚拟机:OAT文件的加载流程 2 | 3 | 作者:[涂程]() 4 | 5 | 校对:[David]() 6 | 7 | 文章状态:编辑中 8 | 9 | **关于项目** 10 | 11 | > [AndroidInterView]()项目旨在通过提供一系列最新的Android高级面试题,最顶尖的行业干货。降低面试Android岗位的门槛,让更多的Android工程师理解Android系统,掌握Android系统。 12 | 13 | **文章目录** 14 | 15 | 16 | 17 | 文章正文 18 | 19 | 20 | 21 | > 本篇文章到这里就结束了,欢迎关注我们的AndroidInterView微信公众平台,AndroidInterView致力于分享Android系统源码的设计与实现相关文章,也欢迎开源爱好者参与到AndroidInterView项目中来。 22 | 23 | 24 | 25 | ##### 后续持续更新中,添加QQ群:4112676, 备注github 26 | 27 | ##### 加微信号,获取Android 2019年面试视频。发送"面试 "即可领取 另附企业内推,架构设计资料,相关视频资料 28 | 29 | 微信号 30 | 31 | [![image](E:/CSDN%E5%AD%A6%E9%99%A2/Github%E7%BB%84%E7%BB%87%E5%8F%B7/img/img.jpg)]( -------------------------------------------------------------------------------- /study/java/art/ART虚拟机:垃圾收集.md: -------------------------------------------------------------------------------- 1 | # ART虚拟机:垃圾收集 2 | 3 | # ART虚拟机:OAT文件的加载流程 4 | 5 | 作者:[涂程]() 6 | 7 | 校对:[David]() 8 | 9 | 文章状态:编辑中 10 | 11 | **关于项目** 12 | 13 | > [AndroidInterView]()项目旨在通过提供一系列最新的Android高级面试题,最顶尖的行业干货。降低面试Android岗位的门槛,让更多的Android工程师理解Android系统,掌握Android系统。 14 | 15 | **文章目录** 16 | 17 | 18 | 19 | 文章正文 20 | 21 | 22 | 23 | > 本篇文章到这里就结束了,欢迎关注我们的AndroidInterView微信公众平台,AndroidInterView致力于分享Android系统源码的设计与实现相关文章,也欢迎开源爱好者参与到AndroidInterView项目中来。 24 | 25 | 26 | 27 | ##### 后续持续更新中,添加QQ群:4112676, 备注github 28 | 29 | ##### 加微信号,获取Android 2019年面试视频。发送"面试 "即可领取 另附企业内推,架构设计资料,相关视频资料 30 | 31 | 微信号 32 | 33 | [![image](E:/CSDN%E5%AD%A6%E9%99%A2/Github%E7%BB%84%E7%BB%87%E5%8F%B7/img/img.jpg)]( -------------------------------------------------------------------------------- /study/java/art/ART虚拟机:机器指令的查找流程.md: -------------------------------------------------------------------------------- 1 | # ART虚拟机:机器指令的查找流程 2 | 3 | # ART虚拟机:OAT文件的加载流程 4 | 5 | 作者:[涂程]() 6 | 7 | 校对:[David]() 8 | 9 | 文章状态:编辑中 10 | 11 | **关于项目** 12 | 13 | > [AndroidInterView]()项目旨在通过提供一系列最新的Android高级面试题,最顶尖的行业干货。降低面试Android岗位的门槛,让更多的Android工程师理解Android系统,掌握Android系统。 14 | 15 | **文章目录** 16 | 17 | 18 | 19 | 文章正文 20 | 21 | 22 | 23 | > 本篇文章到这里就结束了,欢迎关注我们的AndroidInterView微信公众平台,AndroidInterView致力于分享Android系统源码的设计与实现相关文章,也欢迎开源爱好者参与到AndroidInterView项目中来。 24 | 25 | 26 | 27 | ##### 后续持续更新中,添加QQ群:4112676, 备注github 28 | 29 | ##### 加微信号,获取Android 2019年面试视频。发送"面试 "即可领取 另附企业内推,架构设计资料,相关视频资料 30 | 31 | 微信号 32 | 33 | [![image](E:/CSDN%E5%AD%A6%E9%99%A2/Github%E7%BB%84%E7%BB%87%E5%8F%B7/img/img.jpg)]( -------------------------------------------------------------------------------- /study/java/art/ART虚拟机:类与方法的查找流程.md: -------------------------------------------------------------------------------- 1 | # ART虚拟机:类与方法的查找流程 2 | 3 | # ART虚拟机:OAT文件的加载流程 4 | 5 | 作者:[涂程]() 6 | 7 | 校对:[David]() 8 | 9 | 文章状态:编辑中 10 | 11 | **关于项目** 12 | 13 | > [AndroidInterView]()项目旨在通过提供一系列最新的Android高级面试题,最顶尖的行业干货。降低面试Android岗位的门槛,让更多的Android工程师理解Android系统,掌握Android系统。 14 | 15 | **文章目录** 16 | 17 | 18 | 19 | 文章正文 20 | 21 | 22 | 23 | > 本篇文章到这里就结束了,欢迎关注我们的AndroidInterView微信公众平台,AndroidInterView致力于分享Android系统源码的设计与实现相关文章,也欢迎开源爱好者参与到AndroidInterView项目中来。 24 | 25 | 26 | 27 | ##### 后续持续更新中,添加QQ群:4112676, 备注github 28 | 29 | ##### 加微信号,获取Android 2019年面试视频。发送"面试 "即可领取 另附企业内推,架构设计资料,相关视频资料 30 | 31 | 微信号 32 | 33 | [![image](E:/CSDN%E5%AD%A6%E9%99%A2/Github%E7%BB%84%E7%BB%87%E5%8F%B7/img/img.jpg)]( -------------------------------------------------------------------------------- /tencent/img/4758234-70cc79184055aedb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/tencent/img/4758234-70cc79184055aedb.png -------------------------------------------------------------------------------- /tencent/img/4758234-7b0707c5a07f0bc1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/tencent/img/4758234-7b0707c5a07f0bc1.png -------------------------------------------------------------------------------- /tencent/img/4758234-9e2b054d0907c188.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/tencent/img/4758234-9e2b054d0907c188.png -------------------------------------------------------------------------------- /tencent/img/4758234-eba2d00b4718cf19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/tencent/img/4758234-eba2d00b4718cf19.png -------------------------------------------------------------------------------- /tencent/img/4758234-ee5027bfe92f6515.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/tencent/img/4758234-ee5027bfe92f6515.png -------------------------------------------------------------------------------- /音视频副本.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiangjiana/Android-MS/0e5f680e49d8640837a5405cd20bc4a04094453f/音视频副本.png --------------------------------------------------------------------------------