[笔面] 几道典型的编程题目

0001 Singleton 单例模式

题目:设计一个类,我们只能生成该类的一个实例

参考答案

 1 public class Singleton {

 2 

 3     private static Singleton singleton;

 4 

 5     // 注意点: 私有化构造函数

 6     private Singleton() {

 7     }

 8 

 9     // synchronized 多线程环境 

10     public synchronized static Singleton getInsatnce() {

11         if(singleton==null) {

12             singleton = new Singleton();

13 

14         }       

15 

16         return singleton;

17     }

18 }

 

0002 替换空格

题目:请实现一个函数,把字符数组中的每个空格替换成"%20"。如"I am javamm",输出为"I%20am%20javamm"

参考答案

/** 参考思路



1. 遍历一次字符串,得到空格的总数,以及数组的总长度



2. 创建一个新字符数组,长度为原字符串长度 + 空格个数 *2



3. 两个指针,P1指向原字符数组末尾,P2指向新字符数组的末尾 



4. 移动P1,若非空格,复制至新字符串数组,若为空格,P2插入%20



分析



  时间复制度为O(n)

*/

 

0003 从尾到头打印链表

题目:输入一个链表,从尾到头打印出每个结点的值

参考答案

/**

  遍历链表至栈中,因为栈为“后进先出”

*/

 

0004 重建二叉树

题目:输入一个二叉树的前序遍历和中序遍历的结果,请重建出该二叉树(假设不含有重复数字) 。如输入前序遍历{ 1,2,4,7,3,5,6,8} 和中序遍历序列 {4,7,2,1,5,3,8,6}

0005 用两个栈实现队列

题目:用两个栈实现一个队列

0006 旋转数组的最小数字

题目:把一个数组的最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序的一个旋转,输出旋转数组的最小元素。例如:{3,4,5,1,2} 为{1,2,3,4,5}的一个旋转,最小元素为1

参考答案

// 二分查找 O(logn)

 

0006 斐波那契数列

题目:写一个函数,输入n,求Fibonacci数列的第n项

0007 二进制中1的个数

题目:请实现一个函数,输入一个整数,输出该数二进制表示中1的个数。如输入9,二进制为1001,输出结果为2

参考答案

/**

* 把一个整数减1之后,再与原来的整数做位与运算,得到的结果相当于是把整数的二进制表示中的最右边一个1变成0

*/

 

0008 数值的整数次方

题目:求数值的整数次方,不需要考虑大数的问题。

参考答案

// 代码需要完备

// 当指数为负数,底数为0等

 

0009 打印1到最大的n位数

题目:输入一个数字n,按顺序打印出从1到最大n位的十进制数。如输入3,则打印1,2,3...999

参考答案

// 当n很大时,会溢出

// 可考虑用字符串表示数字

 

0010 在O(1)时间删除链表结点

题目:给定单向链表的头指针和一个结点指针,定义一个函数在O(1)时间删除结点

参考答案

// 思路:把需删除结点的下一个结点内容复制到需删除的结点上,再把下一个结点删除

 



0011 调整数组顺序使奇数位于偶数前面

题目:输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有奇数位于数组的前半部分,所有偶数位于数组的后半部分

参考答案

/**

1. 维护两个指针,P1指向数组的第一个数字,向后移动; P2指向数组的最后一个数字,向前移动。

2. 在指针相遇前,若P1指向数字是偶数,P2指向数字是奇数,则交换这两个数字

3. 把比较的逻辑部分抽取出来,实现解耦,以满足更多的比较,如把所有的负数放在非负数前面,能被3整除的数放在不能被3整除的数前面

4. 代码扩展性,可重用性

*/

 

0012 链表中倒数第K个结点

题目:输入一个单向链表,输出该链表中倒数第k个结点

/**

1. 两个指针P1,P2

2. P1从链表头向前遍历走k-1,P2不变

3. 第k步,P1,P2一起移动,当P1到达尾结点时,P2正好是倒数第k个结点

*/

 

0013 求链表的中间结点

题目:如果链表中结点总数为奇数,返回中间结点;如果结点总数是偶数,返回中间两个结点的任意一个

/**

1. 类同0012,定义两个指针P1,P2

2. 遍历链表,P1走一步,P2走两步,当P2至达末尾时,P1正好在链表的中间

*/

0014 

 

判断一个单向链表是形成了环形结构

题目: 判断一个单向链表是形成了环形结构

1. 类同0013,定义两个指针P1,P2

2. 历链表,P1走一步,P2走两步,如果走的快的追上了走的慢的,则为环形链表

3. 如果P2走到了链表末尾,仍没有追上P1,则不是环形链表

0015 反转链表

题目:定义一个函数,输入一个链表的头结点,反转该链表并输出反转后链表的头结点

/**

* 为防止链表断开,需要保存结点

*/

 

0016 合并两个排序的链表

题目:输入两个递增排序的链表,合并这两个链表并使新链表中的结点仍然是按照递增排序的

0017 树的子结构

题目:输入一棵二叉树A和B,判断B是不是A的子结构。

0018 二叉树的镜像

