【YAHOOWY】IT面试题集锦

原文地址:【YAHOOWY】IT面试题集锦 作者:雅虎007
面试之前-准备技术面试

如何准备技术面试

You’ve purchased this book, so you’ve already gone a long way towards good preparation Nice work!

你已经在看本书了,你在面试的道路上已经跨出了一大步了。加油!

That said, there are better and worse ways to prepare Many candidates just read through problems and solutions Don’t do that! Memorizing or trying to learn specific questions won’t help you! Rather, do this:

准备技术面试的方法有好有坏。有些读者看完问题之后直接翻答案。千万别这么做。死记硬背或者敲代码是没有什么用的。更好的方法是这样做:

1 Try to solve the problem on your own I mean, really try to solve it Many questions are designed to be tough - that’s ok! When you’re solving a problem, make sure to think about the space and time efficiency Ask yourself if you could improve the time efficiency by reducing the space efficiency, or vice versa

    1 尝试用自己的方法来解决这个问题。全凭自己的方法。有些问题确实很难,不过没关系。在解决了问题之后一定要考虑下时间和空间复杂度。推敲一下是否能够通过空间换时间或者时间换空间的方法来优化算法。

2 Write the code for the algorithm on paper You’ve been coding all your life on a computer, and you’ve gotten used to the many nice things about it But, in your interview, you won’t have the luxury of syntax highlighting, code completion, or compiling Mimic this situation by coding on paper

    2上写下实现算法的代码。此前你一直在计算机写代码,特别依赖语法高亮、代码自动填补和编译器这些东西。但是在面试的时候是没有这些东西的,为了模仿这样的情况请一定在纸上写代码。

3 Type your paper code as-is into a computer You’ll probably have made a bunch of mistakes Start a list of all the mistakes you made, so that you can keep these in mind in the real interview

    3 把你的代码原封不动的敲到计算机上。你肯定发现自己犯了不少的错。把这些错误都列在一张表里面吧,在面试的时候你就会警惕这些错误了。

4 Do a mock interview CareerCup offers a mock interview service, or you can grab a friend to ask you questions Though your friend may not be an expert interviewer, he or she may still be able to walk you through a coding or algorithm question

    4 做个模拟面试。CareerCup提供一些模拟面试的服务,或者你可以找个朋友让他给你提一些面试的问题。虽然你的朋友不是专业面试官,但也能帮你完成代码或者算法的面试。

What You Need To Know

必备知识

Most interviewers won’t ask about specific algorithms for binary tree balancing or other complex algorithms Frankly, they probably don’t remember these algorithms either

面试官一般不会直接问你一个算法(平衡二叉树或者其他复杂的算法)是如何实现的,说实话这些算法面试官自己可能都忘记了。

You’re usually only expected to know the basics Here’s a list of the absolute must-have knowledge: Data Structures Algorithms Concepts Linked Lists Breadth First Search Bit Manipulation Binary Trees Depth First Search Singleton Design Pattern Tries Binary Search Factory Design Pattern Stacks Merge Sort Memory (Stack vs Heap) Queues Quick Sort Recursion Vectors / ArrayLists Tree Insert / Find / etc Big-O Time Hash Tables

一般面试官只需要你记住一些基本的算法,下面是一个必须知道的知识的列表:

This is not, of course, an all-inclusive list Questions may be asked on areas outside of these topics This is merely a “must know” list

当然这个表格并不包含一切知识点的。面试问题可能超出这个范围。这只是一个必须知道的列表。

For each of the topics, make sure you understand how to implement / use them, and (where applicable) the space and time complexity

对于表格中每一项你都得理解并且知道如何实现和使用它们,以及它们的时间空间复杂度。

Practicing implementing the data structures and algorithms You might be asked to imple- ment them in your interview, or you might be asked to implement a modification of them Either way, the more comfortable you are with implementations the better

好好练习这些数据结构和算法的实现。在面试的时候你可能会被问到如何实现他们,或者对算法进行改进。不论什么情况,你准备的越充分越好咯。

Do you need to know details of C++, Java, etc

语言的琐碎知识点

While I personally never liked asking these sorts of questions (e g , “what is a vtable?”), many interviewers regretfully do ask them For big companies like Microsoft, Google, Amazon, etc, I wouldn’t stress too much about these questions Look up the most common questions and make sure you have answers to them, but I would focus on data structures and algorithms preparation

就我个人来说,我绝不会问这类琐碎的问题(比如:什么是虚函数表?),很多面试官也很不喜欢这类问题。如果去面微软、谷歌或者亚马逊这类大公司,我是不会花太多的力气在这类问题上的。随便翻翻一般的参考书知道答案就可以了,更多的时间还是花在数据结构和算法的准备。

At smaller companies, or non-software companies, these questions can be more important Look up your company on CareerCup com to decide for yourself If your company isn’t listed, look up a similar company as a reference

但是在面试小公司或者非软件行业的公司的话,准备这类问题还是比较重要的。你可以到Careercup.com (需翻墙)看看你讲面试的公司是不是这类公司。如果没在列表里面的话,可以找一家差不多的公司作为参考。

 

面试题集-位操作

如何准备:

Bit manipulation can be a scary thing to many candidates, but it doesn’t need to be! If you’re shaky on bit manipulation, we recommend doing a couple of arithmetic-like problems to boost your skills Compute the following by hand: 1010 - 0001 1010 + 0110 1100^1010 1010 << 1 1001^1001 1001 & 1100 1010 >> 1 0xFF - 1 0xAB + 0x11 If you’re still uncomfortable, examine very carefully what happens when you do subtraction, addition, etc in base 10 Can you repeat that work in base 2?

很多应聘者都很害怕“位操作”的题目,害怕确实是没有必要的。如果真的在位操作方面不太擅长的话,建议你还是通过在一些练习好好准备。笔算下面的题目:

如果这些题目做的时候还有困惑的话,那就把我们平时做10进制加减的规则联系到2进制上。

NOTE: The Windows Calculator knows how to do lots of operations in binary, including ADD, SUBTRACT, AND and OR. Go to View Programmer to get into binary mode while you practice.

注意:windows自带的计算器能完成很多2进制下的计算,加减法,求与求门等。点击计算机的“查看” -> “科学型”,再按F7就能进入二进制模式计算了。

Things to Watch Out For:

注意事项:

