<span style="font-family: 'microsoft yahei';font-size:18px; line-height: 26px;">先将其中一个链表的链头按到另一个链表的尾部,如果他们有交集则会构成一个环,题目等价于找链表中的环的起始结点。找到后将链表还原。</span>
一.两个长链表求交点(考虑环)
<span style="font-size: 48px;"> </span><span style="font-size:18px;"> public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
if (headA == null || headB == null) {
return null;
}
ListNode ta; // 用于记录headA链表的尾结点
ListNode ha = headA;
// 第一步、找到headA的尾结点
while (ha.next != null) {
ha = ha.next;
}
ta = ha; // 记录链表headA的尾结点
// 第二步、将headB接到ta后面
ta.next = headB;
// 第三步、判断是否存在环
// 判断链表是否存在环,办法为:
// 设置两个指针(fast, slow),初始值都指向头,slow每次前进一步,fast每次前进二步,
// 如果链表存在环,则fast必定先进入环,而slow后进入环,两个指针必定相遇。
// (当然,fast先行头到尾部为NULL,则为无环链表)程序如下:
ListNode fast = headA; // 每次前进一步
ListNode slow = headA; // 每次前进二步
while (fast != null && fast.next != null) {
fast = fast.next.next;
slow = slow.next;
if (fast == slow) { // 如果相遇了就退出来
break;
}
}
// 没有环的情况
if (fast == null || fast.next == null) {
ta.next = null; // 解开拼接好的链表
return null;
}
// 有环的情况
// 找到环的入口点
// 当fast若与slow相遇时,slow肯定没有走遍历完链表,而fast已经在环内循环了n圈(1<=n)。
// 假设slow走了s步,则fast走了2s步(fast步数还等于s 加上在环上多转的n圈),设环长为r,则:
//
// 2s = s + nr
// s= nr
//
// 设整个链表长L,入口环与相遇点距离为x,起点到环入口点的距离为a。
// a + x = nr
// a + x = (n – 1)r +r = (n-1)r + L - a
// a = (n-1)r + (L – a – x)
//
// (L – a – x)为相遇点到环入口点的距离,由此可知,从链表头到环入口点等于(n-1)循环内环+相遇点到环入口点,
// 于是我们从链表头、与相遇点分别设一个指针,每次各走一步,两个指针必定相遇,且相遇第一点为环入口点。
slow = headA;
while (slow != fast) {
fast = fast.next;
slow = slow.next;
}
ta.next = null;
return slow;
}
}</span>
二。反转单链表,反转单链表的部分区间
ublic class ListNode {
int val;
ListNode next;
ListNode(int x) { val = x; }
}
1
2
3
4
5
算法实现类
public class Solution {
public ListNode reverseList(ListNode head) {
// 头结点
ListNode root = new ListNode(0);
ListNode nextNode;
while (head != null) {
nextNode = head.next;
head.next = root.next;
root.next = head;
head = nextNode;
}
return root.next;
}
}
三。删除原排序数组内重复次数超过三次的数字(不开辅助空间)
public class Solution {
/**
* @param A: a array of integers
* @return : return an integer
*/
public int removeDuplicates(int[] nums) {
// write your code here
int i = 0;
int numsLen = nums.length;
while(i<numsLen-1){
if(nums[i]==nums[i+1]){
for(int j=i+1;j<numsLen-1;j++)
nums[j]=nums[j+1];
numsLen-=1;
}else
i+=1;
}
return numsLen;
}
}
四。
当我们加上一个正数时,和会增加;当我们加上一个负数时,和会减少。如果当前得到的和是个负数,那么这个和在接下来的累加中应该抛弃并重新清零,不然的话这个负数将会减少接下来的和。实现:
复制代码
//copyright@ July 2010/10/18
//updated,2011.05.25.
#include <iostream.h>
int maxSum(int* a, int n)
{
int sum=0;
//其实要处理全是负数的情况,很简单,如稍后下面第3点所见,直接把这句改成:"int sum=a[0]"即可
//也可以不改,当全是负数的情况,直接返回0,也不见得不行。
int b=0;
for(int i=0; i<n; i++)
{
if(b<0) //...
b=a[i];
else
b+=a[i];
if(sum<b)
sum=b;
}
return sum;
}
int main()
{
int a[10]={1, -2, 3, 10, -4, 7, 2, -5};
//int a[]={-1,-2,-3,-4}; //测试全是负数的用例
cout<<maxSum(a,8)<<endl;
return 0;
}
/*-------------------------------------
五。反转字符串
<pre name="code" class="java">* 将data中start到end之间的数字反转
*
* @param data
* @param start
* @param end
*/
public static void reverse(char[] data, int start, int end) {
if (data == null || data.length < 1 || start < 0 || end > data.length || start > end) {
return;
}
while (start < end) {
char tmp = data[start];
data[start] = data[end];
data[end] = tmp;
start++;
end--;
}
}
/**
* 题目一:输入一个英文句子,翻转句子中单词的顺序,但单词内字啊的顺序不变。
* 为简单起见,标点符号和普通字母一样处理。
*
* @param data
* @return
*/
public static char[] reverseSentence(char[] data) {
if (data == null || data.length < 1) {
return data;
}
reverse(data, 0, data.length - 1);
int start = 0;
int end = 0;
while (start < data.length) {
if (data[start] == ' ') {
start++;
end++;
} else if (end == data.length || data[end] == ' ') {
reverse(data, start, end - 1);
end++;
start = end;
} else {
end++;
}
}
return data;
六。寻找第一个不重复的元素
public class FirstNonRepeatedChar {
public static char getFirstNoRepeatChar1(String str) {
// 使用LinkedHashMap可以记住元素的插入顺序
Map<Character, Integer> map = new LinkedHashMap<Character, Integer>(
str.length());
for (char c : str.toCharArray()) {
// 以字符作为k 出现的个数作为值
map.put(c, map.containsKey(c) ? map.get(c) + 1 : 1);
}
// 遍历MAp 找到第一个值为1的就是找的结果
for (Entry<Character, Integer> entry : map.entrySet()) {
if (entry.getValue() == 1)
return entry.getKey();
}
throw new RuntimeException("没有找到相关的字符");
}
public static char getFirstNoRepeatChar2(String str) {
// 保存重复的元素
Set<Character> repeating = new HashSet<Character>();
// 保存不重复的元素
List<Character> noRepeating = new ArrayList<Character>();
for (int i = 0; i < str.length(); i++) {
// 遍历字符串
char letter = str.charAt(i);
// 集合里已经包含了元素的时候 跳过这个元素
if (repeating.contains(letter)) {
continue;
}
// 在不重复地方集合里包含了元素的时候删除这个元素
if (noRepeating.contains(letter)) {
noRepeating.remove((Character) letter);
repeating.add(letter);
} else {
noRepeating.add(letter);
}
}
// 返回不重复的第一个就可以了
return noRepeating.get(0);
}
public static char getFirstNoRepeatChar3(String str) {
// 用HashMap来存储元素和个数
Map<Character, Integer> map = new HashMap<Character, Integer>();
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
// 要是集合里有的话 就加一
if (map.containsKey(c)) {
map.put(c, map.get(c) + 1);
} else {
// 没有的话 就存储
map.put(c, 1);
}
}
// 遍历集合找到值为一的就是要找的元素
for (int j = 0; j < str.length(); j++) {
char b = str.charAt(j);
if (map.get(b) == 1)
return b;
}
throw new RuntimeException("没有找到");
}
七。将栈变队列
大多数人的思路是:始终维护s1作为存储空间,以s2作为临时缓冲区。
入队时,将元素压入s1。
出队时,将s1的元素逐个“倒入”(弹出并压入)s2,将s2的顶元素弹出作为出队元素,之后再将s2剩下的元素逐个“倒回”s1。
见下面示意图:
2Stacks1Queue