题目:请完成一个函数,输入一个二叉树,输出它的镜像

 /* 前序遍历树的每个结点 * 如果遍历到的结点有子结点,则交换子结点 * 当交换完所有非叶子结点的左右子结点后,就得到了树的镜像 */



public void mirrorRecursively(BinaryTreeNode binaryTreeNode) {



if(binaryTreeNode==null || (binaryTreeNode.leftNode==null && binaryTreeNode.rightNode==null) )



{ return; }



BinaryTreeNode tempNode=binaryTreeNode.leftNode;

binaryTreeNode.leftNode=binaryTreeNode.rightNode;

binaryTreeNode.rightNode=tempNode;



// 递归

mirrorRecursively(binaryTreeNode.leftNode);

mirrorRecursively(binaryTreeNode.rightNode);        

}

 

# 0019 包含min函数的栈 ## 题目:定义栈的数据结构,实现一个得到栈最小值的min函数。使得调用min,push及pop的时间复杂度都为O(1). ##

参考答案

 /* 采用辅助栈,将最小值压入辅助栈中 */

0020 栈的压入,弹出序列

题目:输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序。假设压入栈的所有数字都不相等。如序列1,2,3,4,5为压栈序列,序列4,5,3,2,1为该压栈序列对应的一个弹出序列,但4,3,5,1,2不是该压栈序列的弹出序列

/**

* 如果下一个弹出的数字刚好是栈顶数字,直接弹出

* 如果下一个弹出的数字不在栈顶,把压栈序列中还没有入栈的数字压入辅助栈,直到把下一个需要弹出的数字压入栈顶为止

* 如果所有的数字都压入栈了,仍然没有找到下一下弹出的数字,那么该序列不可能是一个弹出序列

*/

0031 归并排序MergeSort

题目:请写出归并排序

参考答案

Java package com.javamm.al.sort;



/** * * 算法复杂度O(nlogn),冒泡,插入,选择都需要O(n2),若n为10000,n平方100000000,nlogn为40000,若归并需要40s, * 则插入排序需要28h 缺点:需要在存储器有另一个大小等于被排序的数据项目的数组,即要足够的空间 思想:归并两个有序的数组 * 注意:类名请写成MergeSort */ public class MergeSort {



public static void recSort(int[] data, int left, int right) {



    System.out.println("recSort,left:" + left + " right:" + right);



    if (left == right) {



        return;

    }



    int center = (left + right) / 2;



    // 递归左边

    recSort(data, left, center);



    // 递归右边

    recSort(data, center + 1, right);



    // merge

    merge(data, left, center, right);



}



public static void merge(int[] data, int left, int center, int right) {



    System.out.println("merge,left:" + left + " center: " + center

            + " right: " + right);



    int[] tmpData = new int[data.length];

    int mid = center + 1;

    int third = left;

    int tmp = left;

    while (left <= center && mid <= right) {

        if (data[left] <= data[mid]) {

            tmpData[third++] = data[left++];

        } else {

            tmpData[third++] = data[mid++];

        }

    }



    while (mid <= right) {

        tmpData[third++] = data[mid++];

    }



    while (left <= center) {

        tmpData[third++] = data[left++];

    }



    // 将tmpData中的内容复制回原数组

    while (tmp <= right) {

        data[tmp] = tmpData[tmp++];

    }

}



public static void main(String[] args) {



    int[] data = { 3, 2, 1, 6, 0, 8 };



    recSort(data, 0, data.length - 1);



    for (int i = 0; i < data.length; i++) {

        System.out.print(data[i] + " ,");

    }

}

}

 

 # 0032 QuickSort ## 请写出快速排序

## 参考答案Java

/* 思想: * 1. 一躺排序将要排序的数据分成独立的两部分,一部分比另一部分所有数据都小,可用两指针,leftP,rightP,分别指向首尾 * 2. 再按此方法对这两部分数据进行排序,可用递归 * * 算法复杂度: * * 最坏情况算法复杂度:O(n2),最好O(nlogn) */



public class QuickSort {



private static int[] a;



public static void main(String[] args) {

    a = new int[] { 5, 3, 2, 1, 8, 4 };

    recQuickSort(0, a.length - 1);

    display();

}



public static void recQuickSort(int left, int right) {

    // Step 1 :把数组划分成左边和右边,左边比选定的值小,右边比选定的值大

    // Step 2 : 递归调用左边

    // Step 3 : 递归调用右边

    if (left >= right) {

        return;

    }



    int pivot = a[right];

    int partition = partitionIt(left, right, pivot);

    recQuickSort(left, partition - 1);

    recQuickSort(partition + 1, right);

}



public static int partitionIt(int left, int right, int pivot) {

    display();



    // 左指针

    int leftP = left - 1;



    // 右指针

    int rightP = right;



    while (true) {



        // 左边的值都比pivot小时

        while (a[++leftP] < pivot)

            ;



        // 右边的值都比pivot大时

        while (rightP > 0 && a[--rightP] > pivot)

            ;



        if (leftP >= rightP) {

            break;

        } else {

            // 交换

            swap(left, right);

        }

    }

    swap(leftP, right);

    return leftP;

}



public static void swap(int left, int right) {

    int temp = a[left];

    a[left] = a[right];

    a[right] = temp;

}



public static void display() {

    for (int i = 0; i < a.length; i++) {

        System.out.print(a[i] + " ");

    }

    System.out.println("");

}

}

 