» It’s really easy to make mistakes on these problems, so be careful! When you’re writing code, stop and think about what you’re writing every couple of lines - or, better yet, test your code mid-way through! When you’re done, check through your entire code » If you’re bit shifting, what happens when the digits get shifted off the end? Make sure to think about this case to ensure that you’re handling it correctly And (&): 0 & 0 = 0 1 & 0 = 0 0 & 1 = 0 1 & 1 = 1 Or (|): 0 | 0 = 0 1 | 0 = 1 0 | 1 = 1 1 | 1 = 1 Xor (^): 0 ^ 0 = 0 1 ^ 0 = 1 0 ^ 1 = 1 1 ^ 1 = 0

*在写代码的时候涉及到位操作一定要小心。边写的时候就要边想下,最好还能测试下。最后全部写完以后再测试一次。
*在做移位操作的时候,特别注意移位超过边界的时候如何处理。一定要想清楚然后。

Left Shift:

左位移:

x << y means x shifted y bits to the left If you start shifting and you run out of space, the bits just “drop off” For example: 00011001 << 2 = 01100100 00011001 << 4 = 10010000

x< < 表示将x向左位移y位。移动时超出的部分直接丢弃。

Right Shift:

右位移:

x >> y means x shifted y bits to the right If you start shifting and you run out of space, the bits just “drop off” the end Example: 00011001 >> 2 = 00000110 00011001 >> 4 = 00000001

x>>y 表示将x向右位移y位。移动时超出的部分直接丢弃。

5 1 You are given two 32-bit numbers, N and M, and two bit positions, i and j Write a method to set all bits between i and j in N equal to M (e g , M becomes a substring of N located at i and starting at j) EXAMPLE: Input: N = 10000000000, M = 10101, i = 2, j = 6 Output: N = 10001010100

5.1 给你两个32位整数N,M,还有表示位置的i和j。实现方法使得N的i至j位等于M。例如:输入  N = 10000000000, M = 10101, i = 2, j = 6 输出 N = 10001010100
5.1解答:
解法很简单,首先将N的i到j位清零,然后再将M左移i位,最后将两数做或。

5 2 Given a (decimal - e g 3 72) number that is passed in as a string, print the binary rep- resentation If the number can not be represented accurately in binary, print “ERROR”

5.2 以字符串形式传入一个十进制数(例如3.72),输出它的二进制表示形式。如果不能准确表示则输出"ERROR"
5.2解答:首先我们思考一下小数是如何用二进制表示的。以n = 0.101 = 1 * (1/2^1) + 0 * (1/2^2) + 1 * (1/2^3)为例。
打印输出整数部分是非常简单和直接的。小数部分我则采用将n*2,取整数部分,这就相当于“移位”的思想。

如果r>1,那么说明小数点后第一位为1。一直这样做,我们就能得到小数的二进制表示方法。

(译者注:本题作者理解为若32位小数仍无法表示则认为该数无法用二进制准确表示。更为准确的是判断标准为:在转换的任意阶段,若小数部分的最后一个数字非5,在该数无法被二进制数准确表示。)

5 3 Given an integer, print the next smallest and next largest number that have the same number of 1 bits in their binary representation

5.3 给定一个整数,输出与这整数在二进制表示下有相同个数“1",大于n的最小值和小于n的最大值。
5.3解答:
暴力算法:
最简单的方法就是从n向上/向下例举,判断是否有对应个数的”1“。但是这样的方法一点技术含量也没有。
根据数字性质:
首先观察
* 若降一个”1“变为”0“,再另一个”0“必须变为1;
* 若将第i位的0变为了1,第j为的1变为了0,那么数字大小的变化为2^i - 2^j;
* 若要变大数字必须让i大于j。
求大于n的最小值:
* 将n转化为二进制,从右往左依次遍历各位,在经过1后,遇到的第一个0,将其置1。这样就是个数字增大了2^i。例:xxxxx011100 变成 xxxxx111100
* 将i位右边的1置0,这样数字总的变化2^i-2^(i-1)。例:xxxxx111100 变成 xxxxx101100
* 为了让大于n的最小值,将i-1之后的1都移到最右端。
求小于n的最大值,方法类似:
* 将n转化为二进制,从右往左一次遍历各位,在经过0后遇到的第一个。例如xxxxx100011 变为 xxxxx000011
* 将i位右边的0置为1。例如xxxxx000011 变为 xxxxx010011。
* 为求最大值,将i-1位后的1尽量往左移到。
有了算法,开始着手写代码的时候记得将一些常用的方法放到一个公共的类中,写出整洁的代码。

5 4 Explain what the following code does: ((n & (n-1)) == 0)

5.4 解释下面表达式的含义 ((n & (n-1)) == 0)
5.4解答
我们来反向思考这个问题。
A&B=0是什么意思呢?它表示A和B两个数的二进制数每一位都不相同。那么n & (n-1)=0,说明n和n-1也没有相同的位。
那n-1又表示什么意义呢?从下面的例子你能看发现什么呢?

当你做减法的时候,主要看最低位,如果最低位为1,那么最低位直接变0;如果最低位为零,那么向高位借1,再减。从低位开始向高位将0变为1,直到借位的那一位。那么n和n-1的关系将会如下例所示:

如果n&(n-1)为0的话,说明例子中的abcde均为0,也就是说n中只有一位为1。也就是说n为2的整数次幂。

5 5 Write a function to determine the number of bits required to convert integer A to integer B Input: 31, 14 Output: 2

5.5 实现函数计算将整数从A变成B需要变动几位。例如 输入:31,14 输出 2
5.5解答:
本题的解题关键在于发现A和B之间有多少位是不同的。那如何判断A和B那些位不同呢?对XOR!
将获得A和B不同的部分,统计出有多少个1就能判断需要变动几位了。

5 6 Write a program to swap odd and even bits in an integer with as few instructions as possible (e g , bit 0 and bit 1 are swapped, bit 2 and bit 3 are swapped, etc)

5.6 实现方法将一个整数中的偶数位和奇数位交换。(例如:将0位和1位交换,2位和3位交换)
5.6解答:
用10101010(0xAA)这样的掩码提取出偶数位的信息,类似的用0x55提取奇数位的信息。然后错位求或即可。

5 7 An array A[1 n] contains all the integers from 0 to n except for one number which is missing In this problem, we cannot access an entire integer in A with a single operation The elements of A are represented in binary, and the only operation we can use to access them is “fetch the jth bit of A[i]”, which takes constant time Write code to find the missing integer Can you do it in O(n) time?

