赞
踩
给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。
不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
暴力算法
C
int removeElement(int* nums, int numsSize, int val) { int i, j; int len = numsSize; for (i = 0; i < len; i++) { if (nums[i] == val) { j = i+1; while (j < len) { nums[j-1] = nums[j];//j-1是防止下标越界 j++; } len--; i--;//len--的情况下i一定要-- } } return len; }
/* 时间复杂度:O(n^2) 空间复杂度:O(1) */ public int removeElement(int[] nums, int val) { int n = nums.length; for(int i=0;i<n;i++){ if(nums[i]==val){ for(int j=i+1;j<n;j++){ nums[j-1] = nums[j]; // 小心越界 } i--;// 因为下标i以后的数值都向前移动了一位,所以i也向前移动一位 n--; } } return n; }
int removeElement(int* nums, int numsSize, int val){
int solw = 0,fast;
for(fast=0;fast<numsSize;fast++){
if(val!=nums[fast]){
nums[solw++] = nums[fast];
}
}
return solw;
}
// 时间复杂度:O(n)
// 空间复杂度:O(1)
public int removeElement2(int[] nums, int val) {
int slowIndex = 0;
for(int fastIndex = 0; fastIndex< nums.length;fastIndex++){
if(val != nums[fastIndex]){
nums[slowIndex++] = nums[fastIndex];
}
}
return slowIndex;
}
int searchInsert(int* nums, int numsSize, int target){
int low = 0, high = numsSize-1;
int mid;
while (low <= high) {
mid = low + (high - low) / 2;
if (target > nums[mid])
low = mid + 1;
else if (target < nums[mid])
high = mid - 1;
else
return mid;
}
return high+1;
}
public int searchInsert(int[] nums, int target) { int n = nums.length; int left = 0,right = n -1; // 定义target在左闭右闭的区间里,[left, right] while(left<=right) { // 当left==right,区间[left, right]依然有效 int mid = left + ((right - left) / 2); // 防止溢出,等价(left+right)/2 if (target < nums[mid]) { right = mid - 1;// target 在左区间,所以[left, middle - 1] } else if (target > nums[mid]) { left = mid + 1; } else { // nums[middle] == target return mid; } } return right+1; /* 分别处理如下四种情况 1.目标值在数组所有元素之前 [0, -1] target = -1,nums = [1,3,5,7] 第一次循环 right = 3,left = 0,mid = 1 target < nums[1] = 3 --> right = mid -1 = 0 第二次循环 right = 0,left = 0,mid = 0 target < nums[0] = 1 --> right = mid -1 = -1 循环结束,返回 right+1 = 0 2.目标值等于数组中某一个元素 return middle; 3.目标值在数组中间 [left, right],return right + 1 target = 4,nums = [1,3,5,7] 第一次循环 right = 3,left = 0,mid = 1 target > nums[1] = 3 --> left = mid + 1 = 1 第二次循环 right = 3,left = 1,mid = 2 target < nums[2] = 5 --> right = mid -1 = 1 循环结束,返回 right+1 = 2 4.目标值在数组所有元素之后的情况 [left, right], return right + 1 */ }
int minSubArrayLen(int target, int* nums, int numsSize){ int i, j; int sum; int subLen;//用来标识新长度 int result = INT_MAX;//用来标识老长度,这里要取一个最大值 for (i = 0; i < numsSize; i++) { sum = 0; for (j = i; j < numsSize; j++) { sum += nums[j]; if (sum >= target) { subLen = j - i + 1;//获取该sum包含的子数组长度 result = result > subLen ? subLen : result;//判断老长度是否大于新长度 break; } } } return result==INT_MAX ? 0:result;//防止全部元素之和都不大于target }
//暴力解法 //时间复杂度:O(n^2) //空间复杂度:O(1) public int minSubArrayLen(int target, int[] nums) { int result = Integer.MAX_VALUE; // 取一个数组不可能的超过的最大值 int sum = 0; // 子序列的数值之和 int subLength = 0; // 子序列的长度 for(int i=0;i<nums.length;i++){ sum = 0; for(int j=i;j<nums.length;j++){ sum+=nums[j]; if(sum>=target){ subLength = j-i+1; // 取子序列的长度 result = result<subLength?result:subLength; // 与前一次长度作比较 break; // 因为我们是找符合条件最短的子序列,所以一旦符合条件就break } } } // 如果result没有被赋值的话,就返回0,说明没有符合条件的子序列 return result == Integer.MAX_VALUE ? 0:result; }
//滑动窗口 /* 滑动窗口的精妙之处在于根据当前子序列和大小的情况, 不断调节子序列的起始位置。从而将O(n^2)的暴力解法降为O(n)。 */ public int minSubArrayLen_2(int target, int[] nums) { int result = Integer.MAX_VALUE; int sum = 0;//滑动窗口数值之和 int i = 0;//滑动窗口起始位置 int subLength = 0;//滑动窗口的长度 for(int j=0;j< nums.length;j++){ sum+=nums[j]; //使用while,每次更新i(起始位置),并不断比较子序列是否符合条件 while(sum>=target){ subLength = (j - i + 1);//取子序列的长度 result = result < subLength? result:subLength; sum -= nums[i++];//减去第一个数,窗口内数字个数-1,i滑动到i++位置 } } return result == Integer.MAX_VALUE ? 0 : result; /* nums[] = 2 , 3 , 1 , 2 , 4 , 3 target = 7 下标: 0 1 2 3 4 5 sum = 0;i = 0;subLength = 0; 1. ij(指向下标0) --> sum = 0+2 = 2 2. i j --> sum = 2+3 = 5 3. i j --> sum = 5+1 = 6 4. i j --> sum = 6+2 = 8 while-->subLength = j-i+1 = 3-0+1 = 4 -->result = Max < 4 ? Max:4 = 4 -->sum -= nums[i++] = sum - nums[0] = 8-2 = 6 --> i(向前移动i,即窗口缩小) ... ... */ }
int minSubArrayLen(int target, int* nums, int numsSize){
int i = 0,j;
int result = INT_MAX;
int sublen = 0;
int sum = 0;
for(j=0;j<numsSize;j++){
sum += nums[j];
while(sum>=target){
sublen = j-i+1;
result = result > sublen ? sublen:result;
sum -= nums[i++];
}
}
return result==INT_MAX?0:result;
}
给你一个正整数 n ,生成一个包含 1 到 n2 所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix 。
分析:
JAVA
public int[][] generateMatrix(int n) { int[][] nums = new int[n][n]; int startX = 0,startY = 0;//定义每循环一个圈的起始位置,如(0,0),(1,1)... int loop = n / 2;//每个圈循环几次,如n=3为奇数,则loop=1只循环一圈, //矩阵中间的值需要单独处理 int mid = n / 2;//矩阵中间的位置,如n=3,中间位置就是(1,1),n=5-->(2,2) int count = 1;//给矩阵赋值的变量 int offset = 1;//每一圈循环,需要控制每一条边遍历的长度 int i,j; while(loop--!=0){ i = startX; j = startY; //下面开始的四个for就是模拟转一圈 /* → → ↓ ↑ → ↓ ↑ ← ← */ //上行从左到右 for(j = startY;j<startY+n-offset;j++){ nums[startX][j] = count++; } //右列从上到下 for(i = startX;i<startX+n-offset;i++){ nums[i][j] = count++; } //模拟下行从右到左 for(;j>startY;j--){ nums[i][j] = count++; } //模拟左列从下到上 for(;i>startX;i--){ nums[i][j] = count++; } // 第二圈开始的时候,起始位置要各自加1, //例如:第一圈起始位置是(0, 0),第二圈起始位置是(1, 1) /* 如n=4时: 第一圈: 0 1 2 3 0 → → → ↓ 1 ↑ ↓ 2 ↑ ↓ 3 ↑ ← ← ← -->则第一圈从(0,0)开始 第二圈: 1 2 1 → ↓ 2 ↑ ← -->则第二圈从(1,1)开始 */ startX++; startY++; // offset 控制每一圈里每一条边遍历的长度 // 如n=4,第一圈第一行长度=4,第二圈第一行长度为4-2=2 /* 第一圈: → → → ↓ ↑ ↓ ↑ ↓ ↑ ← ← ← 第二圈: → ↓ ↑ ← */ offset += 2; } // 如果n为奇数的话,需要单独给矩阵最中间的位置赋值 /* 如n=3,中心点则为(1,1) n=5,中心点则为(2,2) */ if (n % 2==1) { nums[mid][mid] = count; } return nums; }
代码手推图
*
int cmp(const void* _a, const void* _b) {
int a = *(int*)_a, b = *(int*)_b;
return a - b;
}
bool containsDuplicate(int* nums, int numsSize) {
qsort(nums, numsSize, sizeof(int), cmp);//快速排序
for (int i = 0; i < numsSize - 1; i++) {
if (nums[i] == nums[i + 1]) {
return true;
}
}
return false;
}
int maxSubArray(int* nums, int numsSize) {
int preSum = 0;//之前和
int maxSum = nums[0];//最大和
for (int i = 0; i < numsSize; i++) {
preSum = fmax(preSum + nums[i], nums[i]);//取最大值函数
maxSum = fmax(preSum, maxSum);
}
return maxSum;
}
public ListNode detectCycle(ListNode head) { ListNode fast = head;//定义快慢指针 ListNode slow = head; while( fast!=null && fast.next!=null){ slow = slow.next;//慢指针走一步 fast = fast.next.next;//快指针走两步量 //快慢相遇 if(slow == fast){ ListNode index1 = fast; ListNode index2 = head; while(index1 != index2){ index1 = index1.next; index2 = index2.next; } return index2; //返回入口 } } return null; }
给你一个链表的头节点 head 和一个整数 val
请你删除链表中所有满足 Node.val == val 的节点,并返回新的头节点 。
迭代
/*
因为可能会遇到头结点满足条件时,要删除头结点
如:val = 2
head(2)-->1-->4-->null
==>
dummyHead-->head(2)-->1-->4-->null
则只需将虚拟结点dummyHead指向head.next即可
==>
dummyHead head(2)-->1-->4-->null
| ↑
|_____________|
*/
public ListNode removeElements(ListNode head, int val) { ListNode dummyHead = new ListNode();//设置一个虚拟头结点 dummyHead.next = head;//将虚拟结点指向头结点 ListNode cur = dummyHead; while(cur.next!=null){ if(cur.next.val==val){ cur.next = cur.next.next; }else{ cur = cur.next; } } //当然,返回的最终链表是从虚拟结点的下一个位置开始 return dummyHead.next; }
public ListNode removeElements2(ListNode head,int val){
if(head==null){
return head;
}
head.next = removeElements(head.next, val);
return head.val==val?head.next : head;//当条件为真时,返回head.next后的链表
}
/*
如:
null 1----->2----->3----->4
↑ ↑ ↑
pre curr temp
1. 1<-----2 3----->4
↑ ↑ ↑
pre curr temp
2. 1<-----2<------3 4
↑ ↑ ↑
pre curr temp
3. 1<-----2<------3<------4
↑ ↑ ↑
pre curr temp
*/
public ListNode reverseList(ListNode head) { if(head==null){ return null; } ListNode pre = null; ListNode curr = head;//指向头结点 ListNode temp = null;//保存curr的后一个结点 while(curr!=null){ temp = curr.next; curr.next = pre; pre = curr; curr = temp; } return pre; }
//链表类 public class ListNode { int val; ListNode next; ListNode(int x) { val = x; } } class MyLinkedList{ /* public static void main(String[] args) { MyLinkedList linkedList = new MyLinkedList(); linkedList.addAtHead(1); linkedList.addAtTail(3); linkedList.addAtIndex(1,2); linkedList.get(1); linkedList.deleteAtIndex(1); linkedList.get(1); } */ int size; ListNode head;//虚拟头结点 public int get(int index) { if(index>=size||index<0) return -1;//返回无效索引 ListNode curr = head; for(int i=0;i<index+1;++i){//遍历到index所指结点 curr = curr.next; } return curr.val; } public void addAtHead(int val) { ListNode curr = new ListNode(val); curr.next = head.next; head.next = curr; size++;//长度自增 } public void addAtTail(int val) { ListNode curr = head.next; ListNode addNode = new ListNode(val); while(curr.next!=null){//遍历到链表尾部 curr = curr.next; } curr.next = addNode; size++;//长度自增 } public void addAtIndex(int index, int val) { if(index>size) return ; if(index<0) index = 0; ListNode curr = head; for(int i=0;i<index;i++){//遍历到index下标之前一个结点 curr = curr.next; } ListNode addNode = new ListNode(val); addNode.next = curr.next; curr.next = addNode; size++; } public void deleteAtIndex(int index) { if(index>=size||index<0){//索引无效 return ; } ListNode curr = head; while(index--!=0){//遍历到待删除结点的前一个结点 curr = curr.next; } curr.next = curr.next.next; size--;//长度自减 } }
public ListNode removeNthFromEnd(ListNode head, int n) { ListNode dummyHead = new ListNode(); dummyHead.next = head;//设置虚拟头节点 ListNode fast = dummyHead; ListNode slow = dummyHead; int temp = n; while(temp-- > 0){//fast先走n步 fast = fast.next; } while(fast.next!=null){ fast = fast.next; slow = slow.next; } slow.next = slow.next.next; return dummyHead.next; }
public ListNode getIntersectionNode(ListNode headA, ListNode headB) { ListNode curA = headA; ListNode curB = headB; int lenA = 0,lenB = 0; while(curA!=null){//求链表A的长度 lenA++; curA = curA.next; } while(curB!=null){//求链表B的长度 lenB++; curB = curB.next; } curA = headA;//让指针重新指向头节点 curB = headB; int gap = lenA-lenB;//长度差值 if(lenB>lenA){//若链表b长度较大 curB = headA; curA = headB; gap = lenB - lenA; } while(gap-->0){//让curA(长度较大)遍历到,与curB(长度较小)同一起点上(末尾位置对齐) curA = curA.next; } while(curA!=null){ if(curA==curB){//节点相同 return curA; } curA = curA.next; curB = curB.next; } return null; }
/*
如:
nums = [1,2,3,4] target = 5
1. nums[i] = nums[0] = 1 target-nums[0] = 5-1 = 4(无)
map.put(nums[0],0)--> map = {{1,0}}
2. nums[i] = nums[1] = 2 target-nums[1] = 5-2 = 3(无)
map.put(nums[1],1)--> map = {{1,0},{2,1}}
3. nums[i] = nums[2] = 3 target-nums[2] = 5-3 = 2(有)
return new int[]{map.get(2),2} = {1,2}
*/
public int[] twoSum(int nums[],int target){
//map的key是值,value是下标
Map<Integer,Integer> map =
new HashMap<Integer,Integer>();
for(int i=0;i<nums.length;i++){
if(map.containsKey(target-nums[i])){
//返回一个下标数组
return new int[]{map.get(target-nums[i]),i};
}
map.put(nums[i],i);//将符合条件的数插入表中
}
return new int[0];
}
public List<List<Integer>> threeSum(int[] nums) { List<List<Integer>> ls = new ArrayList<List<Integer>>(); //数组排序 Arrays.sort(nums); for(int i=0;i<nums.length;i++){ if(nums[i]>0){ return ls; } //去重方法 if(i>0&&nums[i]==nums[i-1]){ continue; } int left = i+1;//左指针 int right = nums.length -1;//右指针 while(left<right){ if(nums[i]+nums[left]+nums[right]>0){//当数值大于零,则表示数较大 right--; }else if(nums[i]+nums[left]+nums[right]<0){//同理,数值较小 left++; }else{ List<Integer> result = new ArrayList<Integer>(); result.add(nums[i]); result.add(nums[left]); result.add(nums[right]); ls.add(result);//添加一个三元组 while(left<right&&nums[right]==nums[right-1]) right--; while(left<right&&nums[left]==nums[left+1]) left++; //双指针同时靠拢 right--; left++; } } } return ls; }
public boolean isHappy(int n) { Set<Integer> set = new HashSet<Integer>(); while(true){ int sum = getSum(n);//每一次都会更新sum值 if(sum==1){ return true; } if(set.contains(sum)){//当集合中存在重复的sum时,此数不是快乐数 return false; }else { set.add(sum); } n = sum; } } //取数值各个位上的单数之和 int getSum(int n){ int sum = 0; while(n>0){ sum += (n%10) * (n%10);//求平方和 n /= 10; } return sum; }
给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。
分析:
代码
public boolean isAnagram(String s, String t) { if(s.length()!=t.length()){//比较长度 return false; } int[] record = new int[26];//定义数组,记录串s中字符的次数 char[] arr_s = s.toCharArray(); for(int i=0;i<arr_s.length;i++){ record[arr_s[i] - 'a']++;//映射出字符出现的次数 /* 如: arr[0] = 'b'; --> record[arr[i] - 'a'] = record['b' - 'a'] = record[1]; record[1]++ = 1; 、 即出现b在串s中出现一次,b的下标为1, 同理,a的下标为0 */ } char[] arr_t = t.toCharArray(); for(int i=0;i<arr_t.length;i++){ record[arr_t[i] - 'a']--;//映射出串t中出现的字符,随之映射在record表中,并-1 } for(int i=0;i<26;i++){ if(record[i] != 0){ //判断数组中若存在不为零的次数,则不是异位词 return false; } } //record中所有元素都为零,则两遍映射相抵消,即为异位词 return true; }
public int[] intersection(int[] nums1, int[] nums2) { Set<Integer> set1 = new HashSet<Integer>(); Set<Integer> set2 = new HashSet<Integer>(); //将数组分别装入集合中 for(int num:nums1){ set1.add(num); } for(int num:nums2){ set2.add(num); } return getIntersection(set1,set2); } public int[] getIntersection(Set<Integer> set1,Set<Integer> set2){ if(set1.size()>set2.size()){//遍历集合长度小的那一个 return getIntersection(set2,set1); } Set<Integer> intersectionSet = new HashSet<Integer>(); for(int num:set1){//判断是否有相同数字 if(set2.contains(num)){ intersectionSet.add(num); } } //将集合存入数组并返回 int[] intersection = new int[intersectionSet.size()]; int index = 0; for(int num:intersectionSet){ intersection[index++] = num; } return intersection; }
给定一个赎金信 (ransom) 字符串和一个杂志(magazine)字符串,判断第一个字符串 ransom 能不能由第二个字符串 magazines 里面的字符构成。如果可以构成,返回 true ;否则返回 false。
(题目说明:为了不暴露赎金信字迹,要从杂志上搜索各个需要的字母,组成单词来表达意思。杂志字符串中的每个字符只能在赎金信字符串中使用一次。)
分析:
public boolean canConstruct(String ransomNote, String magazine) { int[] ransomNote_record = new int[26];//默认值为0 int[] magazine_record = new int[26]; for(int i=0;i<ransomNote.length();i++){//映射字母表 ransomNote_record[ransomNote.charAt(i)-'a']++; } for(int j=0;j<magazine.length();j++){ magazine_record[magazine.charAt(j)-'a']++; } for(int i=0;i<ransomNote_record.length;i++){//比较存入的字母次数 //如果r中字母的次数大于m对应的字母次数,则r不能由m表出 if(ransomNote_record[i]>magazine_record[i]){ return false; } } return true; }
给定四个包含整数的数组列表 A , B , C , D ,计算有多少个元组 (i, j, k, l) ,使得 A[i] + B[j] + C[k] + D[l] = 0。
为了使问题简单化,所有的 A, B, C, D 具有相同的长度 N,且 0 ≤ N ≤ 500 。所有整数的范围在 -228 到 228 - 1 之间,最终结果不会超过 231 - 1 。
分析:
/*
如:
nums1=[1,2] nums2=[2,1] nums3=[-1,1] nums4=[-2,1]
map --> {{3,2},{2,1},{4,1}} -->即3出现两次,2出现一次,4出现一次
1. 0-(-1+-2) = 3 -->true
temp += 2 = 2
2. 0-(-1+1) = 0 -->false
3. 0-(1-2) = 1 -->true
temp += 1 = 3
......
*/
public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) { //定义map,key存放a+b和,value存放a+b出现的次数 Map<Integer,Integer> map = new HashMap<Integer,Integer>(); //遍历前两个数组 for(int a:nums1){ for(int b:nums2){ //判断a+b是否出现过:若出现过则+1;反之,从0开始计数 int count = map.containsKey(a+b) ? map.get(a+b):0; map.put(a+b,count+1); } } int temp = 0;//记录a+b+c+d=0的次数 //遍历后两个数组 for(int c:nums3){ for(int d:nums4){ if(map.containsKey(0-(c+d))){ temp += map.get(0-(c+d));//当找到a+b+c+d=0,则记录相应次数 } } } return temp; }
public boolean containsNearbyDuplicate(int[] nums, int k) {
Set<Integer> set = new HashSet<Integer>();
for(int i=0;i<nums.length;i++){
if(set.contains(nums[i])){//存在重复元素
return true;
}
set.add(nums[i]);//添加元素
if(set.size()>k){//滑动窗口个数>k
set.remove(nums[i-k]);//删除元素,i-k为当前第一个元素
}
}
return false;
}
给你一个字符串 s ,逐个翻转字符串中的所有 单词 。
单词 是由非空格字符组成的字符串。s 中使用至少一个空格将字符串中的 单词 分隔开。
请你返回一个翻转 s 中单词顺序并用单个空格相连的字符串。
说明:
输入字符串 s 可以在前面、后面或者单词间包含多余的空格。
翻转后单词间应当仅用一个空格分隔。
翻转后的字符串中不应包含额外的空格。
法一:利用现有方法
public String reverseWords(String s) {
//去除开头和末尾的空白字符
s = s.trim();
//正则匹配连续的空白字符作为分隔符切割
List<String> wordList = Arrays.asList(s.split("\\s+"));
Collections.reverse(wordList);
//按照指定分隔符重组字符串
return String.join(" ",wordList);
}
//利用自定义方法 public String reverseWords_2(String s) { StringBuilder sb = trimSpaces(s); // 翻转字符串 reverse(sb, 0, sb.length() - 1); // 翻转每个单词 reverseEachWord(sb); return sb.toString(); } //去除空格 public StringBuilder trimSpaces(String s){ int left = 0,right = s.length()-1; // 去除首部空格 while(left <= right && s.charAt(left)==' '){ ++left;//左指针往右边靠拢 } //去掉尾部空格 while(left<=right && s.charAt(right)==' '){ --right;//右指针往左边靠拢 } //去除多余的空白字符 StringBuilder sb = new StringBuilder(); while(left <= right){ char c = s.charAt(left); if(c != ' '){ sb.append(c); }else if(sb.charAt(sb.length()-1)!=' '){ sb.append(c); } ++left; } return sb; } //反转 public void reverse(StringBuilder sb,int left,int right){ while(left < right){ char temp = sb.charAt(left); sb.setCharAt(left++,sb.charAt(right));//首尾互换 sb.setCharAt(right--,temp); } } //反转每个字母 public void reverseEachWord(StringBuilder sb){ int n = sb.length(); int start = 0,end = 0; while (start < n) { // 循环至单词的末尾 while (end < n && sb.charAt(end) != ' ') { ++end; } // 翻转单词 reverse(sb, start, end - 1); // 更新start,去找下一个单词 start = end + 1; ++end; } }
编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 char[] 的形式给出。
不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。
你可以假设数组中的所有字符都是 ASCII 码表中的可打印字符。
public void reverseString(char[] s) {
for(int i=0,j=s.length-1;i<j;i++,j--){
char temp = s[i];
s[i] = s[j];
s[j] = temp;
}
System.out.println(s);
}
给定一个字符串 s 和一个整数 k,你需要对从字符串开头算起的每隔 2k 个字符的前 k 个字符进行反转。
示例:
输入: s = “abcdefg”, k = 2
输出: “bacdfeg”
分析:
public String reverseStr(String s, int k) { for(int i=0;i<s.length();i+=(2*k)){ //1.每隔2k个字符,对前k个字符进行反转 //2.剩余字符<2k但>=k,则反转前k个字符 if(i+k<=s.length()){ s = reverse(s,i,i+k-1); continue; } //3.剩余字符<k,则将剩余字符全部进行反转 s = reverse(s,i,s.length()-1); } return s; } //反转下标为a到b的字符 public String reverse(String s,int start,int end){ char[] ch = s.toCharArray(); for(int i = start,j = end;i<j;i++,j--){ char temp = ch[i]; ch[i] = ch[j]; ch[j] = temp; } return new String(ch); }
public String replaceSpace(String s) { //建立字符数组,确保能装入替换后的容量 char[] ch = new char[s.length()*3]; int size = 0;//计算替换后的字符串长度 for(int i=0;i<s.length();i++){ char c = s.charAt(i); if(c == ' '){//当判断为空格时,依次存入 ch[size++] = '%'; ch[size++] = '2'; ch[size++] = '0'; }else{//反之,正常赋值 ch[size++] = c; } } //重新初始化新的字符串,该字符串长度为替换后的长度 String result = new String(ch,0,size); return result; }
public String reverseLeftWords(String s, int n) { int len = s.length(); char[] arr = new char[s.length()]; //赋值下标为k之前的字符 for(int i=s.length()-n;i<len;i++){ arr[i] = s.charAt(i-len+n); } //赋值下标为k以及k后面的字符 for(int i=n;i<len;i++){ arr[i-n] = s.charAt(i); } String result = new String(arr,0,len); return result; }
实现 strStr() 函数。给你两个字符串 haystack 和 needle ,请你在 haystack 字符串中找出 needle 字符串出现的第一个位置(下标从 0 开始)。如果不存在,则返回 -1 。
JAVA
public int strStr(String haystack, String needle) { if(needle==null){ return -1; } int i=0,j = 0,k=0; while(i<haystack.length() && j<needle.length()){ if(haystack.charAt(i) == needle.charAt(j)){ i++; j++; }else{ j=0; i = ++k; } } if(j>=needle.length()){ return k; }else{ return -1; } }
public class MyQueue { Stack<Integer> stIn;//用于输入元素的栈 Stack<Integer> stOut;//用于输出元素的栈 //初始化 public MyQueue() { stIn = new Stack<Integer>(); stOut = new Stack<Integer>(); } //模拟入队 public void push(int x) { stIn.push(x);//进栈 } //模拟出队 public int pop() { // 当stOut输出栈为空时,才让stIn中的元素输入 if(stOut.empty()){ while(!stIn.empty()){ stOut.push(stIn.pop()); } } return stOut.pop();//返回栈顶元素,并删除 } //返回队列头元素 public int peek() { //与模拟出队同理 if(stOut.empty()){ while(!stIn.empty()){ stOut.push(stIn.pop()); } } return stOut.peek();//返回栈顶元素,但不删除 } //判断队列是否为空 public boolean empty() { //当两个栈都为空时,则队列为空 return stIn.empty() && stOut.empty(); } }
请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(push、top、pop 和 empty)。
实现 MyStack 类:
分析:
//252.用队列实现栈 public class MyStack { Deque<Integer> dq; /** Initialize your data structure here. */ public MyStack() { dq = new LinkedList<Integer>(); } /** Push element x onto stack. */ public void push(int x) { int size = dq.size(); dq.offer(x);//插入队尾 for(int i=0;i<size;i++){ dq.offer(dq.poll());//poll返回最先进入的那个元素,即对头元素 //将这个元素插入队尾 //此方法就是将原始队列倒置,已构成先进后出的原则 } } /** Removes the element on top of the stack and returns that element. */ public int pop() { return dq.poll();//返回队头元素 } /** Get the top element. */ public int top() { return dq.peek();//返回第一个元素,即当前队头元素 } /** Returns whether the stack is empty. */ public boolean empty() { return dq.isEmpty(); } }
public boolean isValid(String s) { Stack<Character> st = new Stack<Character>(); for(int i=0;i<s.length();i++){ //这里入栈右括号是方便直接匹配串s中是否有相同的括号 if(s.charAt(i)=='(') st.push(')'); else if(s.charAt(i)=='{') st.push('}'); else if(s.charAt(i)=='[') st.push(']'); //第三种情况,栈已空,但串s未遍历完,则说明存在多余的左括号 //第二种情况,当匹配右括号时,栈中没有发现匹配的字符 else if(st.empty() || st.peek()!=s.charAt(i)) { return false; } /* 隐含的判断成功: s.charAt(i)=='(' 或 s.charAt(i)=='{' 或 s.charAt(i)=='[' */ else st.pop(); } //第一种情况:已遍历完,但栈不空,则说明存在多余右括号 return st.empty(); }
public String removeDuplicates(String s){ Stack<Character> st = new Stack<Character>(); for(int i=0;i<s.length();i++){ if(!st.isEmpty()){ //判断是否有相邻元素 if(st.peek()==s.charAt(i)){ st.pop(); continue; } } st.push(s.charAt(i));//入栈 } //栈无元素则返回空 if(st.isEmpty()){ return ""; } char[] ch = new char[st.size()]; //反转 for(int i=ch.length-1;i>=0;i--){//注意:不能用栈的长度,因为每次出栈后会变化 ch[i] = st.pop(); } //重造字符串 String result = new String(ch, 0, ch.length); return result; }
public int evalRPN(String[] tokens) { Deque<Integer> dq = new LinkedList<Integer>(); for(int i=0;i<tokens.length;i++){ //判断是否为算术符 if(tokens[i].equals("+")||tokens[i].equals("-") ||tokens[i].equals("*")||tokens[i].equals("/")){ int a = dq.pop(); int b = dq.pop(); switch (tokens[i]){ case "+": dq.push(b+a); break; case "-": dq.push(b-a); break; case "*": dq.push(b*a); break; case "/": dq.push(b/a); break; default: } }else{ dq.push(Integer.parseInt(tokens[i]));//字符串转化为数字 } } return dq.peek(); }
void preorder(TreeNode *root,int *res,int *resSize) { if (root != NULL) { //用数组存放值 res[(*resSize)++] = root->val;//数组自增 preorder(root->left, res, resSize); preorder(root->right, res, resSize); } } int* preorderTraversal(struct TreeNode* root, int* returnSize) { int *res = malloc(sizeof(int) * 2000); *returnSize = 0; preorder(root, res, returnSize); return res; }
int* preorderTraversal(struct TreeNode* root, int* returnSize) { int *result = (int*)malloc(sizeof(int) * 2000);//生成一个结果数组 *returnSize = 0; if (root == NULL) { return result; } struct TreeNode *st[2000];//定义一个栈 struct TreeNode *p = root;//定义一个指针 int top = -1;//初始化栈 st[++top] = root;//入栈根节点 while (top != -1) { p = st[top--];//指针指向当前需遍历的结点(根左右) result[(*returnSize)++] = p->val;//入结果数组 if (p->right != NULL) {//右孩子存在 st[++top] = p->right; } if (p->left != NULL) {//左孩子存在 st[++top] = p->left; } } return result; }
void inorder(struct TreeNode* root, int *res, int *resSize) {
if (root == NULL) {
return;
}
inorder(root->left, res, resSize);
res[(*resSize)++] = root->val;
inorder(root->right, res, resSize);
}
int *inorderTraversal(struct TreeNode *root, int *returnSize) {
int *res = (int*)malloc(sizeof(int) * 2000);
*returnSize = 0;
inorder(root, res, returnSize);
return res;
}
int* inorderTraversal(struct TreeNode* root, int* returnSize) { int *result = (int*)malloc(sizeof(int) * 2000);//生成一个结果数组 *returnSize = 0; if (root == NULL) { return result; } struct TreeNode *st[2000];//定义一个栈 struct TreeNode *p;//定义一个指针 int top = -1;//初始化栈的指针 p = root;//p指向根节点 while (top != -1 || p != NULL) {//有可能出现栈空但树未遍历完的情况 while (p != NULL) {//左孩子一直入栈 st[++top] = p; p = p->left; } if (top != -1) {//栈不空时,输出 p = st[top--]; result[(*returnSize)++] = p->val; p = p->right; } } return result; }
void postorder(TreeNode *root, int *res, int *resSize) {
if (root == NULL) {
return;
}
postorder(root->left, res, resSize);
postorder(root->right, res, resSize);
res[(*resSize)++] = root->val;
}
int* postorderTraversal(struct TreeNode* root, int* returnSize) {
int *res = (int*)malloc(sizeof(int) * 2000);
*returnSize = 0;
postorder(root, res, returnSize);
return res;
}
int* postorderTraversal(struct TreeNode* root, int* returnSize) { int *result = (int*)malloc(sizeof(int) * 2000);//结果数组 *returnSize = 0; if (root = NULL) { return result; } struct TreeNode *stack1[2000]; int top1 = 1; struct TreeNode *stack2[2000]; int top2 = -1; struct TreeNode *p = NULL; stack1[++top1] = root;//根节点入栈 while (top1 != -1) { p = stack1[top1--];//指向 stack2[++top2] = p;//再入 if (p->left != NULL) {//反向入栈 stack1[++top1] = p->right; } if (p->right != NULL) { stack1[++top1] = p->left; } } while (top2 != -1) { //再次出栈即为后序遍历 p = stack2[top2--]; result[(*returnSize)++] = p->val; } return result; }
public TreeNode invertTree(TreeNode root) {
if(root == null){
return null;
}
TreeNode temp = root.left;
root.left = root.right;
root.right = temp;
invertTree(root.left);
invertTree(root.right);
return root;
}
public TreeNode invertTree(TreeNode root) {
if(root == null){
return null;
}
TreeNode left = invertTree(root.right);
TreeNode right = invertTree(root.left);
root.left = left;
root.right = right;
return root;
}
public boolean isSymmetric(TreeNode root) { if(root == null) return true; return compare(root.left,root.right); } public boolean compare(TreeNode left,TreeNode right){ //判断四种情况 if(left == null && right != null) return false; else if(left != null && right == null) return false; else if(left == null && right == null) return true; //若左右都不为空时,判断值是否相等 else if(left.val != right.val) return false; //当左右子树值相等时,继续递归遍历 boolean outside = compare(left.left,right.right);//左子树的外层,右子树的外层 boolean inside = compare(left.right,right.left);//左子树的内层,右子树的内层 boolean isSame = outside && inside; return isSame; }
bool isSymmetric(struct TreeNode* root){ bool compare(); if (root == NULL) { return true; } return compare(root->left, root->right); } bool compare(struct TreeNode* left,struct TreeNode *right) { if (left == NULL && right != NULL) return false; else if (left != NULL && right == NULL) return false; else if (left == NULL && right == NULL) return true; else if (left->val != right->val) return false; bool outSide = compare(left->left, right->right); bool inSide = compare(left->right, right->left); bool isSame = outSide && inSide; return isSame; }
int result; public int maxDepth(TreeNode root){ result = 0; if(root == null) return result;//注意细节,返回的是result getDepth(root,1); return result; } public void getDepth(TreeNode root,int depth){ //采用前序遍历 result = depth > result ? depth : result;//中 if(root.left==null && root.right==null) return;//为空 if(root.left!=null){//左 depth++; getDepth(root.left,depth); depth--;//因为已经走到下一层了,depth进行了+1,即回溯,所以深度-1, } if(root.right!=null){//右 depth++; getDepth(root.right,depth); depth--;// } return ; }
public int minDepth(TreeNode root) { if(root == null) return 0; int leftDepth = minDepth(root.left);//取左 int rightDepth = minDepth(root.right);//取右 //求的是根节点到叶子节点的节点距离,所以: //左子树为空,右不为空,这时并不是最低点 if(root.left == null && root.right!=null){ return 1+rightDepth; } //当一个右子树为空,左不为空,这时并不是最低点 if(root.left!=null && root.right==null){ return 1+leftDepth; } return 1+Math.min(leftDepth,rightDepth); }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。