0033 HeapSort

参考答案

/**

*

* 若一个数组节点的索引为x

*

* 其父节点的下标为(x-1)/2

*

* 左子节点下标为2*x +1

*

* 右子节点下标为2*x +2

*

*/
 
  

层次遍历二叉树

题目:写一个函数,层次遍历二叉树

参考答案

/**

* 思路:每打印一个结点的时候,如果该结点有子结点,将子结点放入队列末尾

*/

字符串的排列

题目:输入一个字符串,打印出该字符串中字符的所有排列。如输入abc,则输出acb,bac,bca,cab,cba

参考答案

Java /** * 将字符串分为两部分,一部分是字符串的第一个字符,另一部分是第一个字符外所有字符 * 用递归 */



 # 字符串的所有组合 ##



题目:输入一个字符串,打印出该字符串中字符的所有组合。如输入abc,则输出a,b,c,ab,ac,bc,abc,注,ab,ba是不同的排列,但只算一个组合 Java



/** * 输入n个字符,则能构成长度为1,2,...n的组合 * 求n个字符长度为m的组合的时候,把m个字符分为两部分,第一个和m-1个,递归 */ # 正方体所有面之和相等 ## 输入一个含有8个数字的数组,判断有没有可能这8个数字分别放到正方体的8个顶点上,使得每一面的顶点之和都相等。



 Java /** * 如输入a1,a2,a3,a4,a5,a6,a7,a8,求所有排列,看是否满足条件,a1+a2+a3+a4==a5+a6+a7+a8,a1+a3+a5+a7=a2+a4+a6+a8,并且a1+a2+a5+a6=a3+a4+a7+a8 */ # 0029 数组中出现次数超过一半的数字 ## 题目:数组中有一个数字出现的次数超过了数组长度的一半,请求出这个数字。如{1,2,3,2,2,2,5,4,2},此数字为2 Java /** * 思路一:排序,排好序后,求中间数字 * 根据快排思想,先随机选一个数字,使比他小的都排在左边,比他大的都排右边。完成后,若此数字下标为n/2,即为此数。如果下标> n/2,那么此数位于左边,可在左半部查找,用递归。否则位于右边 * 思路二: * 遍历数组时,保存两个值,一个为数组中数字,一个为次数 * 当遍历下一个数字时,若与保存数字相同,次数+1.若与保存数字不同,次数-1,若次数=0,重新保存新数字,并将次数设为1.最后一次把次数设为1的数字即为所需的数字 * eg: * 1,1 * 2,1 * 3,1 * 2,1 * 2,2 * 2,3 * 2,2 * 2,1 * 2,2 */ # 0030 求一个数组的第k小的数 ## 题目:给定一个无序整数数组,返回这个数组中第k小的数 ```Java /* 思路一: * 最平常的思路是将数组排序,最快的排序是快排,然后返回已排序数组的第k个数,算法时间复杂度为O(nlogn),空间复杂度为O(1)。使用快排的思想,但是每次只对patition之后的数组的一半递归,这样可以将时间复杂度将为O(n)。



具体的思路:将数组按照第一个数字first进行划分,将比first小的放在左边,比first大的放在右边,first放中间。返回patition之后first的下标j。如果此时j+1==k(+1是因为数组下标从0开始)那么说明a[j]就是要找的第k个数。如果j+1<k,递归查找左半部分;如果j+1>k,递归查找右半部分

* * 思路二: * 维持一个大小为k的大顶堆,遍历一次数组,如果数组中的元素比堆顶的元素小,那么就更新堆。最后堆中存放的是数组中的前k小元素。堆顶元素即为要求的第k小个数。



这种算法不需要改变原数组结构,但是需要额外维持一个大小为O(k)的堆,时间复杂度为(nlogk)。当k比n小的多的时候,这个算法也是一个很好的选择 /* # 0031 连续子数组的最大和 ## 题目:输入一个整数型数组,数组中有正数也有负数。数组中一个或连续的多个整数组成一个子数组。求所有子数组的和的最大值Java /**

思路一:列举数组规律

维护一个最大值max

若max < 0 ,抛弃

若 > max ,更新max *

思路二:动态规划

f(i)表示以第i个数字结尾的子数组的最大和,0<=i<n,有如下公式

f(i) = data[i], i=0或f(i-1)<=0

f(i) = f(i-1) + data[i] i!=0 && f(i-1) > 0 */ ``` # 0032 从1到n整数中1出现的次数 ## 题目:输入一个整数n,求从1到n这n个整数的十进制表示中1出现的次数。eg: 输入12,包含1的数字,1,10,11,12,共出现了5次

 

0033 把数组排成最小的数

题目:输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。eg输入数组{3,32,321} ,则打印这3个数字排成的最小数字321323

你可能感兴趣的:(编程)