5.7 一个数组A[1,n]能容纳n个数字,现将0到n这n+1个数字,随机的放入到数组中。最后会有一个数字没有进入数组。现在让你找出这个数字。但是有如下的限制,不能直接访问数组的整个元素,只能访问“A[i]的第j位”。写出代码找出该元素。能否将时间复杂度控制在O(n)。
5.7解答:
(译者注:作者这里假设n为奇数。)
首先我们将0到n的所有数字的二进制表达列出来。那么我们可以发现最低位的,大概是这样的情况:count(0)>=count(1)。
如果我们从中移除了一个数字,会怎么样呢?

如果移除的数最低位为0,那么count(1)>=count(0);如果移除的是1,那么count(0)>count(1)。如果n次访问每个数的最低位,那么用以上的准则我们就能判断出没有进入数组的那个数字的最后一位是什么。如果最低位是0的话,那就可以排除最低位为1的元素;如最低位为1,那就可以排除末尾为0的。
那下一步怎么办呢?看次低位的情况?那么我以n=5,未入数组的数字为3。经过上一轮的排除后,剩下的数字如图所示:

那么现在次低位的情况为0 0 1 0 1 0 ,根据之前的逻辑我们知道,次低位应该是1。那么我们继续排除。只保留末尾为11的元素。剩下的就是:

再继续看倒数第三位。同样方法知道第三位应该是0。那么我们确定出了丢失的元素。
根据以上的方法,确定实现代码如下:

那算法的时间复杂是多少呢?第一次扫描了N次的最低位,第二次为N/2......以此类推,根据下式子:

所以我的算法的复杂度为O(n)。

 

 

面试题集-数组和字符串

哈希表

While not all problems can be solved with hash tables, a shocking number of interview problems can be Before your interview, make sure to practice both using and implementinghash tables

尽管哈希表不能解决所有的问题,但是面试中的大部分问题能用它解决。在面试之前一定要好好准备下哈希表的使用和实现。

1 public HashMap buildMap(Student[] students) {2 HashMap map = new HashMap();3 for (Student s : students) map.put(s.getId(), s);4 return map;5 }


ArrayList (Dynamically Resizing Array):

数组链表

An ArrayList, or a dynamically resizing array, is an array that resizes itself as needed whilestill providing O(1) access A typical implementation is that when a vector is full, the arraydoubles in size Each doubling takes O(n) time, but happens so rarely that its amortized timeis still O(1)

数组链表(大小可动态变化的数组)在使用中能够根据需要扩大数组的容量,并且能够提供O(1)的随机访问效率。数组链表典型的一种实现方法就是:当达到数组上限,就将数组容量扩大一倍。虽然在扩大容量时候的时间复杂度为O(n),但是这样情况都较少发生,所以总的时间开销可近似为O(1)。

1 public ArrayList merge(String[] words, String[] more) {2 ArrayList sentence = new ArrayList();3 for (String w : words) sentence.add(w);4 for (String w : more) sentence.add(w);5 return sentence;6 }


StringBuffer / StringBuilder

字符串

Question: What is the running time of this code?
1 public String makeSentence(String[] words) {2 StringBuffer sentence = new StringBuffer();3 for (String w : words) sentence.append(w);4 return sentence.toString();5 }

问:下面这段代码的时间复杂度?

Answer: O(n^2), where n is the number of letters in sentence Here’s why: each time youappend a string to sentence, you create a copy of sentence and run through all the letters insentence to copy them over If you have to iterate through up to n characters each time in the loop, and you’re looping at least n times, that gives you an O(n^2) run time Ouch! With StringBuffer (or StringBuilder) can help you avoid this problem 1 public String makeSentence(String[] words) {2 StringBuffer sentence = new StringBuffer();3 for (String w : words) sentence.append(w);4 return sentence.toString();5 }

答:O(n^2),这里的n为字符串sentence中的字符的个数。理由如下:每次你在向字符串sentence串中才追加一个数组的时候,就需要重新复制一次sentence中的字符,每次复制都需要从头到尾遍历一次sentence。这样的话把所有的单词追加到sentence中的时间复杂度为O(n^2)。

1.1 Implement an algorithm to determine if a string has all unique characters What if you can not use additional data structures?
For simplicity, assume char set is ASCII (if not, we need to increase the storage size The rest of the logic would be the same) NOTE: This is a great thing to point out to your interviewer!
1 public static boolean isUniqueChars2(String str) {
2 boolean[] char_set = new boolean[256];
3 for (int i = 0; i < str.length(); i++) {
4 int val = str.charAt(i);
5 if (char_set[val]) return false;
6 char_set[val] = true;
7 }
8 return true;
9 }
We can reduce our space usage a little bit by using a bit vector We will assume, in the below code, that the string is only lower case ‘a’ through ‘z’ This will allow us to use just a single int
Alternatively, we could do the following:

1 Check every char of the string with every other char of the string for duplicate occurrences This will take O(n^2) time and no space
2 If we are allowed to destroy the input string, we could sort the string in O(n log n) time and then linearly check the string for neighboring characters that are identical Careful, though - many sorting algorithms take up extra space

1.1 设计算法判断一个字符串中字符都是否唯一的。如果不能使用额外的数据结构呢?
解答1.1:先假设字符串中的字符均为ASCII码(如果不是的可以增大存储空间,而算法的逻辑是相同的)。“假设”在你的面试中非常的重要。

算法的时间空间复杂度均为O(n),n为字符串的长度。

采用bit序列来代替数组可以为我们进一步节省空间。这里我们需要假设字符串中的字符为'a'-'z'。这样只要用一个int型的变量就能记录字符是否出现了。

本题还有其他的解法:
1. 检查每一个字符在字符串中的出现次数,这样的方法时间复杂度为O(n^2),但是空间复杂度为0。
2. 如果字符串中的内容可以破坏的话。我们可以将字符串中的字符排序(时间复杂度为O(nlogn)),然后遍历字符串中的某个字符相邻的字符时候相同。但是要注意有些排序算法是需要额外的存储空间的。

