算法题一:移除元素
1、给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。
2、不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
示例 1:
给定 nums = [3,2,2,3], val = 3,
函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。
你不需要考虑数组中超出新长度后面的元素。
示例 2:
给定 nums = [0,1,2,2,3,0,4,2], val = 2,
函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。
注意这五个元素可为任意顺序。
你不需要考虑数组中超出新长度后面的元素。
这个题目和之前清楚相同元素类似,都可以使用双指针解决:
class Solution {
public int removeElement(int[] nums, int val) {
int length = nums.length;
int i = 0;
for (int j = 0; j < length; j++) {
if (nums[j] != val) {
nums[i] = nums[j];
i++;
}
}
//System.out.println(Arrays.toString(nums));
return i;
}
}
【思路】:
1、首先定义一个指针i
,指向当前数组中最后一个有效的元素的后一位;
2、另外一个指针j
用于遍历数组元素,查找与val不同的值;
3、如果遇到了这个值,让当前的i指针指向的元素等于这个值,然后i指针
挪动一位;
4、最终返回i索引
;
算法题二:回文链表
- 请判断一个链表是否为回文链表。
示例 1:
输入: 1->2
输出: false
示例 2:
输入: 1->2->2->1
输出: true
自己的做法:
class Solution {
public boolean isPalindrome(ListNode head) {
List<Integer> list = new ArrayList();
while (head != null) {
list.add(head.val);
head = head.next;
}
int length = list.size();
boolean flag = true;
for (int i = 0; i < length / 2; i++) {
if ((int) list.get(i) != (int) list.get(length - i - 1)) {
flag = false;
break;
}
}
return flag;
}
}
【思路】:
1、while循环遍历整个链表,将其中所有的值存储在list集合中;
2、for循环遍历list/2次;
3、如果当前位置i上的元素与length - i - 1位置的元素不相等,循环终止,返回false;
4、否则返回true;
这个解法理解起来容易,但是它的时间和空间开销较大;
官方的解法:
我录制了官方给出来的动画解法:递归
代码:
class Solution {
private ListNode frontPointer;
private boolean recursivelyCheck(ListNode currentNode) {
if (currentNode != null) {
if (!recursivelyCheck(currentNode.next)) { //语句1
return false;
}
if (currentNode.val != frontPointer.val) {
return false;
}
frontPointer = frontPointer.next; //语句2
}
//如果currentNode结点为空,返回true之后,语句1此时也执行完了,这个方法就弹栈了
//这个currentNode指向的结点也就被释放资源了
//而此时的这个currentNode是刚才为null的结点的前一个结点
return true;
}
public boolean isPalindrome(ListNode head) {
frontPointer = head;
return recursivelyCheck(head);
}
}
【总结】:
1、给定两个变量,一个是递归函数外面的指针,一个是方法的形参;
2、首先使用递归的做法,使得currentNode指向链表中的最后一个结点;
3、此时frontPointer指针指向的是链表的第一个结点;
4、frontPointer结点依次向后指,而currentNode指针随着方法的弹栈,依次逆向指向结点;
5、如果两个指针指向的结点这时候的值不相等,返回false,整个方法弹栈;
6、语句1方法的进栈弹栈规定了currentNode指针的指向,语句2则规定了递归函数外的frontPointer指针指向;
7、currentNode在每次方法弹栈之后都会向前挪动一位,但是frontPointer指针只有在两个值相等的时候才挪动一次;
8、这个最终返回的结果是由所有次的对比之后的共同结果,如果当前判断中,前面递归方法返回false,整个方法直接返回false;如果前面返回false,但是这一次值不相等,也返回false;
9、也就是说,只有满足回文特征的链表最终返回true;