【内功修炼系列1】线性数据结构(下篇1)

730 阅读6分钟

前言

前一篇文章《【内功修炼系列1】之线性数据结构(上篇)》,我们介绍了线性数据结构:数组、链表、栈、队列、哈希表 的概念以及适合的应用场景。本篇我们就结合一些常用的面试题,对题目进行分析,并用java代码实现这些场景。希望通过实际的代码编写,加深对这些数据的理解,以后遇到类似的场景,我们就会显得得心应手。话不多说,直接开搞!

介绍思路

无论你是初出茅庐的“java小鸟”,还是混迹多年的老江湖。在技术圈里的人,想提高个人的生活质量,到更大平台实现个人的梦想,都有一堵绕不开的墙:技术面试。当然,不同level的开发人员,会遇到相应等级的面试题。所以,我就想先抛出一些常见的面试题给大家,让大家先思考。之后在“实操代码”环节再用代码实现出来,一来让大家先思考一下,再来可以看看实现代码,兄弟们可以给些意见,让我们一起优化。

实操面试题

在这个环节,甭管你是菜鸟还是高手,希望大家先思考一下自己的思路。最后看下自己究竟搞清楚几道题?无论是啥结果,都希望大家在留言区把你们的结果发出来(比如:答题数目、答题时间、甚至是没做出来)。这些问题也是我在面试别人的时候,会问到的。你们的参与和“三连”,才是我的源动力,否则我就自己吃独食啦,整理文章也是很花时间的。。。

数组

  • 实现数组反转;
  • 从一个数组中删除重复元素;
  • 一个数组,除一个元素外其它都是两两相等,求那个元素;
  • 写一个算法,可以将一个二维数组顺时针旋转90度;

链表

  • 将一个链表相邻的两个节点反转;例如:1->2->3->4,输出为:2->1->4->3;
  • 判断一个链表中是否有环;

栈和队列

  • 判断一段文章中,各种括号(大、中、小)是否合法;
  • 用栈实现一个队列;
  • 设计一个循环队列;

哈希表

  • 判断两个字符串的字母是否完全一致;例如:abc和cba;
  • 给定一个int值,和一个数组,返回两数之和的下标;例如:值为11,数组[1,10,9,2,3,7,8],返回0,1和2,3和4,6;

思考时间

拿出你们电脑,撸一会代码。

上代码

数组

1、实现数组反转;

分析:这道题是基本操作,不必分析啦。。如果你有更骚的方法,留言吧。

package com.demo.array;

/**
 * 数组反转
 *
 * @author dongx on 2020/9/20
 */
public class ArrayReverseDemo {

    public static int[] reverse(int[] arr){
        int[] arrTemp = new int[arr.length];
        for(int i = arr.length-1;i >= 0;i--){
            arrTemp[arr.length-i-1] = arr[i];
        }
        return arrTemp;
    }

    public static void main(String[] args) {
        int[] arr = new int[]{1, 0, 1, 3, 4, 2};
        for (int elem : arr) {
            System.out.print(elem + ",");
        }
        // 打印反转后的元素
        arr = reverse(arr);
        System.out.println();
        for (int elem : arr) {
            System.out.print(elem + ",");
        }
    }

}

结果

2、从一个数组中删除重复元素;

分析:基本操作,不分析。其实也可以用Map和Set操作,时间复杂度会降低。

package com.demo.array;

import java.util.ArrayList;
import java.util.List;

/**
 * 去掉数组中重复的元素
 *
 * @author dongx on 2020/9/20
 */
public class ArrayRepeatDemo {
    public static Object[] ifRepeat(Object[] arr) {
        // 创建一个集合
        List<Object> list = new ArrayList<>();
        // 遍历数组往集合里存元素
        for (int i = 0; i < arr.length; i++) {
            // 如果集合里面没有相同的元素才往里存
            if (!list.contains(arr[i])) {
                list.add(arr[i]);
            }
        }
        // 直接toArray
        Object[] newArr = list.toArray();
        return newArr;
    }

    public static void main(String[] args) {

        String[] arr = new String[5];
        arr[0] = "hello";
        arr[1] = "world";
        arr[2] = "你好";
        arr[3] = "hello";
        arr[4] = "热心的朝阳群众";

        System.out.println(arr.toString());
        for (String s : arr) {
            System.out.println(s);
        }
        System.out.println("========结果分割线=======");
        Object[] s  = ifRepeat(arr);
        for (Object o : s) {
            System.out.println(o);
        }

    }
}

结果

3、一个数组,除一个元素外其它都是两两相等,求那个元素;

分析:这个可以按照遍历的模式进行匹配,不过这里用到“异或运算”,达到了代码的最简洁程度。题目中除了一个元素以外都是两两相等,因为异或运算可以支持位置交换,两个相等的值,异或为0,一个值与0异或运算,结果为这个值本身。所以这样就非常简单了。

