每天10道:Android面试题整理五(数据结构算法)


在这篇帖子中,我将分享10 道数据结构及算法的题目,相信对于任何Android开发者来说,面试题能够给予他们有所帮助。

糟糕的程序员担心代码。优秀的程序员担心数据结构及其算法。 ——Linus Torvalds

由于怕文章太长我就不做太多说明了,看题目就知道这是啥了,ok,废话不多说,看下面整理出来的题,希望可以对想从事Android开发的兄弟姐妹们有所帮助,下面的题整理出来的,并不全面,欢迎各位提问和补充!Android面试题和答案已按照规范已整理完成,大家可看文末或评论/私信,一起交流技术、进阶提升~

1. Vector,ArrayList与LinkedList有什么区别,应用场景是什么?

● Vector实现了基于动态Object数组的数据结构,线程安全,可以设置增长因子,效率比较低,不建议使用。
● ArrayList实现了基于动态Object数组的数据结构,非线程安全,地址连续,查询效率比较高,插入和删除效率比较低。适合查询操作频繁的场景。
● LinkedList实现了基于链表的数据结构,非线程安全,地址不连续,查询效率比较低,插入和删除效率比较高。适合插入和删除操作频繁的场景。

2. 简单说一说SpareArray的插入流程?

SpareArray的key是一个int有序数组,查找过程使用的二分查找。

  1. 用二分查找法查找元素的key。
  2. 如果插入的数据冲突了,则直接覆盖原则。
  3. 如果当前插入的key上的数据为DELETE,则直接覆盖。
  4. 如果前面几步都失败了,则检查是否需要gc()并且在索引上插入数据。

3. 从长度为m的int数组中随机取出n个元素,每次取的元素都是之前未取过的,如何优化?

string:  Hello
  length:  5

          0 1 2 3 4 
  before: H e l l o
  after:  o l l e H

  index             sum
  0: H--->o  0-->4  4
  1: e--->l  1-->3  4
  2: l--->l  2-->2  4

解法一:使用数组

  1. 将字符串转换为char数组
  2. 遍历循环给char数组赋值
public static String strReverseWithArray2(String string){
    if(string==null||string.length()==0)return string;
    int length = string.length();
    char [] array = string.toCharArray();
    for(int i = 0;i<length/2;i++){
        array[i] = string.charAt(length-1-i);
        array[length-1-i] = string.charAt(i);
    }
    return new String(array);
}

解法二:使用栈

  1. 将字符串转换为char数组
  2. 将char数组中的字符依次压入栈中
  3. 将栈中的字符依次弹出赋值给char数组
    public static String strReverseWithStack(String string){
     if(string==null||string.length()==0)return string;
     Stack<Character> stringStack = new Stack<>();
     char [] array = string.toCharArray();
     for(Character c:array){
         stringStack.push(c);
     }
     int length = string.length();
     for(int i= 0;i<length;i++){
         array[i] = stringStack.pop();
     }
     return new String(array);
    }

解法三:逆序遍历

  1. 逆序遍历字符串中的字符,并将它依次添加到StringBuilder中
public static String strReverseWithReverseLoop(String string){
        if(string==null||string.length()==0)return string;
        StringBuilder sb = new StringBuilder();
        for(int i = string.length()-1;i>=0;i--){
            sb.append(string.charAt(i));
        }
        return sb.toString();
    }

4. HashSet、LinkedHashSet与TreeSet有什么区别,应用场景是什么?

● HashSet:基于HashMap实现,非线程安全,地址不连续,查询效率比较低,插入和删除效率比较高。适合插入和删除操作频繁的场景。
● LinkedHashSet:基于hashCode值来决定元素的存储位置,但是它同时使用链表维护元素的次序。这样使得元素看起来像是以插入顺序保存的。
● TreeSet基于红黑树实现,非线程安全,可以按照自然顺序或者自定义顺序自动排序,不允许插入null值。适合需要排序的场景。
● HashSet基于hash表实现,非线程安全,允许插入null,查找效率高。适合查找操作频繁的场景。

5. 简单说一说SpareArray的插入流程?

SpareArray的key是一个int有序数组,查找过程使用的二分查找。

  1. 用二分查找法查找元素的key。
  2. 如果插入的数据冲突了,则直接覆盖原则。
  3. 如果当前插入的key上的数据为DELETE,则直接覆盖。
  4. 如果前面几步都失败了,则检查是否需要gc()并且在索引上插入数据。

6. 单链表反转,合并多个单链表

单链表的结构就像一个火车的结构,火车头拉着许多车厢,实现链表翻转,可以利用递归翻转法,在反转当前节点之前先反转后续节点。这样从头结点开始,层层深入直到尾结点才开始反转指针域的指向。简单的说就是从尾结点开始,逆向反转各个结点的指针域指向。

public class LinkedListReverse {  