1.2 Write code to reverse a C-Style String (C-String means that “abcd” is represented as five characters, including the null character )SOLUTION :This is a classic interview question    The only “gotcha” is to try to do it in place, and to be care- ful for the null character          void reverse(char *str) { 2                char * end = str; 3                char tmp; 4                if (str) { 5                            while (*end) { 6                                    ++end; 7                            } 8                            --end; 9                            while (str < end) {    10                                tmp = *str;    11                                *str++ = *end;    12                                *end-- = tmp;    13                          14            } 15    }

 1.2 实现C语言风格的字符串反转的算法
(C语言字符串:例如“abcd”字符串为5个字符,最后一个字符为/0用来表示字符串结束。)
解答1.2:
这个是面试的常见问题。如果你说你懂的话,就马上开始写代码吧。


1.3 Design an algorithm and write code to remove the duplicate characters in a string without using any additional buffer NOTE: One or two additional variables are fine An extra copy of the array is notFOLLOW UPWrite the test cases for this method

1.3 设计一个算法移除字符串中的重复字符,算法不使用额外缓冲。并对你的算法设计测试用例。注意:一两个变量使用当是OK的,但是复制整个数组就不行了。
解答1.3:
无字符串缓冲算法
1. 对每个字符判断是否为重复字符。
2. 重复字符直接跳过,非重复字符记录。
时间复杂度为O(n^2)

测试用例:
1. 无重复字符:abcd;
2. 全重复字符:aaaa;
3. 无效字符串:null;
4. 连续重复字符串:aaaabbbb;
5. 非连续重复字符串:abcabc;

字符串缓冲算法:

1. 无重复字符:abcd;
2. 全重复字符:aaaa;
3. 无效字符串:null;
4. 空字符串:empty
5. 连续重复字符串:aaaabbbb;
6. 非连续重复字符串:abcabc;

1.4 Write a method to decide if two strings are anagrams or not

1.4 写一个函数判断两个字符串是否使用相同的字符构成。
解答1.4:
本题有两种解法
法1 排序法

法2 计数法

1.5 Write a method to replace all spaces in a string with ‘ ’

1.5 编写代码将字符串在中的空格替换为‘ ’
解答1.5:
算法流程:
1 遍历字符串,记录下有多少个空格;
2 从字符串尾部重新解析:
  (1) 如果当前字符为空格,在写入字符串' '
  (2) 非空格则直接记录。

1.6 Given an image represented by an NxN matrix, where each pixel in the image is 4 bytes, write a method to rotate the image by 90 degrees Can you do this in place?

1.6 给出一张图片,表示为NXN的居然,每个像素点为4字节。写一个函数实现将这张图片旋转90°。
解答1.6:
图片的旋转可以将像素划分成一圈一圈,然后从最外层一圈一圈上来旋转。旋转某一圈的某个元素的时候,相当于对应的上下左右依次交换。

1.7 Write an algorithm such that if an element in an MxN matrix is 0, its entire row and column is set to 0

1.7 实现算法:在一个MxN的矩阵中,如果某一元素为0,则将其所在的行和列都置为零。
解答1.7:
乍一看题目,先遍历矩阵,出现0元素,就将所在的行列置零。但是这样的方法执行下来的话整个矩阵都变成了0了。
一个变通的方法,在另外一个MxN的矩阵中记录是否出现零的情况,然后根据记录对原来的矩阵中对相应的行列进行置零。可是这样方法的空间复杂度为O(MxN)。有没有改进的空间呢?
经过观察,其实我们只需要记录哪一列和哪一行需要置零即可。那么我们新的记录方法即为:使用两个数组rows[]和col[]来记录需要置零的行列。更具这样的方法算法代码如下:

1.8 Assume you have a method isSubstring which checks if one word is a substring of another Given two strings, s1 and s2, write code to check if s2 is a rotation of s1 using only one call to isSubstring (i e , “waterbottle” is a rotation of “erbottlewat”)

1.8 假设你已经有一个函数用来 isSubstring(s1,s2) 用来判断字符串s1是否是字符串s2的子串。那么现在给你一个字符串s1和s2,让你判断s1是否是s2循环位移得到的。你的算法中只能调用一次isSubstring (比如“waterbottle”循环位移就可以得到"erbottlewat")。
解答1.8:
算法描述:
1 如果length(s1)!= length(s2) 返回 false
2 将是s1和本身连接,得到新字符串s1',调用isSubstring(s2,s1')判断s2是否为s1'的字符串。

 

 

面试题集-链表

如何准备

Linked list questions are extremely common These can range from simple (delete a node ina linked list) to much more challenging Either way, we advise you to be extremely comfortable with the easiest questions Being able to easily manipulate a linked list in the simplestways will make the tougher linked list questions much less tricky With that said, we present some “must know” code about linked list manipulation You should be able to easily writethis code yourself prior to your interview

链表是面试中非常常见的问题。问题难度有难有易。无论题目如何,我们都建议你先练熟简单题目。掌握了简单链表题,面对那些难题的时就会轻松一点。所以下面列出了一些链表题中必备的代码。

Creating a Linked List:

创建一个链表:

NOTE: When you’re discussing a linked list in an interview, make sure to understand whether it is a single linked list or a doubly linked list.
1 class Node {2 Node next = null;3 int data;4 public Node(int d) { data = d; }5 void appendToTail(int d) {6 Node end = new Node(d);7 Node n = this;8 while (n.next != null) { n = n.next; }9 n.next = end;10 }11 }

注意:在面试的时候写链表,一定要先问清楚是写单链表还是双链表!

Deleting a Node from a Singly Linked List

在单链表中删除一个节点

1 Node deleteNode(Node head, int d) {2 Node n = head;3 if (n.data == d) {4 return head.next; 5 }6 while (n.next != null) {7 if (n.next.data == d) {8 n.next = n.next.next;9 return head; 10 }11 n = n.next;12 }13 }

2 1 Write code to remove duplicates from an unsorted linked list;
FOLLOW UP
How would you solve this problem if a temporary buffer is not allowed

2.1从一个未排序的链表中删除重复元素
进阶:如果不能使用额外的空间怎么办?
2.1解答:
如果可以使用哈希表的话,那么检查每一个元素是否重复,然后移除。

如果不能额外使用空间的话,我们就需要两个指针来遍历数组:current用来正常的遍历;runner则用来检查元素是否重复。runner只为一个元素检查一次是否重复,因为每一次runner会删除和元素的所有重复元素。

2.2 Implement an algorithm to find the nth to last element of a singly linked list

