1. 判断链表中是否有环
非开空间复杂度O(1)解法:直接使用Set容器,如果有重复节点值则判断当前有环,这个思路比较简单明确
O(1)解法:使用两个指针,一个一次走两格快指针,一个慢一次走一格慢指针。在有环的情况下因为慢指针是一个一个走的所以快慢指针一定会相遇。有了这思路便可快速的判断出是否有环
public class Solution {
public boolean hasCycle(ListNode head) {
if(head == null) return false;
ListNode low = head;
ListNode fast = head;
while(fast != null && fast.next != null){
low = low.next;
fast = fast.next.next;
if(low == fast){
return true;
}
}
return false;
}
}
2.链表中环的入口
这个题目是上题的变种题,使用上面的思路一 很简单的可以找出链表中环的入口,但是这样的空间复杂度是大的
下面摘抄至Lettcode上的算法题解
如下图所示,X,Y,Z分别为链表起始位置,环开始位置和两指针相遇位置,则根据快指针速度为慢指针速度的两倍,可以得出:
2*(a + b) = a + b + n * (b + c);即
a=(n - 1) * b + n * c = (n - 1)(b + c) +c;
注意到b+c恰好为环的长度,故可以推出,如将此时两指针分别放在起始位置和相遇位置,并以相同速度前进,当一个指针走完距离a时,另一个指针恰好走出 绕环n-1圈加上c的距离。
故两指针会在环开始位置相遇。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-j9KZfiOx-1617769634106)(http://cdn.noteblogs.cn/122270_1439340467801_QQ%E6%88%AA%E5%9B%BE20150812084712.jpg)]
set解法
import java.util.*;
public class Solution {
public ListNode detectCycle(ListNode head) {
Set<ListNode> set = new HashSet<>();
if(head == null) return null;
while(head != null){
if(set.contains(head)){
return head;
}
set.add(head);
head = head.next;
}
return null;
}
}
快慢指针解法,TODO
3. 两数之和
给出一个整数数组,请在数组中找出两个加起来等于目标值的数,
你给出的函数twoSum 需要返回这两个数字的下标(index1,index2),需要满足 index1 小于index2.。注意:下标是从1开始的
假设给出的数组中只存在唯一解
例如:
给出的数组为 {20, 70, 110, 150},目标值为90
输出 index1=1, index2=2
思路:还是使用Set。解决普通解法两次循环问题,一次遍历即可。遍历nums[i]的时候判断target -nums[i]是否在set容器中,如果在说明已经找到了这两个数,如果不在容器中则将nums[i]加入set容器中
public class Solution {
/**
*
* @param numbers int整型一维数组
* @param target int整型
* @return int整型一维数组
*/
public int[] twoSum (int[] numbers, int target) {
int[] res = new int[2];
// write code here
Map<Integer, Integer> map = new HashMap<>();
map.put(numbers[0], 0);
for(int i = 1; i < numbers.length; i++){
if(map.containsKey(target - numbers[i])){
res[0] = map.get(target - numbers[i]) + 1;
res[1] = i + 1;
}
map.put(numbers[i], i);
}
return res;
}
}
4. 找到字符串的最长无重复字符子串
使用一个队列维护一个窗口
public class Solution {
/**
*
* @param arr int整型一维数组 the array
* @return int整型
*/
public int maxLength (int[] arr) {
// write code here
Deque<Integer> q = new LinkedList<>();
int res = 0;
for(int i = 0;i < arr.length;i++){
// 注意这个while 如果发现包含应该要将窗口内的元素都移除
while(q.contains(arr[i])){
q.pollFirst();
}
q.offerLast(arr[i]);
res = Math.max(res, q.size());
}
return res;
}
}
5. 括号序列
简单的思路:使用栈,如果遇到’(‘则加入’)‘到栈中,相反如果遇到’)'则弹出栈判断是否相等,其余两个字符也是一样的
public class Solution {
/**
*
* @param s string字符串
* @return bool布尔型
*/
public boolean isValid (String s) {
// write code here
Stack<Character> stack = new Stack<>();
for(int i = 0;i < s.length();i++){
if(s.charAt(i) == '('){
stack.push(')');
continue;
}
else if(s.charAt(i) == '['){
stack.push(']');
continue;
}
else if(s.charAt(i) == '{') {
stack.push('}');
continue;
}
else{
if(stack.isEmpty() || stack.pop() != s.charAt(i)) return false;
}
}
return stack.isEmpty();
}
}
6. 二分查找
请实现有重复数字的升序数组的二分查找
给定一个 元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1
题目的关键点在于重复数字,对于升序序列来说可以使用二分查找,但是因为有重复元素,所以应该要向左逼近
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
* 如果目标值存在返回下标,否则返回 -1
* @param nums int整型一维数组
* @param target int整型
* @return int整型
*/
public int search (int[] nums, int target) {
// write code here
if(nums == null || nums.length == 0) return -1;
int left = 0, right = nums.length - 1;
while(left < right){
int mid = (left + right) >> 1;
if(nums[mid] < target){
left = mid + 1;
}else{
//向左逼近
right = mid;
}
}
return nums[left] == target ? left : -1;
}
}
target){
left = mid + 1;
}else{
//向左逼近
right = mid;
}
}
return nums[left] == target ? left : -1;
}
}