== 现在有一个单向链表,谈一谈,如何判断链表中是否出现了环==
单链表有环,是指单链表中某个节点的next指针域指向的是链表中在它之前的某一个节点,这样在链表的尾部形成一个环形结构。
// 链表的节点结构如下 typedef struct node { int data; struct node *next; } NODE;
最常用方法:定义两个指针,同时从链表的头节点出发,一个指针一次走一步,另一个指针一次走两步。如果走得快的指针追上了走得慢的指针,那么链表就是环形链表;如果走得快的指针走到了链表的末尾(next指向 NULL)都没有追上第一个指针,那么链表就不是环形链表。
通过使用STL库中的map表进行映射。首先定义 map<NODE *, int> m; 将一个 NODE * 指针映射成数组的下标,并赋值为一个 int 类型的数值。然后从链表的头指针开始往后遍历,每次遇到一个指针p,就判断 m[p] 是否为0。如果为0,则将m[p]赋值为1,表示该节点第一次访问;而如果m[p]的值为1,则说明这个节点已经被访问过一次了,于是就形成了环。
<mark>谈一谈,bucket如果用链表存储,它的缺点是什么?</mark>
①查找速度慢,因为查找时,需要循环链表访问
②如果进行频繁插入和删除操作,会导致速度很慢。
== 有一个链表,奇数位升序偶数位降序,如何将链表变成升序==
public class OddIncreaseEvenDecrease {
/** * 按照奇偶位拆分成两个链表 */
public static Node[] getLists(Node head) {
Node head1=null;
Node head2=null;
Node cur1=null;
Node cur2=null;
int count=1;//用来计数
while (head!=null) {
if (count%2==1) {
if (cur1!=null) {
cur1.next=head;
cur1=cur1.next;
}else {
cur1=head;
head1=cur1;
}
}else {
if (cur2!=null) {
cur2.next=head;
cur2=cur2.next;
}else {
cur2=head;
head2=cur2;
}
}
head=head.next;
count++;
}
//跳出循环,记得最后两个末尾的下一个元素指向null
cur1.next=null;
cur2.next=null;
Node[] nodes=new Node[] {head1,head2};
return nodes;
}
/** * 反转链表 */
public static Node reverseList(Node head) {
Node pre=null;
Node next=null;
while (head!=null) {
next=head.next;
head.next=pre;
pre=head;
head=next;
}
return pre;
}
/** * 合并两个有序链表 */
public static Node combineList(Node head1,Node head2) {
if (head1==null||head2==null) {
return head1!=null? head1:head2;
}
Node head=head1.val<head2.val? head1:head2;
Node cur1=head==head1? head1:head2;
Node cur2=head==head1? head2:head1;
Node pre=null;
Node next=null;
while (cur1!=null&&cur2!=null) {
//这里一定要有=,否则一旦cur1的value和cur2的value相等的话,
//下面的pre.next会出现空指针异常
if (cur1.val<=cur2.val) {
pre=cur1;
cur1=cur1.next;
}else {
next=cur2.next;
pre.next=cur2;
cur2.next=cur1;
pre=cur2;
cur2=next;
}
}
pre.next=cur1==null? cur2:cur1;
return head;
}
}
class Node{
Node next;
int val=0;
public Node(int val) {
this.val=val;
}
}
<mark>随机链表的复制</mark>
//随机链表的复制
public RandomListNode copyRandomList(RandomListNode head) {
if (head == null)
return null;
RandomListNode p = head;
// copy every node and insert to list
while (p != null) {
RandomListNode copy = new RandomListNode(p.label);
copy.next = p.next;
p.next = copy;
p = copy.next;
}
// copy random pointer for each new node
p = head;
while (p != null) {
if (p.random != null)
p.next.random = p.random.next;
p = p.next.next;
}
// break list to two
p = head;
RandomListNode newHead = head.next;
while (p != null) {
RandomListNode temp = p.next;
p.next = temp.next;
if (temp.next != null)
temp.next = temp.next.next;
p = p.next;
}
return newHead;
}
<mark>一个数组,除一个元素外其它都是两两相等,求那个元素?</mark>
public static int find1From2(int[] a){
int len = a.length, res = 0;
for(int i = 0; i < len; i++){
res= res ^ a[i];
}
return res;
}
<mark>找出数组中和为S的一对组合,找出一组就行</mark>
//从数组中找出一对数和为S的一对数
public int[] twoSum(int[] nums, int target) {
HashMap<Integer, Integer> map = new HashMap<Integer, Integer>();
int[] a = new int[2];
map.put(nums[0], 0);
for (int i = 1; i < nums.length;i++) {
if (map.containsKey(target - nums[i])) {
a[0] = map.get(target -nums[i]);
a[1] = i;
return a;
} else {
map.put(nums[i], i);
}
}
return a;
}
<mark>求一个数组中连续子向量的最大和</mark>
//求一个数组中连续子向量的最大和
public class FindGreatestSumOfSubArray {
public int findGreatestSumOfSubArray(int[] array) {
int sum = array[0];
int max = array[0];
for(int i = 1;i < array.length;i ++) {
//前面sum大于0,认为是有贡献的,可以叠加在上面。否则认为没有贡献,另起炉灶
if(sum >= 0) {
sum = sum + array[i];
}
else {
sum = array[i];
}
if(sum > max) {
max = sum;
}
}
return max;
}
<mark>介绍一下,排序都有哪几种方法?请列举出来。</mark>
排序的方法有:插入排序(直接插入排序、希尔排序),交换排序(冒泡排序、快速排序),选择排序(直接选择排序、堆排序),
归并排序,分配排序(箱排序、基数排序)
快速排序的伪代码。
/ /使用快速排序方法对a[ 0 :n- 1 ]排序
从a[ 0 :n- 1 ]中选择一个元素作为m i d d l e,该元素为支点
把余下的元素分割为两段left 和r i g h t,使得l e f t中的元素都小于等于支点,而right 中的元素都大于等于支点
递归地使用快速排序方法对left 进行排序
递归地使用快速排序方法对right 进行排序
所得结果为l e f t + m i d d l e + r i g h t