2.2 实现算法查找单链表中的倒数第n个元素。
注意:这个问题强烈的暗示递归算法,但是这里才采用一种更巧妙的方法。像这样类似的问题就,一定要多思考看看。能不能用非递归的方法代替递归的方法。
2.2解答:
这里我们假设链表的长度至少为n。
算法描述:
(1) 创建两个指针p1和p2,均指向链表头。
(2) 让p2增加n-1次,使得p2指向从链表头第n个元素(使得p1和p2之间距离为n)
(3) 若p2->next为空,则返回p1;不为空则同时增加p1,p2。(如果p2->next为空,则表示p1所指的元素为倒数第n个,因为p1,p2的距离为n。)
(4) 重复(3)

2.3 Implement an algorithm to delete a node in the middle of a single linked list, given only access to that node
EXAMPLE  Input: the node ‘c’ from the linked list a->b->c->d->e    Result: nothing is returned, but the new linked list looks like a->b->d->e

2.3 实现一个算法,只给你链表中间的一个元素(没有链表头),将其从链表中删除。
例如:
输入:节点 c (原链表为 a->b->c->d->e)
输出:没有任何返回值。但链表变成 a->b->d->e
2.3解答:
本题的解答只是把输入的下一个元素拷贝到输入的这个元素中以完成删除输入的元素。(译者注:原文的代码没有释放下一元素的空间。)
注意:这样的方法并不能删除链表的最后一个元素。这一点需要和你的面试官说清楚。算法有缺陷没有关系,大胆的告诉你的面试官,他们喜欢看到你提出这些。至于怎么解决可以和你的面试官讨论。

2.4 You have two numbers represented by a linked list, where each node contains a single digit The digits are stored in reverse order, such that the 1’s digit is at the head of the list Write a function that adds the two numbers and returns the sum as a linked list    EXAMPLE Input: (3 -> 1 -> 5) + (5 -> 9 -> 2)    Output: 8 -> 0 -> 8

2.4 两个用链表表示的数字,最低位在表头。写一个函数对两个这样的链表求和,采用相同的形式返回结果。
例如: (3 -> 1 -> 5) + (5 -> 9 -> 2)  返回  8 -> 0 -> 8
2.4解答:
本题可以采用递归的方式逐位的做加法。算法流程:

2

2 5 Given a circular linked list, implement an algorithm which returns node at the begin- ning of the loop    DEFINITION Circular linked list: A (corrupt) linked list in which a node’s next pointer points to an earlier node, so as to make a loop in the linked list    EXAMPLE    input: A -> B -> C -> D -> E -> C [the same C as earlier]    output: C
solution:
If we move two pointers, one with speed 1 and another with speed 2, they will end up meeting if the linked list has a loop    Why?  Think about two cars driving on a track—the faster car will always pass the slower one! The tricky part here is finding the start of the loop    Imagine, as an analogy, two people racing around a track, one running twice as fast as the other    If they start off at the same place, when will they next meet?  They will next meet at the start of the next lap
Now, let’s suppose Fast Runner had a head start of k meters on an n step lap When will
they next meet?  They will meet k meters before the start of the next lap    (Why? Fast Runner would have made k + 2(n - k) steps, including its head start, and Slow Runner would have made n - k steps    Both will be k steps before the start of the loop )
Now, going back to the problem, when Fast Runner (n2) and Slow Runner (n1) are moving around our circular linked list, n2 will have a head start on the loop when n1 enters    Specifically, it will have a head start of k, where k is the number of nodes before the loop    Since n2 has a head start of k nodes, n1 and n2 will meet k nodes before the start of the loop 
So, we now know the following:
      Head is k nodes from LoopStart (by definition) 
      MeetingPoint for n1 and n2 is k nodes from LoopStart (as shown above) 
Thus, if we move n1 back to Head and keep n2 at MeetingPoint, and move them both at the same pace, they will meet at LoopStart 

2.5 给一个带有环的链表,设计算法查找这个环的起点。
环的定义:链表中的某一元素的下一个元素为之前的一个元素。
例如:输入 A -> B -> C -> D -> E -> C 输出 C
2.5 解答:
如果在链表中有两个指针,从表头开始p1以每次一个节点的速度前进,p2每次2个。那么这两个指针一定在链表的环中相遇。想想两辆车以不同的速度在一个环形跑道上运动,那么他们肯定会在跑道上再次相遇。
这个问题最难的部分就在于如何超出这个环开始的节点。假想下如果是在一个圆形的跑道上p2以两倍的速度于p1同时从起点出发,他们将会哪里相遇。还是在起点!
现在我们再假设如果p2超前起跑线k米起跑,他们第一次在哪里相遇呢?在起跑线后面k米处。(为什么?假设p2过了起跑线之后跑了x和p1相遇,那么p2跑了l-k+x,其中l为跑道的长度,至相遇时p1也跑了x。根据相遇时消耗的时间相等得方程 (l-k-x)/2=x/1,解得 x = l-k,也就是在起跑线后k处相遇。)

那重新回到问题本身,当p1指针刚进入环的时候,p2在环中恰好领先p1指正k个节点,k为链表头节点到环开始处的距离。根据之前的结论,当p1、p2相遇的时候,他们都相遇环开始节点k个距离。
那么我们得到如下结论:
(1)表头距离环开始处k节点
(2)p1,p2距离环开始处也是k个节点。
如果当p1、p2相遇之后,将p1至于表头然后两个指针都采用1的速度移动的话。那么相遇处即为环开始处。

 

面试题集-堆栈和队列

如何准备:

Whether you are asked to implement a simple stack / queue, or you are asked to implementa modified version of one, you will have a big leg up on other candidates if you can flawlessly work with stacks and queues Practice makes perfect! Here is some skeleton code for a Stackand Queue class

当面试官需要你实现一个简单的堆栈或者列队的时候,你能顺利的写完,那你就比一般的应聘者先人一步了。熟能生巧,下面的这些基本的堆栈和队列的框架代码一定要掌握。

Implementing a Stack

堆栈

1 class Stack {2 Node top;3 Node pop() {4 if (top != null) {5 Object item = top.data;6 top = top.next;7 return item;8 }9 return null;10 }11 void push(Object item) {12 Node t = new Node(item);13 t.next = top;14 top = t;15 }16 }

Implementing a Queue

队列

1 class Queue {2 Node first, last;3 void enqueue(Object item) {4 if (!first) {5 back = new Node(item);6 first = back;7 } else {8 back.next = new Node(item);9 back = back.next;10 }11 }12 Node dequeue(Node n) {13 if (front != null) {14 Object item = front.data;15 front = front.next;16 return item;17 }18 return null;19 }20 }

