// 单链表的反转【腾讯面试题】
// 方式一、 递归方式翻转
/**
- 用来反转整个链表
*/
public void reverse1(){
//判断当前链表是否为空链表,如果是空链表,则结束运行,如果不是,则调用重载的reverse方法完成反转
if (isEmpty()){
return;
}
reverse(head.next);
}
/**
-
反转指定的结点curr,并把反转后的结点返回
-
@param curr
-
@return
*/
public Node reverse(Node curr){ // aa bb cc
if (curr.next==null){
head.next=curr;
return curr;
}
//递归的反转当前结点curr的下一个结点;返回值就是链表反转后,当前结点的上一个结点
Node pre = reverse(curr.next);
//让返回的结点的下一个结点变为当前结点curr;
pre.next=curr;
//把当前结点的下一个结点变为null
curr.next=null;
return curr;
}
方式二
- 从尾到头打印单链表 【百度面试题】
方式 1:反向遍历(这里就不写代码了,和前一个基本一样)
方式 2:Stack 栈 (利用栈
的先进后出
的特点,来实现逆序打印效果)
2. 单向循环链表
单链表的一个变形是单向循环链表,链表中最后一个节点的next
域不再为null
,而是指向链表的头节点。
单线无头循环链表代码实现
public class MyHeadlessLinkedList {
// 虽然没有头部但是依旧需要使用一个字段来记录第一个值
private Node head;
//记录链表的长度
private int N;
public MyHeadlessLinkedList(){
}
/**
- 定义节点类
*/
public class Node{
T item ; //存储数据
Node next; //下一个节点
public Node(T item, Node next) {
this.item = item;
this.next = next;
}
}
/**
- 清空链表
*/
public void clear(){
this.head = null;
this.N = 0;
}
/**
-
判断链表是否为空,是返回true,否返回false
-
@return
*/
public boolean isEmpty(){
return this.N == 0;
}
/**
-
获取链表中元素的个数
-
@return
*/
public int length(){
return this.N;
}
/**
-
读取并返回链表中的第index个元素的值
-
@param index
-
@return
*/
public T get(int index){
if(index > this.N){
System.out.println(“链表长度越界!”);
return null;
}
Node n = this.head;
for (int i = 0; i < index; i++) {
n = n.next;
}
return n.item;
}
public Node getNode(int index){
if(index > this.N){
System.out.println(“链表长度越界!”);
return null;
}
Node n = this.head;
for (int i = 0; i < index; i++) {
n = n.next;
}
return n;
}
/**
-
往链表中添加一个元素
-
@param t
*/
public void insert(T t){
if(isEmpty()){
this.head = new Node(t, null);
}
Node n = this.head;
for (int i = 1; i < this.N ; i++) {
n=n.next;
}
//让当前最后一个结点指向新结点
n.next = new Node(t, this.head);
N ++;
}
/**
-
在链表的第index个元素之前插入一个值为t的数据元素
-
@param index
-
@param t
*/
public void insert(int index,T t){
//找到index位置前一个结点
Node pre = this.head;
for (int i = 0; i <= index - 1 ; i++) {
pre = pre.next;
}
//要找到index位置的结点
Node curr = pre.next;
pre.next = new Node(t,curr);
this.N ++;
}
/**
-
删除并返回链表中第i个数据元素
-
@param index
-
@return
*/
public T remove(int index){
//找到index位置前一个结点
Node curr = null;
if(index == 0){ // index 为0时表示需要重新处理head
curr = head;
head = head.next;
}else {
Node pre = this.head;
for (int i = 0; i < index - 1 ; i++) {
pre = pre.next;
}
//要找到index位置的结点
curr = pre.next;
//找到index位置的下一个结点
pre.next = curr.next;
}
this.N --;
return curr.item;
}
/**
*返回链表中首次出现的指定的数据元素的位序号,若不存在,则返回-1
-
@param t
-
@return
*/
public int indexOf(T t){
Node pre = this.head;
int count = 0;
while (pre.next!=null){
count ++ ;
pre = pre.next;
if(pre.item.equals(t)){
return count;
}
}
return -1;
}
}
案例使用 约瑟夫问题
问题描述:
传说有这样一个故事,在罗马人占领乔塔帕特后,39 个犹太人与约瑟夫及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被敌人抓到,于是决定了一个自杀方式,41个人排成一个圆圈,第一个人从1开始报数,依次往后,如果有人报数到3,那么这个人就必须自杀,然后再由他的下一个人重新从1开始报数,直到所有人都自杀身亡为止。然而约瑟夫和他的朋友并不想遵从。于是,约瑟夫要他的朋友先假装遵从,他将朋友与自己安排在第16个与第31个位置,从而逃过了这场死亡游戏。
问题转换:
-
41个人坐一圈,第一个人编号为1,第二个人编号为2,第n个人编号为n。
-
编号为1的人开始从1报数,依次向后,报数为3的那个人退出圈;
-
自退出那个人开始的下一个人再次从1开始报数,以此类推;
-
求出最后退出的那个人的编号。
解题思路:
-
构建含有41个结点的单向循环链表,分别存储1~41的值,分别代表这41个人;
-
使用计数器count,记录当前报数的值;
-
遍历链表,每循环一次,count++;
-
判断count的值,如果是3,则从链表中删除这个结点并打印结点的值,把count重置为0
代码实现
- 方式一(链表实现)、
public static void main(String[] args) {
/*
-
"约瑟夫环"问题
-
共S个人,从第F个人开始报数,报数1—N
-
这里初始化的41个,人从第1个开始报数,数到3的出局
-
S 为人数 ,F 为开始人的编号 ,N为需要走的个数
-
最后运行结果:3,6,9,12,15,18,21,24,27,30,33,36,39,1,5,10,14,19,23,28,32,37,41,7,13,20,26,34,40,8,17,29,38,11,25,2,22,4,35,16,31
*/
int S=41;
int F=1;
int N=3;
MyHeadlessLinkedList iml = new MyHeadlessLinkedList();
for (int i = 1; i <= S; i++) {
iml.insert(i);
}
MyHeadlessLinkedList.Node node = iml.getNode(F-1); // 因为下标零开始所以 F-1
MyHeadlessLinkedList.Node temp=null;
int count = 0 ;
while (node.next != node){ //当自己与自己的next相等时,表示剩最后一个了停止循环
count++ ;
if(count == N ){
temp.next = node.next;
System.out.print(node.item+“,”);
count = 0;
}else {
temp = node;
}
node = node.next;
}
System.out.println(node.item+“\n”);
}
方式二
public static void main(String args[]) {
final int N=41,S=1,M=3;
int i = S-1, k = N, g = 1, j;
int a[] = new int[N]; //使用数组存放人;
for(int h = 1; h <= N; h++){
a[h-1] = h; //将编号为h的人存到下标为h-1的数组中
}
do {
i = i + (M -1) ; //计算出圈人下标,因为自身需要报数所以减一
while(i >= k)
i = i-k;
System.out.print(a[i]+“,”);
j = i;
while ( j < k-1) {
a[j] = a[j+1]; //第i个人出圈后将后面的人的编号往前移动,相当于把数到5的踢出局
j++;
}
k–; //圈中人数k-1
g++; //循环次数g+1
}while(g <= N); //最多N轮循环
}
方式三
public static void main(String args[]) {
final int N = 41, S = 1, M = 3; //N为总人数,从第S个人开始报数,报数到M的为出圈
int a[] = new int[N + 1];
int i, j, k;
k = S - 1; //k等于S-1,表示从S开始数出圈人的下标
for (i = 1; i <= N; i++) {
for (j = 1; j <= M; j++) {
if (k == N)
k = 1; //当出圈人的下标到末尾时,记数从1开始
else
k++;
if (a[k] == 1) //a[k] 做标记,说明下标为k的人已经出圈了
j–; //j-1, 以保证每次数超过M个
}
a[k] = 1; //标记出圈
System.out.print((k) + “,”); //下标为k的人标号为k
}
}
3. 双向链表
一种更复杂的链表是**“双向链表”或“双面链表”**。每个节点有两个链接:一个指向前一个节点,当此节点为第一个节点时,指向空值;而另一个指向下一个节点,当此节点为最后一个节点时,指向空值。
直接上代码
public class TowWayLinkedList implements Iterable{
// 首节点
private Node head;
// 尾节点
private Node last;
// 链表长度
private int N;
public TowWayLinkedList(){
this.head = new Node(null,null,null);
this.last = null;
this.N = 0;
}
class Node {
T item;
Node next;
Node pre;
public Node(T item,Node next,Node pre){
this.item = item;
this.next = next;
this.pre = pre;
}
}
/**
- 空置链表
*/
public void clear(){
this.last = null;
this.head = new Node(null,null,null);
this.N = 0;
}
/**
-
判断链表是否为空,是返回true,否返回false
-
@return
*/
public boolean isEmpty(){
return this.N==0;
}
/**
-
获取链表中元素的个数;
-
@return
*/
public int length(){
return this.N;
}
/**
-
:读取并返回链表中的第i个元素的值
-
@param indix
-
@return
*/
public T get(int indix){
Node node = this.head;
for (int i = 0; i < indix; i++) {
node = node.next;
}
return node.item;
}
/**
-
往链表中添加一个元素
-
@param t
*/
public void insert(T t){
if(this.last==null){
last = new Node(t,null,head);
head.next = last;
}else{
Node oldLast = this.last;
Node node = new Node(t,null,oldLast);
oldLast.next = node;
last = node;
}
N++;
}
/**
-
在链表的第i个元素之前插入一个值为t的数据元素
-
@param index
-
@param t
*/
public void insert(int index,T t){
Node node = this.head;
// 获取需要插入数据的上一个节点
for (int i = 0; i < index; i++) {
node = node.next;
}
// 当前节点
Node curr = node.next;
// 需要插入的节点,上一个节点为原来的上一个节点,下一个节点是当前节点的位置
Node newNode = new Node(t, curr, node);
// 上一个节点的next标记为新增节点
node.next = newNode;
// 当前节点往后移以为,上一个节点标记为新增节点
curr.pre = newNode;
N++;
}
/**
*删除并返回链表中第i个数据元素;
-
@param index
-
@return
*/
public T remove(int index){
Node node = this.head;
// 获取需要插入数据的上一个节点
for (int i = 0; i < index; i++) {
node = node.next;
}
// index当前节点
Node curr = node.next;
// index 下一个节点
Node currNext = curr.next;
// 上一个节点的next标记为index的下一个节点
最后
分享一套我整理的面试干货,这份文档结合了我多年的面试官经验,站在面试官的角度来告诉你,面试官提的那些问题他最想听到你给他的回答是什么,分享出来帮助那些对前途感到迷茫的朋友。
面试经验技巧篇
- 经验技巧1 如何巧妙地回答面试官的问题
- 经验技巧2 如何回答技术性的问题
- 经验技巧3 如何回答非技术性问题
- 经验技巧4 如何回答快速估算类问题
- 经验技巧5 如何回答算法设计问题
- 经验技巧6 如何回答系统设计题
- 经验技巧7 如何解决求职中的时间冲突问题
- 经验技巧8 如果面试问题曾经遇见过,是否要告知面试官
- 经验技巧9 在被企业拒绝后是否可以再申请
- 经验技巧10 如何应对自己不会回答的问题
- 经验技巧11 如何应对面试官的“激将法”语言
- 经验技巧12 如何处理与面试官持不同观点这个问题
- 经验技巧13 什么是职场暗语
面试真题篇
- 真题详解1 某知名互联网下载服务提供商软件工程师笔试题
- 真题详解2 某知名社交平台软件工程师笔试题
- 真题详解3 某知名安全软件服务提供商软件工程师笔试题
- 真题详解4 某知名互联网金融企业软件工程师笔试题
- 真题详解5 某知名搜索引擎提供商软件工程师笔试题
- 真题详解6 某初创公司软件工程师笔试题
- 真题详解7 某知名游戏软件开发公司软件工程师笔试题
- 真题详解8 某知名电子商务公司软件工程师笔试题
- 真题详解9 某顶级生活消费类网站软件工程师笔试题
- 真题详解10 某知名门户网站软件工程师笔试题
- 真题详解11 某知名互联网金融企业软件工程师笔试题
- 真题详解12 国内某知名网络设备提供商软件工程师笔试题
- 真题详解13 国内某顶级手机制造商软件工程师笔试题
- 真题详解14 某顶级大数据综合服务提供商软件工程师笔试题
- 真题详解15 某著名社交类上市公司软件工程师笔试题
- 真题详解16 某知名互联网公司软件工程师笔试题
- 真题详解17 某知名网络安全公司校园招聘技术类笔试题
- 真题详解18 某知名互联网游戏公司校园招聘运维开发岗笔试题
资料整理不易,点个关注再走吧
对前途感到迷茫的朋友。
面试经验技巧篇
- 经验技巧1 如何巧妙地回答面试官的问题
- 经验技巧2 如何回答技术性的问题
- 经验技巧3 如何回答非技术性问题
- 经验技巧4 如何回答快速估算类问题
- 经验技巧5 如何回答算法设计问题
- 经验技巧6 如何回答系统设计题
- 经验技巧7 如何解决求职中的时间冲突问题
- 经验技巧8 如果面试问题曾经遇见过,是否要告知面试官
- 经验技巧9 在被企业拒绝后是否可以再申请
- 经验技巧10 如何应对自己不会回答的问题
- 经验技巧11 如何应对面试官的“激将法”语言
- 经验技巧12 如何处理与面试官持不同观点这个问题
- 经验技巧13 什么是职场暗语
[外链图片转存中…(img-XipgDhFT-1714373343203)]
面试真题篇
- 真题详解1 某知名互联网下载服务提供商软件工程师笔试题
- 真题详解2 某知名社交平台软件工程师笔试题
- 真题详解3 某知名安全软件服务提供商软件工程师笔试题
- 真题详解4 某知名互联网金融企业软件工程师笔试题
- 真题详解5 某知名搜索引擎提供商软件工程师笔试题
- 真题详解6 某初创公司软件工程师笔试题
- 真题详解7 某知名游戏软件开发公司软件工程师笔试题
- 真题详解8 某知名电子商务公司软件工程师笔试题
- 真题详解9 某顶级生活消费类网站软件工程师笔试题
- 真题详解10 某知名门户网站软件工程师笔试题
- 真题详解11 某知名互联网金融企业软件工程师笔试题
- 真题详解12 国内某知名网络设备提供商软件工程师笔试题
- 真题详解13 国内某顶级手机制造商软件工程师笔试题
- 真题详解14 某顶级大数据综合服务提供商软件工程师笔试题
- 真题详解15 某著名社交类上市公司软件工程师笔试题
- 真题详解16 某知名互联网公司软件工程师笔试题
- 真题详解17 某知名网络安全公司校园招聘技术类笔试题
- 真题详解18 某知名互联网游戏公司校园招聘运维开发岗笔试题
[外链图片转存中…(img-SnP7Am6u-1714373343204)]
资料整理不易,点个关注再走吧