유지 관리는 정말 쉽지 않습니다. 도움이 필요하면 좋아요를 누르고 팔로우하세요. 공개 계정
bigsai
답장进群
을 따라 체크인에 참여하세요.
모든 단어 연결
제목 설명:
문자열 s와 같은 길이의 단어가 주어집니다. 단어의 모든 단어를 연결하여 형성 할 수있는 s에서 하위 문자열의 시작 위치를 찾습니다.
하위 문자열은 단어의 단어와 정확히 일치해야하며 중간에 다른 문자가있을 수 없지만 단어의 순서를 고려할 필요는 없습니다.
예 1 :
입력 :
s = "barfoothefoobarman",
words = [ "foo", "bar"]
출력 : [0,9]
설명 :
인덱스 0과 9에서 시작 하는 하위 문자열은 각각 "barfoo"및 "foobar"입니다.
출력 순서는 중요하지 않으며 [9,0]도 유효한 답입니다.
예 2 :
입력 :
s = "wordgoodgoodgoodbestword",
words = [ "word", "good", "best", "word"]
출력 : []
분석 :
이 질문의 진실을 밝히기위한 기술과 계획이 꽤 있고,이 질문에 많은 생각을 쏟았으며 고려해야 할 점이 조금 더 있습니다. 아이디어는 문자열 s의 특정 문자열이 단어의 모든 단어로 구성 될 수 있음을 찾는 것입니다. 일치하는 하위 문자열을 충족하는 첫 번째 숫자를 반환합니다.
재귀 방법 :
이론적으로는 처리 방법에서 재귀를 사용할 수 있지만 너무 많은 레이어와 개별적인 상대적으로 특수한 데이터로 인해 스택 TL이 버스트 될 수 있습니다. 여기에 교훈이 있습니다.
당시 질문을주의 깊게 읽지 않았고, 각 단어의 길이가 같은지 신경 쓰지 않아서 검색 질문이라고 생각했습니다. 나중에 질문을주의 깊게 읽고 문제를 발견했습니다.
일반 해시 방법 (슬라이딩 창)
은 어떤 사람들이 슬라이딩 창이라고 부르는 아름다운 이름입니다. 여기서 간단히 해시 방법이라고 부를 것입니다. 이 문제를 분석하고 처리하는 방법은 무엇입니까? 몇 가지 중요한 조건을 살펴볼 수 있습니다.
- 단어의 모든 단어는 길이가 같습니다.
- 모든 단어를 한 번만 사용해야합니다.
즉, 매칭 할 때 단어별로 매칭 할 수 있습니다.
그러나 각 문자열을 판단 할 때 여러 단어로 나누어 판단 할 수 있습니다 .
두 개의 HashMap을 사용하여 단어 수를 저장하고 저장 중에 판단을 내리고 불만이 있으면 중지하십시오. 끝까지 달릴 수 있다면이 마크를 추가 할 수 있습니다.
구체적인 구현 코드는 다음과 같습니다.
public List<Integer> findSubstring(String s, String[] words)
{
List<Integer>value=new ArrayList<Integer>();
Map<String, Integer>map=new HashMap<String, Integer>();
for(int i=0;i<words.length;i++)
{
int num=map.getOrDefault(words[i], 0);
map.put(words[i], num+1);
}
int wordlen=words[0].length();
int len=words[0].length()*words.length;
StringBuilder sBuilder=new StringBuilder(" ");
sBuilder.append(s.substring(0, len-1));
for(int i=0;i<s.length()-len+1;i++)
{
sBuilder.deleteCharAt(0);
sBuilder.append(s.charAt(i+len-1));
int num=0;//统计总共满足的单词数量
Map<String, Integer>map2=new HashMap<String, Integer>();
//map2.putAll(map);
int index=0;
while (index<len) {
String team=sBuilder.substring(index,index+wordlen);
int number=map2.getOrDefault(team, 0);//次数
map2.put(team, number+1);
if(number+1>map.getOrDefault(team, 0))
break;
index+=wordlen;
}
if(index==len)
value.add(i);
}
return value;
}
해시 슬라이딩 윈도우 최적화
위에서 언급 한 슬라이딩 처리에서는 현재 문자열의 HashMap을 재 계산하고 재 매치해야 함을 알 수 있습니다. 이런 식으로 많은 매칭 상황이 낭비됩니다.
따라서 반복되는 계산을 제거하기 위해서는 최적화가 필요하며 , 먼저 문자열을 단어 길이 그룹으로 나누어 별도로 계산해야합니다.
그런 다음 각 그룹은 세부 진행 중에 간격 일치를 나타 내기 위해 동적으로 오른쪽으로 이동하는 두 개의 포인터가 필요합니다. 일반적으로 맵은 매번 새로 고칠 필요가 없으며 재사용 할 수 있습니다. 좌표 j는 시작을 나타내고 인덱스는 현재 끝을 나타냅니다 .
다음과 같은 상황이 발생할 수 있습니다.
- 새 단어가 없으면 j와 index가 해당 단어로 이동하고 다시 시작되며 저장된 동적 맵을 지워야합니다.
- 발견 된 단어가 존재하지만 너무 많습니다. 중복 된 단어가 제거 될 때까지 j를 오른쪽으로 이동하고 동시에 동적 맵을 수정해야합니다.
- 일반적으로 색인과지도는 오버레이 일치를 통해 업데이트됩니다.
위의 단계가 완료된 후 j + len == index이면 일치가 완료되면이 숫자를 추가합니다. 그러나 동시에 다음 단어가 현재 첫 번째 단어와 같은지 판단 할 수 있으며, 같으면 해당 j와 인덱스를 직접 업데이트하여 결과 집합에 추가하지만 동적 맵을 업데이트 할 필요는 없습니다.
위의 최적화 아이디어를 사용하여 코드를 코딩 할 수 있습니다. 구현의 세부 사항, 닫기 전에 열기 등에주의하십시오. 특정 코드는 다음과 같습니다.
public List<Integer> findSubstring(String s, String[] words) {
List<Integer>value=new ArrayList<Integer>();//返回的结果
Map<String, Integer>map=new HashMap<String, Integer>();//统计单词个数
for(String team:words)//进行统计
{
int num=map.getOrDefault(team, 0);
map.put(team, num+1);
}
int wordlen=words[0].length();//单个单词的长度
int len=words[0].length()*words.length;//总长度
for(int i=0;i<wordlen;i++)//分组分别进行
{
int j=i,index=j;
Map<String, Integer>map2=new HashMap<String, Integer>();
while (j<=s.length()-len&&index+wordlen<=s.length()) {
String word=s.substring(index,index+wordlen);
int num=map2.getOrDefault(word, 0);
map2.put(word, num+1);
if(!map.containsKey(word))//不包含该元素,直接跳过
{
j=index+wordlen;
map2.clear();
}
else if(map.get(word)<num+1)//元素存在但次数过多
{
String teamstr="";
while (!(teamstr=s.substring(j,j+wordlen)).equals(word)) {
//找到第一个不相等得
map2.put(teamstr, map2.get(teamstr)-1);
j+=wordlen;
}
map2.put(teamstr, map2.get(teamstr)-1);
j+=wordlen;
}
index+=wordlen;
if(index==j+len)
{
value.add(j);
while (index+wordlen<=s.length()&&s.substring(j, j+wordlen).equals(s.substring(index, index+wordlen))) {
value.add(j+wordlen);
j+=wordlen;index+=wordlen;
}
String teamstr=s.substring(j,j+wordlen);
map2.put(teamstr, map2.get(teamstr)-1);
j+=wordlen;
}
}
}
return value;
}
다음 순열
제목 설명 :
다음 순열을 얻는 기능 을 달성 하기 위해 알고리즘은 주어진 숫자 시퀀스를 사전 식 순서에서 다음으로 큰 순열로 재 배열해야합니다.
다음으로 큰 배열이 없으면 숫자를 가장 작은 배열 (즉, 오름차순)으로 다시 정렬합니다.
현장에서 수정해야하며 여분의 일정한 공간 만 허용됩니다.
다음은 몇 가지 예입니다. 입력은 왼쪽 열에 있고 해당 출력은 오른쪽 열에 있습니다.
1,2,3 → 1,3,2
3,2,1 → 1,2,3
1,1,5 → 1,5,1
분석 :
전체 배열과 비슷하지만 전체 배열은 아닙니다. 다음 사전 순서를 찾아야합니다.
시퀀스를 분석하면 다음 두 가지 법칙을 찾을 수 있습니다.
먼저 첫 번째 양의 순서를 오른쪽에서 왼쪽으로 바꿉니다.
- 예를 들어, 12 34 5 4는 3과 4를 교체하여 12 4 5 3이됩니다.
둘째, 교환 간격 에 따라 오른쪽에서 왼쪽으로 역순으로 쌍을 교환합니다 (이중주기).
- 예를 들어, 위는 12 4 3 5가됩니다.
이를 구현할 때 위치 번호와 같은 문제에주의하십시오. 구체적인 코드는 다음과 같습니다.
public void nextPermutation(int[] nums) {
boolean jud=false;
int i,j=0;
for( i=nums.length-2;i>=0;i--)
{
for( j=nums.length-1;j>i;j--)
{
if(!jud&&nums[i]<nums[j])
{
int team=nums[i];
nums[i]=nums[j];
nums[j]=team;
jud=true;
break;
}
}
if(jud)break;
}
if(jud)
for(int k=nums.length-1;k>i;k--)
{
for(int m=k-1;m>i;m--)
{
if(nums[k]<nums[m])
{
int team=nums[k];
nums[k]=nums[m];
nums[m]=team;
}
}
}
int team;
if(!jud)
for( i=0;i<nums.length/2;i++)
{
team=nums[i];
nums[i]=nums[nums.length-1-i];
nums[nums.length-1-i]=team;
}
}
알겠습니다.이 체크인이 여기에 있습니다. 관심 bigsai
을 기울여 주셔서 감사합니다. 그룹에 응답하여 체크인에 참여하고 bigsai에 응답하여 pdf 리소스 모음을 받으십시오.