3 1 Describe how you could use a single array to implement three stacks

3.1 怎样用一个数组实现三个堆栈
3.1解答:
解法一:
将数组划分成3等份,每一份独立的用来实现堆栈。
*第一个堆栈:从 0     至 n/3
*第二个堆栈:从 n/3  至 2n/3
*第三个堆栈:从2n/3 至 n
这种解法是基于对每个堆栈的使用没有额外的使用说明,所以我们直接为每个堆栈划分固定的大小。

解法二:
解法二中的,主要数组中还有空余的空间,堆栈就还能增长。
每次为堆栈分配一个空间的时候,在这个新空间中记录上一个空间地址。这样堆栈中的每个元素都有一个指针指向之前的元素。
这样的实现方法有一个问题就是如果一个堆栈弹出一个空间(释放空间),这个空间并不会作为空闲空间现在数组后面。这样话我们就不能使用新产生的空闲空间。
为了解决这个问题,我们用一个列表来记录空闲的空间。当有新空闲空间出现,我们就把它加入到这个表中。如果需要新分配一个空间,就从这个表中删除一个元素。
这样的实现方法使得3个堆栈能够动态的使用数组的空间,但是这是以增大空间复杂度换来的。

3 2 How would you design a stack which, in addition to push and pop, also has a function min which returns the minimum element? Push, pop and min should all operate in O(1) time

3.2 适合实现一个堆栈,除了有函数push、pop函数之外还有min函数,min函数范围堆栈中的最小元素。要求push,pop和min三个函数的时间复杂度均为O(1)。
3.2解答:
在每个堆栈中的节点中记录目前堆栈中的最小值。那么调用min( )函数时只需要看看栈顶元素中记录的最小值即可。

但是这样解法存在的问题是,如果堆栈的需要记录的元素非常多,那么这样的方法将会消耗大量的空间。因为我们在每个堆栈的元素中都记录来了最小值。这个能不能改进呢?
我们可以在创建一个辅助的堆栈只用来记录最小的元素。

这样的方法就是不是有更高的效率呢,在堆栈s2中只记录最小值,避免了大量的冗余数据的记录。

3 3 Imagine a (literal) stack of plates If the stack gets too high, it might topple There- fore, in real life, we would likely start a new stack when the previous stack exceeds some threshold Implement a data structure SetOfStacks that mimics this SetOf- Stacks should be composed of several stacks, and should create a new stack once the previous one exceeds capacity SetOfStacks push() and SetOfStacks pop() should behave identically to a single stack (that is, pop() should return the same values as it would if there were just a single stack)    FOLLOW UP    Implement a function popAt(int index) which performs a pop operation on a specific sub-stack

3.3 想象下啊:一堆盘子,如果堆得太高的话,就容易倒下来。所以在现实中如果盘子堆到一定高度,我们就会重新起一个堆。现在实现一个新的数据结构来模拟这样现象。SetOfStack当中包含很多的堆栈,当一个堆栈达到上限的时候,启用下一个堆栈。SetOfStack.push 和 SetOfStack.pop应该和普通堆栈的操作一样。
进阶:
实现一个函数popAt(int index),指定在哪个堆栈上弹出元素。
3.3解答:
根据题意,我们的数据结构大体上应该是这么一个框架:

由于要和普通的堆栈的push()有相同的效果,也就是说每次push()都必须将元素放到最近使用的一个堆栈中。但是在这个堆栈已经满了情况下,那就必须建一个新的堆栈然后再入栈。那么push的实现如下:

那pop()如何实现呢?和push()差不多,也一定要在最近的一个堆栈上操作。但是如果最后一个堆栈是空的话,就应该将其移除。

那进阶的问题这么处理呢?
这个问题确实有点难度。实现起来也比较麻烦,因为整个系统看起来应该像一个“翻转”系统。如果我从堆栈1中弹出一个元素,那么我们需要将堆栈2底部的元素压到堆栈1的顶端。堆栈3的元素要到堆栈2....
注:你可能会不同意我的说法。认为实现这个函数不需要“翻转”整个堆栈。系统中的每个堆栈并不需要都是满栈的,这样的话也可以省下很多的时间复杂度,特别是在堆栈非常大的时候。但是如果假设除了最后一个堆栈之外,所有的堆栈必须满栈的话,这样的方法就不行了。具体采用什么样的结构,你可以在面试时和面试官好好沟通然后决定。

3 4 In the classic problem of the Towers of Hanoi, you have 3 rods and N disks of different sizes which can slide onto any tower The puzzle starts with disks sorted in ascending order of size from top to bottom (e g , each disk sits on top of an even larger one) You have the following constraints:    (A) Only one disk can be moved at a time    (B) A disk is slid off the top of one rod onto the next rod    (C) A disk can only be placed on top of a larger disk    Write a program to move the disks from the first rod to the last using Stacks

3.4 经典的汉诺塔问题,有3根柱子,柱子上串有N个尺寸不同的碟子。汉诺塔问题的起始状态为,所有的碟子都从小到大的穿在柱子上(下面的碟子最大)。在满足下面三个限制:(A) 每次只能移动一个碟子;(B) 只有每根柱子顶端的碟子才能移动;(C)任何碟子只能放在比它大的碟子上。写一段程序(要求使用堆栈),将第一个根柱子上所有的碟子移动到移到最后一根柱子上。

3.4解答:
首先我们考虑解题的算法:将N个碟子从第一根柱子移到最后一根柱子。我们先从最简单的情况开始。如果只有一个碟子,那么直接将它移到最后的柱子。那两个碟子呢?
(1)先将第一个碟子从第一根柱子移到第二根
(2)将第二个碟子从第一根柱子上移动到第三根
(3)再将第二根柱子上的碟子移动到第三根上,完成!
那三个碟子呢?
(1)采用两个碟子移动的方法,讲上两个碟子移动到第二根柱子上
(2)将第三个碟子移动到第三根柱子
(3)在采用运来的方法将第二根柱子上的两个碟子移动到第三根柱子。
很明显采用递归算法就能解决本题:

3.5 Implement a MyQueue class which implements a queue using two stacks