    public static void main(String[] args) {  
        Node head = new Node(0);  
        Node node1 = new Node(1);  
        Node node2 = new Node(2);  
        Node node3 = new Node(3);  
        head.setNext(node1);  
        node1.setNext(node2);  
        node2.setNext(node3);  

        // 打印反转前的链表  
        Node h = head;  
        while (null != h) {  
            System.out.print(h.getData() + " ");  
            h = h.getNext();  
        }  
        // 调用反转方法  
        head = Reverse1(head);  

        System.out.println("\n**************************");  
        // 打印反转后的结果  
        while (null != head) {  
            System.out.print(head.getData() + " ");  
            head = head.getNext();  
        }  
    }  

    /** 
     * 递归,在反转当前节点之前先反转后续节点 
     */  
    public static Node Reverse1(Node head) {  
        // head看作是前一结点,head.getNext()是当前结点,reHead是反转后新链表的头结点  
        if (head == null || head.getNext() == null) {  
            return head;// 若为空链或者当前结点在尾结点,则直接还回  
        }  
        Node reHead = Reverse1(head.getNext());// 先反转后续节点head.getNext()  
        head.getNext().setNext(head);// 将当前结点的指针域指向前一结点  
        head.setNext(null);// 前一结点的指针域令为null;  
        return reHead;// 反转后新链表的头结点  
    }  
}  

    class Node {  
        private int Data;// 数据域  
        private Node Next;// 指针域  

        public Node(int Data) {  
            // super();  
            this.Data = Data;  
        }  

        public int getData() {  
            return Data;  
        }  

        public void setData(int Data) {  
            this.Data = Data;  
        }  

        public Node getNext() {  
            return Next;  
        }  

        public void setNext(Node Next) {  
            this.Next = Next;  
        }  
    }

7. 字符串反转技术

 public class ReverseInPlace {

  static char[]  str=null;

    public static void main(String s[]) {
      if(s.length==0)
    System.exit(-1);

       str=s[0].toCharArray();

       int begin=0;
       int end=str.length-1;

       System.out.print("Original string=");
       for(int i=0; i<str.length; i++){
     System.out.print(str[i]);
       }

       while(begin<end){
      str[begin]= (char) (str[begin]^str[end]);
      str[end]= (char)   (str[begin]^str[end]);
      str[begin]= (char) (str[end]^str[begin]);

      begin++;
      end--;       
       }

       System.out.print("\n" + "Reversed string=");
       for(int i=0; i<str.length; i++){
     System.out.print(str[i]);
       }

    }
}

 public AbstractStringBuilder reverse() {
        boolean hasSurrogate = false;
        int n = count - 1;
        for (int j = (n-1) >> 1; j >= 0; --j) {
        char temp = value[j];
        char temp2 = value[n - j];
        if (!hasSurrogate) {
            hasSurrogate = (temp >= Character.MIN_SURROGATE && temp <= Character.MAX_SURROGATE)
            || (temp2 >= Character.MIN_SURROGATE && temp2 <= Character.MAX_SURROGATE);
        }
        value[j] = temp2;
        value[n - j] = temp;
        }
        if (hasSurrogate) {
        // Reverse back all valid surrogate pairs
        for (int i = 0; i < count - 1; i++) {
            char c2 = value[i];
            if (Character.isLowSurrogate(c2)) {
            char c1 = value[i + 1];
            if (Character.isHighSurrogate(c1)) {
                value[i++] = c1;
                value[i] = c2;
            }
            }
        }
        }
        return this;
    }

8. 说说搜索算法中你知道的算法

  • 无序线性搜索
  • 排序/有序线性搜索
  • 二进制搜索

9. 给定 n 个[0,n)区间内的数,统计每个数出现的次数,不使用额外空间

vector<int> nums;

void init(vector<int>& nums) {
    for (int i = 0; i < nums.size(); i++) {
        nums[nums[i]] += n;
    }
}

int cnt(int k) {
    return nums[k] / n;
}

10. 如何判断单链表交叉

    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        if (headA == null || headB == null) {
            return null;
        }
        ```
        ListNode currA = headA;
        ListNode currB = headB;
        int lengthA = 0;
        int lengthB = 0;
        // 让长的先走到剩余长度和短的一样
        while (currA != null) {
            currA = currA.next;
            lengthA++;
        }
        while (currB != null) {
            currB = currB.next;
            lengthB++;
        }
        currA = headA;
        currB = headB;
        while (lengthA > lengthB) {
            currA = currA.next;
            lengthA--;
        }
        while (lengthB > lengthA) {
            currB = currB.next;
            lengthB--;
        }
        // 然后同时走到第一个相同的地方
        while (currA != currB) {
            currA = currA.next;
            currB = currB.next;
        }
        // 返回交叉开始的节点
        return currA;
        ```
    }


公众号:Android Jasper 专注分享面试题|面试技巧|Android学习资料。(dd:16)

#面试##Android##面试题##数据结构##数据结构算法#
全部评论
每天学点新知识
点赞 回复 分享
发布于 2022-09-01 11:00 江苏

相关推荐

点赞 评论 收藏
分享
今天 10:35
已编辑
西安科技大学 后端
点赞 评论 收藏
分享
评论
点赞
4
分享

创作者周榜

更多
牛客网
牛客企业服务