21.合并两个有序链表
该题目思路十分简单,就是两个指针指向两个链表即可然后进行比较结果从而指针移动,这里直接放上代码。
//合并两个有序链表
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
ListNode head = new ListNode();
ListNode temp = head;
while(l1 != null && l2 != null) {
if(l1.val > l2.val) {
temp.next = new ListNode(l2.val);
temp = temp.next;
l2 = l2.next;
}else {
temp.next = new ListNode(l1.val);
temp = temp.next;
l1 = l1.next;
}
}
while(l1 != null) {
temp.next = new ListNode(l1.val);
temp = temp.next;
l1 = l1.next;
}
while (l2 != null) {
temp.next = new ListNode(l2.val);
temp = temp.next;
l2 = l2.next;
}
return head.next;
}
22.有效括号生成
这个题目主要的思想是使用回溯法,是回溯法的经典例题之一。
首先我们需要知道什么事有效括号,即在你添加下一位括号时(左括号/右括号),需要考虑此时的左括号和右括号数量。
1.((),这种情况你就可以插入左括号或者右括号(left > right)。
2.(()),这种情况你就能插入左括号(left = right)。
3.()),这种情况就是典型的违法,所以需要摒弃。
//生成有效括号
public List<String> generateParenthesis(int n) {
List<String> list = new ArrayList<>();
backTrace(list,new StringBuilder(),0,0,n);
return list;
}
public void backTrace(List<String> list,StringBuilder stringBuilder, int left, int right, int n) {
// 出口条件
if(left == n && right == left) {
list.add(stringBuilder.toString());
return;
}
//添加左括号
if(left + 1 <= n) {
stringBuilder.append("(");
backTrace(list,stringBuilder,left + 1,right,n);
stringBuilder.deleteCharAt(stringBuilder.length() - 1);
}
//添加右括号
if(right + 1 <= left) {
stringBuilder.append(")");
backTrace(list,stringBuilder,left,right + 1,n);
stringBuilder.deleteCharAt(stringBuilder.length() - 1);
}
}
24.两两交换链表结点
该题目就是一个链表的结点交换,主要考察这个指针的来回变换以及空节点判断处理问题。
1.我们进行交换时肯定是以2个结点为一个单位进行处理,如果不满足则说明到头了,则直接返回即可。
2.针对于这种需要交换头结点的题目,我个人建议设置一个虚拟头结点,这样方便一些。
剩下就没有什么难度了,直接上代码
//两两交换
public ListNode swapPairs(ListNode head) {
//看他是否满足两个节点的要求
if(head == null || head.next == null) {
return head;
}
ListNode nowHead = new ListNode();
nowHead.next = head;
ListNode prev = nowHead;
ListNode first = head;
//说明第一个结点不存在,直接退出循环
while(first != null) {
ListNode second = first.next;
//说明第二个结点不存在,跳出循环
if(second == null) {
break;
}
first.next = second.next;
second.next = first;
prev.next = second;
prev = first;
first = first.next;
}
return nowHead.next;
}
26.删除排序树组中重复元素
题目中已经说明是排序数组,所以我们只需要记录上一次出现的元素是什么就行了,然后不重复出现时直接覆盖掉Index记录的非重复元素和非重复元素个数。
1.如果当前元素和prev重复则跳过。
2.如果不重复则将prev更改为现在的值,并且直接赋值给index。
这种方法虽然会直接覆盖掉原来数值,但是考虑到被覆盖的元素一定是被访问过的所以针对盖提问题不大。
//删除排序数组中重复元素(这里指将不重复放到前面,返回不重复元素数目)
public int removeDuplicates(int[] nums) {
if(nums.length == 0) {
return 0;
}
int index = 1;
int prev = nums[0];
for(int i=1; i<nums.length; i++) {
//说明重复
if(prev == nums[i]) {
continue;
}
prev = nums[i];
nums[index++] = nums[i];
}
return index;
}
27.移除元素
和26题如出一辙,直接上代码就行了
//原地移除元素
public int removeElement(int[] nums, int val) {
int index = 0;
for(int i=0; i<nums.length; i++) {
if(nums[i] == val) {
continue;
}
nums[index++] = nums[i];
}
return index;
}
28.实现strStr()
该题的解决办法很多,这里我是用的是滑动窗口的思想,因为我们需要找到第一次出现该字符串的下标。
直接上代码吧,就是一个单纯截取字符串比对。
//在haystack中找到第一次出现needle位置,并返回
public int strStr(String haystack, String needle) {
int H_len = haystack.length();
int N_len = needle.length();
for(int start=0; start<H_len-N_len+1; start++) {
if (haystack.substring(start,start+N_len).equals(needle)){
return start;
}
}
return -1;
}
29.两数相除
该题目的要求是不允许使用除法进行运算,mod运算实现除法(余数扔掉)。
我们首先知道除法其实就是一系列的减法操作。
就比如13 / 2举例:
我们可以分解成13 =(2 + 2 + 2)* 2 + 1(这个1是余数可以不要)
18 / 2;
18 = (8 + 1)* 2
主要思路是我们通过每次将除数翻倍的方式最快找到他的除数,同时记录翻倍的次数(一开始次数times = 1),这里我们不采用将除数次数+1的方式是因为这样其实就是暴力求解,我们翻倍的方式时间复杂度logn搜索,效率更高
这里需要注意的一点就是越界的问题,考虑到将MIN_INT除-1成MAX_INT会出现越界问题,所以我们干脆就将全部转换为负数进行计算,最后再根据情况判断结果是整数还是负数(正负得负之类的)
在我们进行翻倍的时候需要考虑到是否会越界(MIN_INT),所以需要在这里进行一个判断
//两数相除
public int divide(int dividend, int divisor) {
if(dividend == 0) {
return 0;
}
if(divisor == 1) {
return dividend;
}
if(divisor == -1) {
if(dividend == Integer.MIN_VALUE) {
//导致越界的
return Integer.MAX_VALUE;
}else {
return -dividend;
}
}
int result = 0;
boolean symbol = true;
if((dividend > 0 && divisor < 0) || (dividend < 0 && divisor > 0)) {
symbol = false;
}
//全部转化为负数,防止越界
if(dividend > 0) {
dividend = -dividend;
}
if(divisor > 0) {
divisor = -divisor;
}
while (dividend <= divisor) {
int divide = divisor;
//将除数翻倍次数
int times = 1;
//越界判断
while((long) divide + divide <= Integer.MIN_VALUE && dividend <= divide + divide) {
times <<= 1;
divide <<= 1;
}
dividend -= divide;
result += times;
}
return symbol ? result:-result;
}