3.5 用两个堆栈来实现一个队列
3.5解答:
堆栈和队列的最大区别在于:一个是先进后出,一个是后进先出。但是题目的要求使得peek和pop的动作恰好相反。那么我们就可以利用第二个堆栈完成入栈元素顺序的反转。(先所有的元素进堆栈S1,这样最先进栈的元素在栈底,最后的在栈顶;然后将S1中的元素依次弹出,并压入堆栈S2中。这样S2中先进的元素就在栈顶后进的就在栈底了。)
但是如果对队列和出队列的动作反复进行的话,我就要在S1和S2两个堆栈中反复的倒来倒去。其实有偷懒的方法。
当有元素要进入队列的时候,直接压如堆栈S1中,元素需要从队列中出列的话,检查S2中是否有元素,如果没有再采用之前的方法将S1中的元素“倒”入到S2中,如果S2中非空在直接弹出元素即为队列中出列的元素。这样的方法就免于在两个堆栈之间倒来倒去了:

3 6 Write a program to sort a stack in ascending order You should not make any assumptions about how the stack is implemented The following are the only functions that should be used to write this program: push | pop | peek | isEmpty

3.6 写一个程序将堆栈升序排序。该堆栈就是一个普通的堆栈,不能有其他假设。函数实现是只能调用函数push(),pop(),peek()和isEmpty这几个函数。
3.6解答:
再建一个堆栈,从原堆栈中弹出一个元素到新的堆栈中。然后再比较原堆栈栈顶元素和新堆栈栈顶大小。如果符合排序规则,再次入新堆栈。如果不符合,在弹出新堆栈中的元素逐个比较直到满足排序关系。这样类似插入排序的方法,之间复杂度为O(n^2)。

 

 

面试题集-树和图

如何着手

Trees and graphs questions typically come in one of two forms: 
1   Implement a tree / find a node / delete a node / other well known algorithm  
2   Implement a modification of a known algorithm 

这类问题主要有以下两种形式:

1、 完成创建一个树/查找一个结点/删除一个结点/其他常见的算法

2、 完成对一个已知算法的修改

Either way, it is strongly recommended to understand the important tree algorithms prior to  your interview   If you’re fluent in these, it’ll make the tougher questions that much easier!  We’ll list some of the most important 

不管怎样,我们强烈推荐你在面试之前搞懂与树有关的重要算法。如果你对树非常熟悉,那么就可以轻松应对一些棘手的问题了。我们给出一些非常重要的几点: 

WARNING: Not all binary trees are binary search trees   When given a binary tree question, many candidates assume that the interviewer means   “binary search tree”, when the interviewer might only mean “binary tree   ”   So, listen carefully  for that word “search   ”   If you don’t hear it, the interviewer may just mean a binary tree with  no particular ordering on the nodes   If you aren’t sure, ask 

重要提示:并非所有的二叉树都是二叉查找树当被问到有关二叉树的时候,许多面试者自以为面试官是指二叉查找树,而面试官实际上是说二叉树。所以,认真听是否有“查找”那个词。如果你没有听到,那么面试官可能就是指那些没有经过特定排序的结点的二叉树。如果你不确定,那就问下吧。

Binary Trees—”Must Know” Algorithms    

有关二叉树的最基础算法

You should be able to easily implement the following algorithms prior to your interview:  
» In-Order: Traverse left node, current node, then right [usually used for binary search  trees]    
»Pre-Order: Traverse current node, then left node, then right node    
» Post-Order: Traverse left node, then right node, then current node    
» Insert Node: On a binary search tree, we insert a value v, by comparing it to the root   If v  > root, we go right, and else we go left   We do this until we hit an empty spot in the tree   

在你面试之前你应该熟知以下算法:

1、中序遍历:首先访问左结点,接着访问根结点,然后访问右结点(通常在二叉查找树中使用)。

2、先序遍历:首先访问根节点,接着访问根节点的左子节点下的子树内的节点,然后访问根节点的右子节点下的子树内的节点。

3、后序遍历:首先访问根节点,接着访问根节点的右子节点下的子树内的节点,然后访问根节点的左子节点下的子树内的节点。

4、插入结点:在二叉查找树中,我们插入一个变量v的方法是这样的。跟根节点比较,如果v大于root,那么去右边,否则去左边。我们重复这样的比较直到有一个空结点。

Note: balancing and deletion of binary search trees are rarely asked, but you might  want to have some idea how they work   It can set you apart from other candidates   

注意:调整或者删除查找树的问题很少会问到,但你应该知道他们是如何工作的。这有助于你从其他面试者区分出来。  

Graph Traversal—”Must Know” Algorithms

有关图遍历的最基础算法

You should be able to easily implement the following algorithms prior to your interview:    
» Depth First Search: DFS involves searching a node and all its children before proceed- ing to its siblings    
» Breadth First Search: BFS involves searching a node and its siblings before going on  to any children

在你面试之前你应该熟知以下算法:

1、深度优先搜索DFS(Depth First Search):DFS算法涉及在访问兄弟结点前先访问自身以及子结点。

2、广度优先搜索BFS(Broad First Search): BFS算法涉及在访问子结点前先访问自身以及兄弟结点。 

例题

4 1   Implement a function to check if a tree is balanced   For the purposes of this question,  a balanced tree is defined to be a tree such that no two leaf nodes differ in distance  from the root by more than one       ________________________________________________________________pg 123 
4 2   Given a directed graph, design an algorithm to find out whether there is a route be- tween two nodes      ________________________________________________________________pg 124 
4 3   Given a sorted (increasing order) array, write an algorithm to create a binary tree with  minimal height      ________________________________________________________________pg 125 

4.1 完成一个用来判断一颗树是否是平衡树的函数。这个问题的目的是,平衡树是指两个叶结点在距离根结点的距离上不会超过1。pg123

解答

思路很简单:最小深度与最大深度的差别是不超过1.因此最大与最小深度的差值就是树中最大的深度差值。


4.2 对于一个有方向的图,设计一种算法用来判断在两个顶点之间是否有路径。pg124思路很简单:最小深度与最大深度的差别是不超过1.因此最大与最小深度的差值就是树中最大的深度差值。

解答

 

这个问题通过对图的遍历就可以轻松解决,比如深度优先搜索或者广度优先搜索。我们从其中一个结点开始遍历,遍历过程中检查另外一个结点是否被找到。我们应该对算法中遍历过的结点进行标记,以避免对结点的重复访问以及循环访问。


 

  

4.3 对于一个升序排列的数组,给出创建最小高度二叉树的算法。pg125

