1.线程安全的单例模式
//饿汉式 线程安全的
class danlie1 {
private danlie1(){}
private static danlie1 d=new danlie1();
public static danlie1 get(){
return d;
}
}
//懒汉式 线程不安全
class Single {
private Single(){}
private static Single d=null;
public static Single get(){
if(d==null) d=new Single();
return d;
}
}
class Single2 {
private Single2(){}
private volatile static Single2 d;
public static Single2 get(){
if(d==null){
synchronized (Single2.class){
if(d==null){
d=new Single2();
}
}
}
return d;
}
}
class Sing3{
private Sing3(){}
private static class rrr{
private static Sing3 sa=new Sing3();
}
public static Sing3 get(){
return rrr.sa;
}
}
enum ddd{
Instance;
}
2.循环打印ABC
public static void main(String[] args) {
ExecutorService executorService = Executors.newSingleThreadExecutor();
Runnable a = new Runnable() {
@Override
public void run() {
System.out.println("A");
executorService.execute(this::run);
}
};
Runnable b = new Runnable() {
@Override
public void run() {
System.out.println("B");
executorService.execute(this::run);
}
};
Runnable c = new Runnable() {
@Override
public void run() {
System.out.println("C");
executorService.execute(this::run);
}
};
executorService.execute(a);
executorService.execute(b);
executorService.execute(c);
}
3.微信扫码登录
4.不使用临时变量实现swap
//方法一:
a=a^b;
b=a^b;
a=a^b;
//方法二:
a=b-a;
b=b-a;
a=b+a;
5.十进制转十六进制
public String toHex(int num) {
if (num == 0) return "0";
char[] chars = new char[]{'0','1','2','3','4','5','6','7','8','9','a', 'b', 'c', 'd', 'e', 'f'};
StringBuffer buffer = new StringBuffer();
int temp;
while (num != 0) {
temp = num & 15;
buffer.insert(0, chars[temp]);
num >>>= 4;
}
return buffer.toString();
}
6.翻转链表
class Solution {
public ListNode reverseList(ListNode head) {
ListNode pre=null;
ListNode curr=head;
while(curr!=null){
ListNode next=curr.next;
curr.next=pre;
pre=curr;
curr=next;
}
return pre;
}
}
7.快排
3 种快排基准选择方法:
随机(rand函数)、固定(队首、队尾)、三数取中(队首、队中和队尾的中间数)
4种优化方式:
优化1:当待排序序列的长度分割到一定大小后,使用插入排序
优化2:在一次分割结束后,可以把与Key相等的元素聚在一起,继续下次分割时,不用再对与key相等元素分割
优化3:优化递归操作
优化4:使用并行或多线程处理子序列
8.top K问题
- 直接排序(适用于数据量小的情况下)
- 快速排序的变形 (只使用于内存够的情况)
(1)这种方法类似于快速排序,首先选择一个划分元,将比这个划分元大的元素放到它的前面,比划分元小的元素放到它的后面,此时完成了一趟排序。
(2)如果此时这个划分元的序号index刚好等于K,那么这个划分元以及它左边的数,刚好就是前K个最大的元素;如果index > K,那么前K大的数据在index的左边,那么就继续递归的从index-1个数中进行一趟排序;如果index < K,那么再从划分元的右边继续进行排序,直到找到序号index刚好等于K为止。再将前K个数进行排序后,返回Top K个元素。这种方法就避免了对除了Top K个元素以外的数据进行排序所带来的不必要的开销。 - 最小堆法
这是一种局部淘汰法。先读取前K个数,建立一个最小堆。然后将剩余的所有数字依次与最小堆的堆顶进行比较,如果小于或等于堆顶数据,则继续比较下一个;否则,删除堆顶元素,并将新数据插入堆中,重新调整最小堆。当遍历完全部数据后,最小堆中的数据即为最大的K个数。 - 分治法
将全部数据分成N份,前提是每份的数据都可以读到内存中进行处理,找到每份数据中最大的K个数。此时剩下NK个数据,如果内存不能容纳NK个数据,则再继续分治处理,分成M份,找出每份数据中最大的K个数,如果M*K个数仍然不能读到内存中,则继续分治处理。直到剩余的数可以读入内存中,那么可以对这些数使用快速排序的变形或者归并排序进行处理。 - Hash法
如果这些数据中有很多重复的数据,可以先通过hash法,把重复的数去掉。这样如果重复率很高的话,会减少很大的内存用量,从而缩小运算空间。处理后的数据如果能够读入内存,则可以直接排序;否则可以使用分治法或者最小堆法来处理数据。
9.8G的int型数据,计算机的内存只有2G,怎么对它进行排序?(外部排序)(百度一面)
添加链接描述
我们可以使用外部排序来对它进行处理。首先将整个文件分成许多份,比如说m份,划分的依据就是使得每一份的大小都能放到内存里。然后我们用快速排序或者堆排序等方法对每一份数据进行一个内部排序,变成有序子串。接着对这m份有序子串进行m路归并排序。取这m份数据的最小元素,进行排序,输出排序后最小的元素到结果中,同时从该元素所在子串中读入一个元素,直到所有数据都被输出到结果中为止。
10.数组 树化
class TreeNode1{
private int val;
TreeNode1 left;
TreeNode1 right;
public TreeNode1(){}
public TreeNode1(int val){
this.val=val;
}
TreeNode1 vec2tree(int[] nums,int idx){
TreeNode1 root;
if(Integer.valueOf(nums[idx])==null){
root=null;
idx++;
}else{
root=new TreeNode1(nums[idx]);
idx++;
root.left=vec2tree(nums,idx);
root.right=vec2tree(nums,idx);
}
return root;
}
}
11.n个骰子出现和为m的概率
int getNSumCount(int n, int sum)
{
if(n<1||sum<n||sum>6*n)
{
return 0;
}
if(n==1)
{
return 1;
}
int resCount=0;
resCount=getNSumCount(n-1,sum-1)+getNSumCount(n-1,sum-2)+
getNSumCount(n-1,sum-3)+getNSumCount(n-1,sum-4)+
getNSumCount(n-1,sum-5)+getNSumCount(n-1,sum-6);
return resCount;
}
class Solution {
public double[] dicesProbability(int n) {
double[] dp = new double[6];
Arrays.fill(dp, 1.0 / 6.0);
for (int i = 2; i <= n; i++) {
double[] tmp = new double[5 * i + 1];
for (int j = 0; j < dp.length; j++) {
for (int k = 0; k < 6; k++) {
tmp[j + k] += dp[j] / 6.0;
}
}
dp = tmp;
}
return dp;
}
}
12.有向图的最短路径–迪杰斯特拉算法
public class DijkstraAlgorithm {
public static void main(String[] args) {
char[] vertex = { 'A', 'B', 'C', 'D', 'E', 'F', 'G' };
// 邻接矩阵
int[][] matrix = new int[vertex.length][vertex.length];
final int N = 65535;// 表示不可以连接
matrix[0] = new int[] { N, 5, 7, N, N, N, 2 };
matrix[1] = new int[] { 5, N, N, 9, N, N, 3 };
matrix[2] = new int[] { 7, N, N, N, 8, N, N };
matrix[3] = new int[] { N, 9, N, N, N, 4, N };
matrix[4] = new int[] { N, N, 8, N, N, 5, 4 };
matrix[5] = new int[] { N, N, N, 4, 5, N, 6 };
matrix[6] = new int[] { 2, 3, N, N, 4, 6, N };
DJS D=new DJS();
int[] dsj = D.dsj(matrix, 6);
System.out.println(Arrays.toString(dsj));
}
}
class DJS{
private int[] already_arr;
private int[] pre_visited;
private int[] dis;
public int[] dsj(int[][] nums, int index) {
int length=nums.length;
this.already_arr = new int[length];
this.pre_visited = new int[length];
this.dis = new int[length];
// 初始化 dis数组
Arrays.fill(dis, 65535);
this.dis[index] = 0;// 设置出发顶点的访问距离为0
this.already_arr[index] = 1; // 设置出发顶点被访问过
update(nums,index);// 更新index顶点到周围顶点的距离和前驱顶点
for (int j = 1; j < nums.length; j++) {
int idx = findNextStartPoint();// 选择并返回新的访问顶点
update(nums,idx); // 更新index顶点到周围顶点的距离和前驱顶点
}
return dis;
}
// 更新index下标顶点到周围顶点的距离和周围顶点的前驱顶点,
private void update(int[][] nums, int index) {
int len = 0;
// 根据遍历我们的邻接矩阵的 matrix[index]行
for (int j = 0; j < nums[index].length; j++) {
// len 含义是 : 出发顶点到index顶点的距离 + 从index顶点到j顶点的距离的和
len = dis[index] + nums[index][j];
// 如果j顶点没有被访问过,并且 len 小于出发顶点到j顶点的距离,就需要更新
if (!(already_arr[j]==1) && len < dis[j] ) {
pre_visited[j]=index;// 更新j顶点的前驱为index顶点
dis[j]=len; // 更新出发顶点到j顶点的距离
}
}
}
public int findNextStartPoint() {
int min = 65535, index = 0;
for (int i = 0; i < already_arr.length; i++) {
if (already_arr[i] == 0 && dis[i] < min) {
min = dis[i];
index = i;
}
}
// 更新 index 顶点被访问过
already_arr[index] = 1;
return index;
}
}
更多推荐
java面试之常见场景题
发布评论