文章目录
- 6.15
- [14. 最长公共前缀](https://leetcode-cn.com/problems/longest-common-prefix/)
- [28. 实现 strStr()](https://leetcode-cn.com/problems/implement-strstr/)
- [459. 重复的子字符串](https://leetcode-cn.com/problems/repeated-substring-pattern/)
- [7. 整数反转](https://leetcode-cn.com/problems/reverse-integer/)
- [112. 路径总和](https://leetcode-cn.com/problems/path-sum/)
- [113. 路径总和 II](https://leetcode-cn.com/problems/path-sum-ii/)
- [437. 路径总和 III](https://leetcode-cn.com/problems/path-sum-iii/)
- [26. 删除排序数组中的重复项](https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array/)
- [80. 删除排序数组中的重复项 II](https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array-ii/)
- [27. 移除元素](https://leetcode-cn.com/problems/remove-element/)
- 6.16
- [203. 移除链表元素](https://leetcode-cn.com/problems/remove-linked-list-elements/)
- [237. 删除链表中的节点](https://leetcode-cn.com/problems/delete-node-in-a-linked-list/)
- [876. 链表的中间结点](https://leetcode-cn.com/problems/middle-of-the-linked-list/)
- [面试题 02.07. 链表相交](https://leetcode-cn.com/problems/intersection-of-two-linked-lists-lcci/)
- [328. 奇偶链表](https://leetcode-cn.com/problems/odd-even-linked-list/)
- [725. 分隔链表](https://leetcode-cn.com/problems/split-linked-list-in-parts/)
- [61. 旋转链表](https://leetcode-cn.com/problems/rotate-list/)
- [189. 旋转数组](https://leetcode-cn.com/problems/rotate-array/)
6.15
14. 最长公共前缀
难度简单
这个题其实就是对字符串的一个简单操作。
class Solution {
public String longestCommonPrefix(String[] strs) {
if(strs.length == 0){
return "";
}
if(strs.length == 1){
return strs[0];
}
String str = getPrefix(strs[0], strs[1]);
for(int i = 2;i < strs.length;i++){
str = getPrefix(strs[i], str);
if(str.length() == 0){
break;
}
}
return str;
}
public String getPrefix(String a, String b){
int length = Math.min(a.length(), b.length());
int len = 0;
for(int i = 0;i < length;i++){
if(a.charAt(i) == b.charAt(i)){
len++;
}else{
break;
}
}
if(len == 0){
return "";
}
return a.substring(0,len);
}
}
28. 实现 strStr()
难度简单
利用String类的indexOf方法能简单快速的找到答案。
class Solution {
public int strStr(String haystack, String needle) {
if(needle == null || needle.length() == 0){
return 0;
}
int index = haystack.indexOf(needle);
return index;
}
}
459. 重复的子字符串
难度简单
这个题就是对上一个的题的进阶。emmmm,自己暴力法写了超出了时间限制。
参照了题解,发现大佬不亏是大佬。主要想法就是,既然能用重复字符串组成,那么就可以把他看作是移动字符位置,能组成与原来相同的字符串。为了避免多余的移动旋转,将字符串加上它本身,如果满足要求,那么在新构成的字符串上,去掉首尾两端,一定包含原来的字符串。
不过我想问一句,这真的是简单吗?
class Solution {
public boolean repeatedSubstringPattern(String s) {
String str = s + s;
return str.substring(1, str.length() - 1).contains(s);
}
}
7. 整数反转
难度简单
利用字符串实现的简单反转问题(用字符串主要是为了解决溢出的问题)。用StringBuilder的效率比String要高得多。
class Solution {
public int reverse(int x) {
StringBuilder str = new StringBuilder();
if(x < 0){
str.append("-");
x = -x;
}
while(x != 0){
str.append(x % 10);
x = x / 10;
}
try{
return Integer.parseInt(str.toString());
}catch(Exception e){
return 0;
}
}
}
112. 路径总和
难度简单
简单的一个dfs的问题。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public boolean hasPathSum(TreeNode root, int sum) {
if(root == null){
return false;
}
List<Integer> path = new LinkedList<>();
return dfs(root, 0, sum, path);
}
public boolean dfs(TreeNode root, int sum, int target, List<Integer> path){
path.add(root.val);
sum += root.val;
if(root.left != null){
if(dfs(root.left, sum, target, path)){
return true;
}
}
if(root.right != null){
if(dfs(root.right, sum, target, path)){
return true;
}
}
if(root.left == null && root.right == null){
if(sum == target){
return true;
}
}
sum -= root.val;
path.remove(path.size() - 1);
return false;
}
}
或者是可以采用更简单,减的方式来完成。这样效率会更高。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public boolean hasPathSum(TreeNode root, int sum) {
if(root == null){
return false;
}
sum -= root.val;
if(root.left == null && root.right == null && sum == 0){
return true;
}
return hasPathSum(root.left, sum) || hasPathSum(root.right, sum);
}
}
113. 路径总和 II
难度中等
在前一题的基础上增加List就行了。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
List<List<Integer>> lists = new ArrayList<>();
public List<List<Integer>> pathSum(TreeNode root, int sum) {
List<Integer> path = new LinkedList<>();
dfs(root, 0, sum, path);
return lists;
}
public void dfs(TreeNode root, int sum, int target, List<Integer> path){
if(root == null){
return;
}
sum += root.val;
path.add(root.val);
if(root.left == null && root.right == null && sum == target){
lists.add(new ArrayList(path));
}
dfs(root.left, sum, target, path);
dfs(root.right, sum, target, path);
sum -= root.val;
path.remove(path.size() - 1);
}
}
437. 路径总和 III
难度简单
实现思路就是以每个节点作为根节点去找有没有对应的路径,把所有的结果相加就行。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public int pathSum(TreeNode root, int sum) {
if(root == null){
return 0;
}
int result = countPath(root,sum);
int a = pathSum(root.left,sum);
int b = pathSum(root.right,sum);
return result + a + b;
}
public int countPath(TreeNode root,int sum){
if(root == null){
return 0;
}
sum = sum - root.val;
int result = sum == 0 ? 1:0;
return result + countPath(root.left,sum) + countPath(root.right,sum);
}
}
26. 删除排序数组中的重复项
难度简单
用一个int记录下当前的数字就行。当遇到相同的就跳过,不相同时与length处的值就交换位置。length++即可。
class Solution {
public int removeDuplicates(int[] nums) {
if(nums == null || nums.length == 0){
return 0;
}
int length = 1;
int num = nums[0];
for(int i = 1;i < nums.length;i++){
if(nums[i] == num){
continue;
}else{
nums[length++] = nums[i];
num = nums[i];
}
}
return length;
}
}
80. 删除排序数组中的重复项 II
难度中等
在上题的基础上增加一个count来记录下每个元素出现过的次数就可以了。
class Solution {
public int removeDuplicates(int[] nums) {
if(nums == null || nums.length == 0){
return 0;
}
int length = 1;
int count = 1;
int num = nums[0];
for(int i = 1;i < nums.length;i++){
if(nums[i] == num && count < 2){
nums[length++] = nums[i];
count++;
}else if(nums[i] == num && count >= 2){
continue;
}else{
nums[length++] = nums[i];
count = 1;
num = nums[i];
}
}
return length;
}
}
27. 移除元素
难度简单
修改之后的结果应该是所有等于val的元素都在数组的后面,所以用双指针来进行操作。把所有等于val的元素都交换到数组后面来。
class Solution {
public int removeElement(int[] nums, int val) {
if(nums == null || nums.length == 0){
return 0;
}
int l = 0;
int r = nums.length - 1;
while(l < r){
while(l < r && nums[l] != val){
l++;
}
while(l < r && nums[r] == val){
r--;
}
if(l >= r){
break;
}
int temp = nums[l];
nums[l] = nums[r];
nums[r] = temp;
l++;
r--;
}
if(nums[l] != val){
l++;
}
return l;
}
}
6.16
203. 移除链表元素
难度简单
简单的对链表进行操作。其中需要注意的是对链表的头部和尾部的额外判断操作以及对空值的判断。
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode removeElements(ListNode head, int val) {
if(head == null){
return null;
}
ListNode node = head;
ListNode pre = null;
while(node != null){
if(node.val != val){
if(pre == null){
head = node;
pre = node;
}else{
pre.next = node;
pre = node;
}
}
if(node.next == null && node.val == val && pre != null){
pre.next = null;
}
node = node.next;
}
if(head.val == val){
return null;
}
return head;
}
}
237. 删除链表中的节点
这个题之前在《剑指offer》上做过,现在突然再看,思维又被限制住了。一直在想为什么head链表为什么没有传进来,之后才想起不需要head。要删除这个node,与下一个节点交换值(非尾节点),更新next就行了。
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public void deleteNode(ListNode node) {
node.val = node.next.val;
node.next = node.next.next;
}
}
876. 链表的中间结点
难度简单
快慢指针就行。
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode middleNode(ListNode head) {
ListNode slow = head, fast = head;
while(fast != null && fast.next != null){
fast = fast.next.next;
slow = slow.next;
}
return slow;
}
}
面试题 02.07. 链表相交
难度简单
这个题目感觉有点问题。题目要求:程序尽量满足 O(n) 时间复杂度,且仅用 O(1) 内存。但是感觉怎么作业到不了这个程度。就算是题解它的时间复杂度也不是O(n)。当然也可能是我太菜了,没有理解大佬的思想。
如果不适用额外空间的话,就用以下的方法进行循环对比,这样可以消除长度差,让链表A的每一个节点都能与链表B的所有节点都继续一次比较。如果没有交点时,这样遍历总会遍历到两者的null对比(也就是最后一个对比的节点)。我个人觉得这样的做法时间复杂度是O(mn),请大佬解惑。
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode p = headA;
ListNode q = headB;
while(p != q){
p = p == null ? headA : p.next;
q = q == null ? headB : q.next;
}
return p;
}
}
328. 奇偶链表
难度中等
实现思路就是利用两个指针分别来存储奇偶位置的节点。之后再将两个链表拼接起来就行了。需要注意的是head==null和链表只有两个节点的情况。前者会引起空值异常,后者会导致循环链表的出现。
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode oddEvenList(ListNode head) {
if(head == null){
return null;
}
ListNode oddNode = head.next, evenNode = head;
ListNode oddList = oddNode, evenList = evenNode;
ListNode node = oddList;
while(oddNode != null && oddNode.next != null && evenNode.next != null
&& evenNode != null){
oddNode = oddNode.next.next;
evenNode = evenNode.next.next;
oddList.next = oddNode;
evenList.next = evenNode;
oddList = oddList.next;
evenList = evenList.next;
}
if(oddNode != null && oddList != oddNode){
oddList.next = oddNode;
}
if(evenNode != null && evenList != evenNode){
evenList.next = evenNode;
}
evenList.next = node;
return head;
}
}
725. 分隔链表
难度中等
想法都是不难,不过要考虑完全还是比较费时间的。主要的特殊情况是当每个数组元素的长度都是1时。
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode[] splitListToParts(ListNode root, int k) {
int length = 0;
ListNode node = root;
while(node != null){
length++;
node = node.next;
}
int len = length / k;
int num = length % k;//余数,前num的列表需要在len的基础上增加一个长度
ListNode[] result = new ListNode[k];
node = root;
int i = 0;
while(node != null){
int indexLen = len;
int index = 1;
if(num != 0){
indexLen = len + 1;
num--;
}
result[i] = node;
if(index == indexLen){//特殊处理,当每个子列表长度都是1时
ListNode temp = node.next;
node.next = null;
node = temp;
}else{
node = node.next;
}
while(node != null && index < indexLen){
if(index == indexLen - 1){
ListNode temp = node.next;
node.next = null;
node = temp;
}else{
node = node.next;
}
index++;
}
i++;
}
return result;
}
}
61. 旋转链表
难度中等
这个题转换思路就是找到倒数第K个节点,以这个节点为头结点,在末尾加上前面的链表就i选哪个了。
所以我们先得到倒数第k个节点,在寻找时需要记录下倒数第k + 1的节点,将其next置为null,避免循环的出现。之后再把头部链表加在末尾就行了。
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode rotateRight(ListNode head, int k) {
if(head == null){
return null;
}
int length = 0;
ListNode node = head;
while(node != null){
node = node.next;
length++;
}
k = k % length;
if(k == 0){
return head;
}
int i = 0;
ListNode pre = null;//前一链表的最后一个节点,需要将其next置为null
//找到倒数第k个节点
ListNode kNode = head;
ListNode temp = head;
while(i < k){
i++;
temp = temp.next;
}
while(temp != null){
if(temp.next == null){
pre = kNode;
}
temp = temp.next;
kNode = kNode.next;
}
pre.next = null;
ListNode h = kNode;
while(kNode.next != null ){
kNode = kNode.next;
}
kNode.next = head;
return h;
}
}
189. 旋转数组
难度简单
emmm,暴力求解
class Solution {
public void rotate(int[] nums, int k) {
if(nums == null || nums.length == 0){
return ;
}
k = k % nums.length;
int index = nums.length - k;
int length = 0;
for(int i = index;i < nums.length;i++){
for(int j = i;j > length;j--){
swap(nums, j - 1, j);
}
length++;
}
}
public void swap(int[] nums, int a, int b){
int temp = nums[a];
nums[a] = nums[b];
nums[b] = temp;
}
}
看了题解之后发现可以用颠倒数组来实现。
原始数组 : 1 2 3 4 5 6 7
反转所有数字后 : 7 6 5 4 3 2 1
反转前 k 个数字后 : 5 6 7 4 3 2 1
反转后 n-k 个数字后 : 5 6 7 1 2 3 4 --> 结果
class Solution {
public void rotate(int[] nums, int k) {
if(nums.length == 0){
return;
}
k = k % nums.length;
reverse(nums, 0, nums.length - 1);
reverse(nums, 0, k - 1);
reverse(nums, k, nums.length - 1);
}
public void reverse(int[] nums, int begin, int end){
while(begin < end){
int temp = nums[begin];
nums[begin++] = nums[end];
nums[end--] = temp;
}
}
}