解答

 

如果可能,我们尝试建立这样一个二叉树,对于每一个结点,他左分支的结点总数与右分支的结点总数一致。

算法如下:

1、插入数组中的中间数

2、将中间数左边的元素插入到左分支

3、将中间数右边的元素插入到右分支

4、递归


 

4 4   Given a binary search tree, design an algorithm which creates a linked list of all the  nodes at each depth (i e , if you have a tree with depth D, you’ll have D linked lists)      ________________________________________________________________pg 126 
4 5   Write an algorithm to find the ‘next’ node (i e , in-order successor) of a given node in  a binary search tree where each node has a link to its parent      ________________________________________________________________pg 127 
4 6   Design an algorithm and write code to find the first common ancestor of two nodes  in a binary tree   Avoid storing additional nodes in a data structure   NOTE: This is not  necessarily a binary search tree      ________________________________________________________________pg 128 

  

4.4 对于一个二叉查找树,设计可以给出在任一深度所有结点的链表的算法(比如树的深度是D,就有D个链接。)pg126

解答

 

我们可以做对树一层层的遍历,对树的初次遍历可以做轻微的修改。

在常见的初次遍历中,我们在遍历结点的时候不关心现在所在的层。在这个问题中,就有必要知道当前的层信息。因此我们使用一个虚拟结点来预测我们是否完成了本层并进行下一层访问。


 

4.5 对于一个每一个结点都有一个指向其父结点的二叉查找树,设计一个寻找给定结点下一个结点的算法。pg127

解答

 

解决这个问题,我们需要仔细思考中序遍历中到底发生了什么。在先序遍历中,我们访问X.left,X,然后是X.right.

因此,如果我们想找到X.successor(),我们这样解决:

1、如果X有右分支,那么所谓的继承者肯定在X的右侧。很明确,在树的那个分支上,需要首先访问最左边的子结点。

2、否则我们访问X的父结点(记做P)

a) 如果X有一个左子结点(P.left=X),那么P就是X的继承者。

b) 如果X有一个右子结点(P.right=X),因此我们就调用successor(P)。


 

4.6 设计一个二叉树中两个结点的第一个共同祖先结点的算法,并给出代码。避免在数据结构中存储额外的结点。注意:这不一定需要是二叉查找树。pg128

解答

 

假设这是二叉查找树,我们可以在这两个结点上做一个改进的搜索来看这两路径在哪里分叉。可惜的是,这不是二叉查找树,因此我们得试其他思路。

思路1

如果每个结点都连接到他的父结点,那么我们就可以跟踪p跟q的路径直到他们交叉。

思路2

另外,你可以看一个p跟q都在同一侧的一个分割线。也就是说,如果p跟q都在结点的左侧,那就在左侧分支中去寻找共同的祖先。当p跟q不在同一侧的时候,你不得另想其他办法。


 

思路3

对于任意一个结点r,我们有以下:

1、如果p在一侧,q在另外一侧,那么r就是最近的共同的祖先。

2、否则的话,最近的共同的祖先就在左侧或者右侧。

因此,我们可以给出一个叫左搜索-右搜索的递归算法来计算当前结点的左侧跟右侧分别有多少个结点(p或者q)。如果在某一侧只有2个结点,那么我们就需要判断这个子结点是不是p或者q(因为这种情况下,当前结点就是最近的共同的祖先)。如果不是p或者q,那我们就得从子结点开始继续搜索。

如果需要寻找的结点(p或者q)在当前结点的右侧,此外另一个结点在另一侧。那么当前及诶点就是最近的共同的祖先。



 

 

4 7   You have two very large binary trees: T1, with millions of nodes, and T2, with hun- dreds of nodes   Create an algorithm to decide if T2 is a subtree of T1      ________________________________________________________________pg 130 
4 8   You are given a binary tree in which each node contains a value   Design an algorithm  to print all paths which sum up to that value   Note that it can be any path in the tree  - it does not have to start at the root      ________________________________________________________________pg 131

4.7 如果有两个巨大的树,T1、T2,其中前者有百万个结点,后者有几百个结点。设计一种算法判断T2是否是T1的一个分支。pg130

解答

 

注意问题的特别指出T1有百万个结点,也就是说我们应该特别注意空间的开支。举个例子,如果T1有1000万个结点,那么单单数据量就是大约40mb。我们可以创建一个字符串来表示中序跟先序的遍历。如果T2的先序遍历是T1先序遍历的一个分支,T2的中序遍历是T1中序遍历的一个分支,那么T2就是T1的第一分支。我们可以通过使用一个后缀树来确认。然而,我们可能会受到内存的限制,因为后缀树对于内存是极端敏感的。如果这个成了一个问题,那么我们就得试下另外一个思路。

其他思路:treeMatch程序访问T2的每个结点最多一次,对于T1的每个结点的访问次数不超过1。最极端的情况是O(m*n),n跟m分别表示T1跟T2的大小。如果k表示T2的根节点在T1中出现的次数,那么极端的时间复杂度是O(k*m+n)。


 

4.8 对于一个任何结点都包含值的二叉树,设计一种算法实现打印出和是那个值的所有路径。注意可以是任何路径(不需要一定从根结点开始)。pg131undefined

解答undefined

undefined

我们通过简化这个问题来求解。假设这个路径从根结点开始会怎样?这样的话,我们就得到一个更简单的问题了:undefined

从根节点开始,然后左分支跟右分支,计算每个路径的总数。当我们找到这个总和的时候,我们就打印出当前路径。注意我们直到找到这个总和才停止计算。为什么?因为我们可以遇到下面这种情况(假设我们找总和是5的路径):2 + 3 + –4 + 3 + 1 + 2。如果我们遇到2+3就停止计算,我们就可以错过其他一些路径(2 + 3 + -4 + 3 + 1 和3 + -4 + 3 + 1 + 2)。因此我们对于每个可能的路径都要试一次。undefined

好,现在假设这个路径可以从任何一个结点开始? 在这种情况下,我们做个小修改。在每个结点,我们核对下是否找到总和。这并不是指我们是否从一个有这个总和的路径开始,而是这个路径达到总和了吗?undefined


这个算法的时间复杂度如何呢?假设一个在第r层的结点,我们做r数量级的计算。我们猜测是O(nlgn),或者我们仔细算下:第r层有2^r个结点
类似的逻辑,空间复杂度是O(nlgn)。

undefined

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值