package com.demo.array;

/**
 * 从一个数组中找出唯一不成对的元素
 *
 * @author dongx on 2020/9/20
 */
public class ArrayFindOneDemo {

    public static int findOne(int[] array) {
        int result = 0;
        for (int i = 0; i < array.length; i++) {
            // 异或运算的骚操作
            result ^= array[i];
        }
        return result;
    }

    public static void main(String[] args) {
        int[] array = {2, 3, 3, 2, 5, 6, 6, 8, 8};
        int result = findOne(array);
        System.out.println("不同的那个数是:" + result);
    }
}

结果

4、写一个算法,可以将一个二维数组顺时针旋转90度;

分析

按照改变顺序先梳理逻辑:(输入中括号有问题,所以截图了。。。)

package com.demo.array;

/**
 * 将二维数组旋转90度
 *
 * @author dongx on 2020/9/20
 */
public class ArraySpin90Demo {
    public static int[][] rotate(int[][] matrix) {
        int n = matrix.length;
        // 对于要旋转的数a[i][j]满足 i<n/2 并且 i<=j<n-1-i
        for (int i = 0; i < n / 2; i++) {
            for (int j = i; j < n - 1 - i; j++) {
                // 引入temp,解决节点顺时针交换
                int temp = matrix[i][j];
                matrix[i][j] = matrix[n - 1 - j][i];
                matrix[n - 1 - j][i] = matrix[n - 1 - i][n - 1 - j];
                matrix[n - 1 - i][n - 1 - j] = matrix[j][n - 1 - i];
                matrix[j][n - 1 - i] = temp;
            }
        }
        return matrix;
    }

    public static void main(String[] args) {

        int[][] array = new int[3][3];
        // 第一行
        array[0][0] = 1;
        array[0][1] = 2;
        array[0][2] = 3;
        // 第二行
        array[1][0] = 4;
        array[1][1] = 5;
        array[1][2] = 6;
        // 第三行
        array[2][0] = 7;
        array[2][1] = 8;
        array[2][2] = 9;

        System.out.println("原始数组:");
        for (int[] is : array) {
            for (int i : is) {
                System.out.print(i + " ");
            }
            System.out.println("");
        }

        int[][] result = rotate(array);
        System.out.println("顺时针翻转90度的数组:");
        for (int[] is : result) {
            for (int i : is) {
                System.out.print(i + " ");
            }
            System.out.println("");
        }
    }
}

结果

链表

1、将一个链表相邻的两个节点反转;例如:1->2->3->4,输出为:2->1->4->3;

分析:通过调整结点指针域的指向来直接调换相邻的两个结点。如果单链表恰好有偶数个结点,那么只需要将奇偶结点对调即可,如果链表有奇数个结点,那么只需要将除了最后一个结点外的其它结点进行奇偶对调即可。

package com.demo.linklist;

/**
 * 将链表相邻两个点调换
 *
 * @author dongx on 2020/9/20
 */
public class LinkedListSwapPairsDemo {

    public static void swapPairs(ListNode head) {
        //判断是否为空
        if(head==null || head.next==null){
            return;
        }
        //当前遍历结点
        ListNode cur = head.next;
        //当前结点的前驱结点
        ListNode pre = head;
        //当前结点后继结点的后继结点
        ListNode next = null;
        while (cur!=null&&cur.next!=null){
            next = cur.next.next;
            pre.next = cur.next;
            cur.next.next = cur;
            cur.next = next;
            pre = cur;
            cur = next;
        }
    }

    static class ListNode {
        /**
         * 数据域
         */
        int data;
        /**
         * 下一个结点的引用
         */
        ListNode next;
    }


    public static void main(String[] args) {
        ListNode head = new ListNode();
        head.next = null;
        ListNode tmp = null;
        ListNode cur = head;
        for (int i = 1; i < 8; i++) {
            tmp = new ListNode();
            tmp.data = i;
            tmp.next = null;
            cur.next = tmp;
            cur = tmp;
        }
        System.out.print("顺序输出:");
        for (cur = head.next; cur != null; cur = cur.next) {
            System.out.print(cur.data + " ");
        }
        swapPairs(head);
        System.out.print("\n逆序输出:");
        for (cur = head.next; cur != null; cur = cur.next) {
            System.out.print(cur.data + " ");
        }
    }
}

结果

提前结束

今天先把前两个部分:数组和链表的题编写出来分享给大家,由于内容比较多,已经超出字数限制,故此分为两篇文章,感谢大家支持,敬请持续关注。。。

特别声明

本文为原创文章,如需转载可与我联系,标明出处。谢谢!

往期文章:

《【内功修炼系列1】线性数据结构(上篇)》

《【内功修炼系列1】线性数据结构(下篇2)》